summaryrefslogtreecommitdiffstats
path: root/demux/demux_mkv.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--demux/demux_mkv.c123
1 files changed, 95 insertions, 28 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 41226c5..443cec0 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -36,6 +36,8 @@
#include <libavcodec/avcodec.h>
#include <libavcodec/version.h>
+#include <libplacebo/utils/libav.h>
+
#include "config.h"
#if HAVE_ZLIB
@@ -108,10 +110,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;
- bool v_projection_pose_roll_set;
uint32_t a_channels, a_bps;
float a_sfreq;
@@ -387,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);
@@ -399,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};
}
@@ -573,24 +583,24 @@ 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.hdr.max_cll = colour->max_cll;
@@ -649,15 +659,30 @@ 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_pose_yaw || projection->n_projection_pose_pitch)
- MP_WARN(demuxer, "Projection pose yaw/pitch not supported!\n");
+ 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;
- track->v_projection_pose_roll_set = true;
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,
@@ -795,7 +820,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 {
@@ -1082,8 +1110,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),
@@ -1438,6 +1466,7 @@ static const char *const mkv_video_tags[][2] = {
{"V_PNG", "png"},
{"V_AVS2", "avs2"},
{"V_AVS3", "avs3"},
+ {"V_FFV1", "ffv1"},
{0}
};
@@ -1523,10 +1552,6 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
}
const char *codec = sh_v->codec ? sh_v->codec : "";
- if (mp_codec_is_image(codec)) {
- sh->still_image = true;
- sh->image = true;
- }
if (!strcmp(codec, "mjpeg")) {
sh_v->codec_tag = MKTAG('m', 'j', 'p', 'g');
track->require_keyframes = true;
@@ -1569,8 +1594,8 @@ 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_set) {
- int rotate = lrintf(fmodf(fmodf(track->v_projection_pose_roll, 360) + 360, 360));
+ if (track->v_projection_pose_roll) {
+ int rotate = lrintf(fmodf(fmodf(-1 * track->v_projection_pose_roll, 360) + 360, 360));
sh_v->rotate = rotate;
}
@@ -1647,6 +1672,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" },
@@ -1835,7 +1861,7 @@ 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;
@@ -1921,6 +1947,7 @@ 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"},
@@ -1962,7 +1989,7 @@ 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 (!strcmp(sh->codec->codec, "arib_caption") && track->private_size >= 3) {
+ 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);
@@ -2002,6 +2029,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)
+ 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;
@@ -2034,6 +2094,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);
@@ -2254,6 +2316,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;
}
@@ -2795,6 +2858,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)
@@ -2944,20 +3009,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;
}