<div dir="ltr"><div class="gmail_quote"><div dir="ltr">Dear all,<div><br></div><div><div>Currently I have a problem when generating fragmented MP4 file from code using libavformat. My file can be played using VLC, but can't be streamed (via WebSocket) and played (via MediaSource) in (Chrome) browser. (I used [this](<a href="https://github.com/codeaholicguy/mediasource-over-websocket" target="_blank">https://github.com/<wbr>codeaholicguy/mediasource-<wbr>over-websocket</a>) to test streaming fragmented MP4 file to browser via WebSocket).</div><div><br></div><div>Note: The files below is encoded by Baseline profile, level 4. So you should change the MIME type (in index.html) to const mimeCodec = 'video/mp4; codecs="avc1.42C028"'; to be able to play them.</div><div><br></div><div>I checked and found that my generated Mp4 file is a bit different with the file generated by using `ffmpeg` tool. </div><div><br></div><div>Here's what I've done:</div><div>  </div><div> I have a .h264 [file](<a href="https://drive.google.com/open?id=0B34Y_mnzP99cMVlPMGpPQ2xfdmM" target="_blank">https://drive.google.<wbr>com/open?id=0B34Y_<wbr>mnzP99cMVlPMGpPQ2xfdmM</a>)</div><div><br></div><div> 1. The first approach, I use ffmpeg to generate the [fragmented MP4 file](<a href="https://drive.google.com/open?id=0B34Y_mnzP99cT21lWlV2VlpjOVU" target="_blank">https://drive.google.<wbr>com/open?id=0B34Y_<wbr>mnzP99cT21lWlV2VlpjOVU</a>).</div><div><br></div><div>        ffmpeg -i temp.h264 -vcodec copy -f mp4 -movflags empty_moov+default_base_moof+<wbr>frag_keyframe ffmpeg.mp4</div><div><br></div><div>    The generated file can be played by both Quicktime player and VLC player, and also can be streamed to web browser.</div><div><br></div><div> 2. The second approach, I programmaticaly generate the [fragmented Mp4 file by using libavformat](<a href="https://drive.google.com/open?id=0B34Y_mnzP99cZHVRZjRmbmNoU0U" target="_blank">https://drive.<wbr>google.com/open?id=0B34Y_<wbr>mnzP99cZHVRZjRmbmNoU0U</a>)</div><div><br></div><div>    First I initialize the context, the `codec` in code is the `AVCodecContext*` of the input stream</div><div><br></div><div>         av_register_all();</div><div>         avcodec_register_all();</div><div>         int ret;</div><div>         AVOutputFormat* fmt = av_guess_format("mp4", 0, 0);</div><div>         if(!fmt) {</div><div>           return;</div><div>         }</div><div><br></div><div>         AVFormatContext* ctx = avformat_alloc_context();</div><div>         // Create AVIO context to capture generated Mp4 contain</div><div>         uint8_t *avio_ctx_buffer = NULL;</div><div>         size_t avio_ctx_buffer_size = 50000;</div><div>         IOOutput buffer = {};</div><div>         const size_t bd_buf_size = 50000;</div><div>         avio_ctx_buffer = (uint8_t*)av_malloc(avio_ctx_<wbr>buffer_size);</div><div>         buffer.buff = (uint8_t*)av_malloc(bd_buf_<wbr>size);</div><div><br></div><div>         buffer.size = bd_buf_size;</div><div>         AVIOContext* ioCtx = avio_alloc_context(avio_ctx_<wbr>buffer, (int)avio_ctx_buffer_size, 1, &buffer, NULL, MP4Formatter::onWritePacket, NULL);</div><div><br></div><div>         ctx->oformat = fmt;</div><div>         if (ctx->oformat->flags & AVFMT_GLOBALHEADER)</div><div>           ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;</div><div>         ctx->pb = ioCtx;</div><div>         av_opt_set(ctx, "movflags", "frag_keyframe+empty_moov+<wbr>default_base_moof", 0);</div><div><br></div><div>         AVStream* st = avformat_new_stream(ctx, codec->codec);</div><div>         if (!st) {</div><div>           return;</div><div>         }</div><div><br></div><div>         st->id = (ctx->nb_streams - 1);</div><div>         avcodec_parameters_from_<wbr>context(st->codecpar, codec);</div><div>         st->time_base = codec->time_base;</div><div>         ioCtx->seekable = false;</div><div><br></div><div>    Second I implement the onWritePacket callback</div><div>         </div><div>         int MP4Formatter::onWritePacket(<wbr>void *opaque, uint8_t* buf, int buf_size) {</div><div>           file.write((char*)buf, buf_size);</div><div>         }</div><div><br></div><div>    Third, on every packet from h264 file, I write it using `av_interleaved_write_frame`</div><div><br></div><div>         if (firstFrame) {</div><div>           AVDictionary *opts = NULL;</div><div>           av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+<wbr>default_base_moof", 0);</div><div>           if(!parseSPSPPS(data, length)) {</div><div>             return;</div><div>           }</div><div>           cout << "spslen " << spslen << " ppslen " << ppslen << endl;</div><div>           auto c = st->codecpar;</div><div>           // Extradata contains PPS & SPS for AVCC format</div><div>           int extradata_len = 8 + spslen + 1 + 2 + ppslen;</div><div>           c->extradata = (uint8_t*)av_mallocz(<wbr>extradata_len);</div><div>           c->extradata_size = extradata_len;</div><div>           c->extradata[0] = 0x01;</div><div>           c->extradata[1] = sps[1];</div><div>           c->extradata[2] = sps[2];</div><div>           c->extradata[3] = sps[3];</div><div>           c->extradata[4] = 0xFC | 3;</div><div>           c->extradata[5] = 0xE0 | 1;</div><div>           int tmp = spslen;</div><div>           c->extradata[6] = (tmp >> 8) & 0x00ff;</div><div>           c->extradata[7] = tmp & 0x00ff;</div><div>           int i = 0;</div><div>           for (i=0; i<tmp; i++) {</div><div>             c->extradata[8 + i] = sps[i];</div><div>           }</div><div>           c->extradata[8 + tmp] = 0x01;</div><div>           int tmp2 = ppslen;</div><div>           c->extradata[8 + tmp + 1] = (tmp2 >> 8) & 0x00ff;</div><div>           c->extradata[8 + tmp + 2] = tmp2 & 0x00ff;</div><div>           for (i=0; i<tmp2; i++) {</div><div>             c->extradata[8 + tmp + 3 + i] = pps[i];</div><div>           }</div><div>           int ret = avformat_write_header(ctx, &opts);</div><div>           if(ret < 0) {</div><div>             return;</div><div>           }</div><div>           firstFrame = false;</div><div>         }</div><div>         AVPacket pkt;</div><div>         av_init_packet(&pkt);</div><div>         pkt.buf = av_buffer_alloc(length);</div><div>         memcpy(pkt.buf->data, data, length);</div><div>         pkt.buf->size = length;</div><div>         pkt.data = pkt.buf->data;</div><div>         pkt.size = pkt.buf->size;</div><div>         pkt.pts = ts;</div><div>         pkt.dts = ts;</div><div>    </div><div>         if (keyFrame) {</div><div>           pkt.flags |= AV_PKT_FLAG_KEY;</div><div>         }</div><div>         else {</div><div>           pkt.flags = 0;</div><div>         }</div><div><br></div><div>         pkt.stream_index = st->id;</div><div><br></div><div>         av_interleaved_write_frame(<wbr>ctx, &pkt);</div><div>         av_buffer_unref(&pkt.buf);</div><div>         av_packet_unref(&pkt);</div><div><br></div><div>Can you guys take a look at my file to see what's wrong?</div><div><br clear="all"><div><div class="m_6011919050790591664gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><img src="https://docs.google.com/uc?export=download&id=0B34Y_mnzP99caFVsQW1xT2czaGc&revid=0B34Y_mnzP99cWmdiUTZOMU5HL055RTdtNC90TzRpOWFpeFpvPQ"><br></div></div></div></div></div><div><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><br><div><font color="#999999" face="courier new, monospace"><span style="color:rgb(19,79,92)"><a href="mailto:nguyencatdinhgl@gmail.com" target="_blank"><img src="https://docs.google.com/uc?export=download&id=0B34Y_mnzP99cWkY0bWNXQ0dXNk0&revid=0B34Y_mnzP99cdC84bHYxMzRXalJNd2xWUlJoa21LckZuN3hrPQ"></a> <a href="mailto:nguyencatdinh@yahoo.com" target="_blank"><img src="https://docs.google.com/uc?export=download&id=0B34Y_mnzP99cX3dFQTFLeTZpSWc&revid=0B34Y_mnzP99cNEZrb1hUTTUzaDRRZG9tMXQxbzI1bTZDVC9jPQ"></a> <a href="http://is.gd/71k8Yn" target="_blank"><img src="https://docs.google.com/uc?export=download&id=0B34Y_mnzP99cb09PZ1V2bGxpMlU&revid=0B34Y_mnzP99cREdQN2VEalhmaTJLM0VQQzhkdUliWnR0WHFjPQ"></a><span></span><span></span><a href="http:///" target="_blank"></a> <a href="https://www.facebook.com/catdinh.nguyen" target="_blank"><img src="https://docs.google.com/uc?export=download&id=0B34Y_mnzP99cUTBrNEhBaWFNZzQ&revid=0B34Y_mnzP99ceXJpeGdzbWhLZmswb01qN3pLZHM1aUFmclBrPQ"></a> <a href="https://vn.linkedin.com/in/nguyencatdinh" target="_blank"><img src="https://docs.google.com/uc?export=download&id=0B34Y_mnzP99cTmRpS2JLa3RKV1k&revid=0B34Y_mnzP99cWEZvU2ZxcHh0UEZQek1xN0pOREZKUUdwQWtBPQ"></a></span></font></div></div></div></div></div></div></div></div></div></div></div></div>
</div></div></div>
</div><br></div>