ffmepg dav转mp4 cpp示例
时间: 2024-06-09 08:11:12 浏览: 118
以下是一个简单的使用FFmpeg将dav格式转换为mp4格式的CPP示例代码:
```cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
int main(int argc, char *argv[]) {
AVFormatContext *input_ctx = NULL, *output_ctx = NULL;
AVCodecContext *decoder_ctx = NULL, *encoder_ctx = NULL;
AVCodec *decoder = NULL, *encoder = NULL;
AVPacket pkt;
AVFrame *frame = NULL, *encoder_frame = NULL;
int stream_index;
int ret = 0, got_frame = 0;
if (argc != 3) {
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
exit(1);
}
av_register_all();
avcodec_register_all();
avformat_network_init();
// 打开输入文件
if ((ret = avformat_open_input(&input_ctx, argv[1], NULL, NULL)) < 0) {
fprintf(stderr, "Could not open input file '%s'", argv[1]);
goto end;
}
// 查找流信息
if ((ret = avformat_find_stream_info(input_ctx, NULL)) < 0) {
fprintf(stderr, "Could not find stream information");
goto end;
}
// 找到视频流
ret = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
if (ret < 0) {
fprintf(stderr, "Could not find video stream in input file '%s'", argv[1]);
goto end;
}
stream_index = ret;
// 分配解码器上下文
decoder_ctx = avcodec_alloc_context3(decoder);
if (!decoder_ctx) {
fprintf(stderr, "Failed to allocate decoder context");
goto end;
}
// 复制解码器参数
if ((ret = avcodec_parameters_to_context(decoder_ctx, input_ctx->streams[stream_index]->codecpar)) < 0) {
fprintf(stderr, "Failed to copy decoder parameters to context");
goto end;
}
// 打开解码器
if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) {
fprintf(stderr, "Failed to open decoder");
goto end;
}
// 打开输出文件
if ((ret = avformat_alloc_output_context2(&output_ctx, NULL, NULL, argv[2])) < 0) {
fprintf(stderr, "Could not create output context");
goto end;
}
// 找到编码器
encoder = avcodec_find_encoder_by_name("libx264");
if (!encoder) {
fprintf(stderr, "Could not find encoder");
goto end;
}
// 创建输出流
AVStream *output_stream = avformat_new_stream(output_ctx, encoder);
if (!output_stream) {
fprintf(stderr, "Failed to create output stream");
goto end;
}
// 分配编码器上下文
encoder_ctx = avcodec_alloc_context3(encoder);
if (!encoder_ctx) {
fprintf(stderr, "Failed to allocate encoder context");
goto end;
}
// 复制编码器参数
encoder_ctx->codec_id = encoder->id;
encoder_ctx->bit_rate = decoder_ctx->bit_rate;
encoder_ctx->width = decoder_ctx->width;
encoder_ctx->height = decoder_ctx->height;
encoder_ctx->time_base = decoder_ctx->time_base;
encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
if ((output_ctx->oformat->flags & AVFMT_GLOBALHEADER) != 0) {
encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
// 打开编码器
if ((ret = avcodec_open2(encoder_ctx, encoder, NULL)) < 0) {
fprintf(stderr, "Failed to open encoder");
goto end;
}
// 初始化输出文件
if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {
if ((ret = avio_open(&output_ctx->pb, argv[2], AVIO_FLAG_WRITE)) < 0) {
fprintf(stderr, "Could not open output file '%s'", argv[2]);
goto end;
}
}
// 写文件头
if ((ret = avformat_write_header(output_ctx, NULL)) < 0) {
fprintf(stderr, "Error occurred when opening output file");
goto end;
}
// 分配解码帧内存
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Failed to allocate frame");
goto end;
}
// 分配编码帧内存
encoder_frame = av_frame_alloc();
if (!encoder_frame) {
fprintf(stderr, "Failed to allocate encoder frame");
goto end;
}
// 循环读取帧
while (av_read_frame(input_ctx, &pkt) >= 0) {
// 判断是否为视频流
if (pkt.stream_index == stream_index) {
// 发送数据包到解码器
ret = avcodec_send_packet(decoder_ctx, &pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding");
goto end;
}
// 循环解码帧
while (ret >= 0) {
ret = avcodec_receive_frame(decoder_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error during decoding");
goto end;
}
// 将解码后的帧转换为YUV420P格式
SwsContext *sws_ctx = sws_getContext(
decoder_ctx->width, decoder_ctx->height, decoder_ctx->pix_fmt,
encoder_ctx->width, encoder_ctx->height, encoder_ctx->pix_fmt,
SWS_BILINEAR, NULL, NULL, NULL);
if (!sws_ctx) {
fprintf(stderr, "Failed to initialize sws context");
goto end;
}
sws_scale(sws_ctx, frame->data, frame->linesize, 0, decoder_ctx->height, encoder_frame->data, encoder_frame->linesize);
sws_freeContext(sws_ctx);
// 编码帧
ret = avcodec_send_frame(encoder_ctx, encoder_frame);
if (ret < 0) {
fprintf(stderr, "Error sending a frame for encoding");
goto end;
}
while (ret >= 0) {
ret = avcodec_receive_packet(encoder_ctx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error during encoding");
goto end;
}
// 更新时间戳
av_packet_rescale_ts(&pkt, decoder_ctx->time_base, output_stream->time_base);
pkt.stream_index = output_stream->index;
// 写入输出文件
ret = av_interleaved_write_frame(output_ctx, &pkt);
if (ret < 0) {
fprintf(stderr, "Error writing packet to output file");
goto end;
}
}
}
}
// 释放数据包
av_packet_unref(&pkt);
}
// 写文件尾
av_write_trailer(output_ctx);
end:
if (decoder_ctx) {
avcodec_free_context(&decoder_ctx);
}
if (encoder_ctx) {
avcodec_free_context(&encoder_ctx);
}
if (input_ctx) {
avformat_close_input(&input_ctx);
}
if (output_ctx) {
if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {
avio_closep(&output_ctx->pb);
}
avformat_free_context(output_ctx);
}
if (frame) {
av_frame_free(&frame);
}
if (encoder_frame) {
av_frame_free(&encoder_frame);
}
return ret < 0;
}
```
注意:在使用该示例代码之前,需要先安装FFmpeg库,并在编译时链接该库。
阅读全文