繁体   English   中英

ffmpeg和代码生成的碎片化mp4文件的区别

[英]Different between fragmented mp4 files generated by ffmpeg and by code

目前,我在使用 libavformat 从代码生成碎片 MP4 文件时遇到问题。 我的文件可以使用 VLC 播放,但不能在 (Chrome) 浏览器中流式传输(通过 WebSocket)和播放(通过 MediaSource)。 (我用来测试通过 WebSocket 将碎片化的 MP4 文件流式传输到浏览器)。

注意:以下文件由 Baseline 配置文件,级别 4 编码。因此您应该将 MIME 类型(在 index.html 中)更改为 const mimeCodec = 'video/mp4; 编解码器="avc1.42C028"'; 能够播放它们。

查了一下,发现我生成的Mp4文件和使用ffmpeg工具生成的文件有点不同。

这是我所做的:

我有一个 .h264 文件

  1. 第一种方法,我使用ffmpeg生成 碎片化的MP4文件

     ffmpeg -i temp.h264 -vcodec copy -f mp4 -movflags empty_moov+default_base_moof+frag_keyframe ffmpeg.mp4

    生成的文件可以被 Quicktime 播放器和 VLC 播放器播放

  2. 第二种方法,我 使用libavformat以编程方式生成 碎片化的Mp4文件

    第一I初始化上下文中, codec中的代码是AVCodecContext*输入流的

     av_register_all(); avcodec_register_all(); int ret; AVOutputFormat* fmt = av_guess_format("mp4", 0, 0); if(!fmt) { return; } AVFormatContext* ctx = avformat_alloc_context(); // Create AVIO context to capture generated Mp4 contain uint8_t *avio_ctx_buffer = NULL; size_t avio_ctx_buffer_size = 50000; IOOutput buffer = {}; const size_t bd_buf_size = 50000; avio_ctx_buffer = (uint8_t*)av_malloc(avio_ctx_buffer_size); buffer.buff = (uint8_t*)av_malloc(bd_buf_size); buffer.size = bd_buf_size; AVIOContext* ioCtx = avio_alloc_context(avio_ctx_buffer, (int)avio_ctx_buffer_size, 1, &buffer, NULL, MP4Formatter::onWritePacket, NULL); ctx->oformat = fmt; if (ctx->oformat->flags & AVFMT_GLOBALHEADER) ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; ctx->pb = ioCtx; av_opt_set(ctx, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0); AVStream* st = avformat_new_stream(ctx, codec->codec); if (!st) { return; } st->id = (ctx->nb_streams - 1); avcodec_parameters_from_context(st->codecpar, codec); st->time_base = codec->time_base; ioCtx->seekable = false;

    其次我实现了 onWritePacket 回调

     int MP4Formatter::onWritePacket(void *opaque, uint8_t* buf, int buf_size) { file.write((char*)buf, buf_size); }

    第三,在来自 h264 文件的每个数据包上,我使用av_interleaved_write_frame编写它

     if (firstFrame) { AVDictionary *opts = NULL; av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0); if(!parseSPSPPS(data, length)) { return; } cout << "spslen " << spslen << " ppslen " << ppslen << endl; auto c = st->codecpar; // Extradata contains PPS & SPS for AVCC format int extradata_len = 8 + spslen + 1 + 2 + ppslen; c->extradata = (uint8_t*)av_mallocz(extradata_len); c->extradata_size = extradata_len; c->extradata[0] = 0x01; c->extradata[1] = sps[1]; c->extradata[2] = sps[2]; c->extradata[3] = sps[3]; c->extradata[4] = 0xFC | 3; c->extradata[5] = 0xE0 | 1; int tmp = spslen; c->extradata[6] = (tmp >> 8) & 0x00ff; c->extradata[7] = tmp & 0x00ff; int i = 0; for (i=0; i<tmp; i++) { c->extradata[8 + i] = sps[i]; } c->extradata[8 + tmp] = 0x01; int tmp2 = ppslen; c->extradata[8 + tmp + 1] = (tmp2 >> 8) & 0x00ff; c->extradata[8 + tmp + 2] = tmp2 & 0x00ff; for (i=0; i<tmp2; i++) { c->extradata[8 + tmp + 3 + i] = pps[i]; } int ret = avformat_write_header(ctx, &opts); if(ret < 0) { return; } firstFrame = false; } AVPacket pkt; av_init_packet(&pkt); pkt.buf = av_buffer_alloc(length); memcpy(pkt.buf->data, data, length); pkt.buf->size = length; pkt.data = pkt.buf->data; pkt.size = pkt.buf->size; pkt.pts = ts; pkt.dts = ts; if (keyFrame) { pkt.flags |= AV_PKT_FLAG_KEY; } else { pkt.flags = 0; } pkt.stream_index = st->id; av_interleaved_write_frame(ctx, &pkt); av_buffer_unref(&pkt.buf); av_packet_unref(&pkt);

你们可以看看我的文件,看看有什么问题吗?

也许你可以试试这个:

AVDictionary* opts = NULL;
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);

进而:

avformat_write_header(formatContext, &opts);

作为这个问题如何以编程方式生成碎片化的 mp4 文件

暂无
暂无

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

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