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.c586
1 files changed, 397 insertions, 189 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index a62057dfa0..9bee8a4011 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -20,6 +20,7 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <float.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
@@ -35,6 +36,8 @@
#include <libavcodec/avcodec.h>
#include <libavcodec/version.h>
+#include <libplacebo/utils/libav.h>
+
#include "config.h"
#if HAVE_ZLIB
@@ -45,6 +48,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"
@@ -106,8 +110,12 @@ typedef struct mkv_track {
double v_frate;
uint32_t colorspace;
int stereo_mode;
- struct mp_colorspace color;
- struct mp_spherical_params spherical;
+ 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;
@@ -186,7 +194,6 @@ typedef struct mkv_demuxer {
mkv_index_t *indexes;
size_t num_indexes;
bool index_complete;
- int index_mode;
int edition_id;
@@ -210,6 +217,12 @@ typedef struct mkv_demuxer {
// temporary data, and not normally larger than 0 or 1 elements.
struct block_info *blocks;
int num_blocks;
+
+ // Packets to return.
+ struct demux_packet **packets;
+ int num_packets;
+
+ bool probably_webm_dash_init;
} mkv_demuxer_t;
#define OPT_BASE_STRUCT struct demux_mkv_opts
@@ -218,20 +231,20 @@ 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 = {
.opts = (const m_option_t[]) {
- OPT_CHOICE("subtitle-preroll", subtitle_preroll, 0,
- ({"no", 0}, {"yes", 1}, {"index", 2})),
- OPT_DOUBLE("subtitle-preroll-secs", subtitle_preroll_secs,
- M_OPT_MIN, .min = 0),
- OPT_DOUBLE("subtitle-preroll-secs-index", subtitle_preroll_secs_index,
- M_OPT_MIN, .min = 0),
- OPT_CHOICE("probe-video-duration", probe_duration, 0,
- ({"no", 0}, {"yes", 1}, {"full", 2})),
- OPT_FLAG("probe-start-time", probe_start_time, 0),
+ {"subtitle-preroll", OPT_CHOICE(subtitle_preroll,
+ {"no", 0}, {"yes", 1}, {"index", 2})},
+ {"subtitle-preroll-secs", OPT_DOUBLE(subtitle_preroll_secs),
+ M_RANGE(0, DBL_MAX)},
+ {"subtitle-preroll-secs-index", OPT_DOUBLE(subtitle_preroll_secs_index),
+ M_RANGE(0, DBL_MAX)},
+ {"probe-video-duration", OPT_CHOICE(probe_duration,
+ {"no", 0}, {"yes", 1}, {"full", 2})},
+ {"probe-start-time", OPT_BOOL(probe_start_time)},
{0}
},
.size = sizeof(struct demux_mkv_opts),
@@ -239,6 +252,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 = true,
},
};
@@ -256,6 +270,17 @@ static void probe_first_timestamp(struct demuxer *demuxer);
static int read_next_block_into_queue(demuxer_t *demuxer);
static void free_block(struct block_info *block);
+static void add_packet(struct demuxer *demuxer, struct sh_stream *stream,
+ struct demux_packet *pkt)
+{
+ mkv_demuxer_t *mkv_d = demuxer->priv;
+ if (!pkt)
+ return;
+
+ pkt->stream = stream->index;
+ MP_TARRAY_APPEND(mkv_d, mkv_d->packets, mkv_d->num_packets, pkt);
+}
+
#define AAC_SYNC_EXTENSION_TYPE 0x02b7
static int aac_get_sample_rate_index(uint32_t sample_rate)
{
@@ -366,6 +391,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);
@@ -378,6 +407,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};
}
@@ -388,7 +419,7 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
stream_t *s = demuxer->stream;
int res = 0;
- MP_VERBOSE(demuxer, "|+ segment information...\n");
+ MP_DBG(demuxer, "|+ segment information...\n");
mkv_d->tc_scale = 1000000;
mkv_d->duration = 0;
@@ -398,12 +429,12 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
if (ebml_read_element(s, &parse_ctx, &info, &ebml_info_desc) < 0)
return -1;
if (info.muxing_app)
- MP_VERBOSE(demuxer, "| + muxing app: %s\n", info.muxing_app);
+ MP_DBG(demuxer, "| + muxing app: %s\n", info.muxing_app);
if (info.writing_app)
- MP_VERBOSE(demuxer, "| + writing app: %s\n", info.writing_app);
+ MP_DBG(demuxer, "| + writing app: %s\n", info.writing_app);
if (info.n_timecode_scale) {
mkv_d->tc_scale = info.timecode_scale;
- MP_VERBOSE(demuxer, "| + timecode scale: %"PRId64"\n", mkv_d->tc_scale);
+ MP_DBG(demuxer, "| + timecode scale: %"PRId64"\n", mkv_d->tc_scale);
if (mkv_d->tc_scale < 1 || mkv_d->tc_scale > INT_MAX) {
res = -1;
goto out;
@@ -411,7 +442,7 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
}
if (info.n_duration) {
mkv_d->duration = info.duration * mkv_d->tc_scale / 1e9;
- MP_VERBOSE(demuxer, "| + duration: %.3fs\n",
+ MP_DBG(demuxer, "| + duration: %.3fs\n",
mkv_d->duration);
demuxer->duration = mkv_d->duration;
}
@@ -425,11 +456,11 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
} else {
memcpy(demuxer->matroska_data.uid.segment, info.segment_uid.start,
len);
- MP_VERBOSE(demuxer, "| + segment uid");
+ MP_DBG(demuxer, "| + segment uid");
for (size_t i = 0; i < len; i++)
- MP_VERBOSE(demuxer, " %02x",
+ MP_DBG(demuxer, " %02x",
demuxer->matroska_data.uid.segment[i]);
- MP_VERBOSE(demuxer, "\n");
+ MP_DBG(demuxer, "\n");
}
}
if (demuxer->params && demuxer->params->matroska_wanted_uids) {
@@ -523,23 +554,23 @@ static void parse_trackaudio(struct demuxer *demuxer, struct mkv_track *track,
{
if (audio->n_sampling_frequency) {
track->a_sfreq = audio->sampling_frequency;
- MP_VERBOSE(demuxer, "| + Sampling frequency: %f\n", track->a_sfreq);
+ MP_DBG(demuxer, "| + Sampling frequency: %f\n", track->a_sfreq);
} else {
track->a_sfreq = 8000;
}
if (audio->n_output_sampling_frequency) {
track->a_osfreq = audio->output_sampling_frequency;
- MP_VERBOSE(demuxer, "| + Output sampling frequency: %f\n", track->a_osfreq);
+ MP_DBG(demuxer, "| + Output sampling frequency: %f\n", track->a_osfreq);
} else {
track->a_osfreq = track->a_sfreq;
}
if (audio->n_bit_depth) {
track->a_bps = audio->bit_depth;
- MP_VERBOSE(demuxer, "| + Bit depth: %"PRIu32"\n", track->a_bps);
+ MP_DBG(demuxer, "| + Bit depth: %"PRIu32"\n", track->a_bps);
}
if (audio->n_channels) {
track->a_channels = audio->channels;
- MP_VERBOSE(demuxer, "| + Channels: %"PRIu32"\n", track->a_channels);
+ MP_DBG(demuxer, "| + Channels: %"PRIu32"\n", track->a_channels);
} else {
track->a_channels = 1;
}
@@ -552,36 +583,75 @@ 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);
- MP_VERBOSE(demuxer, "| + Matrix: %s\n",
- m_opt_choice_str(mp_csp_names, track->color.space));
+ track->repr.sys = pl_system_from_av(colour->matrix_coefficients);
+ MP_DBG(demuxer, "| + Matrix: %s\n",
+ 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);
- MP_VERBOSE(demuxer, "| + Primaries: %s\n",
- m_opt_choice_str(mp_csp_prim_names, track->color.primaries));
+ track->color.primaries = pl_primaries_from_av(colour->primaries);
+ MP_DBG(demuxer, "| + Primaries: %s\n",
+ 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);
- MP_VERBOSE(demuxer, "| + Gamma: %s\n",
- m_opt_choice_str(mp_csp_trc_names, track->color.gamma));
+ track->color.transfer = pl_transfer_from_av(colour->transfer_characteristics);
+ MP_DBG(demuxer, "| + Gamma: %s\n",
+ 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);
- MP_VERBOSE(demuxer, "| + Levels: %s\n",
- m_opt_choice_str(mp_csp_levels_names, track->color.levels));
+ track->repr.levels = pl_levels_from_av(colour->range);
+ MP_DBG(demuxer, "| + Levels: %s\n",
+ 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;
- MP_VERBOSE(demuxer, "| + MaxCLL: %"PRIu64"\n", colour->max_cll);
+ track->color.hdr.max_cll = colour->max_cll;
+ MP_DBG(demuxer, "| + MaxCLL: %"PRIu64"\n", colour->max_cll);
+ }
+ if (colour->n_max_fall) {
+ track->color.hdr.max_fall = colour->max_fall;
+ MP_DBG(demuxer, "| + MaxFALL: %"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_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_VERBOSE(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);
}
}
}
@@ -589,43 +659,29 @@ static void parse_trackcolour(struct demuxer *demuxer, struct mkv_track *track,
static void parse_trackprojection(struct demuxer *demuxer, struct mkv_track *track,
struct ebml_projection *projection)
{
- if (projection->n_projection_type) {
- const char *name;
- switch (projection->projection_type) {
- case 0:
- name = "rectangular";
- track->spherical.type = MP_SPHERICAL_NONE;
- break;
- case 1:
- name = "equirectangular";
- track->spherical.type = MP_SPHERICAL_EQUIRECTANGULAR;
- break;
- default:
- name = "unknown";
- track->spherical.type = MP_SPHERICAL_UNKNOWN;
- }
- MP_VERBOSE(demuxer, "| + ProjectionType: %s (%"PRIu64")\n", name,
- projection->projection_type);
- }
- if (projection->n_projection_private) {
- MP_VERBOSE(demuxer, "| + ProjectionPrivate: %zd bytes\n",
- projection->projection_private.len);
- MP_WARN(demuxer, "Unknown ProjectionPrivate element.\n");
- }
if (projection->n_projection_pose_yaw) {
- track->spherical.ref_angles[0] = projection->projection_pose_yaw;
- MP_VERBOSE(demuxer, "| + ProjectionPoseYaw: %f\n",
- projection->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->spherical.ref_angles[1] = projection->projection_pose_pitch;
- MP_VERBOSE(demuxer, "| + ProjectionPosePitch: %f\n",
- projection->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->spherical.ref_angles[2] = projection->projection_pose_roll;
- MP_VERBOSE(demuxer, "| + ProjectionPoseRoll: %f\n",
- projection->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);
}
}
@@ -633,44 +689,57 @@ static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track,
struct ebml_video *video)
{
if (video->n_frame_rate) {
- MP_VERBOSE(demuxer, "| + Frame rate: %f (ignored)\n", video->frame_rate);
+ MP_DBG(demuxer, "| + Frame rate: %f (ignored)\n", video->frame_rate);
}
if (video->n_display_width) {
track->v_dwidth = video->display_width;
track->v_dwidth_set = true;
- MP_VERBOSE(demuxer, "| + Display width: %"PRIu32"\n",
- track->v_dwidth);
+ MP_DBG(demuxer, "| + Display width: %"PRIu32"\n", track->v_dwidth);
}
if (video->n_display_height) {
track->v_dheight = video->display_height;
track->v_dheight_set = true;
- MP_VERBOSE(demuxer, "| + Display height: %"PRIu32"\n",
- track->v_dheight);
+ MP_DBG(demuxer, "| + Display height: %"PRIu32"\n", track->v_dheight);
}
if (video->n_pixel_width) {
track->v_width = video->pixel_width;
- MP_VERBOSE(demuxer, "| + Pixel width: %"PRIu32"\n", track->v_width);
+ MP_DBG(demuxer, "| + Pixel width: %"PRIu32"\n", track->v_width);
}
if (video->n_pixel_height) {
track->v_height = video->pixel_height;
- MP_VERBOSE(demuxer, "| + Pixel height: %"PRIu32"\n", track->v_height);
+ MP_DBG(demuxer, "| + Pixel height: %"PRIu32"\n", track->v_height);
}
if (video->n_colour_space && video->colour_space.len == 4) {
uint8_t *d = (uint8_t *)&video->colour_space.start[0];
track->colorspace = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24);
- MP_VERBOSE(demuxer, "| + Colorspace: %#"PRIx32"\n",
- track->colorspace);
+ MP_DBG(demuxer, "| + Colorspace: %#"PRIx32"\n", track->colorspace);
}
if (video->n_stereo_mode) {
const char *name = MP_STEREO3D_NAME(video->stereo_mode);
if (name) {
track->stereo_mode = video->stereo_mode;
- MP_VERBOSE(demuxer, "| + StereoMode: %s\n", name);
+ MP_DBG(demuxer, "| + StereoMode: %s\n", name);
} else {
MP_WARN(demuxer, "Unknown StereoMode: %"PRIu64"\n",
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)
@@ -697,7 +766,7 @@ static void parse_trackentry(struct demuxer *demuxer,
track->tnum = entry->track_number;
if (track->tnum) {
- MP_VERBOSE(demuxer, "| + Track number: %d\n", track->tnum);
+ MP_DBG(demuxer, "| + Track number: %d\n", track->tnum);
} else {
MP_ERR(demuxer, "Missing track number!\n");
}
@@ -705,39 +774,39 @@ static void parse_trackentry(struct demuxer *demuxer,
if (entry->name) {
track->name = talloc_strdup(track, entry->name);
- MP_VERBOSE(demuxer, "| + Name: %s\n", track->name);
+ MP_DBG(demuxer, "| + Name: %s\n", track->name);
}
track->type = entry->track_type;
- MP_VERBOSE(demuxer, "| + Track type: ");
+ MP_DBG(demuxer, "| + Track type: ");
switch (track->type) {
case MATROSKA_TRACK_AUDIO:
- MP_VERBOSE(demuxer, "Audio\n");
+ MP_DBG(demuxer, "Audio\n");
break;
case MATROSKA_TRACK_VIDEO:
- MP_VERBOSE(demuxer, "Video\n");
+ MP_DBG(demuxer, "Video\n");
break;
case MATROSKA_TRACK_SUBTITLE:
- MP_VERBOSE(demuxer, "Subtitle\n");
+ MP_DBG(demuxer, "Subtitle\n");
break;
default:
- MP_VERBOSE(demuxer, "unknown\n");
+ MP_DBG(demuxer, "unknown\n");
break;
}
if (entry->n_audio) {
- MP_VERBOSE(demuxer, "| + Audio track\n");
+ MP_DBG(demuxer, "| + Audio track\n");
parse_trackaudio(demuxer, track, &entry->audio);
}
if (entry->n_video) {
- MP_VERBOSE(demuxer, "| + Video track\n");
+ MP_DBG(demuxer, "| + Video track\n");
parse_trackvideo(demuxer, track, &entry->video);
}
if (entry->codec_id) {
track->codec_id = talloc_strdup(track, entry->codec_id);
- MP_VERBOSE(demuxer, "| + Codec ID: %s\n", track->codec_id);
+ MP_DBG(demuxer, "| + Codec ID: %s\n", track->codec_id);
} else {
MP_ERR(demuxer, "Missing codec ID!\n");
track->codec_id = "";
@@ -748,36 +817,39 @@ static void parse_trackentry(struct demuxer *demuxer,
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_VERBOSE(demuxer, "| + CodecPrivate, length %u\n", track->private_size);
+ 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_VERBOSE(demuxer, "| + Language: %s\n", track->language);
+ MP_DBG(demuxer, "| + Language: %s\n", track->language);
} else {
track->language = talloc_strdup(track, "eng");
}
if (entry->n_flag_default) {
track->default_track = entry->flag_default;
- MP_VERBOSE(demuxer, "| + Default flag: %d\n", track->default_track);
+ MP_DBG(demuxer, "| + Default flag: %d\n", track->default_track);
} else {
track->default_track = 1;
}
if (entry->n_flag_forced) {
track->forced_track = entry->flag_forced;
- MP_VERBOSE(demuxer, "| + Forced flag: %d\n", track->forced_track);
+ MP_DBG(demuxer, "| + Forced flag: %d\n", track->forced_track);
}
if (entry->n_default_duration) {
track->default_duration = entry->default_duration / 1e9;
if (entry->default_duration == 0) {
- MP_VERBOSE(demuxer, "| + Default duration: 0");
+ MP_DBG(demuxer, "| + Default duration: 0");
} else {
track->v_frate = 1e9 / entry->default_duration;
- MP_VERBOSE(demuxer, "| + Default duration: %.3fms ( = %.3f fps)\n",
- entry->default_duration / 1000000.0, track->v_frate);
+ MP_DBG(demuxer, "| + Default duration: %.3fms ( = %.3f fps)\n",
+ entry->default_duration / 1000000.0, track->v_frate);
}
}
@@ -795,7 +867,7 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer)
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
stream_t *s = demuxer->stream;
- MP_VERBOSE(demuxer, "|+ segment tracks...\n");
+ MP_DBG(demuxer, "|+ segment tracks...\n");
struct ebml_tracks tracks = {0};
struct ebml_parse_ctx parse_ctx = {demuxer->log};
@@ -805,7 +877,7 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer)
mkv_d->tracks = talloc_zero_array(mkv_d, struct mkv_track*,
tracks.n_track_entry);
for (int i = 0; i < tracks.n_track_entry; i++) {
- MP_VERBOSE(demuxer, "| + a track...\n");
+ MP_DBG(demuxer, "| + a track...\n");
parse_trackentry(demuxer, &tracks.track_entry[i]);
}
talloc_free(parse_ctx.talloc_ctx);
@@ -855,7 +927,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;
}
@@ -895,7 +967,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);
@@ -924,7 +996,7 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer)
if (wanted_edition_uid)
wanted_edition = -1;
- MP_VERBOSE(demuxer, "Parsing chapters...\n");
+ MP_DBG(demuxer, "Parsing chapters...\n");
struct ebml_chapters file_chapters = {0};
struct ebml_parse_ctx parse_ctx = {demuxer->log};
if (ebml_read_element(s, &parse_ctx, &file_chapters,
@@ -1030,16 +1102,16 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer)
chapter.uid.edition = ca->chapter_segment_edition_uid;
else
chapter.uid.edition = 0;
- MP_VERBOSE(demuxer, "Chapter segment uid ");
+ MP_DBG(demuxer, "Chapter segment uid ");
for (int n = 0; n < len; n++)
- MP_VERBOSE(demuxer, "%02x ",
+ MP_DBG(demuxer, "%02x ",
chapter.uid.segment[n]);
- MP_VERBOSE(demuxer, "\n");
+ MP_DBG(demuxer, "\n");
}
}
- MP_VERBOSE(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),
@@ -1133,8 +1205,14 @@ static void process_tags(demuxer_t *demuxer)
if (dst) {
for (int j = 0; j < tag.n_simple_tag; j++) {
if (tag.simple_tag[j].tag_name && tag.simple_tag[j].tag_string) {
- mp_tags_set_str(dst, tag.simple_tag[j].tag_name,
- tag.simple_tag[j].tag_string);
+ char *name = tag.simple_tag[j].tag_name;
+ char *val = tag.simple_tag[j].tag_string;
+ char *old = mp_tags_get_str(dst, name);
+ if (old)
+ val = talloc_asprintf(NULL, "%s / %s", old, val);
+ mp_tags_set_str(dst, name, val);
+ if (old)
+ talloc_free(val);
}
}
}
@@ -1145,7 +1223,7 @@ static int demux_mkv_read_attachments(demuxer_t *demuxer)
{
stream_t *s = demuxer->stream;
- MP_VERBOSE(demuxer, "Parsing attachments...\n");
+ MP_DBG(demuxer, "Parsing attachments...\n");
struct ebml_attachments attachments = {0};
struct ebml_parse_ctx parse_ctx = {demuxer->log};
@@ -1164,8 +1242,8 @@ static int demux_mkv_read_attachments(demuxer_t *demuxer)
char *mime = attachment->file_mime_type;
demuxer_add_attachment(demuxer, name, mime, attachment->file_data.start,
attachment->file_data.len);
- MP_VERBOSE(demuxer, "Attachment: %s, %s, %zu bytes\n",
- name, mime, attachment->file_data.len);
+ MP_DBG(demuxer, "Attachment: %s, %s, %zu bytes\n",
+ name, mime, attachment->file_data.len);
}
talloc_free(parse_ctx.talloc_ctx);
@@ -1220,7 +1298,7 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
struct ebml_seek_head seekhead = {0};
struct ebml_parse_ctx parse_ctx = {demuxer->log};
- MP_VERBOSE(demuxer, "Parsing seek head...\n");
+ MP_DBG(demuxer, "Parsing seek head...\n");
if (ebml_read_element(s, &parse_ctx, &seekhead, &ebml_seek_head_desc) < 0) {
res = -1;
goto out;
@@ -1299,7 +1377,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++) {
@@ -1318,13 +1396,13 @@ static void add_coverart(struct demuxer *demuxer)
if (!codec)
continue;
struct sh_stream *sh = demux_alloc_sh_stream(STREAM_VIDEO);
- sh->demuxer_id = -1 - sh->index; // don't clash with mkv IDs
sh->codec->codec = codec;
sh->attached_picture = new_demux_packet_from(att->data, att->data_size);
if (sh->attached_picture) {
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);
@@ -1376,14 +1454,20 @@ static const char *const mkv_video_tags[][2] = {
{"V_MPEG4/ISO/ASP", "mpeg4"},
{"V_MPEG4/ISO/AP", "mpeg4"},
{"V_MPEG4/ISO/AVC", "h264"},
+ {"V_MPEG4/MS/V3", "msmpeg4v3"},
{"V_THEORA", "theora"},
{"V_VP8", "vp8"},
{"V_VP9", "vp9"},
{"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}
};
@@ -1469,8 +1553,10 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
}
const char *codec = sh_v->codec ? sh_v->codec : "";
- if (!strcmp(codec, "mjpeg"))
+ if (!strcmp(codec, "mjpeg")) {
sh_v->codec_tag = MKTAG('m', 'j', 'p', 'g');
+ track->require_keyframes = true;
+ }
if (extradata_size > 0x1000000) {
MP_WARN(demuxer, "Invalid CodecPrivate\n");
@@ -1488,6 +1574,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};
@@ -1497,7 +1594,11 @@ 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;
- sh_v->spherical = track->spherical;
+
+ if (track->v_projection_pose_roll) {
+ int rotate = lrintf(fmodf(fmodf(-1 * track->v_projection_pose_roll, 360) + 360, 360));
+ sh_v->rotate = rotate;
+ }
done:
demux_add_sh_stream(demuxer, sh);
@@ -1572,6 +1673,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" },
@@ -1621,7 +1723,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
// The private_data contains a WAVEFORMATEX struct
if (track->private_size < 18)
goto error;
- MP_VERBOSE(demuxer, "track with MS compat audio.\n");
+ MP_DBG(demuxer, "track with MS compat audio.\n");
unsigned char *h = track->private_data;
sh_a->codec_tag = AV_RL16(h + 0); // wFormatTag
if (track->a_channels == 0)
@@ -1760,10 +1862,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;
@@ -1819,6 +1925,8 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
sh_a->extradata = extradata;
sh_a->extradata_size = extradata_len;
+ sh->seek_preroll = track->codec_delay;
+
demux_add_sh_stream(demuxer, sh);
return 0;
@@ -1840,13 +1948,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;
@@ -1875,6 +1990,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)
@@ -1883,6 +2030,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 (int i = 0; i < 1000; i++) {
+ int ret = read_next_block_into_queue(demuxer);
+ if (ret == 1 && mkv_d->blocks[i].track == track) {
+ if (timecode != mkv_d->blocks[i].timecode)
+ ++video_blocks;
+ timecode = mkv_d->blocks[i].timecode;
+ }
+ // No need to read more
+ if (video_blocks > 1)