FFmpeg
Loading...
Searching...
No Matches
id3v2chap.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2026 Jun Zhao
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <inttypes.h>
22#include <stdio.h>
23#include <string.h>
24
25#include "libavutil/mem.h"
28#include "libavformat/demux.h"
29#include "libavformat/id3v2.h"
30
31static int readback(const uint8_t *buf, int size)
32{
34 FFIOContext read_pb;
35 ID3v2ExtraMeta *extra = NULL;
36 AVDictionary *meta = NULL;
37 int ret = 1;
38
39 if (!in)
40 return ret;
41
42 ffio_init_read_context(&read_pb, buf, size);
43 ff_id3v2_read_dict(in, &read_pb.pub, &meta, ID3v2_DEFAULT_MAGIC, &extra);
44 if (ff_id3v2_parse_chapters(in, extra) < 0)
45 goto done;
46
47 printf("chapters=%u\n", in->nb_chapters);
48 for (unsigned i = 0; i < in->nb_chapters; i++) {
49 const AVChapter *ch = in->chapters[i];
50 const AVDictionaryEntry *title = av_dict_get(ch->metadata, "title", NULL, 0);
51
52 printf("chapter=%u time_base=%d/%d start=%"PRId64" end=%"PRId64" title=%s\n",
53 i, ch->time_base.num, ch->time_base.den, ch->start, ch->end,
54 title ? title->value : "(missing)");
55 }
56 ret = 0;
57
58done:
59 av_dict_free(&meta);
62 return ret;
63}
64
65/* The first chapter title is long enough that its TIT2 frame is at least
66 * 128 bytes, so a plain size and a synchsafe size differ. */
67static int roundtrip(int version)
68{
69 char long_title[151];
71 AVIOContext *pb = NULL;
72 ID3v2EncContext id3 = { 0 };
73 uint8_t *buf = NULL;
74 int size, chap_pos = -1, ret = 1;
75
76 memset(long_title, 'L', sizeof(long_title) - 1);
77 long_title[sizeof(long_title) - 1] = 0;
78
80 if (!out ||
81 !avpriv_new_chapter(out, 0, av_make_q(1, 1000), 0, 1000, long_title) ||
82 !avpriv_new_chapter(out, 1, av_make_q(1, 1000), 1000, 2000, "End") ||
83 avio_open_dyn_buf(&pb) < 0)
84 goto done;
85
87 if (ff_id3v2_write_metadata(out, pb, &id3) < 0)
88 goto done;
89 ff_id3v2_finish(&id3, pb, 10);
90 size = avio_close_dyn_buf(pb, &buf);
91 pb = NULL;
93 goto done;
94
95 printf("version=%d declared=%d actual=%d\n", version, ff_id3v2_tag_len(buf), size);
96 for (int i = 0; i + 10 <= size; i++) {
97 if (!memcmp(buf + i, "CHAP", 4)) {
98 chap_pos = i;
99 printf("CHAP size bytes=%02x %02x %02x %02x\n",
100 buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]);
101 break;
102 }
103 }
104 if (readback(buf, size))
105 goto done;
106
107 /* Locate the first embedded TIT2 header inside the generated chapter.
108 * Give it an oversized length, leaving the chapter and following CHAP
109 * intact. The reader should retain both chapter timings. */
110 if (chap_pos >= 0) {
111 for (int i = chap_pos + 10; i + 10 <= size; i++) {
112 if (!memcmp(buf + i, "TIT2", 4)) {
113 memset(buf + i + 4, 0x7f, 4);
114 printf("invalid subframe version=%d\n", version);
115 if (readback(buf, size))
116 goto done;
117 break;
118 }
119 }
120 }
121 ret = 0;
122
123done:
125 av_free(buf);
127 return ret;
128}
129
130int main(void)
131{
132 int ret = roundtrip(3);
133
134 ret |= roundtrip(4);
135 return ret;
136}
static FILE * out
Main libavformat public API header.
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition aviobuf.c:1378
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition aviobuf.c:1333
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition aviobuf.c:1406
void ffio_init_read_context(FFIOContext *s, const uint8_t *buffer, int buffer_size)
Wrap a buffer in an AVIOContext for reading.
Definition aviobuf.c:99
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define NULL
Definition coverity.c:32
__device__ int printf(const char *,...)
AVChapter * avpriv_new_chapter(AVFormatContext *s, int64_t id, AVRational time_base, int64_t start, int64_t end, const char *title)
Add a new chapter.
Definition demux_utils.c:46
int ret
Definition ffplay.c:391
SDL_atomic_t done
Definition ffplay.c:392
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition options.c:165
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition avformat.c:165
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:236
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition dict.c:61
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
int ff_id3v2_tag_len(const uint8_t *buf)
Get the length of an ID3v2 tag.
Definition id3v2.c:165
void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
Free memory allocated parsing special (non-text) metadata.
Definition id3v2.c:1196
int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta *cur)
Create chapters for all CHAP tags found in the ID3v2 header.
Definition id3v2.c:1243
void ff_id3v2_read_dict(AVFormatContext *s, AVIOContext *pb, AVDictionary **metadata, const char *magic, ID3v2ExtraMeta **extra_meta)
Read an ID3v2 tag into specified dictionary and retrieve supported extra metadata.
Definition id3v2.c:1184
void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version, const char *magic)
Initialize the encoding context and write the header for a new ID3v2 tag.
Definition id3v2enc.c:355
void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb, int padding_bytes)
Finalize an opened ID3v2 tag.
Definition id3v2enc.c:563
#define ID3v2_DEFAULT_MAGIC
Default magic bytes for ID3v2 header: "ID3".
Definition id3v2.h:35
#define ID3v2_HEADER_SIZE
Definition id3v2.h:30
int ff_id3v2_write_metadata(AVFormatContext *s, AVIOContext *pb, ID3v2EncContext *id3)
Convert and write all global metadata from s into an ID3v2 tag.
Definition id3v2enc.c:483
static int readback(const uint8_t *buf, int size)
Definition id3v2chap.c:31
static int roundtrip(int version)
Definition id3v2chap.c:67
int main(void)
Definition id3v2chap.c:130
version
Definition libkvazaar.c:313
Memory handling functions.
int64_t start
Definition avformat.h:1363
AVDictionary * metadata
Definition avformat.h:1364
int64_t end
chapter start/end time in time_base units
Definition avformat.h:1363
AVRational time_base
time base in which the start/end timestamps are specified
Definition avformat.h:1362
char * value
Definition dict.h:92
Format I/O context.
Definition avformat.h:1401
unsigned int nb_chapters
Number of chapters in AVChapter array.
Definition avformat.h:1502
AVChapter ** chapters
Definition avformat.h:1503
Bytestream IO Context.
Definition avio.h:160
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
AVIOContext pub
#define av_free(p)
int size