Есть ли какие-либо обновления по этому поводу?

тоящее время у меня есть проблема при создании фрагментированного файла MP4 из кода с использованием libavformat. Мой файл может быть воспроизведен с помощью VLC, но не может быть передан (через WebSocket) и воспроизведен (через MediaSource) в (Chrome) браузере. (Я использовалэтот проверить потоковую передачу фрагментированного файла MP4 в браузер через WebSocket).

Примечание. Приведенные ниже файлы кодируются базовым профилем уровня 4. Поэтому вам следует изменить тип MIME (в index.html) на const mimeCodec = 'video / mp4; Кодеки = "avc1.42C028" '; чтобы иметь возможность играть в них.

Я проверил и обнаружил, что мой сгенерированный файл Mp4 немного отличается от файла, созданного с помощьюffmpeg инструмент.

Вот что я сделал:

У меня есть .h264файл

Первый подход, я использую ffmpeg для генерациифрагментированный файл MP4.

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

Созданный файл может воспроизводиться как проигрывателем Quicktime, так и проигрывателем VLC.

Второй подход, я программно генерируюфрагментированный файл Mp4 с использованием libavformat

Сначала я инициализирую контекст,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);

Не могли бы вы, ребята, взглянуть на мой файл, чтобы понять, что не так?

Ответы на вопрос(0)

Ваш ответ на вопрос