summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demux/demux_mkv.c37
-rw-r--r--demux/stheader.h5
-rw-r--r--video/decode/vd_lavc.c13
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: