* [FFmpeg-devel] [PATCH 0/3] avformat/matroska: add ordered-chapter parsing
@ 2025-11-19 13:49 Alexander Westberg-Bladh via ffmpeg-devel
2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 1/3] avformat/matroska: Add element IDs for ordered chapters Alexander Westberg-Bladh via ffmpeg-devel
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Alexander Westberg-Bladh via ffmpeg-devel @ 2025-11-19 13:49 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Alexander Westberg-Bladh
Hi,
This short series lays the groundwork for ordered-chapter playback
in Matroska, fixing trac ticket #3123.
To start with I added type defs and parsing for editions.
I stay compatible with the existing logic by fetching the chapters from
all editions thereby flattening the structure.
I think It would be a good idea to add an option that only fetches the
default or first edition staying compliant to the matroska spec.
Maybe adding --edition X and --default-edition in a future patch is appropriate.
Next steps would be dealing with external chapter files.
This is my first patch let me know if I can improve anything, my C is a
little rusty. I manually added the video from the ticket as a fate test just to make sure it was read corectly.
make fate-matroska
TEST matroska-prores-zlib
TEST matroska-prores-header-insertion-bz2
TEST matroska-remux
TEST matroska-xiph-lacing
TEST matroska-wavpack-missing-codecprivate
TEST matroska-zlib-decompression
TEST matroska-lzo-decompression
TEST matroska-flac-channel-mapping
TEST matroska-flac-extradata-update
TEST webm-av1-extradata-update
TEST matroska-move-cues-to-front
TEST matroska-avoid-negative-ts
TEST matroska-ms-mode
TEST matroska-qt-mode
TEST matroska-pgs-remux
TEST matroska-pgs-remux-durations
TEST matroska-dvbsub-remux
TEST matroska-spherical-mono
TEST matroska-side-data-pref-codec
TEST matroska-side-data-pref-packet
TEST matroska-alac-remux
TEST webm-dash-chapters
TEST matroska-zero-length-block
TEST matroska-non-rotation-displaymatrix
TEST matroska-crop
TEST matroska-dovi-write-config7
TEST matroska-dovi-write-config8
TEST matroska-spherical-mono-remux
TEST matroska-mastering-display-metadata
TEST matroska-h264-remux
TEST matroska-vp8-alpha-remux
TEST matroska-mpegts-remux
TEST matroska-opus-remux
TEST matroska-ogg-opus-remux
TEST matroska-encoding-delay
TEST matroska-stereo_mode
TEST webm-webvtt-remux
TEST webm-hdr10-plus-remux
TEST matroska-hdr10-plus-remux
Kind regards,
Alexander Westberg-Bladh
Alexander Westberg-Bladh (3):
avformat/matroska: Add element IDs for ordered chapters
avformat/matroskadec: Add data structures for ordered chapters
avformat/matroskadec: Update EBML syntax to parse EditionEntry
libavformat/matroska.h | 2 +
libavformat/matroskadec.c | 99 ++++++++++++++++++++++++---------------
2 files changed, 64 insertions(+), 37 deletions(-)
--
2.51.2
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] 4+ messages in thread* [FFmpeg-devel] [PATCH 1/3] avformat/matroska: Add element IDs for ordered chapters 2025-11-19 13:49 [FFmpeg-devel] [PATCH 0/3] avformat/matroska: add ordered-chapter parsing Alexander Westberg-Bladh via ffmpeg-devel @ 2025-11-19 13:49 ` Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 2/3] avformat/matroskadec: Add data structures " Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 3/3] avformat/matroskadec: Update EBML syntax to parse EditionEntry Alexander Westberg-Bladh via ffmpeg-devel 2 siblings, 0 replies; 4+ messages in thread From: Alexander Westberg-Bladh via ffmpeg-devel @ 2025-11-19 13:49 UTC (permalink / raw) To: ffmpeg-devel; +Cc: Alexander Westberg-Bladh Add MATROSKA_ID_CHAPTERSEGMENTUID and MATROSKA_ID_CHAPTERSEGMENTEDITIONUID element IDs to support parsing of ordered chapters segment linking. Signed-off-by: Alexander Westberg-Bladh <alexander.bladh@gmail.com> --- libavformat/matroska.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavformat/matroska.h b/libavformat/matroska.h index 719f2ef796..9118dc216c 100644 --- a/libavformat/matroska.h +++ b/libavformat/matroska.h @@ -274,6 +274,8 @@ #define MATROSKA_ID_CHAPTERFLAGHIDDEN 0x98 #define MATROSKA_ID_CHAPTERFLAGENABLED 0x4598 #define MATROSKA_ID_CHAPTERPHYSEQUIV 0x63C3 +#define MATROSKA_ID_CHAPTERSEGMENTUID 0x6E67 +#define MATROSKA_ID_CHAPTERSEGMENTEDITIONUID 0x6EBC typedef enum { MATROSKA_TRACK_TYPE_NONE = 0x0, -- 2.51.2 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org ^ permalink raw reply [flat|nested] 4+ messages in thread
* [FFmpeg-devel] [PATCH 2/3] avformat/matroskadec: Add data structures for ordered chapters 2025-11-19 13:49 [FFmpeg-devel] [PATCH 0/3] avformat/matroska: add ordered-chapter parsing Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 1/3] avformat/matroska: Add element IDs for ordered chapters Alexander Westberg-Bladh via ffmpeg-devel @ 2025-11-19 13:49 ` Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 3/3] avformat/matroskadec: Update EBML syntax to parse EditionEntry Alexander Westberg-Bladh via ffmpeg-devel 2 siblings, 0 replies; 4+ messages in thread From: Alexander Westberg-Bladh via ffmpeg-devel @ 2025-11-19 13:49 UTC (permalink / raw) To: ffmpeg-devel; +Cc: Alexander Westberg-Bladh Add MatroskaEdition structure and extend MatroskaChapter and MatroskaDemuxContext with fields needed for ordered chapters support. Signed-off-by: Alexander Westberg-Bladh <alexander.bladh@gmail.com> --- libavformat/matroskadec.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 8b5eda8213..0b120bb43e 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -307,11 +307,21 @@ typedef struct MatroskaAttachment { AVStream *stream; } MatroskaAttachment; +typedef struct MatroskaEdition { + uint64_t uid; + uint64_t flag_hidden; + uint64_t flag_default; + uint64_t flag_ordered; + EbmlList chapters; +} MatroskaEdition; + typedef struct MatroskaChapter { uint64_t start; uint64_t end; uint64_t uid; char *title; + EbmlBin segment_uid; + uint64_t segment_edition_uid; AVChapter *chapter; } MatroskaChapter; @@ -438,6 +448,10 @@ typedef struct MatroskaDemuxContext { /* Bandwidth value for WebM DASH Manifest */ int bandwidth; + + /* Editions and ordered chapters support */ + EbmlList editions; + EbmlBin segment_uid; } MatroskaDemuxContext; #define CHILD_OF(parent) { .def = { .n = parent } } -- 2.51.2 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org ^ permalink raw reply [flat|nested] 4+ messages in thread
* [FFmpeg-devel] [PATCH 3/3] avformat/matroskadec: Update EBML syntax to parse EditionEntry 2025-11-19 13:49 [FFmpeg-devel] [PATCH 0/3] avformat/matroska: add ordered-chapter parsing Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 1/3] avformat/matroska: Add element IDs for ordered chapters Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 2/3] avformat/matroskadec: Add data structures " Alexander Westberg-Bladh via ffmpeg-devel @ 2025-11-19 13:49 ` Alexander Westberg-Bladh via ffmpeg-devel 2 siblings, 0 replies; 4+ messages in thread From: Alexander Westberg-Bladh via ffmpeg-devel @ 2025-11-19 13:49 UTC (permalink / raw) To: ffmpeg-devel; +Cc: Alexander Westberg-Bladh Update matroska_chapters[] syntax to parse EditionEntry elements into matroska->editions instead of the flat matroska->chapters list. update chapter finding code to look through all editions. Signed-off-by: Alexander Westberg-Bladh <alexander.bladh@gmail.com> --- libavformat/matroskadec.c | 85 ++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 0b120bb43e..c771f87a06 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -463,7 +463,7 @@ typedef struct MatroskaDemuxContext { static EbmlSyntax ebml_syntax[3], matroska_segment[9], matroska_track_video_color[15], matroska_track_video[19], matroska_track[33], matroska_track_encoding[6], matroska_track_encodings[2], matroska_track_combine_planes[2], matroska_track_operation[2], matroska_block_addition_mapping[5], matroska_tracks[2], - matroska_attachments[2], matroska_chapter_entry[9], matroska_chapter[6], matroska_chapters[2], + matroska_attachments[2], matroska_chapter_entry[10], matroska_edition[6], matroska_chapter[6], matroska_chapters[2], matroska_index_entry[3], matroska_index[2], matroska_tag[3], matroska_tags[2], matroska_seekhead[2], matroska_blockadditions[2], matroska_blockgroup[8], matroska_cluster_parsing[8]; @@ -489,9 +489,9 @@ static EbmlSyntax matroska_info[] = { { MATROSKA_ID_DURATION, EBML_FLOAT, 0, 0, offsetof(MatroskaDemuxContext, duration) }, { MATROSKA_ID_TITLE, EBML_UTF8, 0, 0, offsetof(MatroskaDemuxContext, title) }, { MATROSKA_ID_WRITINGAPP, EBML_NONE }, - { MATROSKA_ID_MUXINGAPP, EBML_UTF8, 0, 0, offsetof(MatroskaDemuxContext, muxingapp) }, - { MATROSKA_ID_DATEUTC, EBML_BIN, 0, 0, offsetof(MatroskaDemuxContext, date_utc) }, - { MATROSKA_ID_SEGMENTUID, EBML_NONE }, + { MATROSKA_ID_MUXINGAPP, EBML_UTF8, 0, 0, offsetof(MatroskaDemuxContext, muxingapp) }, + { MATROSKA_ID_DATEUTC, EBML_BIN, 0, 0, offsetof(MatroskaDemuxContext, date_utc) }, + { MATROSKA_ID_SEGMENTUID, EBML_BIN, 0, 0, offsetof(MatroskaDemuxContext, segment_uid) }, CHILD_OF(matroska_segment) }; @@ -683,28 +683,29 @@ static EbmlSyntax matroska_chapter_display[] = { }; static EbmlSyntax matroska_chapter_entry[] = { - { MATROSKA_ID_CHAPTERTIMESTART, EBML_UINT, 0, 0, offsetof(MatroskaChapter, start), { .u = AV_NOPTS_VALUE } }, - { MATROSKA_ID_CHAPTERTIMEEND, EBML_UINT, 0, 0, offsetof(MatroskaChapter, end), { .u = AV_NOPTS_VALUE } }, - { MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, 0, offsetof(MatroskaChapter, uid) }, - { MATROSKA_ID_CHAPTERDISPLAY, EBML_NEST, 0, 0, 0, { .n = matroska_chapter_display } }, - { MATROSKA_ID_CHAPTERFLAGHIDDEN, EBML_NONE }, - { MATROSKA_ID_CHAPTERFLAGENABLED, EBML_NONE }, - { MATROSKA_ID_CHAPTERPHYSEQUIV, EBML_NONE }, - { MATROSKA_ID_CHAPTERATOM, EBML_NONE }, - CHILD_OF(matroska_chapter) + { MATROSKA_ID_CHAPTERTIMESTART, EBML_UINT, 0, 0, offsetof(MatroskaChapter, start), { .u = AV_NOPTS_VALUE } }, + { MATROSKA_ID_CHAPTERTIMEEND, EBML_UINT, 0, 0, offsetof(MatroskaChapter, end), { .u = AV_NOPTS_VALUE } }, + { MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, 0, offsetof(MatroskaChapter, uid) }, + { MATROSKA_ID_CHAPTERSEGMENTUID, EBML_BIN, 0, 0, offsetof(MatroskaChapter, segment_uid) }, + { MATROSKA_ID_CHAPTERSEGMENTEDITIONUID, EBML_UINT, 0, 0, offsetof(MatroskaChapter, segment_edition_uid) }, + { MATROSKA_ID_CHAPTERDISPLAY, EBML_NEST, 0, 0, 0, { .n = matroska_chapter_display } }, + { MATROSKA_ID_CHAPTERFLAGHIDDEN, EBML_NONE }, + { MATROSKA_ID_CHAPTERFLAGENABLED, EBML_NONE }, + { MATROSKA_ID_CHAPTERPHYSEQUIV, EBML_NONE }, + CHILD_OF(matroska_edition) }; -static EbmlSyntax matroska_chapter[] = { - { MATROSKA_ID_CHAPTERATOM, EBML_NEST, 0, sizeof(MatroskaChapter), offsetof(MatroskaDemuxContext, chapters), { .n = matroska_chapter_entry } }, - { MATROSKA_ID_EDITIONUID, EBML_NONE }, - { MATROSKA_ID_EDITIONFLAGHIDDEN, EBML_NONE }, - { MATROSKA_ID_EDITIONFLAGDEFAULT, EBML_NONE }, - { MATROSKA_ID_EDITIONFLAGORDERED, EBML_NONE }, +static EbmlSyntax matroska_edition[] = { + { MATROSKA_ID_EDITIONUID, EBML_UINT, 0, 0, offsetof(MatroskaEdition, uid) }, + { MATROSKA_ID_EDITIONFLAGHIDDEN, EBML_UINT, 0, 0, offsetof(MatroskaEdition, flag_hidden) }, + { MATROSKA_ID_EDITIONFLAGDEFAULT, EBML_UINT, 0, 0, offsetof(MatroskaEdition, flag_default) }, + { MATROSKA_ID_EDITIONFLAGORDERED, EBML_UINT, 0, 0, offsetof(MatroskaEdition, flag_ordered) }, + { MATROSKA_ID_CHAPTERATOM, EBML_NEST, 0, sizeof(MatroskaChapter), offsetof(MatroskaEdition, chapters), { .n = matroska_chapter_entry } }, CHILD_OF(matroska_chapters) }; static EbmlSyntax matroska_chapters[] = { - { MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, 0, 0, { .n = matroska_chapter } }, + { MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, sizeof(MatroskaEdition), offsetof(MatroskaDemuxContext, editions), { .n = matroska_edition } }, CHILD_OF(matroska_segment) }; @@ -1884,14 +1885,18 @@ static void matroska_convert_tags(AVFormatContext *s) i, tags[i].target.attachuid); } } else if (tags[i].target.chapteruid) { - MatroskaChapter *chapter = matroska->chapters.elem; + MatroskaEdition *editions = matroska->editions.elem; + MatroskaChapter *chapter; int found = 0; - for (j = 0; j < matroska->chapters.nb_elem; j++) { - if (chapter[j].uid == tags[i].target.chapteruid && - chapter[j].chapter) { + for (j = 0; j < matroska->editions.nb_elem && !found; j++) { + chapter = editions[j].chapters.elem; + for (int k = 0; k < editions[j].chapters.nb_elem; k++) { + if (chapter[k].uid == tags[i].target.chapteruid && + chapter[k].chapter) { matroska_convert_tag(s, &tags[i].tag, - &chapter[j].chapter->metadata, NULL); + &chapter[k].chapter->metadata, NULL); found = 1; + } } } if (!found) { @@ -3328,9 +3333,10 @@ static int matroska_read_header(AVFormatContext *s) FFFormatContext *const si = ffformatcontext(s); MatroskaDemuxContext *matroska = s->priv_data; EbmlList *attachments_list = &matroska->attachments; - EbmlList *chapters_list = &matroska->chapters; MatroskaAttachment *attachments; - MatroskaChapter *chapters; + EbmlList *editions_list = &matroska->editions; + MatroskaEdition *editions; + MatroskaChapter *chapters = NULL; uint64_t max_start = 0; int64_t pos; Ebml ebml = { 0 }; @@ -3456,17 +3462,22 @@ static int matroska_read_header(AVFormatContext *s) } } - chapters = chapters_list->elem; - for (i = 0; i < chapters_list->nb_elem; i++) - if (chapters[i].start != AV_NOPTS_VALUE && chapters[i].uid && - (max_start == 0 || chapters[i].start > max_start)) { - chapters[i].chapter = - avpriv_new_chapter(s, chapters[i].uid, - (AVRational) { 1, 1000000000 }, - chapters[i].start, chapters[i].end, - chapters[i].title); - max_start = chapters[i].start; + editions = editions_list->elem; + for (i = 0; i < editions_list->nb_elem; i++) { + chapters = editions[i].chapters.elem; + + for (j = 0; j < editions[i].chapters.nb_elem; j++) { + if (chapters[j].start != AV_NOPTS_VALUE && chapters[j].uid && + (max_start == 0 || chapters[j].start > max_start)) { + chapters[j].chapter = + avpriv_new_chapter(s, chapters[j].uid, + (AVRational) { 1, 1000000000 }, + chapters[j].start, chapters[j].end, + chapters[j].title); + max_start = chapters[j].start; + } } + } matroska_add_index_entries(matroska); -- 2.51.2 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-11-19 18:19 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2025-11-19 13:49 [FFmpeg-devel] [PATCH 0/3] avformat/matroska: add ordered-chapter parsing Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 1/3] avformat/matroska: Add element IDs for ordered chapters Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 2/3] avformat/matroskadec: Add data structures " Alexander Westberg-Bladh via ffmpeg-devel 2025-11-19 13:49 ` [FFmpeg-devel] [PATCH 3/3] avformat/matroskadec: Update EBML syntax to parse EditionEntry Alexander Westberg-Bladh via ffmpeg-devel
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