diff --git a/patches/ffmpeg-n8.1.2/0028-bluray-probe-streams-from-later-playlist-clips.patch b/patches/ffmpeg-n8.1.2/0028-bluray-probe-streams-from-later-playlist-clips.patch new file mode 100644 index 00000000..3f90bce6 --- /dev/null +++ b/patches/ffmpeg-n8.1.2/0028-bluray-probe-streams-from-later-playlist-clips.patch @@ -0,0 +1,181 @@ +From 65624c5e5a0427461d43feaadec6d780de71fcbb Mon Sep 17 00:00:00 2001 +From: Justin +Date: Wed, 19 Aug 2026 12:06:29 +0800 +Subject: [PATCH] bluray probe streams from later playlist clips + +--- + libavformat/bluray.c | 121 +++++++++++++++++++++++++++++++++++++++++++ + libavformat/demux.c | 14 +++++ + 2 files changed, 135 insertions(+) + +diff --git a/libavformat/bluray.c b/libavformat/bluray.c +index 2bed615..c171b96 100644 +--- a/libavformat/bluray.c ++++ b/libavformat/bluray.c +@@ -179,6 +179,125 @@ static void bluray_set_stream_language(URLContext *h, AVStream *st, + av_dict_set(&st->metadata, "language", lang, 0); + } + ++static int bluray_pid_seen_before(const BLURAY_TITLE_INFO *title_info, ++ enum AVMediaType type, uint32_t clip_idx, ++ int pid) ++{ ++ uint32_t i; ++ ++ for (i = 0; i < clip_idx; i++) { ++ const BLURAY_CLIP_INFO *clip = &title_info->clips[i]; ++ const BLURAY_STREAM_INFO *streams; ++ int stream_count; ++ int j; ++ ++ if (type == AVMEDIA_TYPE_AUDIO) { ++ streams = clip->audio_streams; ++ stream_count = clip->audio_stream_count; ++ } else { ++ streams = clip->pg_streams; ++ stream_count = clip->pg_stream_count; ++ } ++ ++ for (j = 0; j < stream_count; j++) { ++ if (streams[j].pid == pid) ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static uint64_t bluray_latest_deferred_stream_time(const BLURAY_TITLE_INFO *title_info) ++{ ++ uint64_t latest_start_time = 0; ++ uint32_t clip_idx; ++ ++ for (clip_idx = 1; clip_idx < title_info->clip_count; clip_idx++) { ++ const BLURAY_CLIP_INFO *clip = &title_info->clips[clip_idx]; ++ const BLURAY_STREAM_INFO *streams[] = { ++ clip->audio_streams, ++ clip->pg_streams, ++ }; ++ const int stream_counts[] = { ++ clip->audio_stream_count, ++ clip->pg_stream_count, ++ }; ++ const enum AVMediaType types[] = { ++ AVMEDIA_TYPE_AUDIO, ++ AVMEDIA_TYPE_SUBTITLE, ++ }; ++ int group_idx; ++ ++ for (group_idx = 0; group_idx < FF_ARRAY_ELEMS(streams); group_idx++) { ++ int stream_idx; ++ ++ for (stream_idx = 0; stream_idx < stream_counts[group_idx]; stream_idx++) { ++ int pid = streams[group_idx][stream_idx].pid; ++ ++ if (pid > 0 && ++ !bluray_pid_seen_before(title_info, types[group_idx], ++ clip_idx, pid)) { ++ latest_start_time = FFMAX(latest_start_time, ++ clip->start_time); ++ } ++ } ++ } ++ } ++ ++ return latest_start_time; ++} ++ ++#define BLURAY_PROBE_MARGIN (3LL * AV_TIME_BASE) ++#define BLURAY_PROBE_BITRATE 64000000LL ++#define BLURAY_MAX_PROBE_SIZE (256LL * 1024 * 1024) ++ ++static void bluray_configure_stream_probe(URLContext *h, AVFormatContext *ic, ++ const BLURAY_TITLE_INFO *title_info) ++{ ++ uint64_t deferred_start_time; ++ int64_t analyze_duration; ++ int64_t probe_size; ++ int64_t uncapped_probe_size; ++ ++ deferred_start_time = bluray_latest_deferred_stream_time(title_info); ++ if (!deferred_start_time) ++ return; ++ ++ analyze_duration = av_rescale_q(deferred_start_time, ++ (AVRational){ 1, 90000 }, ++ AV_TIME_BASE_Q); ++ analyze_duration = FFMIN(analyze_duration, INT64_MAX - BLURAY_PROBE_MARGIN) + ++ BLURAY_PROBE_MARGIN; ++ uncapped_probe_size = av_rescale(analyze_duration, BLURAY_PROBE_BITRATE, ++ 8LL * AV_TIME_BASE); ++ probe_size = FFMIN(uncapped_probe_size, BLURAY_MAX_PROBE_SIZE); ++ ++ if (ic->max_analyze_duration >= analyze_duration && ++ ic->probesize >= probe_size) ++ return; ++ ++ if (uncapped_probe_size > BLURAY_MAX_PROBE_SIZE) { ++ av_log(h, AV_LOG_WARNING, ++ "bluray deferred streams require probe size %"PRId64 ++ ", capped at %"PRId64" bytes\n", ++ uncapped_probe_size, BLURAY_MAX_PROBE_SIZE); ++ } ++ ++ av_log(h, AV_LOG_INFO, ++ "bluray deferred streams start by %.3f seconds; " ++ "analyzeduration %"PRId64" -> %"PRId64 ++ ", probesize %"PRId64" -> %"PRId64"\n", ++ deferred_start_time / 90000.0, ++ ic->max_analyze_duration, ++ FFMAX(ic->max_analyze_duration, analyze_duration), ++ ic->probesize, FFMAX(ic->probesize, probe_size)); ++ ++ ic->max_analyze_duration = FFMAX(ic->max_analyze_duration, ++ analyze_duration); ++ ic->probesize = FFMAX(ic->probesize, probe_size); ++} ++ + static int bluray_close(URLContext *h) + { + BlurayContext *bd = h->priv_data; +@@ -378,6 +497,8 @@ static int bluray_parse_priv(AVFormatContext *ic, URLContext *h) + goto fail; + } + ++ bluray_configure_stream_probe(h, ic, title_info); ++ + for (i = 0; i < ic->nb_streams; i++) { + bluray_set_stream_language(h, ic->streams[i], title_info); + } +diff --git a/libavformat/demux.c b/libavformat/demux.c +index f40defa..1d10292 100644 +--- a/libavformat/demux.c ++++ b/libavformat/demux.c +@@ -50,6 +50,18 @@ + #include "internal.h" + #include "url.h" + ++static void call_url_parse_priv(AVFormatContext *s) ++{ ++ URLContext *url_context; ++ ++ if (!s->pb) ++ return; ++ ++ url_context = ffio_geturlcontext(s->pb); ++ if (url_context && url_context->prot && url_context->prot->url_parse_priv) ++ url_context->prot->url_parse_priv(s, url_context); ++} ++ + static int64_t wrap_timestamp(const AVStream *st, int64_t timestamp) + { + const FFStream *const sti = cffstream(st); +@@ -3245,6 +3257,8 @@ find_stream_info_err: + av_log(ic, AV_LOG_DEBUG, "After avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d frames:%d\n", + avio_tell(ic->pb), ctx->bytes_read, ctx->seek_count, count); + } ++ if (ret >= 0) ++ call_url_parse_priv(ic); + return ret; + + unref_then_goto_end: