项目中需要将编码器编码出的H264数据保存为avi格式文件。使用ffmpeg接口进行实现。
ffmpeg一般是直接打开本地视频文件(如avi、mp4等)或者网络视频流(如:rtmp流媒体等),只需要直接将本地视频文件名或者流媒体的URL作为avformat_open_input的参数即可。但是这次的项目中,则需要直接将编码器编码出的H264流保存为avi文件。原本准备参考雷神的《ffmpeg 从内存中读取数据(或将数据输出到内存)》,但是这样对现有的程序结构改动比较大,因此考虑更为直接的方式,跳过avformat_open_input过程:
#include "libavformat/avformat.h"
int main(int argc, char **argv)
{
int ret;
char buf[] = "";
AVOutputFormat *ofmt_ctx = NULL;
AVStream *out_stream = NULL;
AVPacket pkt = { 0 };
av_register_all();
av_log_set_level(AV_LOG_DEBUG); /* allocate the output media context */
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);
if (!ofmt_ctx) {
printf("Could not deduce output format from file extension: using AVI.\n");
avformat_alloc_output_context2(&ofmt_ctx, NULL, "avi", filename);
}
if(!ofmt_ctx) {
goto exit;
}
out_stream = avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream) {
printf( "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN; goto exit;
}
AVCodecContext *avctx = out_stream->codec;
avctx->codec_type = AVMEDIA_TYPE_VIDEO; /*此处,需指定编码后的H264数据的分辨率、帧率及码率*/
avctx->codec_id = AV_CODEC_ID_H264;
avctx->bit_rate = 2000000;
avctx->width = 640;
avctx->height = 480;
avctx->time_base.num = 1;
avctx->time_base.den = 30; /* print output stream information*/
av_dump_format(ofmt_ctx, 0, filename, 1);
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0) {
printf( "Could not open output file '%s'\n", filename); goto exit;
}
printf("Open output file success!\n");
}
//写文件头(Write file header)
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
printf( "write avi file header failed\n");
goto exit;
}
printf("Write avi header success!\n");
while(...) {
av_init_packet(&pkt);
// get a video frame(从编码器获取一帧编码后的H264数据) ...
// determine whether the I frame
if (/* I frame */) {
// 判断该H264帧是否为I帧
pkt.flags |= AV_PKT_FLAG_KEY;
} else { /* p frame*/
pkt.flags = 0;
}
pkt.dts = pkt.pts = AV_NOPTS_VALUE;
pkt.size = size; /*帧大小*/
pkt.data = data; /*帧数据*/
if(!pkt.data) {
printf("no data\n");
}
//写入(Write)
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0) {
av_strerror(ret, buf, 1024);
}
av_packet_unref(&pkt);
}
av_write_trailer(ofmt_ctx);
exit: /* close output */
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
return 0;
}
上面的代码只贴出了创建ffmpeg输入流、创建并保存数据到AVI文件的部分程序,方式已验证,能正常录制avi并使用VLC等进行播放。若是想保存为MP4文件,则还需另外写入extradata,否则会出现VLC能播放,但其它播放器无法播放,或播放帧率不对的问题。
---------------------
作者:wb8933
来源:CSDN
原文:https://blog.csdn.net/WB8933/article/details/76791798