diff options
Diffstat (limited to '')
-rw-r--r-- | demux/cache.c | 8 | ||||
-rw-r--r-- | demux/codec_tags.c | 79 | ||||
-rw-r--r-- | demux/codec_tags.h | 2 | ||||
-rw-r--r-- | demux/demux.c | 4 | ||||
-rw-r--r-- | demux/demux_disc.c | 2 | ||||
-rw-r--r-- | demux/demux_lavf.c | 25 | ||||
-rw-r--r-- | demux/demux_libarchive.c | 2 | ||||
-rw-r--r-- | demux/demux_mf.c | 76 | ||||
-rw-r--r-- | demux/demux_mkv.c | 123 | ||||
-rw-r--r-- | demux/demux_playlist.c | 8 | ||||
-rw-r--r-- | demux/packet.h | 6 | ||||
-rw-r--r-- | demux/stheader.h | 14 |
12 files changed, 205 insertions, 144 deletions
diff --git a/demux/cache.c b/demux/cache.c index 562eab0..6398f61 100644 --- a/demux/cache.c +++ b/demux/cache.c @@ -26,6 +26,7 @@ #include "common/msg.h" #include "common/av_common.h" #include "demux.h" +#include "misc/io_utils.h" #include "options/path.h" #include "options/m_config.h" #include "options/m_option.h" @@ -214,7 +215,7 @@ int64_t demux_cache_write(struct demux_cache *cache, struct demux_packet *dp) } assert(!dp->is_cached); - assert(dp->len >= 0 && dp->len <= INT32_MAX); + assert(dp->len <= INT32_MAX); assert(dp->avpacket->flags >= 0 && dp->avpacket->flags <= INT32_MAX); assert(dp->avpacket->side_data_elems >= 0 && dp->avpacket->side_data_elems <= INT32_MAX); @@ -260,7 +261,7 @@ int64_t demux_cache_write(struct demux_cache *cache, struct demux_packet *dp) for (int n = 0; n < dp->avpacket->side_data_elems; n++) { AVPacketSideData *sd = &dp->avpacket->side_data[n]; - assert(sd->size >= 0 && sd->size <= INT32_MAX); + assert(sd->size <= INT32_MAX); assert(sd->type >= 0 && sd->type <= INT32_MAX); struct sd_header sd_hd = { @@ -293,9 +294,6 @@ struct demux_packet *demux_cache_read(struct demux_cache *cache, uint64_t pos) if (!read_raw(cache, &hd, sizeof(hd))) return NULL; - if (hd.data_len >= (size_t)-1) - return NULL; - struct demux_packet *dp = new_demux_packet(hd.data_len); if (!dp) goto fail; diff --git a/demux/codec_tags.c b/demux/codec_tags.c index 55700d9..d118fbe 100644 --- a/demux/codec_tags.c +++ b/demux/codec_tags.c @@ -48,8 +48,8 @@ static const char *lookup_tag(int type, uint32_t tag) /* * As seen in the following page: * - * https://web.archive.org/web/20220406060153/ - * http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html + * <https://web.archive.org/web/20220406060153/ + * http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html> * * Note that the GUID struct in the above citation has its * integers encoded in little-endian format, which means that @@ -180,81 +180,6 @@ void mp_set_pcm_codec(struct mp_codec_params *c, bool sign, bool is_float, c->codec = talloc_strdup(c, codec); } -// map file extension/type to an image codec name -static const char *const type_to_codec[][2] = { - { "bmp", "bmp" }, - { "dpx", "dpx" }, - { "j2c", "jpeg2000" }, - { "j2k", "jpeg2000" }, - { "jp2", "jpeg2000" }, - { "jpc", "jpeg2000" }, - { "jpeg", "mjpeg" }, - { "jpg", "mjpeg" }, - { "jps", "mjpeg" }, - { "jls", "ljpeg" }, - { "thm", "mjpeg" }, - { "db", "mjpeg" }, - { "pcd", "photocd" }, - { "pfm", "pfm" }, - { "phm", "phm" }, - { "hdr", "hdr" }, - { "pcx", "pcx" }, - { "png", "png" }, - { "pns", "png" }, - { "ptx", "ptx" }, - { "tga", "targa" }, - { "tif", "tiff" }, - { "tiff", "tiff" }, - { "sgi", "sgi" }, - { "sun", "sunrast" }, - { "ras", "sunrast" }, - { "rs", "sunrast" }, - { "ra", "sunrast" }, - { "im1", "sunrast" }, - { "im8", "sunrast" }, - { "im24", "sunrast" }, - { "im32", "sunrast" }, - { "sunras", "sunrast" }, - { "xbm", "xbm" }, - { "pam", "pam" }, - { "pbm", "pbm" }, - { "pgm", "pgm" }, - { "pgmyuv", "pgmyuv" }, - { "ppm", "ppm" }, - { "pnm", "ppm" }, - { "gif", "gif" }, - { "pix", "brender_pix" }, - { "exr", "exr" }, - { "pic", "pictor" }, - { "qoi", "qoi" }, - { "xface", "xface" }, - { "xwd", "xwd" }, - { "svg", "svg" }, - {0} -}; - -bool mp_codec_is_image(const char *codec) -{ - if (codec) { - for (int n = 0; type_to_codec[n][0]; n++) { - if (strcasecmp(type_to_codec[n][1], codec) == 0) - return true; - } - } - return false; -} - -const char *mp_map_type_to_image_codec(const char *type) -{ - if (type) { - for (int n = 0; type_to_codec[n][0]; n++) { - if (strcasecmp(type_to_codec[n][0], type) == 0) - return type_to_codec[n][1]; - } - } - return NULL; -}; - static const char *const mimetype_to_codec[][2] = { {"image/apng", "apng"}, {"image/avif", "av1"}, diff --git a/demux/codec_tags.h b/demux/codec_tags.h index 8fc49df..147760b 100644 --- a/demux/codec_tags.h +++ b/demux/codec_tags.h @@ -28,8 +28,6 @@ void mp_set_codec_from_tag(struct mp_codec_params *c); void mp_set_pcm_codec(struct mp_codec_params *c, bool sign, bool is_float, int bits, bool is_be); -bool mp_codec_is_image(const char *codec); -const char *mp_map_type_to_image_codec(const char *type); const char *mp_map_mimetype_to_video_codec(const char *mimetype); #endif diff --git a/demux/demux.c b/demux/demux.c index 256e1b6..9aa63bc 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -367,7 +367,7 @@ struct demux_stream { bool eager; // try to keep at least 1 packet queued // if false, this stream is disabled, or passively // read (like subtitles) - bool still_image; // stream has still video images + bool still_image; // stream consists of multiple sparse still images bool refreshing; // finding old position after track switches bool eof; // end of demuxed stream? (true if no more packets) @@ -663,7 +663,7 @@ static void update_seek_ranges(struct demux_cached_range *range) } } - if (range->seek_start >= range->seek_end) + if (range->seek_start >= range->seek_end && !(range->is_bof && range->is_eof)) goto broken; prune_metadata(range); diff --git a/demux/demux_disc.c b/demux/demux_disc.c index 3dfff45..8cd4b7b 100644 --- a/demux/demux_disc.c +++ b/demux/demux_disc.c @@ -94,7 +94,7 @@ static void add_dvd_streams(demuxer_t *demuxer) // emulate the extradata struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS; - struct mp_cmat cmatrix; + struct pl_transform3x3 cmatrix; mp_get_csp_matrix(&csp, &cmatrix); char *s = talloc_strdup(sh, ""); diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 663fab4..fa9fd5c 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -29,14 +29,15 @@ #include <libavformat/avformat.h> #include <libavformat/avio.h> + #include <libavutil/avutil.h> #include <libavutil/avstring.h> -#include <libavutil/mathematics.h> -#include <libavutil/replaygain.h> #include <libavutil/display.h> -#include <libavutil/opt.h> - #include <libavutil/dovi_meta.h> +#include <libavutil/mathematics.h> +#include <libavutil/opt.h> +#include <libavutil/pixdesc.h> +#include <libavutil/replaygain.h> #include "audio/chmap_avchannel.h" @@ -146,7 +147,6 @@ struct format_hack { // segment, with e.g. HLS, player knows about the playlist main file only). bool clear_filepos : 1; bool linearize_audio_ts : 1;// compensate timestamp resets (audio only) - bool fix_editlists : 1; bool is_network : 1; bool no_seek : 1; bool no_pcm_seek : 1; @@ -175,8 +175,7 @@ static const struct format_hack format_hacks[] = { {"mxf", .use_stream_ids = true}, {"avi", .use_stream_ids = true}, {"asf", .use_stream_ids = true}, - {"mp4", .skipinfo = true, .fix_editlists = true, .no_pcm_seek = true, - .use_stream_ids = true}, + {"mp4", .skipinfo = true, .no_pcm_seek = true, .use_stream_ids = true}, {"matroska", .skipinfo = true, .no_pcm_seek = true, .use_stream_ids = true}, {"v4l2", .no_seek = true}, @@ -512,6 +511,10 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check) break; } + // AVIF always needs to find stream info + if (bstrcasecmp0(ext, "avif") == 0) + priv->format_hack.skipinfo = false; + if (score >= lavfdopts->probescore) break; @@ -673,6 +676,7 @@ static bool is_image(AVStream *st, bool attached_picture, const AVInputFormat *a bstr_endswith0(bstr0(avif->name), "_pipe") || strcmp(avif->name, "alias_pix") == 0 || strcmp(avif->name, "gif") == 0 || + strcmp(avif->name, "ico") == 0 || strcmp(avif->name, "image2pipe") == 0 || (st->codecpar->codec_id == AV_CODEC_ID_AV1 && st->nb_frames == 1) ); @@ -723,6 +727,7 @@ static void handle_new_stream(demuxer_t *demuxer, int i) sh->codec->samplerate = codec->sample_rate; sh->codec->bitrate = codec->bit_rate; + sh->codec->format_name = talloc_strdup(sh, av_get_sample_fmt_name(codec->format)); double delay = 0; if (codec->sample_rate > 0) @@ -761,6 +766,7 @@ static void handle_new_stream(demuxer_t *demuxer, int i) sh->codec->disp_w = codec->width; sh->codec->disp_h = codec->height; + sh->codec->format_name = talloc_strdup(sh, av_get_pix_fmt_name(codec->format)); if (st->avg_frame_rate.num) sh->codec->fps = av_q2d(st->avg_frame_rate); if (is_image(st, sh->attached_picture, priv->avif)) { @@ -1065,9 +1071,6 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) guess_and_set_vobsub_name(demuxer, &dopts); - if (priv->format_hack.fix_editlists) - av_dict_set(&dopts, "advanced_editlist", "0", 0); - avfc->interrupt_callback = (AVIOInterruptCB){ .callback = interrupt_cb, .opaque = demuxer, @@ -1267,8 +1270,6 @@ static bool demux_lavf_read_packet(struct demuxer *demux, dp->duration = pkt->duration * av_q2d(st->time_base); dp->pos = pkt->pos; dp->keyframe = pkt->flags & AV_PKT_FLAG_KEY; - if (pkt->flags & AV_PKT_FLAG_DISCARD) - MP_ERR(demux, "Edit lists are not correctly supported (FFmpeg issue).\n"); av_packet_unref(pkt); if (priv->format_hack.clear_filepos) diff --git a/demux/demux_libarchive.c b/demux/demux_libarchive.c index ec50498..a85e40f 100644 --- a/demux/demux_libarchive.c +++ b/demux/demux_libarchive.c @@ -91,7 +91,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) qsort(files, num_files, sizeof(files[0]), cmp_filename); for (int n = 0; n < num_files; n++) - playlist_add_file(pl, files[n]); + playlist_append_file(pl, files[n]); playlist_set_stream_flags(pl, demuxer->stream_origin); diff --git a/demux/demux_mf.c b/demux/demux_mf.c index 8f7cb70..d971f04 100644 --- a/demux/demux_mf.c +++ b/demux/demux_mf.c @@ -95,7 +95,6 @@ static mf_t *open_mf_pattern(void *talloc_ctx, struct demuxer *d, char *filename } free_stream(s); - mp_info(log, "number of files: %d\n", mf->nr_of_files); goto exit_mf; } mp_info(log, "%s is not indirect filelist\n", filename + 1); @@ -117,7 +116,6 @@ static mf_t *open_mf_pattern(void *talloc_ctx, struct demuxer *d, char *filename } talloc_free(fname2); } - mp_info(log, "number of files: %d\n", mf->nr_of_files); goto exit_mf; } @@ -143,7 +141,6 @@ static mf_t *open_mf_pattern(void *talloc_ctx, struct demuxer *d, char *filename continue; mf_add(mf, gg.gl_pathv[i]); } - mp_info(log, "number of files: %d\n", mf->nr_of_files); globfree(&gg); goto exit_mf; } @@ -189,7 +186,9 @@ static mf_t *open_mf_pattern(void *talloc_ctx, struct demuxer *d, char *filename // nspec==0 (zero specifiers) is rejected because fname wouldn't advance. if (bad_spec || nspec != 1) { - mp_err(log, "unsupported expr format: '%s'\n", filename); + mp_err(log, + "unsupported expr format: '%s' - exactly one format specifier of the form %%[.][NUM]d is expected\n", + filename); goto exit_mf; } @@ -208,9 +207,8 @@ static mf_t *open_mf_pattern(void *talloc_ctx, struct demuxer *d, char *filename } } - mp_info(log, "number of files: %d\n", mf->nr_of_files); - exit_mf: + mp_info(log, "number of files: %d\n", mf->nr_of_files); return mf; } @@ -284,6 +282,65 @@ static bool demux_mf_read_packet(struct demuxer *demuxer, return true; } +// map file extension/type to a codec name + +static const struct { + const char *type; + const char *codec; +} type2format[] = { + { "bmp", "bmp" }, + { "dpx", "dpx" }, + { "j2c", "jpeg2000" }, + { "j2k", "jpeg2000" }, + { "jp2", "jpeg2000" }, + { "jpc", "jpeg2000" }, + { "jpeg", "mjpeg" }, + { "jpg", "mjpeg" }, + { "jps", "mjpeg" }, + { "jls", "ljpeg" }, + { "thm", "mjpeg" }, + { "db", "mjpeg" }, + { "pcd", "photocd" }, + { "pfm", "pfm" }, + { "phm", "phm" }, + { "hdr", "hdr" }, + { "pcx", "pcx" }, + { "png", "png" }, + { "pns", "png" }, + { "ptx", "ptx" }, + { "tga", "targa" }, + { "tif", "tiff" }, + { "tiff", "tiff" }, + { "sgi", "sgi" }, + { "sun", "sunrast" }, + { "ras", "sunrast" }, + { "rs", "sunrast" }, + { "ra", "sunrast" }, + { "im1", "sunrast" }, + { "im8", "sunrast" }, + { "im24", "sunrast" }, + { "im32", "sunrast" }, + { "sunras", "sunrast" }, + { "xbm", "xbm" }, + { "pam", "pam" }, + { "pbm", "pbm" }, + { "pgm", "pgm" }, + { "pgmyuv", "pgmyuv" }, + { "ppm", "ppm" }, + { "pnm", "ppm" }, + { "gif", "gif" }, // usually handled by demux_lavf + { "pix", "brender_pix" }, + { "exr", "exr" }, + { "pic", "pictor" }, + { "qoi", "qoi" }, + { "xface", "xface" }, + { "xwd", "xwd" }, + { "svg", "svg" }, + { "webp", "webp" }, + { "jxl", "jpegxl" }, + {0} +}; + static const char *probe_format(mf_t *mf, char *type, enum demux_check check) { if (check > DEMUX_CHECK_REQUEST) @@ -294,9 +351,10 @@ static const char *probe_format(mf_t *mf, char *type, enum demux_check check) if (p) type = p + 1; } - const char *codec = mp_map_type_to_image_codec(type); - if (codec) - return codec; + for (int i = 0; type2format[i].type; i++) { + if (type && strcasecmp(type, type2format[i].type) == 0) + return type2format[i].codec; + } if (check == DEMUX_CHECK_REQUEST) { if (!org_type) { MP_ERR(mf, "file type was not set! (try --mf-type=ext)\n"); 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; } diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index 63355be..66be4b1 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -202,7 +202,7 @@ static void pl_free_line(struct pl_parser *p, bstr line) static void pl_add(struct pl_parser *p, bstr entry) { char *s = bstrto0(NULL, entry); - playlist_add_file(p->pl, s); + playlist_append_file(p->pl, s); talloc_free(s); } @@ -266,7 +266,7 @@ ok: talloc_free(fn); e->title = talloc_steal(e, title); title = NULL; - playlist_add(p->pl, e); + playlist_insert_at(p->pl, e, NULL); } pl_free_line(p, line); line = pl_get_line(p); @@ -296,7 +296,7 @@ static int parse_ref_init(struct pl_parser *p) bstr burl = bstr0(p->s->url); if (bstr_eatstart0(&burl, "http://") && check_mimetype(p->s, mmsh_types)) { MP_INFO(p, "Redirecting to mmsh://\n"); - playlist_add_file(p->pl, talloc_asprintf(p, "mmsh://%.*s", BSTR_P(burl))); + playlist_append_file(p->pl, talloc_asprintf(p, "mmsh://%.*s", BSTR_P(burl))); return 0; } @@ -456,7 +456,7 @@ static bool scan_dir(struct pl_parser *p, char *path, scan_dir(p, file, dir_stack, num_dir_stack + 1); } else { - playlist_add_file(p->pl, dir_entries[n].path); + playlist_append_file(p->pl, dir_entries[n].path); } } diff --git a/demux/packet.h b/demux/packet.h index cd1183d..8087216 100644 --- a/demux/packet.h +++ b/demux/packet.h @@ -58,6 +58,12 @@ typedef struct demux_packet { struct mp_codec_params *codec; // set to non-NULL iff segmented is set double start, end; // set to non-NOPTS iff segmented is set + // subtitles only + bool animated; + bool seen; + int seen_pos; + double sub_duration; + // private struct demux_packet *next; struct AVPacket *avpacket; // keep the buffer allocation and sidedata diff --git a/demux/stheader.h b/demux/stheader.h index 1bc036d..4f33bbc 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -49,7 +49,7 @@ struct sh_stream { bool visual_impaired_track; // container flag bool hearing_impaired_track;// container flag bool image; // video stream is an image - bool still_image; // video stream contains still images + bool still_image; // video consists of multiple sparse still images int hls_bitrate; int program_id; @@ -72,6 +72,12 @@ struct mp_codec_params { // E.g. "h264" (usually corresponds to AVCodecDescriptor.name) const char *codec; + // Usually corresponds to AVCodecDescriptor.long_name + const char *codec_desc; + + // Corresponding codec profile + const char *codec_profile; + // Usually a FourCC, exact meaning depends on codec. unsigned int codec_tag; @@ -105,11 +111,13 @@ struct mp_codec_params { int disp_w, disp_h; // display size int rotate; // intended display rotation, in degrees, [0, 359] int stereo_mode; // mp_stereo3d_mode (0 if none/unknown) - struct mp_colorspace color; // colorspace info where available - struct mp_rect crop; // crop to be applied + struct pl_color_space color; // colorspace info where available + struct pl_color_repr repr; // color representaion info where available + struct mp_rect crop; // crop to be applied // STREAM_VIDEO + STREAM_AUDIO int bits_per_coded_sample; + char *format_name; // pixel format (video) or sample format (audio) // STREAM_SUB double frame_based; // timestamps are frame-based (and this is the |