From: Marth64 <marth64@proxyid.net>
To: FFmpeg development discussions and patches
<ffmpeg-devel@ffmpeg.org>, Marth64 <marth64@proxyid.net>
Subject: Re: [FFmpeg-devel] [PATCH 2/3] avformat/dvdvideodec: add menu demuxing support
Date: Wed, 6 Mar 2024 10:35:55 -0600
Message-ID: <CA+28BfDuQcybu9SZfxQW0Q=VXkabeH7fRiMV-sR=UU0d-Aj52Q@mail.gmail.com> (raw)
In-Reply-To: <ZeiOxH4FN8gesSLx@mariano>
Thank you Stefano for the review on the whole set. I will take the feedback
and come back with a better organized set in the next 2 or so days.
On Wed, Mar 6, 2024 at 09:42 Stefano Sabatini <stefasab@gmail.com> wrote:
> On date Wednesday 2024-03-06 01:19:12 -0600, Marth64 wrote:
> > Many DVDs have valuable assets in their menu structures, including
> background
> > video or music. Some discs also abuse the menu feature to include actual
> > feature footage that needs to change aspect ratio (in order to trick the
> DVD player).
> >
> > This patch allows extraction and archival of these assets, but does not
> enable
> > controllable playback (which needs a full-fledged player and nav VM).
> > Menus are processed directly with dvdread and the existing foundation of
> the demuxer.
> >
> > Will eventually add option to list their coordinates as well, so users
> > do not have to rely on other tools to find them.
> >
> > Signed-off-by: Marth64 <marth64@proxyid.net>
> > ---
> > doc/demuxers.texi | 43 +++++-
> > libavformat/dvdvideodec.c | 315 ++++++++++++++++++++++++++++++++++++--
> > 2 files changed, 339 insertions(+), 19 deletions(-)
> >
> > diff --git a/doc/demuxers.texi b/doc/demuxers.texi
> > index 1a17c6db16..e2ea66c1a5 100644
> > --- a/doc/demuxers.texi
> > +++ b/doc/demuxers.texi
> > @@ -289,8 +289,10 @@ This demuxer accepts the following option:
> >
> > DVD-Video demuxer, powered by libdvdnav and libdvdread.
> >
> > -Can directly ingest DVD titles, specifically sequential PGCs,
> > -into a conversion pipeline. Menus and seeking are not supported at this
> time.
> > +Can directly ingest DVD titles, specifically sequential PGCs, into
> > +a conversion pipeline. Menu assets, such as background video or audio,
> > +can also be demuxed given the menu's coordinates (at best effort).
> > +Seeking is not supported at this time.
> >
> > Block devices (DVD drives), ISO files, and directory structures are
> accepted.
> > Activate with @code{-f dvdvideo} in front of one of these inputs.
> > @@ -347,37 +349,56 @@ This demuxer accepts the following options:
> >
> > @item title @var{int}
> > The title number to play. Must be set if @option{pgc} and @option{pg}
> are not set.
> > +Not applicable to menus.
> > Default is 0 (auto), which currently only selects the first available
> title (title 1)
> > and notifies the user about the implications.
> >
> > @item chapter_start @var{int}
> > -The chapter, or PTT (part-of-title), number to start at. Default is 1.
> > +The chapter, or PTT (part-of-title), number to start at. Not applicable
> to menus.
> > +Default is 1.
> >
> > @item chapter_end @var{int}
> > -The chapter, or PTT (part-of-title), number to end at. Default is 0,
> > -which is a special value to signal end at the last possible chapter.
> > +The chapter, or PTT (part-of-title), number to end at. Not applicable
> to menus.
> > +Default is 0, which is a special value to signal end at the last
> possible chapter.
> >
> > @item angle @var{int}
> > The video angle number, referring to what is essentially an additional
> > video stream that is composed from alternate frames interleaved in the
> VOBs.
> > +Not applicable to menus.
> > Default is 1.
> >
> > @item region @var{int}
> > The region code to use for playback. Some discs may use this to default
> playback
> > at a particular angle in different regions. This option will not affect
> the region code
> > -of a real DVD drive, if used as an input. Default is 0, "world".
> > +of a real DVD drive, if used as an input. Not applicable to menus.
> > +Default is 0, "world".
> > +
>
> > +@item menu @var{bool}
> > +Demux menu assets instead of navigating a title. Requires exact
> coordinates
> > +of the menu (@option{menu_lu}, @option{menu_vts}, @option{pgc},
> @option{pg}).
> > +Default is false.
> > +
>
> > +@item menu_lu @var{int}
> > +The menu language to demux. In DVD, menus are grouped by language.
> > +Default is 0, the first language unit.
> > +
> > +@item menu_vts @var{int}
> > +The VTS where the menu lives, or 0 if it is a VMG menu (root-level).
> > +Default is 0, VMG menu.
> >
> > @item pgc @var{int}
> > The entry PGC to start playback, in conjunction with @option{pg}.
> > Alternative to setting @option{title}.
> > Chapter markers are not supported at this time.
> > +Must be explicitly set for menus.
> > Default is 0, automatically resolve from value of @option{title}.
> >
> > @item pg @var{int}
> > The entry PG to start playback, in conjunction with @option{pgc}.
> > Alternative to setting @option{title}.
> > Chapter markers are not supported at this time.
> > -Default is 0, automatically resolve from value of @option{title}.
> > +Default is 0, automatically resolve from value of @option{title}, or
> > +start from the beginning (PG 1) of the menu.
> >
> > @item preindex @var{bool}
> > Enable this to have accurate chapter (PTT) markers and duration
> measurement,
> > @@ -385,6 +406,7 @@ which requires a slow second pass read in order to
> index the chapter marker
> > timestamps from NAV packets. This is non-ideal extra work for real
> optical drives.
> > It is recommended and faster to use this option with a backup of the
> DVD structure
> > stored on a hard drive. Not compatible with @option{pgc} and
> @option{pg}.
> > +Not applicable to menus.
> > Default is 0, false.
> >
> > @item trim @var{bool}
> > @@ -392,6 +414,7 @@ Skip padding cells (i.e. cells shorter than 1
> second) from the beginning.
> > There exist many discs with filler segments at the beginning of the PGC,
> > often with junk data intended for controlling a real DVD player's
> > buffering speed and with no other material data value.
> > +Not applicable to menus.
> > Default is 1, true.
> >
> > @item clut_rgb @var{bool}
> > @@ -421,6 +444,12 @@ Open only chapter 5 from title 1 from a given DVD
> structure:
> > @example
> > ffmpeg -f dvdvideo -chapter_start 5 -chapter_end 5 -title 1 -i <path to
> DVD> ...
> > @end example
> > +
> > +@item
> > +Demux menu with language 1 from VTS 1, PGC 1, starting at PG 1:
> > +@example
> > +ffmpeg -f dvdvideo -menu 1 -menu_lu 1 -menu_vts 1 -pgc 1 -pg 1 -i <path
> to DVD> ...
> > +@end example
> > @end itemize
> >
> > @section ea
> > diff --git a/libavformat/dvdvideodec.c b/libavformat/dvdvideodec.c
> > index 3bc76f5c65..2c7ffdd148 100644
> > --- a/libavformat/dvdvideodec.c
> > +++ b/libavformat/dvdvideodec.c
> > @@ -57,9 +57,11 @@
> > #define DVDVIDEO_BLOCK_SIZE 2048
> > #define DVDVIDEO_TIME_BASE_Q (AVRational) {
> 1, 90000 }
> > #define DVDVIDEO_PTS_WRAP_BITS 64 /* VOBUs use
> 32 (PES allows 33) */
> > -
> > #define DVDVIDEO_LIBDVDX_LOG_BUFFER_SIZE 1024
> >
> > +#define PCI_START_BYTE 45 /*
> complement dvdread's DSI_START_BYTE */
> > +static const uint8_t dvdvideo_nav_header[4] = { 0x00, 0x00,
> 0x01, 0xBF };
> > +
> > enum DVDVideoSubpictureViewport {
> > DVDVIDEO_SUBP_VIEWPORT_FULLSCREEN,
> > DVDVIDEO_SUBP_VIEWPORT_WIDESCREEN,
> > @@ -121,6 +123,15 @@ typedef struct DVDVideoPlaybackState {
> > uint64_t *pgc_pg_times_est; /* PG start times
> as reported by IFO */
> > pgc_t *pgc; /* handle to the
> active PGC */
> > dvdnav_t *dvdnav; /* handle to the
> dvdnav VM */
> > +
> > + /* the following fields are only used for menu playback */
> > + int celln_start; /* starting cell
> number */
> > + int celln_end; /* ending cell
> number */
> > + int sector_offset; /* current sector
> relative to the current VOB */
> > + uint32_t sector_end; /* end sector
> relative to the current VOBU */
> > + uint32_t vobu_next; /* the next VOBU
> pointer */
> > + uint32_t vobu_remaining; /* remaining blocks
> for current VOBU */
> > + dvd_file_t *vob_file; /* handle to the
> menu VOB (VMG or VTS) */
> > } DVDVideoPlaybackState;
> >
> > typedef struct DVDVideoDemuxContext {
> > @@ -131,6 +142,9 @@ typedef struct DVDVideoDemuxContext {
> > int opt_chapter_end; /* the
> user-provided exit PTT (0 for last) */
> > int opt_chapter_start; /* the
> user-provided entry PTT (1-indexed) */
> > int opt_clut_rgb; /* output subtitle
> palette (CLUT) as RGB */
> > + int opt_menu; /* demux menu
> domain instead of title domain */
> > + int opt_menu_lu; /* the menu
> language unit (logical grouping) */
> > + int opt_menu_vts; /* the menu VTS, or
> 0 for VMG (main menu) */
> > int opt_pg; /* the
> user-provided PG number (1-indexed) */
> > int opt_pgc; /* the
> user-provided PGC number (1-indexed) */
> > int opt_preindex; /* pre-indexing
> mode (2-pass read) */
> > @@ -227,6 +241,16 @@ static int dvdvideo_ifo_open(AVFormatContext *s)
> > return AVERROR_EXTERNAL;
> > }
> >
> > + if (c->opt_menu) {
> > + if (c->opt_menu_vts > 0 && !(c->vts_ifo = ifoOpen(c->dvdread,
> c->opt_menu_vts))) {
> > + av_log(s, AV_LOG_ERROR, "Unable to open IFO structure for
> VTS %d\n", c->opt_menu_vts);
> > +
> > + return AVERROR_EXTERNAL;
> > + }
> > +
> > + return 0;
> > + }
> > +
> > if (c->opt_title > c->vmg_ifo->tt_srpt->nr_of_srpts) {
> > av_log(s, AV_LOG_ERROR, "Title %d not found\n", c->opt_title);
> >
> > @@ -290,6 +314,182 @@ static int
> dvdvideo_is_pgc_promising(AVFormatContext *s, pgc_t *pgc)
> > return 0;
> > }
> >
> > +static void dvdvideo_menu_close(AVFormatContext *s,
> DVDVideoPlaybackState *state)
> > +{
> > + if (state->vob_file)
> > + DVDCloseFile(state->vob_file);
> > +}
> > +
> > +static int dvdvideo_menu_open(AVFormatContext *s, DVDVideoPlaybackState
> *state)
> > +{
> > + DVDVideoDemuxContext *c = s->priv_data;
> > + pgci_ut_t *pgci_ut;
> > +
> > + pgci_ut = c->opt_menu_vts ? c->vts_ifo->pgci_ut :
> c->vmg_ifo->pgci_ut;
> > + if (!pgci_ut) {
> > + av_log(s, AV_LOG_ERROR, "Invalid PGC table for menu [LU %d, PGC
> %d]\n",
> > + c->opt_menu_lu, c->opt_pgc);
> > +
> > + return AVERROR_INVALIDDATA;
> > + }
> > +
> > + if (c->opt_pgc < 1 ||
> > + c->opt_menu_lu < 1 ||
> > + c->opt_menu_lu > pgci_ut->nr_of_lus ||
> > + c->opt_pgc > pgci_ut->lu[c->opt_menu_lu -
> 1].pgcit->nr_of_pgci_srp) {
> > +
> > + av_log(s, AV_LOG_ERROR, "Menu [LU %d, PGC %d] not found\n",
> c->opt_menu_lu, c->opt_pgc);
> > +
> > + return AVERROR(EINVAL);
> > + }
> > +
> > + /* make sure the PGC is valid */
> > + state->pgcn = c->opt_pgc - 1;
> > + state->pgc = pgci_ut->lu[c->opt_menu_lu -
> 1].pgcit->pgci_srp[c->opt_pgc - 1].pgc;
> > +
> > + if (!state->pgc || !state->pgc->program_map ||
> !state->pgc->cell_playback) {
> > + av_log(s, AV_LOG_ERROR, "Invalid PGC structure for menu [LU %d,
> PGC %d]\n",
> > + c->opt_menu_lu, c->opt_pgc);
> > +
> > + return AVERROR_INVALIDDATA;
> > + }
> > +
> > + /* make sure the PG is valid */
> > + state->entry_pgn = c->opt_pg;
> > + if (state->entry_pgn < 1 || state->entry_pgn >
> state->pgc->nr_of_programs) {
> > + av_log(s, AV_LOG_ERROR, "Entry PG %d not found\n",
> state->entry_pgn);
> > +
> > + return AVERROR(EINVAL);
> > + }
> > +
> > + /* make sure the program map isn't leading us to nowhere */
> > + state->celln_start = state->pgc->program_map[state->entry_pgn -
> 1];
> > + state->celln_end = state->pgc->nr_of_cells;
> > + state->celln = state->celln_start;
> > + if (state->celln_start > state->pgc->nr_of_cells) {
> > + av_log(s, AV_LOG_ERROR, "Invalid PGC structure: program map
> points to unknown cell\n");
> > +
> > + return AVERROR_INVALIDDATA;
> > + }
> > +
> > + state->sector_end = state->pgc->cell_playback[state->celln -
> 1].last_sector;
> > + state->vobu_next = state->pgc->cell_playback[state->celln -
> 1].first_sector;
> > + state->sector_offset = state->vobu_next;
> > +
> > + if (c->opt_menu_vts > 0)
> > + state->in_vts = 1;
> > +
> > + if (!(state->vob_file = DVDOpenFile(c->dvdread, c->opt_menu_vts,
> DVD_READ_MENU_VOBS))) {
> > + av_log(s, AV_LOG_ERROR, !c->opt_menu_vts ?
> > + "Unable to open main menu VOB
> (VIDEO_TS.VOB)\n" :
> > + "Unable to open menu VOBs for VTS
> %d\n", c->opt_menu_vts);
> > +
> > + return AVERROR_EXTERNAL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int dvdvideo_menu_next_ps_block(AVFormatContext *s,
> DVDVideoPlaybackState *state,
> > + uint8_t *buf, int buf_size,
> > + void (*flush_cb)(AVFormatContext
> *s))
> > +{
> > + ssize_t blocks_read = 0;
> > + uint8_t read_buf[DVDVIDEO_BLOCK_SIZE] = {0};
> > + pci_t pci = (pci_t) {0};
> > + dsi_t dsi = (dsi_t) {0};
> > +
> > + if (buf_size != DVDVIDEO_BLOCK_SIZE) {
> > + av_log(s, AV_LOG_ERROR, "Invalid buffer size (expected=%d
> actual=%d)\n",
> > + DVDVIDEO_BLOCK_SIZE, buf_size);
> > +
> > + return AVERROR(EINVAL);
> > + }
> > +
> > + /* we were at the end of a vobu, so now go to the next one or EOF */
> > + if (!state->vobu_remaining && state->in_pgc) {
> > + if (state->vobu_next == SRI_END_OF_CELL) {
> > + if (state->celln == state->celln_end &&
> state->sector_offset > state->sector_end)
> > + return AVERROR_EOF;
> > +
> > + state->celln++;
> > + state->sector_offset =
> state->pgc->cell_playback[state->celln - 1].first_sector;
> > + state->sector_end =
> state->pgc->cell_playback[state->celln - 1].last_sector;
> > + } else {
> > + state->sector_offset = state->vobu_next;
> > + }
> > + }
> > +
> > + /* continue reading the VOBU */
> > + av_log(s, AV_LOG_TRACE, "reading block at offset %d\n",
> state->sector_offset);
> > +
> > + blocks_read = DVDReadBlocks(state->vob_file, state->sector_offset,
> 1, read_buf);
>
> > + if (blocks_read != 1) {
> > + av_log(s, AV_LOG_ERROR, "Unable to read VOB block at offset
> %d\n", state->sector_offset);
>
> nit: you might show blocks_read in case it is an error message to aid
> debugging
>
> > +
> > + return AVERROR_INVALIDDATA;
> > + }
> > +
> > + /* we are at the start of a VOBU, so we are expecting a NAV packet
> */
> > + if (!state->vobu_remaining) {
> > + if (!memcmp(&read_buf[PCI_START_BYTE - 4], dvdvideo_nav_header,
> 4) ||
> > + !memcmp(&read_buf[DSI_START_BYTE - 4], dvdvideo_nav_header,
> 4) ||
> > + read_buf[PCI_START_BYTE - 1] != 0x00
> ||
> > + read_buf[DSI_START_BYTE - 1] != 0x01) {
> > +
> > + av_log(s, AV_LOG_ERROR, "Invalid NAV packet at offset %d:
> PCI or DSI header mismatch\n",
> > + state->sector_offset);
> > +
> > + return AVERROR_INVALIDDATA;
> > + }
> > +
> > + navRead_PCI(&pci, &read_buf[PCI_START_BYTE]);
> > + navRead_DSI(&dsi, &read_buf[DSI_START_BYTE]);
> > +
> > + if (!pci.pci_gi.vobu_s_ptm ||
> > + !pci.pci_gi.vobu_e_ptm ||
> > + pci.pci_gi.vobu_s_ptm > pci.pci_gi.vobu_e_ptm) {
> > +
> > + av_log(s, AV_LOG_ERROR, "Invalid NAV packet at offset %d:
> PCI header is invalid\n",
> > + state->sector_offset);
> > +
> > + return AVERROR_INVALIDDATA;
> > + }
> > +
> > + state->vobu_remaining = dsi.dsi_gi.vobu_ea;
> > + state->vobu_next = dsi.vobu_sri.next_vobu ==
> SRI_END_OF_CELL ? SRI_END_OF_CELL :
> > + dsi.dsi_gi.nv_pck_lbn +
> (dsi.vobu_sri.next_vobu & 0x7FFFFFFF);
> > + state->sector_offset++;
> > +
> > + if (state->in_pgc) {
> > + if (state->vobu_e_ptm != pci.pci_gi.vobu_s_ptm) {
> > + if (flush_cb)
> > + flush_cb(s);
> > +
> > + state->ts_offset += state->vobu_e_ptm -
> pci.pci_gi.vobu_s_ptm;
> > + }
> > + } else {
> > + state->in_pgc = 1;
> > + }
> > +
> > + state->vobu_e_ptm = pci.pci_gi.vobu_e_ptm;
> > +
> > + av_log(s, AV_LOG_DEBUG, "NAV packet: sector=%d "
> > + "vobu_s_ptm=%d vobu_e_ptm=%d
> ts_offset=%ld\n",
> > + dsi.dsi_gi.nv_pck_lbn,
> > + pci.pci_gi.vobu_s_ptm,
> pci.pci_gi.vobu_e_ptm, state->ts_offset);
> > +
> > + return FFERROR_REDO;
> > + }
> > +
> > + /* we are in the middle of a VOBU, so pass on the PS packet */
> > + memcpy(buf, &read_buf, DVDVIDEO_BLOCK_SIZE);
> > + state->sector_offset++;
> > + state->vobu_remaining--;
> > +
> > + return DVDVIDEO_BLOCK_SIZE;
> > +}
> > +
> > static void dvdvideo_play_close(AVFormatContext *s,
> DVDVideoPlaybackState *state)
> > {
> > if (!state->dvdnav)
> > @@ -716,7 +916,7 @@ static int
> dvdvideo_chapters_setup_preindex(AVFormatContext *s)
> > goto end_close;
> >
> > av_log(s, AV_LOG_INFO,
> > - "Indexing chapter markers, this will take a long time.
> Please wait...\n");
>
> > + "Indexing chapter markers, this may take a long time. Please
> wait...\n");
>
> nit++: unrelated
>
> >
> > while (!(interrupt = ff_check_interrupt(&s->interrupt_callback))) {
> > ret = dvdvideo_play_next_ps_block(s, &state, nav_buf,
> DVDVIDEO_BLOCK_SIZE,
> > @@ -858,8 +1058,15 @@ static int
> dvdvideo_video_stream_setup(AVFormatContext *s)
> >
> > int ret = 0;
> > DVDVideoVTSVideoStreamEntry entry = {0};
> > + video_attr_t video_attr;
> >
> > - if ((ret = dvdvideo_video_stream_analyze(s,
> c->vts_ifo->vtsi_mat->vts_video_attr, &entry)) < 0 ||
> > + if (c->opt_menu)
> > + video_attr = !c->opt_menu_vts ?
> c->vmg_ifo->vmgi_mat->vmgm_video_attr :
> > +
> c->vts_ifo->vtsi_mat->vtsm_video_attr;
> > + else
> > + video_attr = c->vts_ifo->vtsi_mat->vts_video_attr;
> > +
> > + if ((ret = dvdvideo_video_stream_analyze(s, video_attr, &entry)) <
> 0 ||
> > (ret = dvdvideo_video_stream_add(s, &entry,
> AVSTREAM_PARSE_HEADERS)) < 0) {
> >
> > av_log(s, AV_LOG_ERROR, "Unable to add video stream\n");
> > @@ -1009,15 +1216,29 @@ static int
> dvdvideo_audio_stream_add_all(AVFormatContext *s)
> > DVDVideoDemuxContext *c = s->priv_data;
> >
> > int ret = 0;
> > + int nb_streams;
> >
> > - for (int i = 0; i < c->vts_ifo->vtsi_mat->nr_of_vts_audio_streams;
> i++) {
> > + if (c->opt_menu)
> > + nb_streams = !c->opt_menu_vts ?
> c->vmg_ifo->vmgi_mat->nr_of_vmgm_audio_streams :
> > +
> c->vts_ifo->vtsi_mat->nr_of_vtsm_audio_streams;
> > + else
> > + nb_streams = c->vts_ifo->vtsi_mat->nr_of_vts_audio_streams;
> > +
> > + for (int i = 0; i < nb_streams; i++) {
> > DVDVideoPGCAudioStreamEntry entry = {0};
> > + audio_attr_t audio_attr;
> > +
> > + if (c->opt_menu)
> > + audio_attr = !c->opt_menu_vts ?
> c->vmg_ifo->vmgi_mat->vmgm_audio_attr :
> > +
> c->vts_ifo->vtsi_mat->vtsm_audio_attr;
> > + else
> > + audio_attr = c->vts_ifo->vtsi_mat->vts_audio_attr[i];
> >
> > if (!(c->play_state.pgc->audio_control[i] & 0x8000))
> > continue;
> >
> > - if ((ret = dvdvideo_audio_stream_analyze(s,
> c->vts_ifo->vtsi_mat->vts_audio_attr[i],
> > -
> c->play_state.pgc->audio_control[i], &entry)) < 0)
> > + if ((ret = dvdvideo_audio_stream_analyze(s, audio_attr,
> c->play_state.pgc->audio_control[i],
> > + &entry)) < 0)
> > goto break_error;
> >
> > /* IFO structures can declare duplicate entries for the same
> startcode */
> > @@ -1127,7 +1348,16 @@ static int
> dvdvideo_subp_stream_add_all(AVFormatContext *s)
> > {
> > DVDVideoDemuxContext *c = s->priv_data;
> >
> > - for (int i = 0; i < c->vts_ifo->vtsi_mat->nr_of_vts_subp_streams;
> i++) {
> > + int nb_streams;
> > +
> > + if (c->opt_menu)
> > + nb_streams = !c->opt_menu_vts ?
> c->vmg_ifo->vmgi_mat->nr_of_vmgm_subp_streams :
> > +
> c->vts_ifo->vtsi_mat->nr_of_vtsm_subp_streams;
> > + else
> > + nb_streams = c->vts_ifo->vtsi_mat->nr_of_vts_subp_streams;
> > +
> > +
> > + for (int i = 0; i < nb_streams; i++) {
> > int ret = 0;
> > uint32_t subp_control;
> > subp_attr_t subp_attr;
> > @@ -1139,8 +1369,16 @@ static int
> dvdvideo_subp_stream_add_all(AVFormatContext *s)
> >
> > /* there can be several presentations for one SPU */
> > /* the DAR check is flexible in order to support weird
> authoring */
> > - video_attr = c->vts_ifo->vtsi_mat->vts_video_attr;
> > - subp_attr = c->vts_ifo->vtsi_mat->vts_subp_attr[i];
> > + if (c->opt_menu) {
> > + video_attr = !c->opt_menu_vts ?
> c->vmg_ifo->vmgi_mat->vmgm_video_attr :
> > +
> c->vts_ifo->vtsi_mat->vtsm_video_attr;
> > +
> > + subp_attr = !c->opt_menu_vts ?
> c->vmg_ifo->vmgi_mat->vmgm_subp_attr :
> > +
> c->vts_ifo->vtsi_mat->vtsm_subp_attr;
> > + } else {
> > + video_attr = c->vts_ifo->vtsi_mat->vts_video_attr;
> > + subp_attr = c->vts_ifo->vtsi_mat->vts_subp_attr[i];
> > + }
> >
> > /* 4:3 */
> > if (!video_attr.display_aspect_ratio) {
> > @@ -1196,8 +1434,12 @@ static int dvdvideo_subdemux_read_data(void
> *opaque, uint8_t *buf, int buf_size)
> > if (c->play_end)
> > return AVERROR_EOF;
> >
> > - ret = dvdvideo_play_next_ps_block(opaque, &c->play_state, buf,
> buf_size,
> > - &nav_event,
> dvdvideo_subdemux_flush);
> > + if (c->opt_menu)
> > + ret = dvdvideo_menu_next_ps_block(s, &c->play_state, buf,
> buf_size,
> > + dvdvideo_subdemux_flush);
> > + else
> > + ret = dvdvideo_play_next_ps_block(opaque, &c->play_state, buf,
> buf_size,
> > + &nav_event,
> dvdvideo_subdemux_flush);
> >
> > if (ret == AVERROR_EOF) {
> > c->mpeg_pb.pub.eof_reached = 1;
> > @@ -1261,6 +1503,47 @@ static int dvdvideo_read_header(AVFormatContext
> *s)
> >
> > int ret = 0;
> >
> > + if (c->opt_menu) {
> > + if (c->opt_region ||
> > + c->opt_title > 1 ||
> > + c->opt_preindex ||
> > + c->opt_chapter_start > 1 ||
> > + c->opt_chapter_end > 0) {
>
> > + av_log(s, AV_LOG_ERROR, "-menu is not compatible with the
> -region, -title, "
> > + "-preindex, or
> -chapter_start/-chapter_end options\n");
>
> unrelated note: I wonder if we should use "-foo" for mentioning
> options, since this in theory might be used also from the API,
> probably we should just say: the menu option is not compatible with
> ... (this is not blocking and might be addressed by a further patch).
>
> > + return AVERROR(EINVAL);
> > + }
> > +
> > + if (!c->opt_pgc) {
> > + av_log(s, AV_LOG_ERROR, "If -menu is enabled, -pgc must be
> set to a non-zero value\n");
> > +
> > + return AVERROR(EINVAL);
> > + }
> > +
> > + if (!c->opt_menu_lu) {
> > + av_log(s, AV_LOG_INFO, "Defaulting to menu language unit
> #1. "
> > + "This is not always desirable,
> validation suggested.\n");
> > +
> > + c->opt_menu_lu = 1;
> > + }
> > +
> > + if (!c->opt_pg) {
> > + av_log(s, AV_LOG_INFO, "Defaulting to menu PG #1. "
> > + "This is not always desirable,
> validation suggested.\n");
> > +
> > + c->opt_pg = 1;
> > + }
> > +
> > + if ((ret = dvdvideo_ifo_open(s)) < 0 ||
> > + (ret = dvdvideo_menu_open(s, &c->play_state)) < 0 ||
> > + (ret = dvdvideo_subdemux_open(s)) < 0 ||
> > + (ret = dvdvideo_video_stream_setup(s)) < 0 ||
> > + (ret = dvdvideo_audio_stream_add_all(s)) < 0)
> > + return ret;
> > +
> > + return 0;
> > + }
> > +
> > if (c->opt_title == 0) {
> > av_log(s, AV_LOG_INFO, "Defaulting to title #1. "
> > "This is not always the main feature,
> validation suggested.\n");
> > @@ -1376,7 +1659,12 @@ static int dvdvideo_close(AVFormatContext *s)
> > DVDVideoDemuxContext *c = s->priv_data;
> >
> > dvdvideo_subdemux_close(s);
> > - dvdvideo_play_close(s, &c->play_state);
> > +
> > + if (c->opt_menu)
> > + dvdvideo_menu_close(s, &c->play_state);
> > + else
> > + dvdvideo_play_close(s, &c->play_state);
> > +
> > dvdvideo_ifo_close(s);
> >
> > return 0;
> > @@ -1388,6 +1676,9 @@ static const AVOption dvdvideo_options[] = {
> > {"chapter_end", "exit chapter (PTT) number (0=end)",
> OFFSET(opt_chapter_end), AV_OPT_TYPE_INT, { .i64=0 },
> 0, 99, AV_OPT_FLAG_DECODING_PARAM },
> > {"chapter_start", "entry chapter (PTT) number",
> OFFSET(opt_chapter_start), AV_OPT_TYPE_INT, { .i64=1 },
> 1, 99, AV_OPT_FLAG_DECODING_PARAM },
> > {"clut_rgb", "output subtitle palette (CLUT) as RGB",
> OFFSET(opt_clut_rgb), AV_OPT_TYPE_BOOL, { .i64=1 },
> 0, 1, AV_OPT_FLAG_DECODING_PARAM },
> > + {"menu", "demux menu domain",
> OFFSET(opt_menu), AV_OPT_TYPE_BOOL, { .i64=0 },
> 0, 1, AV_OPT_FLAG_DECODING_PARAM },
> > + {"menu_lu", "menu language unit (0=auto)",
> OFFSET(opt_menu_lu), AV_OPT_TYPE_INT, { .i64=0 },
> 0, 99, AV_OPT_FLAG_DECODING_PARAM },
> > + {"menu_vts", "menu VTS (0=VMG main menu)",
> OFFSET(opt_menu_vts), AV_OPT_TYPE_INT, { .i64=0 },
> 0, 99, AV_OPT_FLAG_DECODING_PARAM },
> > {"pg", "entry PG number (0=auto)",
> OFFSET(opt_pg), AV_OPT_TYPE_INT, { .i64=0 },
> 0, 255, AV_OPT_FLAG_DECODING_PARAM },
> > {"pgc", "entry PGC number (0=auto)",
> OFFSET(opt_pgc), AV_OPT_TYPE_INT, { .i64=0 },
> 0, 999, AV_OPT_FLAG_DECODING_PARAM },
> > {"preindex", "enable for accurate chapter markers, slow
> (2-pass read)", OFFSET(opt_preindex), AV_OPT_TYPE_BOOL, { .i64=0
> }, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
>
> No more comments from me, nice feature!!
>
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2024-03-06 16:36 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-06 7:19 [FFmpeg-devel] [PATCH 1/3] avformat/dvdvideodec: add CLUT utilities and subtitle palette support Marth64
2024-03-06 7:19 ` [FFmpeg-devel] [PATCH 2/3] avformat/dvdvideodec: add menu demuxing support Marth64
2024-03-06 15:41 ` Stefano Sabatini
2024-03-06 16:35 ` Marth64 [this message]
2024-03-06 7:19 ` [FFmpeg-devel] [PATCH 3/3] avformat/dvdvideodec: assign mono channel layout explicitly Marth64
2024-03-06 15:10 ` Stefano Sabatini
2024-03-06 15:37 ` Marth64
2024-03-06 15:09 ` [FFmpeg-devel] [PATCH 1/3] avformat/dvdvideodec: add CLUT utilities and subtitle palette support Stefano Sabatini
2024-03-06 15:17 ` Timo Rothenpieler
2024-03-06 15:36 ` Marth64
2024-03-06 15:43 ` Marth64
2024-03-06 16:00 ` Stefano Sabatini
2024-03-07 9:53 ` Anton Khirnov
2024-03-07 10:36 ` Andreas Rheinhardt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CA+28BfDuQcybu9SZfxQW0Q=VXkabeH7fRiMV-sR=UU0d-Aj52Q@mail.gmail.com' \
--to=marth64@proxyid.net \
--cc=ffmpeg-devel@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git