mirror of
https://github.com/mpv-player/mpv
synced 2025-03-11 08:37:59 +00:00
demux_mkv: use new EBML parser to read all track headers
This commit is contained in:
parent
2fd4dc45de
commit
1b22101c77
@ -441,20 +441,15 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int demux_mkv_read_trackencodings(demuxer_t *demuxer,
|
||||
mkv_track_t *track)
|
||||
static void parse_trackencodings(struct demuxer *demuxer,
|
||||
struct mkv_track *track,
|
||||
struct ebml_content_encodings *encodings)
|
||||
{
|
||||
stream_t *s = demuxer->stream;
|
||||
// initial allocation to be a non-NULL context before realloc
|
||||
mkv_content_encoding_t *ce = talloc_size(track, 1);
|
||||
|
||||
struct ebml_content_encodings encodings = {};
|
||||
struct ebml_parse_ctx parse_ctx = {};
|
||||
if (ebml_read_element(s, &parse_ctx, &encodings,
|
||||
&ebml_content_encodings_desc) < 0)
|
||||
return 0;
|
||||
for (int n_enc = 0; n_enc < encodings.n_content_encoding; n_enc++) {
|
||||
struct ebml_content_encoding *enc = encodings.content_encoding + n_enc;
|
||||
for (int n_enc = 0; n_enc < encodings->n_content_encoding; n_enc++) {
|
||||
struct ebml_content_encoding *enc = encodings->content_encoding + n_enc;
|
||||
struct mkv_content_encoding e = {};
|
||||
e.order = enc->content_encoding_order;
|
||||
if (enc->n_content_encoding_scope)
|
||||
@ -512,78 +507,61 @@ static int demux_mkv_read_trackencodings(demuxer_t *demuxer,
|
||||
}
|
||||
|
||||
track->encodings = ce;
|
||||
track->num_encodings = encodings.n_content_encoding;
|
||||
talloc_free(parse_ctx.talloc_ctx);
|
||||
return parse_ctx.bytes_read;
|
||||
track->num_encodings = encodings->n_content_encoding;
|
||||
}
|
||||
|
||||
static int demux_mkv_read_trackaudio(demuxer_t *demuxer, mkv_track_t *track)
|
||||
static void parse_trackaudio(struct demuxer *demuxer, struct mkv_track *track,
|
||||
struct ebml_audio *audio)
|
||||
{
|
||||
stream_t *s = demuxer->stream;
|
||||
|
||||
struct ebml_audio audio = {};
|
||||
struct ebml_parse_ctx parse_ctx = {};
|
||||
if (ebml_read_element(s, &parse_ctx, &audio, &ebml_audio_desc) < 0)
|
||||
return 0;
|
||||
if (audio.n_sampling_frequency) {
|
||||
track->a_sfreq = audio.sampling_frequency;
|
||||
if (audio->n_sampling_frequency) {
|
||||
track->a_sfreq = audio->sampling_frequency;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V,
|
||||
"[mkv] | + Sampling frequency: %f\n", track->a_sfreq);
|
||||
} else
|
||||
track->a_sfreq = 8000;
|
||||
if (audio.n_bit_depth) {
|
||||
track->a_bps = audio.bit_depth;
|
||||
if (audio->n_bit_depth) {
|
||||
track->a_bps = audio->bit_depth;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Bit depth: %u\n",
|
||||
track->a_bps);
|
||||
}
|
||||
if (audio.n_channels) {
|
||||
track->a_channels = audio.channels;
|
||||
if (audio->n_channels) {
|
||||
track->a_channels = audio->channels;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Channels: %u\n",
|
||||
track->a_channels);
|
||||
} else
|
||||
track->a_channels = 1;
|
||||
talloc_free(parse_ctx.talloc_ctx);
|
||||
return parse_ctx.bytes_read;
|
||||
}
|
||||
|
||||
static int demux_mkv_read_trackvideo(demuxer_t *demuxer, mkv_track_t *track)
|
||||
static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track,
|
||||
struct ebml_video *video)
|
||||
{
|
||||
stream_t *s = demuxer->stream;
|
||||
|
||||
struct ebml_video video = {};
|
||||
struct ebml_parse_ctx parse_ctx = {};
|
||||
if (ebml_read_element(s, &parse_ctx, &video, &ebml_video_desc) < 0)
|
||||
return 0;
|
||||
if (video.n_frame_rate) {
|
||||
track->v_frate = video.frame_rate;
|
||||
if (video->n_frame_rate) {
|
||||
track->v_frate = video->frame_rate;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Frame rate: %f\n",
|
||||
track->v_frate);
|
||||
// XXX default_duration should take priority
|
||||
if (track->v_frate > 0)
|
||||
track->default_duration = 1 / track->v_frate;
|
||||
}
|
||||
if (video.n_display_width) {
|
||||
track->v_dwidth = video.display_width;
|
||||
if (video->n_display_width) {
|
||||
track->v_dwidth = video->display_width;
|
||||
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;
|
||||
if (video->n_display_height) {
|
||||
track->v_dheight = video->display_height;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Display height: %u\n",
|
||||
track->v_dheight);
|
||||
}
|
||||
if (video.n_pixel_width) {
|
||||
track->v_width = video.pixel_width;
|
||||
if (video->n_pixel_width) {
|
||||
track->v_width = video->pixel_width;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Pixel width: %u\n",
|
||||
track->v_width);
|
||||
}
|
||||
if (video.n_pixel_height) {
|
||||
track->v_height = video.pixel_height;
|
||||
if (video->n_pixel_height) {
|
||||
track->v_height = video->pixel_height;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Pixel height: %u\n",
|
||||
track->v_height);
|
||||
}
|
||||
talloc_free(parse_ctx.talloc_ctx);
|
||||
return parse_ctx.bytes_read;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -592,210 +570,141 @@ static int demux_mkv_read_trackvideo(demuxer_t *demuxer, mkv_track_t *track)
|
||||
*/
|
||||
static void demux_mkv_free_trackentry(mkv_track_t *track)
|
||||
{
|
||||
free(track->name);
|
||||
free(track->codec_id);
|
||||
free(track->language);
|
||||
free(track->private_data);
|
||||
free(track->audio_buf);
|
||||
free(track->audio_timestamp);
|
||||
talloc_free(track);
|
||||
}
|
||||
|
||||
static int demux_mkv_read_trackentry(demuxer_t *demuxer)
|
||||
static void parse_trackentry(struct demuxer *demuxer,
|
||||
struct ebml_track_entry *entry)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
stream_t *s = demuxer->stream;
|
||||
mkv_track_t *track;
|
||||
uint64_t len, length, l;
|
||||
uint64_t num;
|
||||
int il;
|
||||
struct mkv_track *track = talloc_zero_size(NULL, sizeof(*track));
|
||||
|
||||
track = talloc_zero_size(NULL, sizeof(*track));
|
||||
/* set default values */
|
||||
track->default_track = 1;
|
||||
track->name = 0;
|
||||
track->language = strdup("eng");
|
||||
track->tnum = entry->track_number;
|
||||
if (track->tnum)
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Track number: %u\n",
|
||||
track->tnum);
|
||||
else
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Missing track number!\n");
|
||||
|
||||
len = length = ebml_read_length(s, &il);
|
||||
len += il;
|
||||
while (length > 0) {
|
||||
switch (ebml_read_id(s, &il)) {
|
||||
case MATROSKA_ID_TRACKNUMBER:
|
||||
num = ebml_read_uint(s, &l);
|
||||
if (num == EBML_UINT_INVALID)
|
||||
goto err_out;
|
||||
track->tnum = num;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Track number: %u\n",
|
||||
track->tnum);
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_NAME:
|
||||
track->name = ebml_read_utf8(s, &l);
|
||||
if (track->name == NULL)
|
||||
goto err_out;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Name: %s\n",
|
||||
track->name);
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_TRACKTYPE:
|
||||
num = ebml_read_uint(s, &l);
|
||||
if (num == EBML_UINT_INVALID)
|
||||
return 0;
|
||||
track->type = num;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Track type: ");
|
||||
switch (track->type) {
|
||||
case MATROSKA_TRACK_AUDIO:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Audio\n");
|
||||
break;
|
||||
case MATROSKA_TRACK_VIDEO:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Video\n");
|
||||
break;
|
||||
case MATROSKA_TRACK_SUBTITLE:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Subtitle\n");
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "unknown\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_AUDIO:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Audio track\n");
|
||||
l = demux_mkv_read_trackaudio(demuxer, track);
|
||||
if (l == 0)
|
||||
goto err_out;
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_VIDEO:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Video track\n");
|
||||
l = demux_mkv_read_trackvideo(demuxer, track);
|
||||
if (l == 0)
|
||||
goto err_out;
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_CODECID:
|
||||
track->codec_id = ebml_read_ascii(s, &l);
|
||||
if (track->codec_id == NULL)
|
||||
goto err_out;
|
||||
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 = MATROSKA_SUBTYPE_VOBSUB;
|
||||
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 = MATROSKA_SUBTYPE_SSA;
|
||||
} else if (!strcmp(track->codec_id, MKV_S_TEXTASCII))
|
||||
track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
|
||||
if (!strcmp(track->codec_id, MKV_S_TEXTUTF8)) {
|
||||
track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
|
||||
}
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Codec ID: %s\n",
|
||||
track->codec_id);
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_CODECPRIVATE:;
|
||||
int x;
|
||||
num = ebml_read_length(s, &x);
|
||||
// audit: cheap guard against overflows later..
|
||||
if (num > SIZE_MAX - 1000)
|
||||
return 0;
|
||||
l = x + num;
|
||||
track->private_data = malloc(num + AV_LZO_INPUT_PADDING);
|
||||
if (stream_read(s, track->private_data, num) != (int) num)
|
||||
goto err_out;
|
||||
track->private_size = num;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V,
|
||||
"[mkv] | + CodecPrivate, length " "%u\n",
|
||||
track->private_size);
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_LANGUAGE:
|
||||
free(track->language);
|
||||
track->language = ebml_read_utf8(s, &l);
|
||||
if (track->language == NULL)
|
||||
goto err_out;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Language: %s\n",
|
||||
track->language);
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_FLAGDEFAULT:
|
||||
num = ebml_read_uint(s, &l);
|
||||
if (num == EBML_UINT_INVALID)
|
||||
goto err_out;
|
||||
track->default_track = num;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Default flag: %u\n",
|
||||
track->default_track);
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_DEFAULTDURATION:
|
||||
num = ebml_read_uint(s, &l);
|
||||
if (num == EBML_UINT_INVALID)
|
||||
goto err_out;
|
||||
if (num == 0)
|
||||
mp_msg(MSGT_DEMUX, MSGL_V,
|
||||
"[mkv] | + Default duration: 0");
|
||||
else {
|
||||
track->v_frate = 1000000000.0 / num;
|
||||
track->default_duration = num / 1000000000.0;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V,
|
||||
"[mkv] | + Default duration: "
|
||||
"%.3fms ( = %.3f fps)\n", num / 1000000.0,
|
||||
track->v_frate);
|
||||
}
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_CONTENTENCODINGS:
|
||||
l = demux_mkv_read_trackencodings(demuxer, track);
|
||||
if (l == 0)
|
||||
goto err_out;
|
||||
break;
|
||||
|
||||
default:
|
||||
ebml_read_skip(s, &l);
|
||||
break;
|
||||
}
|
||||
length -= l + il;
|
||||
if (entry->n_name) {
|
||||
track->name = talloc_strndup(track, entry->name.start,
|
||||
entry->name.len);
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Name: %s\n",
|
||||
track->name);
|
||||
}
|
||||
|
||||
mkv_d->tracks[mkv_d->num_tracks++] = track;
|
||||
return len;
|
||||
track->type = entry->track_type;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Track type: ");
|
||||
switch (track->type) {
|
||||
case MATROSKA_TRACK_AUDIO:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Audio\n");
|
||||
break;
|
||||
case MATROSKA_TRACK_VIDEO:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Video\n");
|
||||
break;
|
||||
case MATROSKA_TRACK_SUBTITLE:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "Subtitle\n");
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "unknown\n");
|
||||
break;
|
||||
}
|
||||
|
||||
err_out:
|
||||
demux_mkv_free_trackentry(track);
|
||||
return 0;
|
||||
if (entry->n_audio) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Audio track\n");
|
||||
parse_trackaudio(demuxer, track, &entry->audio);
|
||||
}
|
||||
|
||||
if (entry->n_video) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Video track\n");
|
||||
parse_trackvideo(demuxer, track, &entry->video);
|
||||
}
|
||||
|
||||
if (entry->n_codec_id) {
|
||||
track->codec_id = talloc_strndup(track, entry->codec_id.start,
|
||||
entry->codec_id.len);
|
||||
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 = MATROSKA_SUBTYPE_VOBSUB;
|
||||
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 = MATROSKA_SUBTYPE_SSA;
|
||||
} else if (!strcmp(track->codec_id, MKV_S_TEXTASCII))
|
||||
track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
|
||||
if (!strcmp(track->codec_id, MKV_S_TEXTUTF8)) {
|
||||
track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
|
||||
}
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Codec ID: %s\n",
|
||||
track->codec_id);
|
||||
} else
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Missing codec ID!\n");
|
||||
|
||||
if (entry->n_codec_private) {
|
||||
int len = entry->codec_private.len;
|
||||
track->private_data = talloc_size(track, len + AV_LZO_INPUT_PADDING);
|
||||
memcpy(track->private_data, entry->codec_private.start, len);
|
||||
track->private_size = len;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + CodecPrivate, length %u\n",
|
||||
track->private_size);
|
||||
}
|
||||
|
||||
if (entry->n_language) {
|
||||
track->language = talloc_strndup(track, entry->language.start,
|
||||
entry->language.len);
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Language: %s\n",
|
||||
track->language);
|
||||
} else
|
||||
track->language = talloc_strdup(track, "eng");
|
||||
|
||||
if (entry->n_flag_default) {
|
||||
track->default_track = entry->flag_default;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Default flag: %u\n",
|
||||
track->default_track);
|
||||
} else
|
||||
track->default_track = 1;
|
||||
|
||||
if (entry->n_default_duration) {
|
||||
track->default_duration = entry->default_duration / 1e9;
|
||||
if (entry->default_duration == 0)
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Default duration: 0");
|
||||
else {
|
||||
if (!track->v_frate)
|
||||
track->v_frate = 1e9 / entry->default_duration;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V,
|
||||
"[mkv] | + Default duration: %.3fms ( = %.3f fps)\n",
|
||||
entry->default_duration / 1000000.0, track->v_frate);
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->n_content_encodings)
|
||||
parse_trackencodings(demuxer, track, &entry->content_encodings);
|
||||
|
||||
mkv_d->tracks[mkv_d->num_tracks++] = track;
|
||||
}
|
||||
|
||||
static int demux_mkv_read_tracks(demuxer_t *demuxer)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
stream_t *s = demuxer->stream;
|
||||
uint64_t length, l;
|
||||
int il;
|
||||
|
||||
mkv_d->tracks = malloc(sizeof(*mkv_d->tracks));
|
||||
mkv_d->num_tracks = 0;
|
||||
struct ebml_tracks tracks = {};
|
||||
struct ebml_parse_ctx parse_ctx = {};
|
||||
if (ebml_read_element(s, &parse_ctx, &tracks, &ebml_tracks_desc) < 0)
|
||||
return 1;
|
||||
|
||||
length = ebml_read_length(s, NULL);
|
||||
while (length > 0) {
|
||||
switch (ebml_read_id(s, &il)) {
|
||||
case MATROSKA_ID_TRACKENTRY:
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + a track...\n");
|
||||
mkv_d->tracks = realloc(mkv_d->tracks, (mkv_d->num_tracks + 1)
|
||||
* sizeof(*mkv_d->tracks));
|
||||
l = demux_mkv_read_trackentry(demuxer);
|
||||
if (l == 0)
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
ebml_read_skip(s, &l);
|
||||
break;
|
||||
}
|
||||
length -= l + il;
|
||||
mkv_d->tracks = talloc_size(mkv_d,
|
||||
tracks.n_track_entry * sizeof(*mkv_d->tracks));
|
||||
for (int i = 0; i < tracks.n_track_entry; i++) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + a track...\n");
|
||||
parse_trackentry(demuxer, &tracks.track_entry[i]);
|
||||
}
|
||||
talloc_free(parse_ctx.talloc_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1864,7 +1773,6 @@ static void demux_close_mkv(demuxer_t *demuxer)
|
||||
if (mkv_d->tracks) {
|
||||
for (i = 0; i < mkv_d->num_tracks; i++)
|
||||
demux_mkv_free_trackentry(mkv_d->tracks[i]);
|
||||
free(mkv_d->tracks);
|
||||
}
|
||||
free(mkv_d->indexes);
|
||||
free(mkv_d->cluster_positions);
|
||||
|
Loading…
Reference in New Issue
Block a user