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.c1190
1 files changed, 572 insertions, 618 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 4452aa9929..62d8dcac7c 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -73,6 +73,10 @@ static const int cook_fl2bps[COOK_FLAVORS] = {
12016, 16408, 22911, 33506
};
+enum {
+ MAX_NUM_LACES = 256,
+};
+
typedef struct mkv_content_encoding {
uint64_t order, type, scope;
uint64_t comp_algo;
@@ -83,7 +87,7 @@ typedef struct mkv_content_encoding {
typedef struct mkv_track {
int tnum;
char *name;
- int id; // -aid / -sid / -vid option value
+ struct sh_stream *stream;
char *codec_id;
int ms_compat;
@@ -129,12 +133,13 @@ typedef struct mkv_track {
int fix_i_bps;
double qt_last_a_pts;
- int subtitle_type;
-
/* generic content encoding support */
mkv_content_encoding_t *encodings;
int num_encodings;
+ /* latest added index entry for this track */
+ int last_index_entry;
+
/* For VobSubs and SSA/ASS */
sh_sub_t *sh_sub;
} mkv_track_t;
@@ -156,11 +161,11 @@ typedef struct mkv_demuxer {
uint64_t tc_scale, cluster_tc;
uint64_t cluster_start;
- uint64_t cluster_size;
- uint64_t blockgroup_size;
+ uint64_t cluster_end;
mkv_index_t *indexes;
int num_indexes;
+ bool index_complete;
int64_t *parsed_pos;
int num_parsed_pos;
@@ -170,18 +175,9 @@ typedef struct mkv_demuxer {
bool parsed_chapters;
bool parsed_attachments;
- struct cluster_pos {
- uint64_t filepos;
- uint64_t timecode;
- } *cluster_positions;
- int num_cluster_pos;
-
uint64_t skip_to_timecode;
int v_skip_to_keyframe, a_skip_to_keyframe;
bool subtitle_preroll;
-
- int num_audio_tracks;
- int num_video_tracks;
} mkv_demuxer_t;
#define REALHEADER_SIZE 16
@@ -225,36 +221,6 @@ static bool is_parsed_header(struct mkv_demuxer *mkv_d, int64_t pos)
return false;
}
-static mkv_track_t *find_track_by_num(struct mkv_demuxer *d, int n, int type)
-{
- for (int i = 0; i < d->num_tracks; i++)
- if (d->tracks[i] != NULL && d->tracks[i]->type == type)
- if (d->tracks[i]->id == n)
- return d->tracks[i];
-
- return NULL;
-}
-
-static void add_cluster_position(mkv_demuxer_t *mkv_d, uint64_t filepos,
- uint64_t timecode)
-{
- if (mkv_d->indexes)
- return;
-
- int n = mkv_d->num_cluster_pos;
- if (n > 0 && mkv_d->cluster_positions[n-1].filepos >= filepos)
- return;
-
- mkv_d->cluster_positions =
- grow_array(mkv_d->cluster_positions, mkv_d->num_cluster_pos,
- sizeof(*mkv_d->cluster_positions));
- mkv_d->cluster_positions[mkv_d->num_cluster_pos++] = (struct cluster_pos){
- .filepos = filepos,
- .timecode = timecode,
- };
-}
-
-
#define AAC_SYNC_EXTENSION_TYPE 0x02b7
static int aac_get_sample_rate_index(uint32_t sample_rate)
{
@@ -268,27 +234,27 @@ static int aac_get_sample_rate_index(uint32_t sample_rate)
return i;
}
-static void demux_mkv_decode(mkv_track_t *track, uint8_t *src,
- uint8_t **dest, uint32_t *size, uint32_t type)
+static bstr demux_mkv_decode(mkv_track_t *track, bstr data, uint32_t type)
{
+ uint8_t *src = data.start;
uint8_t *orig_src = src;
-
- *dest = src;
+ uint8_t *dest = src;
+ uint32_t size = data.len;
for (int i = 0; i < track->num_encodings; i++) {
struct mkv_content_encoding *enc = track->encodings + i;
if (!(enc->scope & type))
continue;
- if (src != *dest && src != orig_src)
+ if (src != dest && src != orig_src)
talloc_free(src);
- src = *dest; // output from last iteration is new source
+ src = dest; // output from last iteration is new source
if (enc->comp_algo == 0) {
#if CONFIG_ZLIB
/* zlib encoded track */
- if (*size == 0)
+ if (size == 0)
continue;
z_stream zstream;
@@ -302,21 +268,21 @@ static void demux_mkv_decode(mkv_track_t *track, uint8_t *src,
goto error;
}
zstream.next_in = (Bytef *) src;
- zstream.avail_in = *size;
+ zstream.avail_in = size;
- *dest = NULL;
- zstream.avail_out = *size;
+ dest = NULL;
+ zstream.avail_out = size;
int result;
do {
- *size += 4000;
- *dest = talloc_realloc_size(NULL, *dest, *size);
- zstream.next_out = (Bytef *) (*dest + zstream.total_out);
+ size += 4000;
+ dest = talloc_realloc_size(NULL, dest, size);
+ zstream.next_out = (Bytef *) (dest + zstream.total_out);
result = inflate(&zstream, Z_NO_FLUSH);
if (result != Z_OK && result != Z_STREAM_END) {
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
"[mkv] zlib decompression failed.\n");
- talloc_free(*dest);
- *dest = NULL;
+ talloc_free(dest);
+ dest = NULL;
inflateEnd(&zstream);
goto error;
}
@@ -324,46 +290,47 @@ static void demux_mkv_decode(mkv_track_t *track, uint8_t *src,
} while (zstream.avail_out == 4000 && zstream.avail_in != 0
&& result != Z_STREAM_END);
- *size = zstream.total_out;
+ size = zstream.total_out;
inflateEnd(&zstream);
#endif
} else if (enc->comp_algo == 2) {
/* lzo encoded track */
int out_avail;
- int dstlen = *size * 3;
+ int dstlen = size * 3;
- *dest = NULL;
+ dest = NULL;
while (1) {
- int srclen = *size;
- *dest = talloc_realloc_size(NULL, *dest,
- dstlen + AV_LZO_OUTPUT_PADDING);
+ int srclen = size;
+ dest = talloc_realloc_size(NULL, dest,
+ dstlen + AV_LZO_OUTPUT_PADDING);
out_avail = dstlen;
- int result = av_lzo1x_decode(*dest, &out_avail, src, &srclen);
+ int result = av_lzo1x_decode(dest, &out_avail, src, &srclen);
if (result == 0)
break;
if (!(result & AV_LZO_OUTPUT_FULL)) {
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
"[mkv] lzo decompression failed.\n");
- talloc_free(*dest);
- *dest = NULL;
+ talloc_free(dest);
+ dest = NULL;
goto error;
}
mp_msg(MSGT_DEMUX, MSGL_DBG2,
"[mkv] lzo decompression buffer too small.\n");
dstlen *= 2;
}
- *size = dstlen - out_avail;
+ size = dstlen - out_avail;
} else if (enc->comp_algo == 3) {
- *dest = talloc_size(NULL, *size + enc->comp_settings_len);
- memcpy(*dest, enc->comp_settings, enc->comp_settings_len);
- memcpy(*dest + enc->comp_settings_len, src, *size);
- *size += enc->comp_settings_len;
+ dest = talloc_size(NULL, size + enc->comp_settings_len);
+ memcpy(dest, enc->comp_settings, enc->comp_settings_len);
+ memcpy(dest + enc->comp_settings_len, src, size);
+ size += enc->comp_settings_len;
}
}
error:
- if (src != *dest && src != orig_src)
+ if (src != dest && src != orig_src)
talloc_free(src);
+ return (bstr){dest, size};
}
@@ -584,6 +551,7 @@ static void parse_trackentry(struct demuxer *demuxer,
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
struct mkv_track *track = talloc_zero_size(NULL, sizeof(*track));
+ track->last_index_entry = -1;
track->tnum = entry->track_number;
if (track->tnum)
@@ -632,22 +600,12 @@ static void parse_trackentry(struct demuxer *demuxer,
if (!strcmp(track->codec_id, MKV_V_MSCOMP)
|| !strcmp(track->codec_id, MKV_A_ACM))
track->ms_compat = 1;
- else if (!strcmp(track->codec_id, MKV_S_VOBSUB))
- track->subtitle_type = 'v';
- else if (!strcmp(track->codec_id, MKV_S_TEXTSSA)
- || !strcmp(track->codec_id, MKV_S_TEXTASS)
- || !strcmp(track->codec_id, MKV_S_SSA)
- || !strcmp(track->codec_id, MKV_S_ASS))
- track->subtitle_type = 'a';
- else if (!strcmp(track->codec_id, MKV_S_TEXTASCII)
- || !strcmp(track->codec_id, MKV_S_TEXTUTF8))
- track->subtitle_type = 't';
- else if (!strcmp(track->codec_id, MKV_S_PGS))
- track->subtitle_type = 'p';
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Codec ID: %s\n",
track->codec_id);
- } else
+ } else {
mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Missing codec ID!\n");
+ track->codec_id = "";
+ }
if (entry->n_codec_private) {
int len = entry->codec_private.len;
@@ -712,6 +670,38 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer)
return 0;
}
+static void cue_index_add(demuxer_t *demuxer, int track_id, uint64_t filepos,
+ uint64_t timecode)
+{
+ mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
+
+ mkv_d->indexes = grow_array(mkv_d->indexes, mkv_d->num_indexes,
+ sizeof(mkv_index_t));
+ mkv_d->indexes[mkv_d->num_indexes].tnum = track_id;
+ mkv_d->indexes[mkv_d->num_indexes].timecode = timecode;
+ mkv_d->indexes[mkv_d->num_indexes].filepos = filepos;
+ mkv_d->num_indexes++;
+}
+
+static void add_block_position(demuxer_t *demuxer, struct mkv_track *track,
+ uint64_t filepos, uint64_t timecode)
+{
+ mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
+
+ if (mkv_d->index_complete || !track)
+ return;
+ if (track->last_index_entry >= 0) {
+ mkv_index_t *index = &mkv_d->indexes[track->last_index_entry];
+ // filepos is always the cluster position, which can contain multiple
+ // blocks with different timecodes - one is enough.
+ // Also, never add block which are already covered by the index.
+ if (index->filepos == filepos || index->timecode >= timecode)
+ return;
+ }
+ cue_index_add(demuxer, track->tnum, filepos, timecode);
+ track->last_index_entry = mkv_d->num_indexes - 1;
+}
+
static int demux_mkv_read_cues(demuxer_t *demuxer)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
@@ -737,23 +727,18 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
for (int i = 0; i < cuepoint->n_cue_track_positions; i++) {
struct ebml_cue_track_positions *trackpos =
&cuepoint->cue_track_positions[i];
- uint64_t track = trackpos->cue_track;
- uint64_t pos = trackpos->cue_cluster_position;
- mkv_d->indexes =
- grow_array(mkv_d->indexes, mkv_d->num_indexes,
- sizeof(mkv_index_t));
- mkv_d->indexes[mkv_d->num_indexes].tnum = track;
- mkv_d->indexes[mkv_d->num_indexes].timecode = time;
- mkv_d->indexes[mkv_d->num_indexes].filepos =
- mkv_d->segment_start + pos;
+ uint64_t pos = mkv_d->segment_start + trackpos->cue_cluster_position;
+ cue_index_add(demuxer, trackpos->cue_track, pos, time);
mp_msg(MSGT_DEMUX, MSGL_DBG2,
"[mkv] |+ found cue point for track %" PRIu64
- ": timecode %" PRIu64 ", filepos: %" PRIu64 "\n", track,
- time, mkv_d->segment_start + pos);
- mkv_d->num_indexes++;
+ ": timecode %" PRIu64 ", filepos: %" PRIu64 "\n",
+ trackpos->cue_track, time, pos);
}
}
+ // Do not attempt to create index on the fly.
+ mkv_d->index_complete = true;
+
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n");
talloc_free(parse_ctx.talloc_ctx);
return 0;
@@ -1078,77 +1063,40 @@ static int read_header_element(struct demuxer *demuxer, uint32_t id,
-static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
- int vid);
-static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track,
- int aid);
-static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track,
- int sid);
+static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track);
+static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track);
+static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track);
static void display_create_tracks(demuxer_t *demuxer)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
- int i, vid = 0, aid = 0, sid = 0;
- for (i = 0; i < mkv_d->num_tracks; i++) {
+ for (int i = 0; i < mkv_d->num_tracks; i++) {
char *type = "unknown", str[32];
*str = '\0';
switch (mkv_d->tracks[i]->type) {
case MATROSKA_TRACK_VIDEO:
type = "video";
- mkv_d->tracks[i]->id = -1;
- if (vid == MAX_V_STREAMS)
- break;
- mkv_d->tracks[i]->id = vid;
- demux_mkv_open_video(demuxer, mkv_d->tracks[i], vid);
- if (mkv_d->tracks[i]->name)
- mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VID_%d_NAME=%s\n", vid,
- mkv_d->tracks[i]->name);
- sprintf(str, "-vid %u", vid++);
+ demux_mkv_open_video(demuxer, mkv_d->tracks[i]);
break;
case MATROSKA_TRACK_AUDIO:
type = "audio";
- mkv_d->tracks[i]->id = -1;
- if (aid == MAX_A_STREAMS)
- break;
- mkv_d->tracks[i]->id = aid;
- demux_mkv_open_audio(demuxer, mkv_d->tracks[i], aid);
- if (mkv_d->tracks[i]->name)
- mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_NAME=%s\n", aid,
- mkv_d->tracks[i]->name);
- mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", aid,
- mkv_d->tracks[i]->language);
- sprintf(str, "-aid %u, -alang %.5s", aid++,
- mkv_d->tracks[i]->language);
+ demux_mkv_open_audio(demuxer, mkv_d->tracks[i]);
break;
case MATROSKA_TRACK_SUBTITLE:
type = "subtitles";
- mkv_d->tracks[i]->id = -1;
- if (sid == MAX_S_STREAMS)
- break;
- mkv_d->tracks[i]->id = sid;
- demux_mkv_open_sub(demuxer, mkv_d->tracks[i], sid);
- if (mkv_d->tracks[i]->name)
- mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_NAME=%s\n", sid,
- mkv_d->tracks[i]->name);
- mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", sid,
- mkv_d->tracks[i]->language);
- sprintf(str, "-sid %u, -slang %.5s", sid++,
- mkv_d->tracks[i]->language);
+ demux_mkv_open_sub(demuxer, mkv_d->tracks[i]);
break;
}
if (mkv_d->tracks[i]->name)
mp_tmsg(MSGT_DEMUX, MSGL_V,
- "[mkv] Track ID %u: %s (%s) \"%s\", %s\n",
+ "[mkv] Track ID %u: %s (%s) \"%s\"\n",
mkv_d->tracks[i]->tnum, type, mkv_d->tracks[i]->codec_id,
- mkv_d->tracks[i]->name, str);
+ mkv_d->tracks[i]->name);
else
- mp_tmsg(MSGT_DEMUX, MSGL_V, "[mkv] Track ID %u: %s (%s), %s\n",
- mkv_d->tracks[i]->tnum, type, mkv_d->tracks[i]->codec_id,
- str);
+ mp_tmsg(MSGT_DEMUX, MSGL_V, "[mkv] Track ID %u: %s (%s)\n",
+ mkv_d->tracks[i]->tnum, type, mkv_d->tracks[i]->codec_id);
}
- mkv_d->num_audio_tracks = aid;
- mkv_d->num_video_tracks = vid;
}
typedef struct {
@@ -1167,13 +1115,16 @@ static const videocodec_info_t vinfo[] = {
{MKV_V_MPEG4_AVC, mmioFOURCC('a', 'v', 'c', '1'), 1},
{MKV_V_THEORA, mmioFOURCC('t', 'h', 'e', 'o'), 1},
{MKV_V_VP8, mmioFOURCC('V', 'P', '8', '0'), 0},
+ {MKV_V_VP9, mmioFOURCC('V', 'P', '9', '0'), 0},
{NULL, 0, 0}
};
-static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
- int vid)
+static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
{
- BITMAPINFOHEADER *bih;
+ BITMAPINFOHEADER *bih = &(BITMAPINFOHEADER){0};
+ unsigned char *extradata;
+ unsigned int extradata_size = 0;
+ struct sh_stream *sh;
sh_video_t *sh_v;
bool raw = false;
@@ -1185,7 +1136,6 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
return 1;
src = (BITMAPINFOHEADER *) track->private_data;
- bih = calloc(1, track->private_size);
bih->biSize = le2me_32(src->biSize);
bih->biWidth = le2me_32(src->biWidth);
bih->biHeight = le2me_32(src->biHeight);
@@ -1197,16 +1147,14 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
bih->biYPelsPerMeter = le2me_32(src->biYPelsPerMeter);
bih->biClrUsed = le2me_32(src->biClrUsed);
bih->biClrImportant = le2me_32(src->biClrImportant);
- memcpy(bih + 1,
- src + 1,
- track->private_size - sizeof(*bih));
+ extradata = track->private_data + sizeof(*bih);
+ extradata_size = track->private_size - sizeof(*bih);
if (track->v_width == 0)
track->v_width = bih->biWidth;
if (track->v_height == 0)
track->v_height = bih->biHeight;
} else {
- bih = calloc(1, sizeof(*bih));
bih->biSize = sizeof(*bih);
bih->biWidth = track->v_width;
bih->biHeight = track->v_height;
@@ -1218,14 +1166,13 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
|| !strcmp(track->codec_id, MKV_V_REALV20)
|| !strcmp(track->codec_id, MKV_V_REALV30)
|| !strcmp(track->codec_id, MKV_V_REALV40))) {
- unsigned char *dst, *src;
+ unsigned char *src;
uint32_t type2;
unsigned int cnt;
src = (uint8_t *) track->private_data + RVPROPERTIES_SIZE;
cnt = track->private_size - RVPROPERTIES_SIZE;
- bih = realloc(bih, sizeof(*bih) + 8 + cnt);
bih->biSize = 48 + cnt;
bih->biPlanes = 1;
type2 = AV_RB32(src - 4);
@@ -1234,9 +1181,9 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
else
bih->biCompression =
mmioFOURCC('R', 'V', track->codec_id[9], '0');
- dst = (unsigned char *) (bih + 1);
// copy type1 and type2 info from rv properties
- memcpy(dst, src - 8, 8 + cnt);
+ extradata_size = cnt + 8;
+ extradata = src - 8;
track->realmedia = 1;
} else if (strcmp(track->codec_id, MKV_V_UNCOMPRESSED) == 0) {
// raw video, "like AVI" - this is a FourCC
@@ -1250,24 +1197,34 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
if (vi->extradata && track->private_data
&& (track->private_size > 0)) {
bih->biSize += track->private_size;
- bih = realloc(bih, bih->biSize);
- memcpy(bih + 1, track->private_data, track->private_size);
+ extradata = track->private_data;
+ extradata_size = track->private_size;
}
if (!vi->id) {
mp_tmsg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported "
"CodecID (%s) or missing/bad CodecPrivate\n"
"[mkv] data (track %u).\n",
track->codec_id, track->tnum);
- free(bih);
return 1;
}
}
}
- sh_v = new_sh_video(demuxer, vid);
+ sh = new_sh_stream(demuxer, STREAM_VIDEO);
+ if (!sh)
+ return 1;
+ track->stream = sh;
+ sh_v = sh->video;
sh_v->gsh->demuxer_id = track->tnum;
sh_v->gsh->title = talloc_strdup(sh_v, track->name);
- sh_v->bih = bih;
+ sh_v->bih = malloc(sizeof(BITMAPINFOHEADER) + extradata_size);
+ if (!sh_v->bih) {
+ mp_msg(MSGT_DEMUX, MSGL_FATAL, "Memory allocation failure!\n");
+ abort();
+ }
+ *sh_v->bih = *bih;
+ if (extradata_size)
+ memcpy(sh_v->bih + 1, extradata, extradata_size);
sh_v->format = sh_v->bih->biCompression;
if (raw) {
sh_v->gsh->codec = "rawvideo";
@@ -1298,7 +1255,6 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
}
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Aspect: %f\n", sh_v->aspect);
- sh_v->ds = demuxer->video;
return 0;
}
@@ -1339,19 +1295,19 @@ static struct mkv_audio_tag {
};
-static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track,
- int aid)
+static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
{
- sh_audio_t *sh_a = new_sh_audio(demuxer, aid);
- if (!sh_a)
+ struct sh_stream *sh = new_sh_stream(demuxer, STREAM_AUDIO);
+ if (!sh)
return 1;
+ track->stream = sh;
+ sh_audio_t *sh_a = sh->audio;
if (track->language && (strcmp(track->language, "und") != 0))
sh_a->gsh->lang = talloc_strdup(sh_a, track->language);
sh_a->gsh->demuxer_id = track->tnum;
sh_a->gsh->title = talloc_strdup(sh_a, track->name);
sh_a->gsh->default_track = track->default_track;
- sh_a->ds = demuxer->audio;
if (track->ms_compat) {
if (track->private_size < sizeof(*sh_a->wf))
goto error;
@@ -1603,36 +1559,56 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track,
return 1;
}
-static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track,
- int sid)
+static const char *mkv_sub_tag[][2] = {
+ { MKV_S_VOBSUB, "dvd_subtitle" },
+ { MKV_S_TEXTSSA, "ass"},
+ { MKV_S_TEXTASS, "ass"},
+ { MKV_S_SSA, "ass"},
+ { MKV_S_ASS, "ass"},
+ { MKV_S_TEXTASCII, "subrip"},
+ { MKV_S_TEXTUTF8, "subrip"},
+ { MKV_S_PGS, "hdmv_pgs_subtitle"},
+ {0}
+};
+
+static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
{
- if (track->subtitle_type) {
- int size;
- uint8_t *buffer;
- sh_sub_t *sh = new_sh_sub(demuxer, sid);
- sh->gsh->demuxer_id = track->tnum;
- track->sh_sub = sh;
- sh->type = track->subtitle_type;
- size = track->private_size;
- demux_mkv_decode(track, track->private_data, &buffer, &size, 2);
- if (buffer && buffer != track->private_data) {
- talloc_free(track->private_data);
- talloc_steal(track, buffer);
- track->private_data = buffer;
- track->private_size = size;
+ const char *subtitle_type = NULL;
+ for (int n = 0; mkv_sub_tag[n][0]; n++) {
+ if (strcmp(track->codec_id, mkv_sub_tag[n][0]) == 0) {
+ subtitle_type = mkv_sub_tag[n][1];
+ break;
}
- sh->extradata = malloc(track->private_size);
- memcpy(sh->extradata, track->private_data, track->private_size);
- sh->extradata_len = track->private_size;
- if (track->language && (strcmp(track->language, "und") != 0))
- sh->gsh->lang = talloc_strdup(sh, track->language);
- sh->gsh->title = talloc_strdup(sh, track->name);
- sh->gsh->default_track = track->default_track;
- } else {
+ }
+
+ bstr in = (bstr){track->private_data, track->private_size};
+ struct sh_stream *gsh = new_sh_stream(demuxer, STREAM_SUB);
+ if (!gsh)
+ return 1;
+ track->stream = gsh;
+ sh_sub_t *sh = gsh->sub;
+ sh->gsh->demuxer_id = track->tnum;
+ track->sh_sub = sh;
+ sh->gsh->codec = subtitle_type;
+ bstr buffer = demux_mkv_decode(track, in, 2);
+ if (buffer.start && buffer.start != track->private_data) {
+ talloc_free(track->private_data);
+ talloc_steal(track, buffer.start);
+ track->private_data = buffer.start;
+ track->private_size = buffer.len;
+ }
+ sh->extradata = malloc(track->private_size);
+ memcpy(sh->extradata, track->private_data, track->private_size);
+ sh->extradata_len = track->private_size;
+ if (track->language && (strcmp(track->language, "und") != 0))
+ sh->gsh->lang = talloc_strdup(sh, track->language);
+ sh->gsh->title = talloc_strdup(sh, track->name);
+ sh->gsh->default_track = track->default_track;
+
+ if (!subtitle_type) {
mp_tmsg(MSGT_DEMUX, MSGL_ERR,
"[mkv] Subtitle type '%s' is not supported.\n",
track->codec_id);
- return 1;
}
return 0;
@@ -1646,16 +1622,12 @@ static void mkv_free(struct demuxer *demuxer)
for (int i = 0; i < mkv_d->num_tracks; i++)
demux_mkv_free_trackentry(mkv_d->tracks[i]);
free(mkv_d->indexes);
- free(mkv_d->cluster_positions);
}
-static int demux_mkv_open(demuxer_t *demuxer)
+static int read_ebml_header(demuxer_t *demuxer)
{
stream_t *s = demuxer->stream;
- mkv_demuxer_t *mkv_d;
- mkv_track_t *track;
- stream_seek(s, s->start_pos);
if (ebml_read_id(s, NULL) != EBML_ID_EBML)
return 0;
struct ebml_ebml ebml_master = {};
@@ -1691,26 +1663,70 @@ static int demux_mkv_open(demuxer_t *demuxer)
}
talloc_free(parse_ctx.talloc_ctx);
- mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Found the head...\n");
+ return 1;
+}
- if (ebml_read_id(s, NULL) != MATROSKA_ID_SEGMENT) {
- mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] but no segment :(\n");
- return 0;
+static int read_mkv_segment_header(demuxer_t *demuxer)
+{
+ stream_t *s = demuxer->stream;
+ int num_skip = 0;
+ if (demuxer->params)
+ num_skip = demuxer->params->matroska_wanted_segment;
+
+ while (!s->eof) {
+ if (ebml_read_id(s, NULL) != MATROSKA_ID_SEGMENT) {
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] segment not found\n");
+ return 0;
+ }
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n");
+ uint64_t len = ebml_read_length(s, NULL);
+ if (num_skip <= 0)
+ return 1;
+ num_skip--;
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] (skipping)\n");
+ if (len == EBML_UINT_INVALID)
+ break;
+ if (!stream_seek(s, stream_tell(s) + len)) {
+ mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Failed to seek in file\n");
+ return 0;
+ }
+ // Segments are like concatenated Matroska files
+ if (!read_ebml_header(demuxer))
+ return 0;
}
- ebml_read_length(s, NULL); /* return bytes number until EOF */
- mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n");
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] End of file, no further segments.\n");
+ return 0;
+}
+
+static int demux_mkv_open(demuxer_t *demuxer)
+{
+ stream_t *s = demuxer->stream;
+ mkv_demuxer_t *mkv_d;
+
+ stream_seek(s, s->start_pos);
+
+ if (!read_ebml_header(demuxer))
+ return 0;
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Found the head...\n");
+
+ if (!read_mkv_segment_header(demuxer))
+ return 0;
mkv_d = talloc_zero(demuxer, struct mkv_demuxer);
demuxer->priv = mkv_d;
mkv_d->tc_scale = 1000000;
mkv_d->segment_start = stream_tell(s);
+ if (demuxer->params && demuxer->params->matroska_was_valid)
+ *demuxer->params->matroska_was_valid = true;
+
while (1) {
uint32_t id = ebml_read_id(s, NULL);
if (s->eof) {
- mp_tmsg(MSGT_DEMUX, MSGL_ERR, "[mkv] Unexpected end of file\n");
- return 0;
+ mp_tmsg(MSGT_DEMUX, MSGL_WARN,
+ "[mkv] Unexpected end of file (no clusters found)\n");
+ break;
}
if (id == MATROSKA_ID_CLUSTER) {
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ found cluster, headers are "
@@ -1727,42 +1743,6 @@ static int demux_mkv_open(demuxer_t *demuxer)
display_create_tracks(demuxer);
- /* select video track */
- track = NULL;
- if (demuxer->video->id == -1) { /* automatically select a video track */
- /* search for a video track that has the 'default' flag set */
- for (int i = 0; i < mkv_d->num_tracks; i++)
- if (mkv_d->tracks[i]->type == MATROSKA_TRACK_VIDEO
- && mkv_d->tracks[i]->default_track) {
- track = mkv_d->tracks[i];
- break;
- }
-
- if (track == NULL)
- /* no track has the 'default' flag set */
- /* let's take the first video track */
- for (int i = 0; i < mkv_d->num_tracks; i++)
- if (mkv_d->tracks[i]->type == MATROSKA_TRACK_VIDEO
- && mkv_d->tracks[i]->id >= 0) {
- track = mkv_d->tracks[i];
- break;
- }
- } else if (demuxer->video->id != -2) /* -2 = no video at all */
- track = find_track_by_num(mkv_d, demuxer->video->id,
- MATROSKA_TRACK_VIDEO);
-
- if (track && demuxer->v_streams[track->id]) {
- mp_tmsg(MSGT_DEMUX, MSGL_V, "[mkv] Will play video track %u.\n",
- track->tnum);
- demuxer->video->id = track->id;
- demuxer->video->sh = demuxer->v_streams[track->id];
- } else {
- mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[mkv] No video track found/wanted.\n");
- demuxer->video->id = -2;
- }
-
- demuxer->audio->id = -2; // wait for higher-level code to select track
-
if (s->end_pos == 0)
demuxer->seekable = 0;
else {
@@ -1776,97 +1756,91 @@ static int demux_mkv_open(demuxer_t *demuxer)
return DEMUXER_TYPE_MATROSKA;
}
-static int demux_mkv_read_block_lacing(uint8_t *buffer, uint64_t *size,
- uint8_t *laces,
- uint32_t **all_lace_sizes)
+static bool bstr_read_u8(bstr *buffer, uint8_t *out_u8)
+{
+ if (buffer->len > 0) {
+ *out_u8 = buffer->start[0];
+ buffer->len -= 1;
+ buffer->start += 1;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static int demux_mkv_read_block_lacing(bstr *buffer, int *laces,
+ uint32_t lace_size[MAX_NUM_LACES])
{
uint32_t total = 0;
- uint32_t *lace_size = NULL;
- uint8_t flags;
+ uint8_t flags, t;
int i;
- *all_lace_sizes = NULL;
/* lacing flags */
- if (*size < 1)
+ if (!bstr_read_u8(buffer, &flags))
goto error;
- flags = *buffer++;
- (*size)--;
- switch ((flags & 0x06) >> 1) {
- case 0: /* no lacing */
+ int type = (flags >> 1) & 0x03;
+ if (type == 0) { /* no lacing */
*laces = 1;
- lace_size = calloc(*laces, sizeof(uint32_t));
- lace_size[0] = *size;
- break;
-
- case 1: /* xiph lacing */
- case 2: /* fixed-size lacing */
- case 3: /* EBML lacing */
- if (*size < 1)
+ lace_size[0] = buffer->len;
+ } else {
+ if (!bstr_read_u8(buffer, &t))
goto error;
- *laces = *buffer++;
- (*size)--;
- (*laces)++;
- lace_size = calloc(*laces, sizeof(uint32_t));
+ *laces = t + 1;
- switch ((flags & 0x06) >> 1) {
+ switch (type) {
case 1: /* xiph lacing */
for (i = 0; i < *laces - 1; i++) {
lace_size[i] = 0;
do {
- if (!*size)
+ if (!bstr_read_u8(buffer, &t))
goto error;
- lace_size[i] += *buffer;
- (*size)--;
- } while (*buffer++ == 0xFF);
- if (lace_size[i] > *size - total || total > *size)
- goto error;
+ lace_size[i] += t;
+ } while (t == 0xFF);
total += lace_size[i];
}
- lace_size[i] = *size - total;
+ lace_size[i] = buffer->len - total;
break;
case 2: /* fixed-size lacing */
for (i = 0; i < *laces; i++)
- lace_size[i] = *size / *laces;
+ lace_size[i] = buffer->len / *laces;
break;
case 3:; /* EBML lacing */
- int l;
- uint64_t num = ebml_read_vlen_uint(buffer, &l);
+ uint64_t num = ebml_read_vlen_uint(buffer);
if (num == EBML_UINT_INVALID)
goto error;
- buffer += l;
- if (*size < l)
- goto error;
- *size -= l;
- if (num > *size)
+ if (num > buffer->len)
goto error;
total = lace_size[0] = num;
for (i = 1; i < *laces - 1; i++) {
- int64_t snum = ebml_read_vlen_int(buffer, &l);
+ int64_t snum = ebml_read_vlen_int(buffer);
if (snum == EBML_INT_INVALID)
goto error;
- buffer += l;
- if (*size < l)
- goto error;
- *size -= l;
lace_size[i] = lace_size[i - 1] + snum;
- if (lace_size[i] > *size - total || total > *size)
- goto error;
total += lace_size[i];
}
- lace_size[i] = *size - total;
+ lace_size[i] = buffer->len - total;
break;
+
+ default: abort();
}
- break;
}
- *all_lace_sizes = lace_size;
+
+ total = buffer->len;
+ for (i = 0; i < *laces; i++) {
+ if (lace_size[i] > total)
+ goto error;
+ total -= lace_size[i];
+ }
+ if (total != 0)
+ goto error;
+
return 0;
error:
- free(lace_size);
mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Bad input [lacing]\n");
return 1;
}
@@ -1879,9 +1853,9 @@ static double real_fix_timestamp(unsigned char *buf, unsigned int timestamp, uns
unsigned char *s = buf + 1 + (*buf+1)*8;
uint32_t buffer= (s[0]<<24) + (s[1]<<16) + (s[2]<<8) + s[3];
unsigned int kf=timestamp;
- int pict_type;
if(format==mmioFOURCC('R','V','3','0') || format==mmioFOURCC('R','V','4','0')){
+ int pict_type;
if(format==mmioFOURCC('R','V','3','0')){
SKIP_BITS(3);
pict_type= SH