c++ ffmpeg mp4 转 ts
时间: 2024-10-24 21:18:22 浏览: 25
在C++中利用FFmpeg库来转换MP4为TS(Transport Stream)文件,可以编写一个简单的命令行调用程序。这里我们不直接提供完整的C++代码,因为FFmpeg通常作为命令行工具使用,但在C++中可以通过`system()`函数执行外部命令。
首先,确保你的项目包含了FFmpeg的编译链接。以下是如何通过`system()`函数调用FFmpeg命令的例子:
```cpp
#include <cstdlib>
int main() {
std::string command = "ffmpeg -i input.mp4 -codec copy -bsf:a aac_adtstoasc -f mpegts output.ts";
// 注意替换input.mp4和output.ts为你实际的输入和输出文件路径
std::system(command.c_str());
return 0;
}
```
这段代码会运行FFmpeg命令,将`input.mp4`转换为TS格式并保存为`output.ts`。`-codec copy`选项用于保留原始编码,`-bsf:a aac_adtstoasc`确保音频编码适配TS格式,`-f mpegts`指定输出格式为TS。
相关问题
C++ffmpeg视频编码
以下是使用C++和FFmpeg进行视频编码的基本步骤:
1.导入FFmpeg库并初始化:
```c++
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
int main(int argc, char* argv[]) {
av_register_all();
avcodec_register_all();
avformat_network_init();
return 0;
}
```
2.打开输入文件并获取输入格式:
```c++
AVFormatContext* inputFormatContext = NULL;
if (avformat_open_input(&inputFormatContext, inputFileName, NULL, NULL) != 0) {
std::cout << "Could not open input file " << inputFileName << std::endl;
return -1;
}
if (avformat_find_stream_info(inputFormatContext, NULL) < 0) {
std::cout << "Could not find stream information" << std::endl;
return -1;
}
```
3.查找视频流并获取编解码器:
```c++
AVCodec* codec = NULL;
int videoStreamIndex = -1;
for (int i = 0; i < inputFormatContext->nb_streams; i++) {
if (inputFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
codec = avcodec_find_decoder(inputFormatContext->streams[i]->codecpar->codec_id);
if (codec == NULL) {
std::cout << "Unsupported codec!" << std::endl;
return -1;
}
break;
}
}
if (videoStreamIndex == -1) {
std::cout << "Could not find video stream!" << std::endl;
return -1;
}
AVCodecContext* codecContext = avcodec_alloc_context3(codec);
if (codecContext == NULL) {
std::cout << "Could not allocate codec context!" << std::endl;
return -1;
}
if (avcodec_parameters_to_context(codecContext, inputFormatContext->streams[videoStreamIndex]->codecpar) < 0) {
std::cout << "Could not copy codec parameters to codec context!" << std::endl;
return -1;
}
if (avcodec_open2(codecContext, codec, NULL) < 0) {
std::cout << "Could not open codec!" << std::endl;
return -1;
}
```
4.创建输出文件并获取输出格式:
```c++
AVFormatContext* outputFormatContext = NULL;
if (avformat_alloc_output_context2(&outputFormatContext, NULL, NULL, outputFileName) < 0) {
std::cout << "Could not allocate output format context!" << std::endl;
return -1;
}
AVOutputFormat* outputFormat = outputFormatContext->oformat;
if (outputFormat->video_codec == AV_CODEC_ID_NONE) {
std::cout << "Could not find suitable video codec!" << std::endl;
return -1;
}
AVStream* outputStream = avformat_new_stream(outputFormatContext, NULL);
if (outputStream == NULL) {
std::cout << "Could not allocate output stream!" << std::endl;
return -1;
}
AVCodecContext* outputCodecContext = avcodec_alloc_context3(NULL);
if (outputCodecContext == NULL) {
std::cout << "Could not allocate output codec context!" << std::endl;
return -1;
}
outputCodecContext->codec_id = outputFormat->video_codec;
outputCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
outputCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
outputCodecContext->width = codecContext->width;
outputCodecContext->height = codecContext->height;
outputCodecContext->time_base = codecContext->time_base;
outputCodecContext->bit_rate = 400000;
outputCodecContext->gop_size = 10;
outputCodecContext->max_b_frames = 1;
if (outputFormatContext->oformat->flags & AVFMT_GLOBALHEADER) {
outputCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
if (avcodec_open2(outputCodecContext, NULL, NULL) < 0) {
std::cout << "Could not open output codec!" << std::endl;
return -1;
}
if (avcodec_parameters_from_context(outputStream->codecpar, outputCodecContext) < 0) {
std::cout << "Could not copy codec parameters to output stream!" << std::endl;
return -1;
}
```
5.创建SwsContext并分配缓冲区:
```c++
SwsContext* swsContext = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt, outputCodecContext->width, outputCodecContext->height, outputCodecContext->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
if (swsContext == NULL) {
std::cout << "Could not create SwsContext!" << std::endl;
return -1;
}
AVFrame* inputFrame = av_frame_alloc();
if (inputFrame == NULL) {
std::cout << "Could not allocate input frame!" << std::endl;
return -1;
}
AVFrame* outputFrame = av_frame_alloc();
if (outputFrame == NULL) {
std::cout << "Could not allocate output frame!" << std::endl;
return -1;
}
outputFrame->format = outputCodecContext->pix_fmt;
outputFrame->width = outputCodecContext->width;
outputFrame->height = outputCodecContext->height;
if (av_frame_get_buffer(outputFrame, 32) < 0) {
std::cout << "Could not allocate output frame buffer!" << std::endl;
return -1;
}
```
6.读取输入文件并编码输出文件:
```c++
AVPacket packet;
av_init_packet(&packet);
packet.data = NULL;
packet.size = 0;
while (av_read_frame(inputFormatContext, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
if (avcodec_send_packet(codecContext, &packet) < 0) {
std::cout << "Error sending a packet for decoding!" << std::endl;
break;
}
while (avcodec_receive_frame(codecContext, inputFrame) == 0) {
sws_scale(swsContext, inputFrame->data, inputFrame->linesize, 0, codecContext->height, outputFrame->data, outputFrame->linesize);
outputFrame->pts = av_rescale_q(inputFrame->pts, codecContext->time_base, outputCodecContext->time_base);
if (avcodec_send_frame(outputCodecContext, outputFrame) < 0) {
std::cout << "Error sending a frame for encoding!" << std::endl;
break;
}
while (avcodec_receive_packet(outputCodecContext, &packet) == 0) {
av_packet_rescale_ts(&packet, outputCodecContext->time_base, outputStream->time_base);
packet.stream_index = outputStream->index;
if (av_interleaved_write_frame(outputFormatContext, &packet) < 0) {
std::cout << "Error while writing output packet!" << std::endl;
break;
}
av_packet_unref(&packet);
}
}
}
av_packet_unref(&packet);
}
```
7.释放资源:
```c++
avformat_close_input(&inputFormatContext);
avformat_free_context(inputFormatContext);
avcodec_free_context(&codecContext);
avformat_free_context(outputFormatContext);
avcodec_free_context(&outputCodecContext);
av_frame_free(&inputFrame);
av_frame_free(&outputFrame);
sws_freeContext(swsContext);
```
c++ ffmpeg进行rtsp 推流
在 C++ 中使用 FFmpeg 进行 RTSP 推流,主要需要以下步骤:
1. 初始化 FFmpeg 库:调用 av_register_all() 函数注册 FFmpeg 库中的所有可用文件格式和编解码器。
2. 打开输入流:调用 avformat_open_input() 函数打开 RTSP 输入流,获取输入流的相关信息。
3. 查找视频流:调用 avformat_find_stream_info() 函数查找视频流的相关信息。
4. 查找编码器:调用 avcodec_find_encoder() 函数查找编码器,以便将视频流编码为指定格式。
5. 创建输出格式上下文:调用 avformat_alloc_output_context2() 函数创建输出格式上下文。
6. 添加视频流:调用 avformat_new_stream() 函数创建一个新的视频流。
7. 打开输出流:调用 avio_open2() 函数打开输出流。
8. 写文件头:调用 avformat_write_header() 函数将输出格式上下文中的头部信息写入输出流中。
9. 循环读取视频帧:调用 av_read_frame() 函数循环读取视频帧。
10. 编码视频帧:调用 avcodec_encode_video2() 函数将读取的视频帧编码为指定格式。
11. 写入编码后的帧数据:调用 av_write_frame() 函数将编码后的帧数据写入输出流中。
12. 写文件尾:调用 av_write_trailer() 函数将输出格式上下文的尾部信息写入输出流中。
13. 释放资源:释放所有资源。
以下是一个简单的示例代码:
```C++
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <unistd.h>
extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <libavutil/error.h>
}
#define RTSP_URL "rtsp://localhost:8554/test.sdp" // RTSP 输入地址
#define OUTPUT_URL "rtmp://localhost:1935/live/test" // RTMP 输出地址
int main(int argc, char *argv[])
{
av_register_all(); // 注册所有可用文件格式和编解码器
AVFormatContext *ifmt_ctx = NULL;
int ret = 0;
// 打开 RTSP 输入流
if ((ret = avformat_open_input(&ifmt_ctx, RTSP_URL, NULL, NULL)) < 0)
{
std::cerr << "Could not open input stream " << RTSP_URL << std::endl;
return ret;
}
// 查找视频流信息
if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0)
{
std::cerr << "Could not find stream information" << std::endl;
return ret;
}
AVCodecContext *codec_ctx = NULL;
AVCodec *codec = NULL;
// 查找 H.264 编码器
codec = avcodec_find_encoder_by_name("libx264");
if (!codec)
{
std::cerr << "Could not find h264 encoder" << std::endl;
return AVERROR(EINVAL);
}
// 创建编码器上下文
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx)
{
std::cerr << "Could not allocate codec context" << std::endl;
return AVERROR(ENOMEM);
}
// 设置编码器参数
codec_ctx->codec_id = codec->id;
codec_ctx->bit_rate = 400000;
codec_ctx->width = 640;
codec_ctx->height = 480;
codec_ctx->time_base = {1, 25};
codec_ctx->gop_size = 10;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
// 打开编码器
if ((ret = avcodec_open2(codec_ctx, codec, NULL)) < 0)
{
std::cerr << "Could not open codec" << std::endl;
return ret;
}
AVFormatContext *ofmt_ctx = NULL;
AVOutputFormat *ofmt = NULL;
// 创建输出格式上下文
avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", OUTPUT_URL);
ofmt = ofmt_ctx->oformat;
// 添加视频流
AVStream *out_stream = avformat_new_stream(ofmt_ctx, NULL);
out_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
out_stream->codecpar->codec_id = codec_ctx->codec_id;
out_stream->codecpar->bit_rate = codec_ctx->bit_rate;
out_stream->codecpar->width = codec_ctx->width;
out_stream->codecpar->height = codec_ctx->height;
avcodec_parameters_from_context(out_stream->codecpar, codec_ctx);
// 打开输出流
if (!(ofmt->flags & AVFMT_NOFILE))
{
if ((ret = avio_open2(&ofmt_ctx->pb, OUTPUT_URL, AVIO_FLAG_WRITE, NULL, NULL)) < 0)
{
std::cerr << "Could not open output URL " << OUTPUT_URL << std::endl;
return ret;
}
}
// 写文件头
if ((ret = avformat_write_header(ofmt_ctx, NULL)) < 0)
{
std::cerr << "Error writing header" << std::endl;
return ret;
}
int video_stream_index = 0;
AVPacket pkt = {0};
// 循环读取视频帧
while (true)
{
if ((ret = av_read_frame(ifmt_ctx, &pkt)) < 0)
{
break;
}
if (pkt.stream_index == video_stream_index)
{
// 编码视频帧
if ((ret = avcodec_send_packet(codec_ctx, &pkt)) < 0)
{
std::cerr << "Error sending packet to encoder" << std::endl;
break;
}
// 写入编码后的帧数据
while (ret >= 0)
{
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
std::cerr << "Error receiving frame from encoder" << std::endl;
goto end;
}
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
// 将编码后的帧数据写入输出流
if ((ret = avcodec_send_frame(codec_ctx, frame)) < 0)
{
std::cerr << "Error sending frame to encoder" << std::endl;
goto end;
}
while (ret >= 0)
{
ret = avcodec_receive_packet(codec_ctx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
std::cerr << "Error receiving packet from encoder" << std::endl;
goto end;
}
av_packet_rescale_ts(&pkt, codec_ctx->time_base, out_stream->time_base);
pkt.stream_index = video_stream_index;
if ((ret = av_write_frame(ofmt_ctx, &pkt)) < 0)
{
std::cerr << "Error writing packet to output stream" << std::endl;
goto end;
}
}
av_packet_unref(&pkt);
}
}
av_packet_unref(&pkt);
}
// 写文件尾
av_write_trailer(ofmt_ctx);
end:
// 释放资源
avcodec_free_context(&codec_ctx);
avformat_close_input(&ifmt_ctx);
avformat_free_context(ofmt_ctx);
return 0;
}
```
需要注意的是,该示例代码并未完全测试,仅供参考,具体实现还需要根据实际情况进行调整。同时,需要注意 FFmpeg 的版本问题,不同版本的 API 可能存在差异。
阅读全文