diff options
Diffstat (limited to 'demux/demux_mkv.c')
-rw-r--r-- | demux/demux_mkv.c | 1246 |
1 files changed, 625 insertions, 621 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index a769aac127..86c17ea9a8 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -26,6 +26,7 @@ #include <ctype.h> #include <inttypes.h> #include <stdbool.h> +#include <assert.h> #include <libavutil/common.h> #include <libavutil/lzo.h> @@ -72,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; @@ -82,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; @@ -91,6 +96,7 @@ typedef struct mkv_track { int type; uint32_t v_width, v_height, v_dwidth, v_dheight; + bool v_dwidth_set, v_dheight_set; double v_frate; uint32_t colorspace; @@ -127,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; @@ -154,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; @@ -168,17 +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; - - int num_audio_tracks; - int num_video_tracks; + bool subtitle_preroll; } mkv_demuxer_t; #define REALHEADER_SIZE 16 @@ -222,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) { @@ -265,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; @@ -299,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; } @@ -321,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}; } @@ -537,11 +507,13 @@ static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track, } if (video->n_display_width) { track->v_dwidth = video->display_width; + track->v_dwidth_set = true; mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Display width: %u\n", track->v_dwidth); } if (video->n_display_height) { track->v_dheight = video->display_height; + track->v_dheight_set = true; mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Display height: %u\n", track->v_dheight); } @@ -579,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) @@ -627,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; @@ -707,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; @@ -732,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; @@ -1066,84 +1056,47 @@ static int read_header_element(struct demuxer *demuxer, uint32_t id, default: res = 2; } - if (!at_filepos) + if (!at_filepos && id != EBML_ID_INVALID) ebml_read_skip(s, NULL); return res; } -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 { @@ -1162,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; @@ -1180,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); @@ -1192,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; @@ -1213,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); @@ -1229,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 @@ -1245,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"; @@ -1278,8 +1240,10 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track, if (!track->realmedia) { sh_v->disp_w = track->v_width; sh_v->disp_h = track->v_height; - if (track->v_dheight) - sh_v->aspect = (double) track->v_dwidth / track->v_dheight; + 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; + if (dw && dh) + sh_v->aspect = (double) dw / dh; } else { // vd_realvid.c will set aspect to disp_w/disp_h and rederive // disp_w and disp_h from the RealVideo stream contents returned @@ -1291,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; } @@ -1314,11 +1277,14 @@ static struct mkv_audio_tag { { MKV_A_AAC_4LTP, 0, mmioFOURCC('M', 'P', '4', 'A') }, { MKV_A_AAC, 0, mmioFOURCC('M', 'P', '4', 'A') }, { MKV_A_VORBIS, 0, mmioFOURCC('v', 'r', 'b', 's') }, + { MKV_A_OPUS, 0, mmioFOURCC('O', 'p', 'u', 's') }, + { MKV_A_OPUS_EXP, 0, mmioFOURCC('O', 'p', 'u', 's') }, { MKV_A_QDMC, 0, mmioFOURCC('Q', 'D', 'M', 'C') }, { MKV_A_QDMC2, 0, mmioFOURCC('Q', 'D', 'M', '2') }, { MKV_A_WAVPACK, 0, mmioFOURCC('W', 'V', 'P', 'K') }, { MKV_A_TRUEHD, 0, mmioFOURCC('T', 'R', 'H', 'D') }, { MKV_A_FLAC, 0, mmioFOURCC('f', 'L', 'a', 'C') }, + { MKV_A_ALAC, 0, mmioFOURCC('a', 'L', 'a', 'C') }, { MKV_A_REAL28, 0, mmioFOURCC('2', '8', '_', '8') }, { MKV_A_REALATRC, 0, mmioFOURCC('a', 't', 'r', 'c') }, { MKV_A_REALCOOK, 0, mmioFOURCC('c', 'o', 'o', 'k') }, @@ -1329,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; @@ -1462,6 +1428,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track, memcpy((unsigned char *) (sh_a->wf + 1), track->private_data, sh_a->wf->cbSize); } + } else if (!strcmp(track->codec_id, MKV_A_OPUS) + || !strcmp(track->codec_id, MKV_A_OPUS_EXP)) { + sh_a->format = mmioFOURCC('O', 'p', 'u', 's'); } else if (!strncmp(track->codec_id, MKV_A_REALATRC, 7)) { if (track->private_size < RAPROPERTIES4_SIZE) goto error; @@ -1544,6 +1513,16 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track, sh_a->codecdata_len = size; memcpy(sh_a->codecdata, ptr, size); } + } else if (!strcmp(track->codec_id, MKV_A_ALAC)) { + if (track->private_size && track->private_size < 10000000) { + sh_a->codecdata_len = track->private_size + 12; + sh_a->codecdata = malloc(sh_a->codecdata_len); + char *data = sh_a->codecdata; + AV_WB32(data + 0, sh_a->codecdata_len); + memcpy(data + 4, "alac", 4); + AV_WB32(data + 8, 0); + memcpy(data + 12, track->private_data, track->private_size); + } } else if (track->a_formattag == mmioFOURCC('W', 'V', 'P', 'K') || track->a_formattag == mmioFOURCC('T', 'R', 'H', 'D')) { copy_private_data: @@ -1580,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; @@ -1623,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 = {}; @@ -1668,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 " @@ -1704,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 { @@ -1753,97 +1756,89 @@ 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 */ - |