diff options
Diffstat (limited to 'demux/demux_mkv.c')
-rw-r--r-- | demux/demux_mkv.c | 123 |
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; } |