繁体   English   中英

将AVPackux复用到mp4文件中

[英]Muxing AVPackets into mp4 file

我正在开发一个工具,它从网络接收h.264直播流(发送方是硬件编码器),缓冲最后x分钟并创建最后x分钟的视频文件(如果触发)。

我的工具能够接收实时流,并通过boost :: serialization缓冲AVPackets。 此外,我能够加载缓冲的AVPackets。

但是当我尝试使用加载的AVPacket创建/ mux视频文件(mp4)时,mp4文件或mp4-header中出现错误。 我能够创建一个mp4文件,并使用av_interleaved_write_frame()将数据包写入该文件。 mp4文件的大小也是合理的。 所以它将AVPackets写入文件。

但是当我尝试用像vlc这样的播放器打开mp4文件时,视频无法播放。 播放器提供如下错误:标题不正确且不播放任何帧。 但我用writeHeader()函数将标头写入AVFormatContext。

我想原因是AVFormatContext未正确初始化,但以ffmpeg / libav(muxing-examples)为例我无法解决问题。

有没有一个解决方案(示例代码)或其他示例如何正确初始化AVFormatContext?

谢谢你的帮助。 Olgen

    avcodec_init();
    avcodec_register_all();
    av_register_all();
    av_log_set_level(AV_LOG_DEBUG);

    char *outputFilename = "/tmp/output.mp4";

    // define AVOutputFormat
    AVOutputFormat *outputFormat = NULL;
    outputFormat = av_guess_format("mp4", NULL, NULL);
    if (!outputFormat) {
        fprintf(stderr, "Could not find suitable output format\n");
        return 1;
    }

    // define AVFormatContext
    AVFormatContext *formatContext = NULL;
    // lallocate the output media context
    std::cout << "alloc" << std::endl;
    formatContext = avformat_alloc_context();
//  avformat_alloc_output_context(&formatContext, outputFormat, NULL, NULL);
    if (!formatContext) {
        fprintf(stderr, "Memory error\n");
        return 1;
    }
    std::cout << "stream" << std::endl;
    AVStream * video_st = av_new_stream(formatContext, 0);
    AVCodec * codec = NULL;
    avcodec_get_context_defaults3(video_st->codec, codec);
    video_st->codec->coder_type = AVMEDIA_TYPE_VIDEO;

    video_st->codec->flags = fc->streams[0]->codec->flags;
    video_st->codec->sample_aspect_ratio = fc->streams[0]->codec->sample_aspect_ratio;
    video_st->disposition = fc->streams[0]->disposition;
    video_st->codec->codec_tag = fc->streams[0]->codec->codec_tag;
    video_st->codec->bits_per_raw_sample = fc->streams[0]->codec->bits_per_raw_sample;
    video_st->codec->chroma_sample_location = fc->streams[0]->codec->chroma_sample_location;
    video_st->codec->codec_id = fc->streams[0]->codec->codec_id;
    video_st->codec->codec_tag = fc->streams[0]->codec->codec_tag;
    video_st->codec->time_base = fc->streams[0]->codec->time_base;
    video_st->codec->extradata = fc->streams[0]->codec->extradata;
    video_st->codec->extradata_size = fc->streams[0]->codec->extradata_size;
    video_st->codec->pix_fmt = fc->streams[0]->codec->pix_fmt;
    video_st->codec->width = fc->streams[0]->codec->width;
    video_st->codec->height = fc->streams[0]->codec->height;
    video_st->codec->sample_aspect_ratio = fc->streams[0]->codec->sample_aspect_ratio;


    std::cout << "file" << std::endl;
    avio_open(&formatContext->pb, outputFilename, AVIO_FLAG_WRITE);
    std::cout << "header" << std::endl;
    avformat_write_header(formatContext, NULL);
//  av_write_header(formatContext);

// loop to write AVPackets with av_write_frame

程序在具有内存错误的avformat_write_header(formatContext,NULL)之后崩溃。 我也试过avformat_alloc_output_context()而不是avformat_alloc_output_context2(),但这两个函数都不起作用。 所以我使用了avformat_alloc_context()(见上文)

我认为存在分配问题,但为什么我不能使用avformat_alloc_output_context2或avformat_alloc_output_context。 有人可以在这里找出我的问题吗?

这是一个通用方案,显示如何从现有数据包中复用视频文件

AVOutputFormat * outFmt = av_guess_format("mp4", NULL, NULL);
AVFormatContext *outFmtCtx = NULL;
avformat_alloc_output_context2(&outFmtCtx, outFmt, NULL, NULL);
AVStream * outStrm = av_new_stream(outFmtCtx, 0);

AVCodec * codec = NULL;
avcodec_get_context_defaults3(outStrm->codec, codec);
outStrm->codec->coder_type = AVMEDIA_TYPE_VIDEO;

///....
/// set some required value, such as
/// outStrm->codec->flags
/// outStrm->codec->sample_aspect_ratio
/// outStrm->disposition
/// outStrm->codec->codec_tag
/// outStrm->codec->bits_per_raw_sample
/// outStrm->codec->chroma_sample_location
/// outStrm->codec->codec_id
/// outStrm->codec->codec_tag
/// outStrm->codec->time_base
/// outStrm->codec->extradata 
/// outStrm->codec->extradata_size
/// outStrm->codec->pix_fmt
/// outStrm->codec->width
/// outStrm->codec->height
/// outStrm->codec->sample_aspect_ratio
/// see ffmpeg.c for details  

avio_open(&outFmtCtx->pb, outputFileName, AVIO_FLAG_WRITE);

avformat_write_header(outFmtCtx, NULL);

for (...)
{
av_write_frame(outFmtCtx, &pkt);
}

av_write_trailer(outFmtCtx);
avio_close(outFmtCtx->pb);
avformat_free_context(outFmtCtx);

对于故障排除,设置详细日志记录非常有用: av_log_set_level(AV_LOG_DEBUG);

可能不是这种情况,但avformat_write_header函数应该用于在AVOutputFormat.write_header编写头而不是函数指针

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM