diff options
-rw-r--r-- | demux/demux_mkv.c | 37 | ||||
-rw-r--r-- | demux/stheader.h | 5 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 13 |
3 files changed, 55 insertions, 0 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index f6182bd23c..03be67e3de 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -254,6 +254,7 @@ const struct m_sub_options demux_mkv_conf = { static void probe_last_timestamp(struct demuxer *demuxer, int64_t start_pos); static void probe_first_timestamp(struct demuxer *demuxer); +static int read_next_block_into_queue(demuxer_t *demuxer); static void free_block(struct block_info *block); #define AAC_SYNC_EXTENSION_TYPE 0x02b7 @@ -1878,6 +1879,41 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track) return 0; } +static void probe_x264_garbage(demuxer_t *demuxer) +{ + mkv_demuxer_t *mkv_d = demuxer->priv; + + for (int n = 0; n < mkv_d->num_tracks; n++) { + mkv_track_t *track = mkv_d->tracks[n]; + struct sh_stream *sh = track->stream; + + if (!sh || sh->type != STREAM_VIDEO) + continue; + + if (sh->codec->codec && strcmp(sh->codec->codec, "h264") != 0) + continue; + + struct block_info *block = NULL; + + // Find first block for this track. + // Restrict reading number of total packets. (Arbitrary to avoid bloat.) + for (int i = 0; i < 100; i++) { + if (i >= mkv_d->num_blocks && read_next_block_into_queue(demuxer) < 1) + break; + if (mkv_d->blocks[i].track == track) { + block = &mkv_d->blocks[i]; + break; + } + } + + if (!block || block->num_laces < 1) + continue; + + sh->codec->first_packet = new_demux_packet_from_buf(block->laces[0]); + talloc_steal(mkv_d, sh->codec->first_packet); + } +} + static int read_ebml_header(demuxer_t *demuxer) { stream_t *s = demuxer->stream; @@ -2077,6 +2113,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check) probe_first_timestamp(demuxer); if (mkv_d->opts->probe_duration) probe_last_timestamp(demuxer, start_pos); + probe_x264_garbage(demuxer); return 0; } diff --git a/demux/stheader.h b/demux/stheader.h index a0820f55b7..467d0e09a0 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -76,6 +76,11 @@ struct mp_codec_params { // Timestamp granularity for converting double<->rational timestamps. int native_tb_num, native_tb_den; + // Used by an obscure bug workaround mechanism. As an exception to the usual + // rules, demuxers are allowed to set this after adding the sh_stream, but + // only before the demuxer open call returns. + struct demux_packet *first_packet; + // STREAM_AUDIO int samplerate; struct mp_chmap channels; diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 0f31de9f02..79adc311a9 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -666,6 +666,19 @@ static void init_avctx(struct dec_video *vd) if (avcodec_open2(avctx, lavc_codec, NULL) < 0) goto error; + // Sometimes, the first packet contains information required for correct + // decoding of the rest of the stream. The only currently known case is the + // x264 build number (encoded in a SEI element), needed to enable a + // workaround for broken 4:4:4 streams produced by older x264 versions. + if (lavc_codec->id == AV_CODEC_ID_H264 && c->first_packet) { + AVPacket avpkt; + mp_set_av_packet(&avpkt, c->first_packet, &ctx->codec_timebase); + avcodec_send_packet(avctx, &avpkt); + avcodec_receive_frame(avctx, ctx->pic); + av_frame_unref(ctx->pic); + avcodec_flush_buffers(ctx->avctx); + } + return; error: |