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.c396
1 files changed, 354 insertions, 42 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 2e03fac874..4a9bfb2faf 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -29,6 +29,7 @@
#include <assert.h>
#include <libavutil/common.h>
+#include <libavutil/dovi_meta.h>
#include <libavutil/lzo.h>
#include <libavutil/intreadwrite.h>
#include <libavutil/avstring.h>
@@ -36,6 +37,8 @@
#include <libavcodec/avcodec.h>
#include <libavcodec/version.h>
+#include <libplacebo/utils/libav.h>
+
#include "config.h"
#if HAVE_ZLIB
@@ -46,6 +49,7 @@
#include "common/av_common.h"
#include "options/m_config.h"
#include "options/m_option.h"
+#include "options/options.h"
#include "misc/bstr.h"
#include "stream/stream.h"
#include "video/csputils.h"
@@ -107,7 +111,12 @@ typedef struct mkv_track {
double v_frate;
uint32_t colorspace;
int stereo_mode;
- struct mp_colorspace color;
+ struct pl_color_repr repr;
+ struct pl_color_space color;
+ uint32_t v_crop_top, v_crop_left, v_crop_right, v_crop_bottom;
+ float v_projection_pose_yaw;
+ float v_projection_pose_pitch;
+ float v_projection_pose_roll;
uint32_t a_channels, a_bps;
float a_sfreq;
@@ -146,6 +155,8 @@ typedef struct mkv_track {
/* latest added index entry for this track */
size_t last_index_entry;
+
+ AVDOVIDecoderConfigurationRecord *dovi_config;
} mkv_track_t;
typedef struct mkv_index {
@@ -186,7 +197,6 @@ typedef struct mkv_demuxer {
mkv_index_t *indexes;
size_t num_indexes;
bool index_complete;
- int index_mode;
int edition_id;
@@ -224,7 +234,7 @@ struct demux_mkv_opts {
double subtitle_preroll_secs;
double subtitle_preroll_secs_index;
int probe_duration;
- int probe_start_time;
+ bool probe_start_time;
};
const struct m_sub_options demux_mkv_conf = {
@@ -237,7 +247,7 @@ const struct m_sub_options demux_mkv_conf = {
M_RANGE(0, DBL_MAX)},
{"probe-video-duration", OPT_CHOICE(probe_duration,
{"no", 0}, {"yes", 1}, {"full", 2})},
- {"probe-start-time", OPT_FLAG(probe_start_time)},
+ {"probe-start-time", OPT_BOOL(probe_start_time)},
{0}
},
.size = sizeof(struct demux_mkv_opts),
@@ -245,7 +255,7 @@ const struct m_sub_options demux_mkv_conf = {
.subtitle_preroll = 2,
.subtitle_preroll_secs = 1.0,
.subtitle_preroll_secs_index = 10.0,
- .probe_start_time = 1,
+ .probe_start_time = true,
},
};
@@ -384,6 +394,10 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
}
size = dstlen - out_avail;
} else if (enc->comp_algo == 3) {
+ if (enc->comp_settings_len == 0 || !enc->comp_settings) {
+ mp_warn(log, "missing comp_settings, unable to reconstruct the data.\n");
+ goto error;
+ }
dest = talloc_size(track->parser_tmp, size + enc->comp_settings_len);
memcpy(dest, enc->comp_settings, enc->comp_settings_len);
memcpy(dest + enc->comp_settings_len, src, size);
@@ -396,6 +410,8 @@ static bstr demux_mkv_decode(struct mp_log *log, mkv_track_t *track,
talloc_free(src);
if (!size)
dest = NULL;
+ if (!dest)
+ size = 0;
return (bstr){dest, size};
}
@@ -570,40 +586,108 @@ static void parse_trackcolour(struct demuxer *demuxer, struct mkv_track *track,
// 23001-8:2013/DCOR1, which is the same order used by libavutil/pixfmt.h,
// so we can just re-use our avcol_ conversion functions.
if (colour->n_matrix_coefficients) {
- track->color.space = avcol_spc_to_mp_csp(colour->matrix_coefficients);
+ track->repr.sys = pl_system_from_av(colour->matrix_coefficients);
MP_DBG(demuxer, "| + Matrix: %s\n",
- m_opt_choice_str(mp_csp_names, track->color.space));
+ m_opt_choice_str(pl_csp_names, track->repr.sys));
}
if (colour->n_primaries) {
- track->color.primaries = avcol_pri_to_mp_csp_prim(colour->primaries);
+ track->color.primaries = pl_primaries_from_av(colour->primaries);
MP_DBG(demuxer, "| + Primaries: %s\n",
- m_opt_choice_str(mp_csp_prim_names, track->color.primaries));
+ m_opt_choice_str(pl_csp_prim_names, track->color.primaries));
}
if (colour->n_transfer_characteristics) {
- track->color.gamma = avcol_trc_to_mp_csp_trc(colour->transfer_characteristics);
+ track->color.transfer = pl_transfer_from_av(colour->transfer_characteristics);
MP_DBG(demuxer, "| + Gamma: %s\n",
- m_opt_choice_str(mp_csp_trc_names, track->color.gamma));
+ m_opt_choice_str(pl_csp_trc_names, track->color.transfer));
}
if (colour->n_range) {
- track->color.levels = avcol_range_to_mp_csp_levels(colour->range);
+ track->repr.levels = pl_levels_from_av(colour->range);
MP_DBG(demuxer, "| + Levels: %s\n",
- m_opt_choice_str(mp_csp_levels_names, track->color.levels));
+ m_opt_choice_str(pl_csp_levels_names, track->repr.levels));
}
if (colour->n_max_cll) {
- track->color.sig_peak = colour->max_cll / MP_REF_WHITE;
+ track->color.hdr.max_cll = colour->max_cll;
MP_DBG(demuxer, "| + MaxCLL: %"PRIu64"\n", colour->max_cll);
}
- // if MaxCLL is unavailable, try falling back to the mastering metadata
- if (!track->color.sig_peak && colour->n_mastering_metadata) {
+ if (colour->n_max_fall) {
+ track->color.hdr.max_fall = colour->max_fall;
+ MP_DBG(demuxer, "| + MaxFALL: %"PRIu64"\n", colour->max_cll);
+ }
+ if (colour->n_mastering_metadata) {
struct ebml_mastering_metadata *mastering = &colour->mastering_metadata;
+ if (mastering->n_primary_r_chromaticity_x) {
+ track->color.hdr.prim.red.x = mastering->primary_r_chromaticity_x;
+ MP_DBG(demuxer, "| + PrimaryRChromaticityX: %f\n", track->color.hdr.prim.red.x);
+ }
+ if (mastering->n_primary_r_chromaticity_y) {
+ track->color.hdr.prim.red.y = mastering->primary_r_chromaticity_y;
+ MP_DBG(demuxer, "| + PrimaryRChromaticityY: %f\n", track->color.hdr.prim.red.y);
+ }
+ if (mastering->n_primary_g_chromaticity_x) {
+ track->color.hdr.prim.green.x = mastering->primary_g_chromaticity_x;
+ MP_DBG(demuxer, "| + PrimaryGChromaticityX: %f\n", track->color.hdr.prim.green.x);
+ }
+ if (mastering->n_primary_g_chromaticity_y) {
+ track->color.hdr.prim.green.y = mastering->primary_g_chromaticity_y;
+ MP_DBG(demuxer, "| + PrimaryGChromaticityY: %f\n", track->color.hdr.prim.green.y);
+ }
+ if (mastering->n_primary_b_chromaticity_x) {
+ track->color.hdr.prim.blue.x = mastering->primary_b_chromaticity_x;
+ MP_DBG(demuxer, "| + PrimaryBChromaticityX: %f\n", track->color.hdr.prim.blue.x);
+ }
+ if (mastering->n_primary_b_chromaticity_y) {
+ track->color.hdr.prim.blue.y = mastering->primary_b_chromaticity_y;
+ MP_DBG(demuxer, "| + PrimaryBChromaticityY: %f\n", track->color.hdr.prim.blue.y);
+ }
+ if (mastering->n_white_point_chromaticity_x) {
+ track->color.hdr.prim.white.x = mastering->white_point_chromaticity_x;
+ MP_DBG(demuxer, "| + WhitePointChromaticityX: %f\n", track->color.hdr.prim.white.x);
+ }
+ if (mastering->n_white_point_chromaticity_y) {
+ track->color.hdr.prim.white.y = mastering->white_point_chromaticity_y;
+ MP_DBG(demuxer, "| + WhitePointChromaticityY: %f\n", track->color.hdr.prim.white.y);
+ }
+ if (mastering->n_luminance_min) {
+ track->color.hdr.min_luma = mastering->luminance_min;
+ MP_DBG(demuxer, "| + LuminanceMin: %f\n", track->color.hdr.min_luma);
+ }
if (mastering->n_luminance_max) {
- track->color.sig_peak = mastering->luminance_max / MP_REF_WHITE;
- MP_DBG(demuxer, "| + HDR peak: %f\n", track->color.sig_peak);
+ track->color.hdr.max_luma = mastering->luminance_max;
+ MP_DBG(demuxer, "| + LuminanceMax: %f\n", track->color.hdr.max_luma);
}
}
}
+static void parse_trackprojection(struct demuxer *demuxer, struct mkv_track *track,
+ struct ebml_projection *projection)
+{
+ if (projection->n_projection_pose_yaw) {
+ track->v_projection_pose_yaw = projection->projection_pose_yaw;
+ MP_DBG(demuxer, "| + Projection pose yaw: %f\n",
+ track->v_projection_pose_yaw);
+ }
+
+ if (projection->n_projection_pose_pitch) {
+ track->v_projection_pose_pitch = projection->projection_pose_pitch;
+ MP_DBG(demuxer, "| + Projection pose pitch: %f\n",
+ track->v_projection_pose_pitch);
+ }
+
+ if (projection->n_projection_pose_roll) {
+ track->v_projection_pose_roll = projection->projection_pose_roll;
+ MP_DBG(demuxer, "| + Projection pose roll: %f\n",
+ track->v_projection_pose_roll);
+ }
+
+ if (track->v_projection_pose_yaw || track->v_projection_pose_pitch) {
+ MP_WARN(demuxer, "Not supported projection: yaw %f, pitch %f, roll %f\n",
+ track->v_projection_pose_yaw,
+ track->v_projection_pose_pitch,
+ track->v_projection_pose_roll);
+ }
+}
+
static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track,
struct ebml_video *video)
{
@@ -643,8 +727,104 @@ static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track,
video->stereo_mode);
}
}
+ if (video->n_pixel_crop_top) {
+ track->v_crop_top = video->pixel_crop_top;
+ MP_DBG(demuxer, "| + Crop top: %"PRIu32"\n", track->v_crop_top);
+ }
+ if (video->n_pixel_crop_left) {
+ track->v_crop_left = video->pixel_crop_left;
+ MP_DBG(demuxer, "| + Crop left: %"PRIu32"\n", track->v_crop_left);
+ }
+ if (video->n_pixel_crop_right) {
+ track->v_crop_right = video->pixel_crop_right;
+ MP_DBG(demuxer, "| + Crop right: %"PRIu32"\n", track->v_crop_right);
+ }
+ if (video->n_pixel_crop_bottom) {
+ track->v_crop_bottom = video->pixel_crop_bottom;
+ MP_DBG(demuxer, "| + Crop bottom: %"PRIu32"\n", track->v_crop_bottom);
+ }
if (video->n_colour)
parse_trackcolour(demuxer, track, &video->colour);
+ if (video->n_projection)
+ parse_trackprojection(demuxer, track, &video->projection);
+}
+
+static void parse_dovi_config(struct demuxer *demuxer, struct mkv_track *track,
+ const uint8_t *buf_ptr, size_t size)
+{
+ if (size < 4)
+ return;
+
+ av_free(track->dovi_config);
+
+ size_t dovi_size;
+ track->dovi_config = av_dovi_alloc(&dovi_size);
+ MP_HANDLE_OOM(track->dovi_config);
+
+ track->dovi_config->dv_version_major = *buf_ptr++; // 8 bits
+ track->dovi_config->dv_version_minor = *buf_ptr++; // 8 bits
+
+ uint32_t buf;
+ buf = *buf_ptr++ << 8;
+ buf |= *buf_ptr++;
+
+ track->dovi_config->dv_profile = (buf >> 9) & 0x7f; // 7 bits
+ track->dovi_config->dv_level = (buf >> 3) & 0x3f; // 6 bits
+ track->dovi_config->rpu_present_flag = (buf >> 2) & 0x01; // 1 bit
+ track->dovi_config->el_present_flag = (buf >> 1) & 0x01; // 1 bit
+ track->dovi_config->bl_present_flag = buf & 0x01; // 1 bit
+
+ if (size >= 5) {
+ track->dovi_config->dv_bl_signal_compatibility_id = ((*buf_ptr++) >> 4) & 0x0f; // 4 bits
+ } else {
+ // 0 stands for None
+ // Dolby Vision V1.2.93 profiles and levels
+ track->dovi_config->dv_bl_signal_compatibility_id = 0;
+ }
+
+ MP_DBG(demuxer, "| + Dolby Vision - version: %d.%d, profile: %d, level: %d, "
+ "RPU: %d, EL: %d, BL: %d, ID: %d\n",
+ track->dovi_config->dv_version_major,
+ track->dovi_config->dv_version_minor,
+ track->dovi_config->dv_profile,
+ track->dovi_config->dv_level,
+ track->dovi_config->rpu_present_flag,
+ track->dovi_config->el_present_flag,
+ track->dovi_config->bl_present_flag,
+ track->dovi_config->dv_bl_signal_compatibility_id);
+}
+
+static void parse_block_addition_mapping(struct demuxer *demuxer,
+ struct mkv_track *track,
+ struct ebml_block_addition_mapping *block_addition_mapping,
+ int count)
+{
+ for (int i = 0; i < count; ++i) {
+ if (!block_addition_mapping->n_block_add_id_type)
+ continue;
+ switch (block_addition_mapping->block_add_id_type) {
+ case MATROSKA_BLOCK_ADD_ID_TYPE_ITU_T_T35:
+ break;
+ case MKBETAG('a','v','c','E'):
+ case MKBETAG('h','v','c','E'):
+ MP_WARN(demuxer, "Dolby Vision enhancement-layer playback is not supported.\n");
+ break;
+ case MKBETAG('d','v','c','C'):
+ case MKBETAG('d','v','v','C'):
+ if (block_addition_mapping->n_block_add_id_extra_data) {
+ bstr data = block_addition_mapping->block_add_id_extra_data;
+ parse_dovi_config(demuxer, track, data.start, data.len);
+ }
+ break;
+ case MKBETAG('m','v','c','C'):
+ MP_WARN(demuxer, "MVC configuration is not supported.\n");
+ break;
+ default:
+ MP_WARN(demuxer, "Unsupported block addition type: %" PRIx64 "\n",
+ block_addition_mapping->block_add_id_type);
+ }
+ block_addition_mapping++;
+ }
}
/**
@@ -654,6 +834,7 @@ static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track,
static void demux_mkv_free_trackentry(mkv_track_t *track)
{
talloc_free(track->parser_tmp);
+ av_freep(&track->dovi_config);
talloc_free(track);
}
@@ -721,7 +902,10 @@ static void parse_trackentry(struct demuxer *demuxer,
MP_DBG(demuxer, "| + CodecPrivate, length %u\n", track->private_size);
}
- if (entry->language) {
+ if (entry->language_bcp47) {
+ track->language = talloc_strdup(track, entry->language_bcp47);
+ MP_DBG(demuxer, "| + LanguageBCP47: %s\n", track->language);
+ } else if (entry->language) {
track->language = talloc_strdup(track, entry->language);
MP_DBG(demuxer, "| + Language: %s\n", track->language);
} else {
@@ -757,6 +941,12 @@ static void parse_trackentry(struct demuxer *demuxer,
if (entry->n_codec_delay)
track->codec_delay = entry->codec_delay / 1e9;
+ if (entry->n_block_addition_mapping) {
+ parse_block_addition_mapping(demuxer, track,
+ entry->block_addition_mapping,
+ entry->n_block_addition_mapping);
+ }
+
mkv_d->tracks[mkv_d->num_tracks++] = track;
}
@@ -825,7 +1015,7 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
stream_t *s = demuxer->stream;
- if (mkv_d->index_mode != 1 || mkv_d->index_complete) {
+ if (demuxer->opts->index_mode != 1 || mkv_d->index_complete) {
ebml_read_skip(demuxer->log, -1, s);
return 0;
}
@@ -865,7 +1055,7 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
time, trackpos->cue_duration);
mkv_d->index_has_durations |= trackpos->n_cue_duration > 0;
MP_TRACE(demuxer, "|+ found cue point for track %"PRIu64": "
- "timecode %"PRIu64", filepos: %"PRIu64""
+ "timecode %"PRIu64", filepos: %"PRIu64" "
"offset %"PRIu64", duration %"PRIu64"\n",
trackpos->cue_track, time, pos,
trackpos->cue_relative_position, trackpos->cue_duration);
@@ -1008,8 +1198,8 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer)
}
}
- MP_DBG(demuxer, "Chapter %u from %02d:%02d:%02d.%03d "
- "to %02d:%02d:%02d.%03d, %s\n", i,
+ MP_DBG(demuxer, "Chapter %u from %02d:%02d:%02d.%09d "
+ "to %02d:%02d:%02d.%09d, %s\n", i,
(int) (chapter.start / 60 / 60 / 1000000000),
(int) ((chapter.start / 60 / 1000000000) % 60),
(int) ((chapter.start / 1000000000) % 60),
@@ -1275,7 +1465,7 @@ static void read_deferred_cues(demuxer_t *demuxer)
{
mkv_demuxer_t *mkv_d = demuxer->priv;
- if (mkv_d->index_complete || mkv_d->index_mode != 1)
+ if (mkv_d->index_complete || demuxer->opts->index_mode != 1)
return;
for (int n = 0; n < mkv_d->num_headers; n++) {
@@ -1300,6 +1490,7 @@ static void add_coverart(struct demuxer *demuxer)
sh->attached_picture->pts = 0;
talloc_steal(sh, sh->attached_picture);
sh->attached_picture->keyframe = true;
+ sh->image = true;
}
sh->title = att->name;
demux_add_sh_stream(demuxer, sh);
@@ -1358,9 +1549,13 @@ static const char *const mkv_video_tags[][2] = {
{"V_DIRAC", "dirac"},
{"V_PRORES", "prores"},
{"V_MPEGH/ISO/HEVC", "hevc"},
+ {"V_MPEGI/ISO/VVC", "vvc"},
{"V_SNOW", "snow"},
{"V_AV1", "av1"},
{"V_PNG", "png"},
+ {"V_AVS2", "avs2"},
+ {"V_AVS3", "avs3"},
+ {"V_FFV1", "ffv1"},
{0}
};
@@ -1420,15 +1615,14 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
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) {
- fourcc1 = AV_RL32(track->private_data + 0);
- fourcc2 = AV_RL32(track->private_data + 4);
- }
- if (fourcc1 == MKTAG('S', 'V', 'Q', '3') ||
- fourcc2 == MKTAG('S', 'V', 'Q', '3'))
- {
- sh_v->codec = "svq3";
+ sh_v->codec_tag = AV_RL32(track->private_data + 4);
+ mp_set_codec_from_tag(sh_v);
+ // Some non-compliant files have fourcc at offset 0.
+ if (!sh_v->codec) {
+ sh_v->codec_tag = AV_RL32(track->private_data);
+ mp_set_codec_from_tag(sh_v);
+ }
extradata = track->private_data;
extradata_size = track->private_size;
}
@@ -1467,6 +1661,17 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
sh_v->disp_w = track->v_width;
sh_v->disp_h = track->v_height;
+ // Keep the codec crop rect as 0s if we have no cropping since the
+ // file may have broken width/height tags.
+ if (track->v_crop_left || track->v_crop_top ||
+ track->v_crop_right || track->v_crop_bottom)
+ {
+ sh_v->crop.x0 = track->v_crop_left;
+ sh_v->crop.y0 = track->v_crop_top;
+ sh_v->crop.x1 = track->v_width - track->v_crop_right;
+ sh_v->crop.y1 = track->v_height - track->v_crop_bottom;
+ }
+
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};
@@ -1477,6 +1682,17 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
sh_v->stereo_mode = track->stereo_mode;
sh_v->color = track->color;
+ if (track->v_projection_pose_roll) {
+ int rotate = lrintf(fmodf(fmodf(-1 * track->v_projection_pose_roll, 360) + 360, 360));
+ sh_v->rotate = rotate;
+ }
+
+ if (track->dovi_config) {
+ sh_v->dovi = true;
+ sh_v->dv_level = track->dovi_config->dv_level;
+ sh_v->dv_profile = track->dovi_config->dv_profile;
+ }
+
done:
demux_add_sh_stream(demuxer, sh);
@@ -1550,6 +1766,7 @@ static void parse_flac_chmap(struct mp_chmap *channels, unsigned char *data,
}
static const char *const mkv_audio_tags[][2] = {
+ { "A_MPEG/L1", "mp1" },
{ "A_MPEG/L2", "mp2" },
{ "A_MPEG/L3", "mp3" },
{ "A_AC3", "ac3" },
@@ -1738,10 +1955,14 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
goto error;
const char *codec = sh_a->codec;
- if (!strcmp(codec, "mp2") || !strcmp(codec, "mp3") ||
+ if (!strcmp(codec, "mp1") || !strcmp(codec, "mp2") || !strcmp(codec, "mp3") ||
!strcmp(codec, "truehd") || !strcmp(codec, "eac3"))
{
+ mkv_demuxer_t *mkv_d = demuxer->priv;
+ int64_t segment_timebase = (1e9 / mkv_d->tc_scale);
+
track->parse = true;
+ track->parse_timebase = MPMAX(sh_a->samplerate, segment_timebase);
} else if (!strcmp(codec, "flac")) {
unsigned char *ptr = extradata;
unsigned int size = extradata_len;
@@ -1820,13 +2041,20 @@ static const char *const mkv_sub_tag[][2] = {
{ "S_TEXT/ASCII", "subrip"},
{ "S_TEXT/UTF8", "subrip"},
{ "S_HDMV/PGS", "hdmv_pgs_subtitle"},
+ { "S_HDMV/TEXTST", "hdmv_text_subtitle"},
{ "D_WEBVTT/SUBTITLES", "webvtt-webm"},
{ "D_WEBVTT/CAPTIONS", "webvtt-webm"},
{ "S_TEXT/WEBVTT", "webvtt"},
{ "S_DVBSUB", "dvb_subtitle"},
+ { "S_ARIBSUB", "arib_caption"},
{0}
};
+static void avcodec_par_destructor(void *p)
+{
+ avcodec_parameters_free(p);
+}
+
static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
{
const char *subtitle_type = NULL;
@@ -1855,6 +2083,38 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
sh->codec->extradata = track->private_data;
sh->codec->extradata_size = track->private_size;
+ if (subtitle_type && !strcmp(sh->codec->codec, "arib_caption") && track->private_size >= 3) {
+ struct AVCodecParameters **lavp = talloc_ptrtype(track, lavp);
+
+ talloc_set_destructor(lavp, avcodec_par_destructor);
+
+ struct AVCodecParameters *lav = *lavp = sh->codec->lav_codecpar = avcodec_parameters_alloc();
+ MP_HANDLE_OOM(lav);
+
+ lav->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ lav->codec_id = AV_CODEC_ID_ARIB_CAPTION;
+
+ int component_tag = track->private_data[0];
+ int data_component_id = AV_RB16(track->private_data + 1);
+ switch (data_component_id) {
+ case 0x0008:
+ // [0x30..0x37] are component tags utilized for
+ // non-mobile captioning service ("profile A").
+ if (component_tag >= 0x30 && component_tag <= 0x37)
+ lav->profile = FF_PROFILE_ARIB_PROFILE_A;
+ break;
+ case 0x0012:
+ // component tag 0x87 signifies a mobile/partial reception
+ // (1seg) captioning service ("profile C").
+ if (component_tag == 0x87)
+ lav->profile = FF_PROFILE_ARIB_PROFILE_C;
+ break;
+ }
+ if (lav->profile == FF_PROFILE_UNKNOWN)
+ MP_WARN(demuxer, "ARIB caption profile %02x / %04x not supported.\n",
+ component_tag, data_component_id);
+ }
+
demux_add_sh_stream(demuxer, sh);
if (!subtitle_type)
@@ -1863,6 +2123,39 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
return 0;
}
+// Workaround for broken files that don't set attached_picture
+static void probe_if_image(demuxer_t *demuxer)
+{
+ mkv_demuxer_t *mkv_d = demuxer->priv;
+
+ for (int n = 0; n < mkv_d->num_tracks; n++) {
+ int video_blocks = 0;
+ mkv_track_t *track = mkv_d->tracks[n];
+ struct sh_stream *sh = track->stream;
+
+ if (!sh || sh->type != STREAM_VIDEO || sh->image)
+ continue;
+
+ int64_t timecode = -1;
+ // Arbitrary restriction on packet reading.
+ for (size_t block = 0; block < 100000; block++) {
+ if (block >= mkv_d->num_blocks && read_next_block_into_queue(demuxer) != 1)
+ break;
+ if (mkv_d->blocks[block].track != track)
+ continue;
+ if (timecode != mkv_d->blocks[block].timecode)
+ ++video_blocks;
+ timecode = mkv_d->blocks[block].timecode;
+ if (video_blocks > 1)
+ break;
+ }
+
+ // Assume still image
+ if (video_blocks == 1)
+ sh->image = true;
+ }
+}
+
static void probe_x264_garbage(demuxer_t *demuxer)
{
mkv_demuxer_t *mkv_d = demuxer->priv;
@@ -1895,6 +2188,8 @@ static void probe_x264_garbage(demuxer_t *demuxer)
bstr sblock = {block->laces[0]->data, block->laces[0]->size};
bstr nblock = demux_mkv_decode(demuxer->log, track, sblock, 1);
+ if (!nblock.len)
+ continue;
sh->codec->first_packet = new_demux_packet_from(nblock.start, nblock.len);
talloc_steal(mkv_d, sh->codec->first_packet);
@@ -2020,10 +2315,10 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
mkv_d->segment_start = stream_tell(s);
mkv_d->segment_end = end_pos;
- mp_read_option_raw(demuxer->global, "index", &m_option_type_choice,
- &mkv_d->index_mode);
- mp_read_option_raw(demuxer->global, "edition", &m_option_type_choice,
- &mkv_d->edition_id);
+ struct MPOpts *mp_opts = mp_get_config_group(mkv_d, demuxer->global, &mp_opt_root);
+ mkv_d->edition_id = mp_opts->edition_id;
+ talloc_free(mp_opts);
+
mkv_d->opts = mp_get_config_group(mkv_d, demuxer->global, &demux_mkv_conf);
if (demuxer->params && demuxer->params->matroska_was_valid)
@@ -2115,6 +2410,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
if (mkv_d->opts->probe_duration)
probe_last_timestamp(demuxer, start_pos);
probe_x264_garbage(demuxer);
+ probe_if_image(demuxer);
return 0;
}
@@ -2656,6 +2952,8 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
bstr block = {data->data, data->size};
bstr nblock = demux_mkv_decode(demuxer->log, track, block, 1);
+ if (!nblock.len)
+ break;
if (block.start != nblock.start || block.len != nblock.len) {
// (avoidable copy of the entire data)
@@ -2694,6 +2992,18 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
add->block_additional.start, add->block_additional.len);
}
}
+ if (track->dovi_config) {
+ size_t dovi_size;
+ AVDOVIDecoderConfigurationRecord *dovi = av_dovi_alloc(&dovi_size);
+ MP_HANDLE_OOM(dovi);
+ memcpy(dovi, track->dovi_config, dovi_size);
+ if (av_packet_add_side_data(dp->avpacket,
+ AV_PKT_DATA_DOVI_CONF,
+ (uint8_t *)dovi, dovi_size) < 0)
+ {
+ av_free(dovi);
+ }
+ }
mkv_parse_and_add_packet(demuxer, track, dp);
talloc_free_children(track->parser_tmp);
@@ -2805,20 +3115,22 @@ static int read_next_block_into_queue(demuxer_t *demuxer)
if (end > mkv_d->cluster_end)
goto find_next_cluster;
int res = read_block_group(demuxer, end, &block);
- if (res < 0)
- goto find_next_cluster;
if (res > 0)
goto add_block;
+ free_block(&block);
+ if (res < 0)
+ goto find_next_cluster;
break;
}
case MATROSKA_ID_SIMPLEBLOCK: {
block = (struct block_info){ .simple = true };
int res = read_block(demuxer, mkv_d->cluster_end, &block);
- if (res < 0)
- goto find_next_cluster;
if (res > 0)
goto add_block;
+ free_block(&block);
+ if (res < 0)
+ goto find_next_cluster;
break;
}
@@ -2867,7 +3179,7 @@ static int read_next_block_into_queue(demuxer_t *demuxer)
if (mkv_d->cluster_end != EBML_UINT_INVALID)
mkv_d->cluster_end += stream_tell(s);
}
- assert(0); // unreachable
+ MP_ASSERT_UNREACHABLE();
add_block:
index_block(demuxer, &block);