当前位置: 首页 > 知识库问答 >
问题:

将AVPackets复用到mp4文件中

西门奇希
2023-03-14

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

我的工具能够接收实时流,也能够用Boost::Serialization缓冲AVPackets。此外,我能够加载缓冲的AVPackets。

但是,当我尝试用加载的AVPackets创建/MUX视频文件(mp4)时,mp4文件或mp4头出现错误。我可以创建一个MP4文件,也可以用av_interleaved_write_frame()将数据包写入该文件。MP4文件也有一个合理的大小。这样就可以看出AVPackets被写到了文件中。

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

我想原因是AVFormatContext没有正确初始化,但是用FFMPEG/LIBAV(muxing-examples)的例子,我不能解决这个问题。

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

谢谢你的帮助。奥尔根

    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。有人能解决我的问题吗?

共有1个答案

淳于升
2023-03-14

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

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);

 类似资料:
  • 以下是从mp4文件中提取内容和元数据的程序 - import java.io.File; import java.io.FileInputStream; import java.io.IOException; import org.apache.tika.exception.TikaException; import org.apache.tika.metadata.Metadata; impor

  • 问题内容: 此代码有什么问题? 我在项目中有一个Raw文件(mp4视频文件), 当我这样做时,然后我从SDcard文件获取的文件不相同,因此无法加载视频:( 您是否有另一种自动将原始文件复制到的方法sdcard? 谢谢 问题答案: 如果使用InputStream进行读取,请使用OutputStream进行写入,即BufferedOutputStream包装的FileOutputStream。另外,

  • 我想将文件salesjan2009.csv(存储在本地文件系统中,~/input/salesjan2009.csv)复制到HDFS(Hadoop分布式文件系统)主目录中 我编写了这段代码hduser@ubuntu:/usr/local/hadoop$hdfs dfs-copyfromlocal'/home/hduser/desktop/input/salesjan2009.csv'/hdfs-pa

  • 问题内容: 我正在尝试使用PHP读取mp4文件,而我现在正在做的是: 但是通过这种方式,我无法跳过甚至返回,直到视频未100%加载。当然,当我直接从文件(video.mp4)中读取内容时,一切都会顺利进行。 谢谢。 问题答案: 您需要自己在PHP中实现跳过功能。这是一个代码片段,可以完成此操作。 更高的性能 请注意,这不是最有效的方法,因为整个文件都需要通过PHP进行处理,因此您只需要尝试如何进行

  • 我有一个路由,期望各种文件将被复制到一个传入文件夹。路由将继续将这些文件移动到一个临时文件夹中,并在其中执行其他操作。路线如下: 问题是这些文件可能相当大。假设是1GB。为了将这个文件复制到传入文件夹中,可能需要10秒的时间。在这10秒期间,使用者轮询目录,并抛出一个异常,因为部分文件仍在复制。我能用什么变通办法?

  • 我正在寻找一个命令ffmpeg,它保存活的输入(rtmp或hls)到hls m3u8与mp4段文件。我知道这是可能的,即有infohttps://bitmovin.com/hls-news-wwdc-2016/,但我尝试的每个命令都生成ts文件。有人知道解决办法吗?