1- From e6fdbabaf8902e834a745705c851db193b8d553f Mon Sep 17 00:00:00 2001
1+ From 22d3925e8fec79ca0dd23dbdb7eb6f9a9d53ee96 Mon Sep 17 00:00:00 2001
22From: qianlongxu <qianlongxu@gmail.com>
3- Date: Tue, 17 Dec 2024 18:59:49 +0800
4- Subject: [PATCH 21] custom bluray fs for network Blu-ray Disc and BDMV
3+ Date: Mon, 24 Mar 2025 09:31:42 +0800
4+ Subject: [PATCH 27] custom bluray fs for network Blu-ray Disc and BDMV
55
66---
77 libavformat/Makefile | 2 +-
8- libavformat/bluray.c | 32 ++-
8+ libavformat/bluray.c | 118 +++++++ ++-
99 libavformat/bluray_custom_fs.c | 413 +++++++++++++++++++++++++++++++++
1010 libavformat/bluray_custom_fs.h | 29 +++
11- 4 files changed, 468 insertions(+), 8 deletions(-)
11+ 4 files changed, 553 insertions(+), 9 deletions(-)
1212 create mode 100644 libavformat/bluray_custom_fs.c
1313 create mode 100644 libavformat/bluray_custom_fs.h
1414
1515diff --git a/libavformat/Makefile b/libavformat/Makefile
16- index 427c45a..ffc32b9 100644
16+ index 19ba54e..9ad6d87 100644
1717--- a/libavformat/Makefile
1818+++ b/libavformat/Makefile
19- @@ -666 ,7 +666 ,7 @@ OBJS-$(CONFIG_VAPOURSYNTH_DEMUXER) += vapoursynth.o
19+ @@ -667 ,7 +667 ,7 @@ OBJS-$(CONFIG_VAPOURSYNTH_DEMUXER) += vapoursynth.o
2020 # protocols I/O
2121 OBJS-$(CONFIG_ASYNC_PROTOCOL) += async.o
2222 OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o
@@ -26,10 +26,10 @@ index 427c45a..ffc32b9 100644
2626 OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o
2727 OBJS-$(CONFIG_CONCATF_PROTOCOL) += concat.o
2828diff --git a/libavformat/bluray.c b/libavformat/bluray.c
29- index bf5b88d..96a799a 100644
29+ index 1845551..cd50523 100644
3030--- a/libavformat/bluray.c
3131+++ b/libavformat/bluray.c
32- @@ -21,21 +21,22 @@
32+ @@ -21,23 +21,27 @@
3333 */
3434
3535 #include <libbluray/bluray.h>
@@ -38,9 +38,9 @@ index bf5b88d..96a799a 100644
3838 #include "libavutil/avstring.h"
3939 #include "libavformat/url.h"
4040 #include "libavutil/opt.h"
41- #include "libavutil/dict.h"
42- #include "libavformat/avformat.h"
4341+ #include "bluray_custom_fs.h"
42+ + #include "libavutil/dict.h"
43+ + #include "libavformat/avformat.h"
4444
4545- #define BLURAY_PROTO_PREFIX "bluray:"
4646+ #define BLURAY_PROTO_PREFIX "bluray://"
@@ -55,7 +55,12 @@ index bf5b88d..96a799a 100644
5555 int playlist;
5656 int angle;
5757 int chapter;
58- @@ -110,7 +111,7 @@ static int bluray_close(URLContext *h)
58+ /*int region;*/
59+ + int title_idx;
60+ } BlurayContext;
61+
62+ #define OFFSET(x) offsetof(BlurayContext, x)
63+ @@ -106,23 +110,58 @@ static int bluray_close(URLContext *h)
5964 if (bd->bd) {
6065 bd_close(bd->bd);
6166 }
@@ -64,24 +69,38 @@ index bf5b88d..96a799a 100644
6469 return 0;
6570 }
6671
67- @@ -126,7 +127,7 @@ static void bluray_DebugHandler(const char *psz)
68- }
69- #endif
70-
7172- static int bluray_open(URLContext *h, const char *path, int flags)
72- + static int bluray_open(URLContext *h, const char *path, int flags, AVDictionary **options)
73+ + #ifdef DEBUG_BLURAY
74+ + #include <libbluray/log_control.h>
75+ + #define BLURAY_DEBUG_MASK 0xFFFFF //(0xFFFFF & ~DBG_STREAM)
76+ +
77+ + static void bluray_DebugHandler(const char *psz)
7378 {
74- #ifdef DEBUG_BLURAY
75- bd_set_debug_mask(BLURAY_DEBUG_MASK);
76- @@ -138,11 +139,28 @@ static int bluray_open(URLContext *h, const char *path, int flags)
79+ + size_t len = strlen(psz);
80+ + if(len < 1) return;
81+ + av_log(NULL, AV_LOG_INFO, "[bluray] %s\n",psz);
82+ + }
83+ + #endif
84+ +
85+ +
86+ + static int bluray_open(URLContext *h, const char *path, int flags, AVDictionary **options)
87+ + {
88+ + #ifdef DEBUG_BLURAY
89+ + bd_set_debug_mask(BLURAY_DEBUG_MASK);
90+ + bd_set_debug_handler(bluray_DebugHandler);
91+ + #endif
92+ +
93+ BlurayContext *bd = h->priv_data;
94+ int num_title_idx;
95+ const char *diskname = path;
7796
7897 av_strstart(path, BLURAY_PROTO_PREFIX, &diskname);
7998
8099- bd->bd = bd_open(diskname, NULL);
81100+ fs_access *access = NULL;
82101+
83102+ diskname = ff_urldecode(diskname, 0);
84- +
103+ +
85104+ if (av_strstart(diskname, "file://", NULL) || av_strstart(diskname, "/", NULL)) {
86105+ access = NULL;
87106+ } else {
@@ -103,18 +122,101 @@ index bf5b88d..96a799a 100644
103122
104123 /* check if disc can be played */
105124 if (check_disc_info(h) < 0) {
106- @@ -321,7 +339,7 @@ fail:
125+ @@ -159,12 +198,13 @@ static int bluray_open(URLContext *h, const char *path, int flags)
126+
127+ if (info->duration > duration) {
128+ bd->playlist = info->playlist;
129+ + bd->title_idx = i;
130+ duration = info->duration;
131+ }
132+
133+ bd_free_title_info(info);
134+ }
135+ - av_log(h, AV_LOG_INFO, "selected %05d.mpls\n", bd->playlist);
136+ + av_log(h, AV_LOG_INFO, "select longest playlist: %05d.mpls\n", bd->playlist);
137+ }
138+
139+ /* select playlist */
140+ @@ -222,13 +262,75 @@ static int64_t bluray_seek(URLContext *h, int64_t pos, int whence)
141+ return AVERROR(EINVAL);
142+ }
143+
144+ + static int bluray_parse_priv(AVFormatContext *ic, URLContext *h)
145+ + {
146+ + BlurayContext *bd = h->priv_data;
147+ + BLURAY_TITLE_INFO *title_info = NULL;
148+ + BLURAY_CLIP_INFO clip_info;
149+ +
150+ + int v_idx = 0;
151+ + int a_idx = 0;
152+ + int s_idx = 0;
153+ + int ret = 0;
154+ +
155+ + if (!bd || !bd->bd) {
156+ + return AVERROR(EFAULT);
157+ + }
158+ +
159+ + title_info = bd_get_title_info(bd->bd, bd->title_idx, 0);
160+ + if (!title_info) {
161+ + return AVERROR(EFAULT);
162+ + }
163+ +
164+ + if (title_info->clip_count <= 0) {
165+ + ret = EFAULT;
166+ + goto fail;
167+ + }
168+ + clip_info = title_info->clips[0];
169+ +
170+ + for (int i = 0; i < ic->nb_streams; i++) {
171+ + if (ic->streams[i] && ic->streams[i]->codecpar) {
172+ + switch (ic->streams[i]->codecpar->codec_type) {
173+ + case AVMEDIA_TYPE_VIDEO:
174+ + if (v_idx < clip_info.video_stream_count) {
175+ + av_log(h, AV_LOG_INFO, "video stream %d lang = %s\n", v_idx, clip_info.video_streams[v_idx].lang);
176+ + av_dict_set(&ic->streams[i]->metadata, "language", clip_info.video_streams[v_idx].lang, AV_DICT_DONT_OVERWRITE);
177+ + v_idx++;
178+ + }
179+ + break;
180+ + case AVMEDIA_TYPE_AUDIO:
181+ + if (a_idx < clip_info.audio_stream_count) {
182+ + av_log(h, AV_LOG_INFO, "audio stream %d lang = %s\n", a_idx, clip_info.audio_streams[a_idx].lang);
183+ + av_dict_set(&ic->streams[i]->metadata, "language", clip_info.audio_streams[a_idx].lang, AV_DICT_DONT_OVERWRITE);
184+ + a_idx++;
185+ + }
186+ + break;
187+ + case AVMEDIA_TYPE_SUBTITLE:
188+ + if (s_idx < clip_info.pg_stream_count) {
189+ + av_log(h, AV_LOG_INFO, "subtitle stream %d lang = %s\n", s_idx, clip_info.pg_streams[s_idx].lang);
190+ + av_dict_set(&ic->streams[i]->metadata, "language", clip_info.pg_streams[s_idx].lang, AV_DICT_DONT_OVERWRITE);
191+ + s_idx++;
192+ + }
193+ + break;
194+ + default:
195+ + break;
196+ + }
197+ + }
198+ + }
199+ +
200+ + fail:
201+ + bd_free_title_info(title_info);
202+ +
203+ + return ret != 0 ? AVERROR(ret) : 0;
204+ + }
205+
107206 const URLProtocol ff_bluray_protocol = {
108207 .name = "bluray",
109208 .url_close = bluray_close,
110209- .url_open = bluray_open,
111210+ .url_open2 = bluray_open,
112211 .url_read = bluray_read,
113212 .url_seek = bluray_seek,
114- .url_parse_priv = bluray_parse_priv,
213+ + .url_parse_priv = bluray_parse_priv,
214+ .priv_data_size = sizeof(BlurayContext),
215+ .priv_data_class = &bluray_context_class,
216+ };
115217diff --git a/libavformat/bluray_custom_fs.c b/libavformat/bluray_custom_fs.c
116218new file mode 100644
117- index 0000000..9062a2b
219+ index 0000000..bdf2451
118220--- /dev/null
119221+++ b/libavformat/bluray_custom_fs.c
120222@@ -0,0 +1,413 @@
@@ -181,7 +283,7 @@ index 0000000..9062a2b
181283+ if (!io) {
182284+ return -1;
183285+ }
184- +
286+ +
185287+ ff_builtin_io * app = av_mallocz(sizeof(ff_builtin_io));
186288+ if (!app) {
187289+ return -2;
@@ -215,7 +317,7 @@ index 0000000..9062a2b
215317+ if (is_dir) {
216318+ flags |= AVIO_FLAG_DIRECT;
217319+ }
218- +
320+ +
219321+ int ret = ffurl_open_whitelist(&app->url_context,
220322+ url,
221323+ flags,
@@ -226,8 +328,8 @@ index 0000000..9062a2b
226328+ NULL);
227329+
228330+ av_application_did_http_open(app->app_ctx, (void*)app->url_context, url, ret < 0 ? AVERROR(errno) : 0, ret < 0 ? 500 : 200, 0);
229- +
230- + if (ret < 0) {
331+ +
332+ + if (ret < 0) {
231333+ close_builtin_io(app);
232334+ av_freep(&app);
233335+ }
@@ -246,11 +348,11 @@ index 0000000..9062a2b
246348+ }
247349+
248350+ av_application_will_http_seek(io->app_ctx, (void*)io->url_context, io->url_context->filename, offset);
249- +
351+ +
250352+ int64_t pos = io->url_context->prot->url_seek(io->url_context, offset, origin);
251353+ if (pos < 0) {
252354+ av_application_did_http_seek(io->app_ctx, (void*)io->url_context, io->url_context->filename, offset, AVERROR(errno), 500);
253- + return AVERROR(errno);
355+ + return AVERROR(errno);
254356+ }
255357+ io->offset = pos;
256358+
@@ -282,7 +384,7 @@ index 0000000..9062a2b
282384+
283385+ int bytes = buf_size - buf_size1;
284386+ if (bytes == 0 && read == AVERROR_EOF) {
285- + return AVERROR_EOF;
387+ + return AVERROR_EOF;
286388+ } else {
287389+ av_application_did_io_tcp_read(io->app_ctx, (void*)io->url_context, bytes);
288390+ return bytes;
@@ -404,12 +506,12 @@ index 0000000..9062a2b
404506+ }
405507+ AVDictionary *opts = NULL;
406508+ av_dict_copy(&opts, access->opts, 0);
407- +
509+ +
408510+ ff_builtin_io *io = NULL;
409511+ int ret = create_builtin_io(&io, url, &opts, 0);
410512+ av_dict_free(&opts);
411513+ av_free(url);
412- +
514+ +
413515+ if (0 != ret) {
414516+ av_log(NULL, AV_LOG_ERROR, "can't open url %s,error:%s", url, av_err2str(ret));
415517+ return NULL;
@@ -455,11 +557,11 @@ index 0000000..9062a2b
455557+ }
456558+
457559+ AVIODirEntry *next = NULL;
458- +
560+ +
459561+ if (io->url_context->prot->url_read_dir(io->url_context, &next) < 0 || !next) {
460562+ return -2;
461563+ }
462- +
564+ +
463565+ strncpy(entry->d_name, next->name, sizeof(entry->d_name));
464566+ entry->d_name[sizeof(entry->d_name) - 1] = 0;
465567+
@@ -477,12 +579,12 @@ index 0000000..9062a2b
477579+ }
478580+ AVDictionary *opts = NULL;
479581+ av_dict_copy(&opts, access->opts, 0);
480- +
582+ +
481583+ ff_builtin_io *io = NULL;
482584+ int ret = create_builtin_io(&io, url, &opts, 1);
483585+ av_dict_free(&opts);
484586+ av_free(url);
485- +
587+ +
486588+ if (0 != ret) {
487589+ av_log(NULL, AV_LOG_ERROR, "can't open dir %s,error:%s", url, av_err2str(ret));
488590+ return NULL;
@@ -498,7 +600,7 @@ index 0000000..9062a2b
498600+ dir->internal = io;
499601+ dir->close = _dir_close;
500602+ dir->read = _dir_read;
501- +
603+ +
502604+ return dir;
503605+ }
504606+
@@ -513,9 +615,9 @@ index 0000000..9062a2b
513615+ if (opaque) {
514616+ opaque->url = av_strdup(url);
515617+ if (options) {
516- + av_dict_copy(&opaque->opts, *options, 0);
618+ + av_dict_copy(&opaque->opts, *options, 0);
517619+ }
518- +
620+ +
519621+ int ret = create_builtin_io(&opaque->io, url, options, 0);
520622+ if (0 != ret) {
521623+ av_log(NULL, AV_LOG_ERROR, "can't open file %s,error:%s", url, av_err2str(ret));
@@ -526,7 +628,7 @@ index 0000000..9062a2b
526628+ access->read_blocks = read_blocks;
527629+ access->open_file = open_file;
528630+ access->open_dir = open_dir;
529- +
631+ +
530632+ return access;
531633+ }
532634+ return NULL;
0 commit comments