Diferente entre archivos mp4 fragmentados generados por ffmpeg y por código

Actualmente tengo un problema al generar un archivo MP4 fragmentado a partir de código usando libavformat. Mi archivo se puede reproducir usando VLC, pero no se puede transmitir (a través de WebSocket) y reproducir (a través de MediaSource) en el navegador (Chrome). (Solíaesta para probar la transmisión de archivos MP4 fragmentados al navegador a través de WebSocket).

Nota: Los archivos a continuación están codificados por el perfil de línea de base, nivel 4. Por lo tanto, debe cambiar el tipo MIME (en index.html) a const mimeCodec = 'video / mp4; códecs = "avc1.42C028" '; para poder jugarlos.

Verifiqué y descubrí que mi archivo Mp4 generado es un poco diferente con el archivo generado al usarffmpeg herramienta.

Esto es lo que he hecho:

Tengo un .h264archivo

El primer enfoque, uso ffmpeg para generar elarchivo MP4 fragmentado.

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

El archivo generado puede ser reproducido tanto por el reproductor Quicktime como por el reproductor VLC

El segundo enfoque, genero programáticamentearchivo Mp4 fragmentado utilizando libavformat

Primero inicializo el contexto, elcodec en código es elAVCodecContext* de la secuencia de entrada

 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;

Segundo, implemento la devolución de llamada onWritePacket

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

Tercero, en cada paquete del archivo h264, lo escribo usandoav_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);

¿Pueden echar un vistazo a mi archivo para ver qué pasa?

Respuestas a la pregunta(0)

Su respuesta a la pregunta