summaryrefslogtreecommitdiffstats
path: root/demux/demux_mkv.c
diff options
context:
space:
mode:
Diffstat (limited to 'demux/demux_mkv.c')
-rw-r--r--demux/demux_mkv.c152
1 files changed, 84 insertions, 68 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index a11691b317..024f7e7e6e 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -41,13 +41,14 @@
#include <zlib.h>
#endif
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "common/av_common.h"
#include "options/options.h"
#include "options/m_option.h"
#include "misc/bstr.h"
#include "stream/stream.h"
#include "video/csputils.h"
+#include "video/mp_image.h"
#include "demux.h"
#include "stheader.h"
#include "ebml.h"
@@ -201,15 +202,19 @@ typedef struct mkv_demuxer {
struct demux_mkv_opts {
int subtitle_preroll;
double subtitle_preroll_secs;
+ double subtitle_preroll_secs_index;
int probe_duration;
int probe_start_time;
};
const struct m_sub_options demux_mkv_conf = {
.opts = (const m_option_t[]) {
- OPT_FLAG("subtitle-preroll", subtitle_preroll, 0),
+ OPT_CHOICE("subtitle-preroll", subtitle_preroll, 0,
+ ({"no", 0}, {"yes", 1}, {"index", 2})),
OPT_DOUBLE("subtitle-preroll-secs", subtitle_preroll_secs,
M_OPT_MIN, .min = 0),
+ OPT_DOUBLE("subtitle-preroll-secs-index", subtitle_preroll_secs_index,
+ M_OPT_MIN, .min = 0),
OPT_CHOICE("probe-video-duration", probe_duration, 0,
({"no", 0}, {"yes", 1}, {"full", 2})),
OPT_FLAG("probe-start-time", probe_start_time, 0),
@@ -217,7 +222,9 @@ const struct m_sub_options demux_mkv_conf = {
},
.size = sizeof(struct demux_mkv_opts),
.defaults = &(const struct demux_mkv_opts){
+ .subtitle_preroll = 2,
.subtitle_preroll_secs = 1.0,
+ .subtitle_preroll_secs_index = 10.0,
.probe_start_time = 1,
},
};
@@ -1192,11 +1199,9 @@ static void add_coverart(struct demuxer *demuxer)
const char *codec = mp_map_mimetype_to_video_codec(att->type);
if (!codec)
continue;
- struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO);
- if (!sh)
- break;
+ struct sh_stream *sh = demux_alloc_sh_stream(STREAM_VIDEO);
sh->demuxer_id = -1 - sh->index; // don't clash with mkv IDs
- sh->codec = codec;
+ sh->codec->codec = codec;
sh->attached_picture = new_demux_packet_from(att->data, att->data_size);
if (sh->attached_picture) {
sh->attached_picture->pts = 0;
@@ -1204,6 +1209,7 @@ static void add_coverart(struct demuxer *demuxer)
sh->attached_picture->keyframe = true;
}
sh->title = att->name;
+ demux_add_sh_stream(demuxer, sh);
}
}
@@ -1265,18 +1271,16 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
{
unsigned char *extradata = NULL;
unsigned int extradata_size = 0;
- struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO);
- if (!sh)
- return 1;
+ struct sh_stream *sh = demux_alloc_sh_stream(STREAM_VIDEO);
init_track(demuxer, track, sh);
- sh_video_t *sh_v = sh->video;
+ struct mp_codec_params *sh_v = sh->codec;
sh_v->bits_per_coded_sample = 24;
if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC")) { /* AVI compatibility mode */
// The private_data contains a BITMAPINFOHEADER struct
if (track->private_data == NULL || track->private_size < 40)
- return 1;
+ goto done;
unsigned char *h = track->private_data;
if (track->v_width == 0)
@@ -1284,11 +1288,11 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
if (track->v_height == 0)
track->v_height = AV_RL32(h + 8); // biHeight
sh_v->bits_per_coded_sample = AV_RL16(h + 14); // biBitCount
- sh->codec_tag = AV_RL32(h + 16); // biCompression
+ sh_v->codec_tag = AV_RL32(h + 16); // biCompression
extradata = track->private_data + 40;
extradata_size = track->private_size - 40;
- mp_set_codec_from_tag(sh);
+ mp_set_codec_from_tag(sh_v);
sh_v->avi_dts = true;
} else if (track->private_size >= RVPROPERTIES_SIZE
&& (!strcmp(track->codec_id, "V_REAL/RV10")
@@ -1304,10 +1308,10 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
cnt = track->private_size - RVPROPERTIES_SIZE;
uint32_t t2 = AV_RB32(src - 4);
switch (t2 == 0x10003000 || t2 == 0x10003001 ? '1' : track->codec_id[9]) {
- case '1': sh->codec = "rv10"; break;
- case '2': sh->codec = "rv20"; break;
- case '3': sh->codec = "rv30"; break;
- case '4': sh->codec = "rv40"; break;
+ case '1': sh_v->codec = "rv10"; break;
+ case '2': sh_v->codec = "rv20"; break;
+ case '3': sh_v->codec = "rv30"; break;
+ case '4': sh_v->codec = "rv40"; break;
}
// copy type1 and type2 info from rv properties
extradata_size = cnt + 8;
@@ -1316,8 +1320,8 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
track->parse_timebase = 1e3;
} else if (strcmp(track->codec_id, "V_UNCOMPRESSED") == 0) {
// raw video, "like AVI" - this is a FourCC
- sh->codec_tag = track->colorspace;
- sh->codec = "rawvideo";
+ sh_v->codec_tag = track->colorspace;
+ sh_v->codec = "rawvideo";
} else if (strcmp(track->codec_id, "V_QUICKTIME") == 0) {
uint32_t fourcc1 = 0, fourcc2 = 0;
if (track->private_size >= 8) {
@@ -1327,14 +1331,14 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
if (fourcc1 == MP_FOURCC('S', 'V', 'Q', '3') ||
fourcc2 == MP_FOURCC('S', 'V', 'Q', '3'))
{
- sh->codec = "svq3";
+ sh_v->codec = "svq3";
extradata = track->private_data;
extradata_size = track->private_size;
}
} else {
for (int i = 0; mkv_video_tags[i][0]; i++) {
if (!strcmp(mkv_video_tags[i][0], track->codec_id)) {
- sh->codec = mkv_video_tags[i][1];
+ sh_v->codec = mkv_video_tags[i][1];
break;
}
}
@@ -1344,22 +1348,22 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
}
}
- const char *codec = sh->codec ? sh->codec : "";
+ const char *codec = sh_v->codec ? sh_v->codec : "";
if (!strcmp(codec, "vp9")) {
track->parse = true;
track->parse_timebase = 1e9;
} else if (!strcmp(codec, "mjpeg")) {
- sh->codec_tag = MP_FOURCC('m', 'j', 'p', 'g');
+ sh_v->codec_tag = MP_FOURCC('m', 'j', 'p', 'g');
}
if (extradata_size > 0x1000000) {
MP_WARN(demuxer, "Invalid CodecPrivate\n");
- return 1;
+ goto done;
}
- sh->extradata = talloc_memdup(sh_v, extradata, extradata_size);
- sh->extradata_size = extradata_size;
- if (!sh->codec) {
+ sh_v->extradata = talloc_memdup(sh_v, extradata, extradata_size);
+ sh_v->extradata_size = extradata_size;
+ if (!sh_v->codec) {
MP_WARN(demuxer, "Unknown/unsupported CodecID (%s) or missing/bad "
"CodecPrivate data (track %u).\n",
track->codec_id, track->tnum);
@@ -1367,12 +1371,19 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
sh_v->fps = track->v_frate;
sh_v->disp_w = track->v_width;
sh_v->disp_h = track->v_height;
- uint32_t dw = track->v_dwidth_set ? track->v_dwidth : track->v_width;
- uint32_t dh = track->v_dheight_set ? track->v_dheight : track->v_height;
- sh_v->aspect = (dw && dh) ? (double) dw / dh : 0;
- MP_VERBOSE(demuxer, "Aspect: %f\n", sh_v->aspect);
+
+ int dw = track->v_dwidth_set ? track->v_dwidth : track->v_width;
+ int dh = track->v_dheight_set ? track->v_dheight : track->v_height;
+ struct mp_image_params p = {.w = track->v_width, .h = track->v_height};
+ mp_image_params_set_dsize(&p, dw, dh);
+ sh_v->par_w = p.p_w;
+ sh_v->par_h = p.p_h;
+
sh_v->stereo_mode = track->stereo_mode;
+done:
+ demux_add_sh_stream(demuxer, sh);
+
return 0;
}
@@ -1464,11 +1475,9 @@ static const char *const mkv_audio_tags[][2] = {
static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
{
- struct sh_stream *sh = new_sh_stream(demuxer, STREAM_AUDIO);
- if (!sh)
- return 1;
+ struct sh_stream *sh = demux_alloc_sh_stream(STREAM_AUDIO);
init_track(demuxer, track, sh);
- sh_audio_t *sh_a = sh->audio;
+ struct mp_codec_params *sh_a = sh->codec;
if (track->private_size > 0x1000000)
goto error;
@@ -1483,7 +1492,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
for (int i = 0; mkv_audio_tags[i][0]; i++) {
if (!strcmp(mkv_audio_tags[i][0], track->codec_id)) {
- sh->codec = mkv_audio_tags[i][1];
+ sh_a->codec = mkv_audio_tags[i][1];
break;
}
}
@@ -1494,7 +1503,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
goto error;
MP_VERBOSE(demuxer, "track with MS compat audio.\n");
unsigned char *h = track->private_data;
- sh->codec_tag = AV_RL16(h + 0); // wFormatTag
+ sh_a->codec_tag = AV_RL16(h + 0); // wFormatTag
if (track->a_channels == 0)
track->a_channels = AV_RL16(h + 2); // nChannels
if (sh_a->samplerate == 0)
@@ -1506,15 +1515,15 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
extradata = track->private_data + 18;
extradata_len = track->private_size - 18;
sh_a->bits_per_coded_sample = track->a_bps;
- mp_set_codec_from_tag(sh);
+ mp_set_codec_from_tag(sh_a);
} else if (!strcmp(track->codec_id, "A_PCM/INT/LIT")) {
bool sign = sh_a->bits_per_coded_sample > 8;
- mp_set_pcm_codec(sh, sign, false, sh_a->bits_per_coded_sample, false);
+ mp_set_pcm_codec(sh_a, sign, false, sh_a->bits_per_coded_sample, false);
} else if (!strcmp(track->codec_id, "A_PCM/INT/BIG")) {
bool sign = sh_a->bits_per_coded_sample > 8;
- mp_set_pcm_codec(sh, sign, false, sh_a->bits_per_coded_sample, true);
+ mp_set_pcm_codec(sh_a, sign, false, sh_a->bits_per_coded_sample, true);
} else if (!strcmp(track->codec_id, "A_PCM/FLOAT/IEEE")) {
- sh->codec = sh_a->bits_per_coded_sample == 64 ? "pcm_f64le" : "pcm_f32le";
+ sh_a->codec = sh_a->bits_per_coded_sample == 64 ? "pcm_f64le" : "pcm_f32le";
} else if (!strncmp(track->codec_id, "A_REAL/", 7)) {
if (track->private_size < RAPROPERTIES4_SIZE)
goto error;
@@ -1554,29 +1563,29 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
extradata = src + offset;
if (!strcmp(track->codec_id, "A_REAL/ATRC")) {
- sh->codec = "atrac3";
+ sh_a->codec = "atrac3";
if (flavor >= MP_ARRAY_SIZE(atrc_fl2bps))
goto error;
sh_a->bitrate = atrc_fl2bps[flavor] * 8;
sh_a->block_align = track->sub_packet_size;
} else if (!strcmp(track->codec_id, "A_REAL/COOK")) {
- sh->codec = "cook";
+ sh_a->codec = "cook";
if (flavor >= MP_ARRAY_SIZE(cook_fl2bps))
goto error;
sh_a->bitrate = cook_fl2bps[flavor] * 8;
sh_a->block_align = track->sub_packet_size;
} else if (!strcmp(track->codec_id, "A_REAL/SIPR")) {
- sh->codec = "sipr";
+ sh_a->codec = "sipr";
if (flavor >= MP_ARRAY_SIZE(sipr_fl2bps))
goto error;
sh_a->bitrate = sipr_fl2bps[flavor] * 8;
sh_a->block_align = track->coded_framesize;
} else if (!strcmp(track->codec_id, "A_REAL/28_8")) {
- sh->codec = "ra_288";
+ sh_a->codec = "ra_288";
sh_a->bitrate = 3600 * 8;
sh_a->block_align = track->coded_framesize;
} else if (!strcmp(track->codec_id, "A_REAL/DNET")) {
- sh->codec = "ac3";
+ sh_a->codec = "ac3";
} else {
goto error;
}
@@ -1586,7 +1595,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
track->audio_timestamp =
talloc_array(track, double, track->sub_packet_h);
} else if (!strncmp(track->codec_id, "A_AAC/", 6)) {
- sh->codec = "aac";
+ sh_a->codec = "aac";
/* Recreate the 'private data' (not needed for plain A_AAC) */
int srate_idx = aac_get_sample_rate_index(track->a_sfreq);
@@ -1618,17 +1627,17 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
track->default_duration = 1024.0 / sh_a->samplerate;
}
} else if (!strncmp(track->codec_id, "A_AC3/", 6)) {
- sh->codec = "ac3";
+ sh_a->codec = "ac3";
} else if (!strncmp(track->codec_id, "A_EAC3/", 7)) {
- sh->codec = "eac3";
+ sh_a->codec = "eac3";
}
- if (!sh->codec)
+ if (!sh_a->codec)
goto error;
mp_chmap_set_unknown(&sh_a->channels, track->a_channels);
- const char *codec = sh->codec;
+ const char *codec = sh_a->codec;
if (!strcmp(codec, "mp3") || !strcmp(codec, "truehd")) {
track->parse = true;
} else if (!strcmp(codec, "flac")) {
@@ -1672,8 +1681,10 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
if (sh_a->samplerate == 8000 && strcmp(codec, "ac3") == 0)
track->default_duration = 0;
- sh->extradata = extradata;
- sh->extradata_size = extradata_len;
+ sh_a->extradata = extradata;
+ sh_a->extradata_size = extradata_len;
+
+ demux_add_sh_stream(demuxer, sh);
return 0;
@@ -1681,6 +1692,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
MP_WARN(demuxer, "Unknown/unsupported audio "
"codec ID '%s' for track %u or missing/faulty\n"
"private codec data.\n", track->codec_id, track->tnum);
+ demux_add_sh_stream(demuxer, sh); // add it anyway
return 1;
}
@@ -1712,12 +1724,10 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
if (track->private_size > 0x10000000)
return 1;
- struct sh_stream *sh = new_sh_stream(demuxer, STREAM_SUB);
- if (!sh)
- return 1;
+ struct sh_stream *sh = demux_alloc_sh_stream(STREAM_SUB);
init_track(demuxer, track, sh);
- sh->codec = subtitle_type;
+ sh->codec->codec = subtitle_type;
bstr in = (bstr){track->private_data, track->private_size};
bstr buffer = demux_mkv_decode(demuxer->log, track, in, 2);
if (buffer.start && buffer.start != track->private_data) {
@@ -1726,8 +1736,10 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
track->private_data = buffer.start;
track->private_size = buffer.len;
}
- sh->extradata = track->private_data;
- sh->extradata_size = track->private_size;
+ sh->codec->extradata = track->private_data;
+ sh->codec->extradata_size = track->private_size;
+
+ demux_add_sh_stream(demuxer, sh);
if (!subtitle_type)
MP_ERR(demuxer, "Subtitle type '%s' is not supported.\n", track->codec_id);
@@ -2015,7 +2027,7 @@ static bool handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
if (!track->audio_buf || !track->audio_timestamp || !track->stream)
return false;
- const char *codec = track->stream->codec ? track->stream->codec : "";
+ const char *codec = track->stream->codec->codec ? track->stream->codec->codec : "";
if (!strcmp(codec, "ra_288")) {
for (int x = 0; x < sph / 2; x++) {
uint64_t dst_offset = x * 2 * w + spc * (uint64_t)cfs;
@@ -2075,7 +2087,7 @@ static bool handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
if (++(track->sub_packet_cnt) == sph) {
track->sub_packet_cnt = 0;
// apk_usize has same range as coded_framesize in worst case
- uint32_t apk_usize = track->stream->audio->block_align;
+ uint32_t apk_usize = track->stream->codec->block_align;
if (apk_usize > audiobuf_size)
goto error;
// Release all the audio packets
@@ -2210,7 +2222,7 @@ static void mkv_parse_and_add_packet(demuxer_t *demuxer, mkv_track_t *track,
if (stream->type == STREAM_AUDIO && handle_realaudio(demuxer, track, dp))
return;
- if (stream->codec && strcmp(stream->codec, "wavpack") == 0) {
+ if (strcmp(stream->codec->codec, "wavpack") == 0) {
int size = dp->len;
uint8_t *parsed;
if (libav_parse_wavpack(track, dp->buffer, &parsed, &size) >= 0) {
@@ -2224,7 +2236,7 @@ static void mkv_parse_and_add_packet(demuxer_t *demuxer, mkv_track_t *track,
}
}
- if (stream->codec && strcmp(stream->codec, "prores") == 0) {
+ if (strcmp(stream->codec->codec, "prores") == 0) {
size_t newlen = dp->len + 8;
struct demux_packet *new = new_demux_packet(newlen);
if (new) {
@@ -2239,7 +2251,7 @@ static void mkv_parse_and_add_packet(demuxer_t *demuxer, mkv_track_t *track,
}
if (track->parse && !track->av_parser) {
- int id = mp_codec_to_av_codec_id(track->stream->codec);
+ int id = mp_codec_to_av_codec_id(track->stream->codec->codec);
const AVCodec *codec = avcodec_find_decoder(id);
track->av_parser = av_parser_init(id);
if (codec)
@@ -2435,7 +2447,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
* packets resulting from parsing. */
if (i == 0 || track->default_duration)
dp->pts = mkv_d->last_pts + i * track->default_duration;
- if (stream->video && stream->video->avi_dts)
+ if (stream->codec->avi_dts)
MPSWAP(double, dp->pts, dp->dts);
if (i == 0)
dp->duration = block_duration / 1e9;
@@ -2597,7 +2609,7 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
}
// For the sake of robustness, consider even unknown level 1
// elements the same as unknown/broken IDs.
- if (!ebml_is_mkv_level1_id(id) ||
+ if ((!ebml_is_mkv_level1_id(id) && id != EBML_ID_VOID) ||
ebml_read_skip(demuxer->log, -1, s) != 0)
{
ebml_resync_cluster(demuxer->log, s);
@@ -2718,6 +2730,8 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
// Find the cluster with the highest filepos, that has a timestamp
// still lower than min_tc.
double secs = opts->demux_mkv->subtitle_preroll_secs;
+ if (mkv_d->index_has_durations)
+ secs = MPMAX(secs, opts->demux_mkv->subtitle_preroll_secs_index);
uint64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale);
uint64_t min_tc = pre < index->timecode ? index->timecode - pre : 0;
uint64_t prev_target = 0;
@@ -2780,8 +2794,10 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags)
int cueflags = (flags & SEEK_BACKWARD) ? FLAG_BACKWARD : 0;
mkv_d->subtitle_preroll = NUM_SUB_PREROLL_PACKETS;
- if (((flags & SEEK_HR) || demuxer->opts->demux_mkv->subtitle_preroll) &&
- st_active[STREAM_SUB] && st_active[STREAM_VIDEO])
+ int preroll_opt = demuxer->opts->demux_mkv->subtitle_preroll;
+ if (((flags & SEEK_HR) || preroll_opt == 1 ||
+ (preroll_opt == 2 && mkv_d->index_has_durations))
+ && st_active[STREAM_SUB] && st_active[STREAM_VIDEO])
cueflags |= FLAG_SUBPREROLL;
// Adjust the target a little bit to catch cases where the target position