XenevaOS
Loading...
Searching...
No Matches
minimp4.h
Go to the documentation of this file.
1#ifndef MINIMP4_H
2#define MINIMP4_H
3/*
4 https://github.com/aspt/mp4
5 https://github.com/lieff/minimp4
6 To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide.
7 This software is distributed without any warranty.
8 See <http://creativecommons.org/publicdomain/zero/1.0/>.
9*/
10
11#include <stdio.h>
12#include <stdint.h>
13#include <stdlib.h>
14#include <string.h>
15#include <limits.h>
16#include <assert.h>
17
18#ifdef __cplusplus
19extern "C" {
20#endif
21
22#define MINIMP4_MIN(x, y) ((x) < (y) ? (x) : (y))
23
24/************************************************************************/
25/* Build configuration */
26/************************************************************************/
27
28#define FIX_BAD_ANDROID_META_BOX 1
29
30#define MAX_CHUNKS_DEPTH 64 // Max chunks nesting level
31
32#define MINIMP4_MAX_SPS 32
33#define MINIMP4_MAX_PPS 256
34
35#define MINIMP4_TRANSCODE_SPS_ID 1
36
37// Support indexing of MP4 files over 4 GB.
38// If disabled, files with 64-bit offset fields is still supported,
39// but error signaled if such field contains too big offset
40// This switch affect return type of MP4D_frame_offset() function
41#define MINIMP4_ALLOW_64BIT 1
42
43#define MP4D_TRACE_SUPPORTED 0 // Debug trace
44#define MP4D_TRACE_TIMESTAMPS 1
45// Support parsing of supplementary information, not necessary for decoding:
46// duration, language, bitrate, metadata tags, etc
47#define MP4D_INFO_SUPPORTED 1
48
49// Enable code, which prints to stdout supplementary MP4 information:
50#define MP4D_PRINT_INFO_SUPPORTED 0
51
52#define MP4D_AVC_SUPPORTED 1
53#define MP4D_HEVC_SUPPORTED 1
54#define MP4D_TIMESTAMPS_SUPPORTED 1
55
56// Enable TrackFragmentBaseMediaDecodeTimeBox support
57#define MP4D_TFDT_SUPPORT 0
58
59/************************************************************************/
60/* Some values of MP4(E/D)_track_t->object_type_indication */
61/************************************************************************/
62// MPEG-4 AAC (all profiles)
63#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_14496_3 0x40
64// MPEG-2 AAC, Main profile
65#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_13818_7_MAIN_PROFILE 0x66
66// MPEG-2 AAC, LC profile
67#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_13818_7_LC_PROFILE 0x67
68// MPEG-2 AAC, SSR profile
69#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_13818_7_SSR_PROFILE 0x68
70// H.264 (AVC) video
71#define MP4_OBJECT_TYPE_AVC 0x21
72// H.265 (HEVC) video
73#define MP4_OBJECT_TYPE_HEVC 0x23
74// http://www.mp4ra.org/object.html 0xC0-E0 && 0xE2 - 0xFE are specified as "user private"
75#define MP4_OBJECT_TYPE_USER_PRIVATE 0xC0
76
77/************************************************************************/
78/* API error codes */
79/************************************************************************/
80#define MP4E_STATUS_OK 0
81#define MP4E_STATUS_BAD_ARGUMENTS -1
82#define MP4E_STATUS_NO_MEMORY -2
83#define MP4E_STATUS_FILE_WRITE_ERROR -3
84#define MP4E_STATUS_ONLY_ONE_DSI_ALLOWED -4
85
86/************************************************************************/
87/* Sample kind for MP4E_put_sample() */
88/************************************************************************/
89#define MP4E_SAMPLE_DEFAULT 0 // (beginning of) audio or video frame
90#define MP4E_SAMPLE_RANDOM_ACCESS 1 // mark sample as random access point (key frame)
91#define MP4E_SAMPLE_CONTINUATION 2 // Not a sample, but continuation of previous sample (new slice)
92
93/************************************************************************/
94/* Portable 64-bit type definition */
95/************************************************************************/
96
97#if MINIMP4_ALLOW_64BIT
99#else
100typedef unsigned int boxsize_t;
101#endif
103
104/************************************************************************/
105/* Some values of MP4D_track_t->handler_type */
106/************************************************************************/
107// Video track : 'vide'
108#define MP4D_HANDLER_TYPE_VIDE 0x76696465
109// Audio track : 'soun'
110#define MP4D_HANDLER_TYPE_SOUN 0x736F756E
111// General MPEG-4 systems streams (without specific handler).
112// Used for private stream, as suggested in http://www.mp4ra.org/handler.html
113#define MP4E_HANDLER_TYPE_GESM 0x6765736D
114
115#define HEVC_NAL_VPS 32
116#define HEVC_NAL_SPS 33
117#define HEVC_NAL_PPS 34
118#define HEVC_NAL_BLA_W_LP 16
119#define HEVC_NAL_CRA_NUT 21
120
121/************************************************************************/
122/* Data structures */
123/************************************************************************/
124
125typedef struct MP4E_mux_tag MP4E_mux_t;
126
128
129typedef struct {
130 // MP4 object type code, which defined codec class for the track.
131 // See MP4E_OBJECT_TYPE_* values for some codecs
132 unsigned object_type_indication;
133
134 // Track language: 3-char ISO 639-2T code: "und", "eng", "rus", "jpn" etc...
135 unsigned char language[4];
136
137 track_media_kind_t track_media_kind;
138
139 // 90000 for video, sample rate for audio
140 unsigned time_scale;
141 unsigned default_duration;
142
143 union {
144 struct {
145 // number of channels in the audio track.
146 unsigned channelcount;
147 } a;
148
149 struct {
150 int width;
151 int height;
152 } v;
153 } u;
154
156
158
159typedef struct {
160 /************************************************************************/
161 /* mandatory public data */
162 /************************************************************************/
163 // How many 'samples' in the track
164 // The 'sample' is MP4 term, denoting audio or video frame
165 unsigned sample_count;
166
167 // Decoder-specific info (DSI) data
168 unsigned char* dsi;
169
170 // DSI data size
171 unsigned dsi_bytes;
172
173 // MP4 object type code
174 // case 0x00: return "Forbidden";
175 // case 0x01: return "Systems ISO/IEC 14496-1";
176 // case 0x02: return "Systems ISO/IEC 14496-1";
177 // case 0x20: return "Visual ISO/IEC 14496-2";
178 // case 0x40: return "Audio ISO/IEC 14496-3";
179 // case 0x60: return "Visual ISO/IEC 13818-2 Simple Profile";
180 // case 0x61: return "Visual ISO/IEC 13818-2 Main Profile";
181 // case 0x62: return "Visual ISO/IEC 13818-2 SNR Profile";
182 // case 0x63: return "Visual ISO/IEC 13818-2 Spatial Profile";
183 // case 0x64: return "Visual ISO/IEC 13818-2 High Profile";
184 // case 0x65: return "Visual ISO/IEC 13818-2 422 Profile";
185 // case 0x66: return "Audio ISO/IEC 13818-7 Main Profile";
186 // case 0x67: return "Audio ISO/IEC 13818-7 LC Profile";
187 // case 0x68: return "Audio ISO/IEC 13818-7 SSR Profile";
188 // case 0x69: return "Audio ISO/IEC 13818-3";
189 // case 0x6A: return "Visual ISO/IEC 11172-2";
190 // case 0x6B: return "Audio ISO/IEC 11172-3";
191 // case 0x6C: return "Visual ISO/IEC 10918-1";
192 unsigned object_type_indication;
193
194#if MP4D_INFO_SUPPORTED
195 /************************************************************************/
196 /* informational public data */
197 /************************************************************************/
198 // handler_type when present in a media box, is an integer containing one of
199 // the following values, or a value from a derived specification:
200 // 'vide' Video track
201 // 'soun' Audio track
202 // 'hint' Hint track
203 unsigned handler_type;
204
205 // Track duration: 64-bit value split into 2 variables
206 unsigned duration_hi;
207 unsigned duration_lo;
208
209 // duration scale: duration = timescale*seconds
210 unsigned timescale;
211
212 // Average bitrate, bits per second
213 unsigned avg_bitrate_bps;
214
215 // Track language: 3-char ISO 639-2T code: "und", "eng", "rus", "jpn" etc...
216 unsigned char language[4];
217
218 // MP4 stream type
219 // case 0x00: return "Forbidden";
220 // case 0x01: return "ObjectDescriptorStream";
221 // case 0x02: return "ClockReferenceStream";
222 // case 0x03: return "SceneDescriptionStream";
223 // case 0x04: return "VisualStream";
224 // case 0x05: return "AudioStream";
225 // case 0x06: return "MPEG7Stream";
226 // case 0x07: return "IPMPStream";
227 // case 0x08: return "ObjectContentInfoStream";
228 // case 0x09: return "MPEGJStream";
229 unsigned stream_type;
230
231 union {
232 // for handler_type == 'soun' tracks
233 struct {
234 unsigned channelcount;
235 unsigned samplerate_hz;
236 } audio;
237
238 // for handler_type == 'vide' tracks
239 struct {
240 unsigned width;
241 unsigned height;
242 } video;
243 } SampleDescription;
244#endif
245
246 /************************************************************************/
247 /* private data: MP4 indexes */
248 /************************************************************************/
249 unsigned* entry_size;
250
251 unsigned sample_to_chunk_count;
252 struct MP4D_sample_to_chunk_t_tag* sample_to_chunk;
253
254 unsigned chunk_count;
255 MP4D_file_offset_t* chunk_offset;
256
257 // sample_to_chunk() resume point for the last query, valid whenever a
258 // caller queries nsample in non-decreasing order (the only pattern any
259 // caller in this codebase uses -- see sample_to_chunk()'s comment).
261 unsigned stc_cache_nc;
263
264 // MP4D_frame_offset()'s in-chunk byte-offset resume point -- see that
265 // function's comment. Independent of stc_cache_* above: this caches
266 // the accumulated offset *within whatever chunk the previous query
267 // landed in*, which matters even when sample_to_chunk() never has to
268 // rescan (e.g. a single giant chunk holding every sample).
272
273#if MP4D_TIMESTAMPS_SUPPORTED
274 unsigned* timestamp;
275 unsigned* duration;
276 // Allocated length of timestamp/duration, tracked separately from any
277 // publicly exposed sample count: a malformed file's stsz sample_count
278 // can exceed the total sample count its own stts box declared, and
279 // MP4D_frame_offset() must bound-check against what was actually
280 // allocated, not what stsz merely claims.
282#endif
283
285
286typedef struct MP4D_demux_tag {
287 /************************************************************************/
288 /* mandatory public data */
289 /************************************************************************/
293 int (*read_callback)(int64_t offset, void* buffer, size_t size, void* token);
294 void* token;
295
296 unsigned track_count; // number of tracks in the movie
297
298#if MP4D_INFO_SUPPORTED
299 /************************************************************************/
300 /* informational public data */
301 /************************************************************************/
302 // Movie duration: 64-bit value split into 2 variables
303 unsigned duration_hi;
304 unsigned duration_lo;
305
306 // duration scale: duration = timescale*seconds
307 unsigned timescale;
308
309 // Metadata tag (optional)
310 // Tags provided 'as-is', without any re-encoding
311 struct {
312 unsigned char* title;
313 unsigned char* artist;
314 unsigned char* album;
315 unsigned char* year;
316 unsigned char* comment;
317 unsigned char* genre;
319#endif
320
322
324 unsigned first_chunk;
325 unsigned samples_per_chunk;
326};
327
328typedef struct {
329 void* sps_cache[MINIMP4_MAX_SPS];
330 void* pps_cache[MINIMP4_MAX_PPS];
331 int sps_bytes[MINIMP4_MAX_SPS];
332 int pps_bytes[MINIMP4_MAX_PPS];
333
334 int map_sps[MINIMP4_MAX_SPS];
335 int map_pps[MINIMP4_MAX_PPS];
336
338
339typedef struct mp4_h26x_writer_tag {
340#if MINIMP4_TRANSCODE_SPS_ID
342#endif
346
347int mp4_h26x_write_init(mp4_h26x_writer_t* h, MP4E_mux_t* mux, int width, int height, int is_hevc);
350 const unsigned char* nal,
351 int length,
352 unsigned timeStamp90kHz_next);
353
354/************************************************************************/
355/* API */
356/************************************************************************/
357
367 int (*read_callback)(int64_t offset, void* buffer, size_t size, void* token),
368 void* token,
369 int64_t file_size);
370
382 unsigned int ntrack,
383 unsigned int nsample,
384 unsigned int* frame_bytes,
385 unsigned* timestamp,
386 unsigned* duration);
387
392
404const void* MP4D_read_sps(const MP4D_demux_t* mp4, unsigned int ntrack, int nsps, int* sps_bytes);
405const void* MP4D_read_pps(const MP4D_demux_t* mp4, unsigned int ntrack, int npps, int* pps_bytes);
406
407#if MP4D_PRINT_INFO_SUPPORTED
413void MP4D_printf_info(const MP4D_demux_t* mp4);
414#endif
415
426MP4E_open(int sequential_mode_flag,
427 int enable_fragmentation,
428 void* token,
429 int (*write_callback)(int64_t offset, const void* buffer, size_t size, void* token));
430
439int MP4E_add_track(MP4E_mux_t* mux, const MP4E_track_t* track_data);
440
452 MP4E_mux_t* mux, int track_num, const void* data, int data_bytes, int duration, int kind);
453
463
472int MP4E_set_dsi(MP4E_mux_t* mux, int track_id, const void* dsi, int bytes);
473
479int MP4E_set_vps(MP4E_mux_t* mux, int track_id, const void* vps, int bytes);
480
486int MP4E_set_sps(MP4E_mux_t* mux, int track_id, const void* sps, int bytes);
487
493int MP4E_set_pps(MP4E_mux_t* mux, int track_id, const void* pps, int bytes);
494
500int MP4E_set_text_comment(MP4E_mux_t* mux, const char* comment);
501
502#ifdef __cplusplus
503}
504#endif
505#endif //MINIMP4_H
506
507#if defined(MINIMP4_IMPLEMENTATION) && !defined(MINIMP4_IMPLEMENTATION_GUARD)
508#define MINIMP4_IMPLEMENTATION_GUARD
509
510#define FOUR_CHAR_INT(a, b, c, d) (((uint32_t)(a) << 24) | ((b) << 16) | ((c) << 8) | (d))
511enum {
512 BOX_co64 = FOUR_CHAR_INT('c', 'o', '6', '4'), //ChunkLargeOffsetAtomType
513 BOX_stco = FOUR_CHAR_INT('s', 't', 'c', 'o'), //ChunkOffsetAtomType
514 BOX_crhd = FOUR_CHAR_INT('c', 'r', 'h', 'd'), //ClockReferenceMediaHeaderAtomType
515 BOX_ctts = FOUR_CHAR_INT('c', 't', 't', 's'), //CompositionOffsetAtomType
516 BOX_cprt = FOUR_CHAR_INT('c', 'p', 'r', 't'), //CopyrightAtomType
517 BOX_url_ = FOUR_CHAR_INT('u', 'r', 'l', ' '), //DataEntryURLAtomType
518 BOX_urn_ = FOUR_CHAR_INT('u', 'r', 'n', ' '), //DataEntryURNAtomType
519 BOX_dinf = FOUR_CHAR_INT('d', 'i', 'n', 'f'), //DataInformationAtomType
520 BOX_dref = FOUR_CHAR_INT('d', 'r', 'e', 'f'), //DataReferenceAtomType
521 BOX_stdp = FOUR_CHAR_INT('s', 't', 'd', 'p'), //DegradationPriorityAtomType
522 BOX_edts = FOUR_CHAR_INT('e', 'd', 't', 's'), //EditAtomType
523 BOX_elst = FOUR_CHAR_INT('e', 'l', 's', 't'), //EditListAtomType
524 BOX_uuid = FOUR_CHAR_INT('u', 'u', 'i', 'd'), //ExtendedAtomType
525 BOX_free = FOUR_CHAR_INT('f', 'r', 'e', 'e'), //FreeSpaceAtomType
526 BOX_hdlr = FOUR_CHAR_INT('h', 'd', 'l', 'r'), //HandlerAtomType
527 BOX_hmhd = FOUR_CHAR_INT('h', 'm', 'h', 'd'), //HintMediaHeaderAtomType
528 BOX_hint = FOUR_CHAR_INT('h', 'i', 'n', 't'), //HintTrackReferenceAtomType
529 BOX_mdia = FOUR_CHAR_INT('m', 'd', 'i', 'a'), //MediaAtomType
530 BOX_mdat = FOUR_CHAR_INT('m', 'd', 'a', 't'), //MediaDataAtomType
531 BOX_mdhd = FOUR_CHAR_INT('m', 'd', 'h', 'd'), //MediaHeaderAtomType
532 BOX_minf = FOUR_CHAR_INT('m', 'i', 'n', 'f'), //MediaInformationAtomType
533 BOX_moov = FOUR_CHAR_INT('m', 'o', 'o', 'v'), //MovieAtomType
534 BOX_mvhd = FOUR_CHAR_INT('m', 'v', 'h', 'd'), //MovieHeaderAtomType
535 BOX_stsd = FOUR_CHAR_INT('s', 't', 's', 'd'), //SampleDescriptionAtomType
536 BOX_stsz = FOUR_CHAR_INT('s', 't', 's', 'z'), //SampleSizeAtomType
537 BOX_stz2 = FOUR_CHAR_INT('s', 't', 'z', '2'), //CompactSampleSizeAtomType
538 BOX_stbl = FOUR_CHAR_INT('s', 't', 'b', 'l'), //SampleTableAtomType
539 BOX_stsc = FOUR_CHAR_INT('s', 't', 's', 'c'), //SampleToChunkAtomType
540 BOX_stsh = FOUR_CHAR_INT('s', 't', 's', 'h'), //ShadowSyncAtomType
541 BOX_skip = FOUR_CHAR_INT('s', 'k', 'i', 'p'), //SkipAtomType
542 BOX_smhd = FOUR_CHAR_INT('s', 'm', 'h', 'd'), //SoundMediaHeaderAtomType
543 BOX_stss = FOUR_CHAR_INT('s', 't', 's', 's'), //SyncSampleAtomType
544 BOX_stts = FOUR_CHAR_INT('s', 't', 't', 's'), //TimeToSampleAtomType
545 BOX_trak = FOUR_CHAR_INT('t', 'r', 'a', 'k'), //TrackAtomType
546 BOX_tkhd = FOUR_CHAR_INT('t', 'k', 'h', 'd'), //TrackHeaderAtomType
547 BOX_tref = FOUR_CHAR_INT('t', 'r', 'e', 'f'), //TrackReferenceAtomType
548 BOX_udta = FOUR_CHAR_INT('u', 'd', 't', 'a'), //UserDataAtomType
549 BOX_vmhd = FOUR_CHAR_INT('v', 'm', 'h', 'd'), //VideoMediaHeaderAtomType
550 BOX_url = FOUR_CHAR_INT('u', 'r', 'l', ' '),
551 BOX_urn = FOUR_CHAR_INT('u', 'r', 'n', ' '),
552
553 BOX_gnrv = FOUR_CHAR_INT('g', 'n', 'r', 'v'), //GenericVisualSampleEntryAtomType
554 BOX_gnra = FOUR_CHAR_INT('g', 'n', 'r', 'a'), //GenericAudioSampleEntryAtomType
555
556 //V2 atoms
557 BOX_ftyp = FOUR_CHAR_INT('f', 't', 'y', 'p'), //FileTypeAtomType
558 BOX_padb = FOUR_CHAR_INT('p', 'a', 'd', 'b'), //PaddingBitsAtomType
559
560 //MP4 Atoms
561 BOX_sdhd = FOUR_CHAR_INT('s', 'd', 'h', 'd'), //SceneDescriptionMediaHeaderAtomType
562 BOX_dpnd = FOUR_CHAR_INT('d', 'p', 'n', 'd'), //StreamDependenceAtomType
563 BOX_iods = FOUR_CHAR_INT('i', 'o', 'd', 's'), //ObjectDescriptorAtomType
564 BOX_odhd = FOUR_CHAR_INT('o', 'd', 'h', 'd'), //ObjectDescriptorMediaHeaderAtomType
565 BOX_mpod = FOUR_CHAR_INT('m', 'p', 'o', 'd'), //ODTrackReferenceAtomType
566 BOX_nmhd = FOUR_CHAR_INT('n', 'm', 'h', 'd'), //MPEGMediaHeaderAtomType
567 BOX_esds = FOUR_CHAR_INT('e', 's', 'd', 's'), //ESDAtomType
568 BOX_sync = FOUR_CHAR_INT('s', 'y', 'n', 'c'), //OCRReferenceAtomType
569 BOX_ipir = FOUR_CHAR_INT('i', 'p', 'i', 'r'), //IPIReferenceAtomType
570 BOX_mp4s = FOUR_CHAR_INT('m', 'p', '4', 's'), //MPEGSampleEntryAtomType
571 BOX_mp4a = FOUR_CHAR_INT('m', 'p', '4', 'a'), //MPEGAudioSampleEntryAtomType
572 BOX_mp4v = FOUR_CHAR_INT('m', 'p', '4', 'v'), //MPEGVisualSampleEntryAtomType
573
574 // http://www.itscj.ipsj.or.jp/sc29/open/29view/29n7644t.doc
575 BOX_avc1 = FOUR_CHAR_INT('a', 'v', 'c', '1'),
576 BOX_avc2 = FOUR_CHAR_INT('a', 'v', 'c', '2'),
577 BOX_svc1 = FOUR_CHAR_INT('s', 'v', 'c', '1'),
578 BOX_avcC = FOUR_CHAR_INT('a', 'v', 'c', 'C'),
579 BOX_svcC = FOUR_CHAR_INT('s', 'v', 'c', 'C'),
580 BOX_btrt = FOUR_CHAR_INT('b', 't', 'r', 't'),
581 BOX_m4ds = FOUR_CHAR_INT('m', '4', 'd', 's'),
582 BOX_seib = FOUR_CHAR_INT('s', 'e', 'i', 'b'),
583
584 // H264/HEVC
585 BOX_hev1 = FOUR_CHAR_INT('h', 'e', 'v', '1'),
586 BOX_hvc1 = FOUR_CHAR_INT('h', 'v', 'c', '1'),
587 BOX_hvcC = FOUR_CHAR_INT('h', 'v', 'c', 'C'),
588
589 //3GPP atoms
590 BOX_samr = FOUR_CHAR_INT('s', 'a', 'm', 'r'), //AMRSampleEntryAtomType
591 BOX_sawb = FOUR_CHAR_INT('s', 'a', 'w', 'b'), //WB_AMRSampleEntryAtomType
592 BOX_damr = FOUR_CHAR_INT('d', 'a', 'm', 'r'), //AMRConfigAtomType
593 BOX_s263 = FOUR_CHAR_INT('s', '2', '6', '3'), //H263SampleEntryAtomType
594 BOX_d263 = FOUR_CHAR_INT('d', '2', '6', '3'), //H263ConfigAtomType
595
596 //V2 atoms - Movie Fragments
597 BOX_mvex = FOUR_CHAR_INT('m', 'v', 'e', 'x'), //MovieExtendsAtomType
598 BOX_trex = FOUR_CHAR_INT('t', 'r', 'e', 'x'), //TrackExtendsAtomType
599 BOX_moof = FOUR_CHAR_INT('m', 'o', 'o', 'f'), //MovieFragmentAtomType
600 BOX_mfhd = FOUR_CHAR_INT('m', 'f', 'h', 'd'), //MovieFragmentHeaderAtomType
601 BOX_traf = FOUR_CHAR_INT('t', 'r', 'a', 'f'), //TrackFragmentAtomType
602 BOX_tfhd = FOUR_CHAR_INT('t', 'f', 'h', 'd'), //TrackFragmentHeaderAtomType
603 BOX_tfdt = FOUR_CHAR_INT('t', 'f', 'd', 't'), //TrackFragmentBaseMediaDecodeTimeBox
604 BOX_trun = FOUR_CHAR_INT('t', 'r', 'u', 'n'), //TrackFragmentRunAtomType
605 BOX_mehd = FOUR_CHAR_INT('m', 'e', 'h', 'd'), //MovieExtendsHeaderBox
606
607 // Object Descriptors (OD) data coding
608 // These takes only 1 byte; this implementation translate <od_tag> to
609 // <od_tag> + OD_BASE to keep API uniform and safe for string functions
610 OD_BASE = FOUR_CHAR_INT('$', '$', '$', '0'), //
611 OD_ESD = FOUR_CHAR_INT('$', '$', '$', '3'), //SDescriptor_Tag
612 OD_DCD = FOUR_CHAR_INT('$', '$', '$', '4'), //DecoderConfigDescriptor_Tag
613 OD_DSI = FOUR_CHAR_INT('$', '$', '$', '5'), //DecoderSpecificInfo_Tag
614 OD_SLC = FOUR_CHAR_INT('$', '$', '$', '6'), //SLConfigDescriptor_Tag
615
616 BOX_meta = FOUR_CHAR_INT('m', 'e', 't', 'a'),
617 BOX_ilst = FOUR_CHAR_INT('i', 'l', 's', 't'),
618
619 // Metagata tags, see http://atomicparsley.sourceforge.net/mpeg-4files.html
620 BOX_calb = FOUR_CHAR_INT('\xa9', 'a', 'l', 'b'), // album
621 BOX_cart = FOUR_CHAR_INT('\xa9', 'a', 'r', 't'), // artist
622 BOX_aART = FOUR_CHAR_INT('a', 'A', 'R', 'T'), // album artist
623 BOX_ccmt = FOUR_CHAR_INT('\xa9', 'c', 'm', 't'), // comment
624 BOX_cday = FOUR_CHAR_INT('\xa9', 'd', 'a', 'y'), // year (as string)
625 BOX_cnam = FOUR_CHAR_INT('\xa9', 'n', 'a', 'm'), // title
626 BOX_cgen = FOUR_CHAR_INT('\xa9', 'g', 'e', 'n'), // custom genre (as string or as byte!)
627 BOX_trkn = FOUR_CHAR_INT('t', 'r', 'k', 'n'), // track number (byte)
628 BOX_disk = FOUR_CHAR_INT('d', 'i', 's', 'k'), // disk number (byte)
629 BOX_cwrt = FOUR_CHAR_INT('\xa9', 'w', 'r', 't'), // composer
630 BOX_ctoo = FOUR_CHAR_INT('\xa9', 't', 'o', 'o'), // encoder
631 BOX_tmpo = FOUR_CHAR_INT('t', 'm', 'p', 'o'), // bpm (byte)
632 BOX_cpil = FOUR_CHAR_INT('c', 'p', 'i', 'l'), // compilation (byte)
633 BOX_covr = FOUR_CHAR_INT('c', 'o', 'v', 'r'), // cover art (JPEG/PNG)
634 BOX_rtng = FOUR_CHAR_INT('r', 't', 'n', 'g'), // rating/advisory (byte)
635 BOX_cgrp = FOUR_CHAR_INT('\xa9', 'g', 'r', 'p'), // grouping
636 BOX_stik = FOUR_CHAR_INT(
637 's',
638 't',
639 'i',
640 'k'), // stik (byte) 0 = Movie 1 = Normal 2 = Audiobook 5 = Whacked Bookmark 6 = Music Video 9 = Short Film 10 = TV Show 11 = Booklet 14 = Ringtone
641 BOX_pcst = FOUR_CHAR_INT('p', 'c', 's', 't'), // podcast (byte)
642 BOX_catg = FOUR_CHAR_INT('c', 'a', 't', 'g'), // category
643 BOX_keyw = FOUR_CHAR_INT('k', 'e', 'y', 'w'), // keyword
644 BOX_purl = FOUR_CHAR_INT('p', 'u', 'r', 'l'), // podcast URL (byte)
645 BOX_egid = FOUR_CHAR_INT('e', 'g', 'i', 'd'), // episode global unique ID (byte)
646 BOX_desc = FOUR_CHAR_INT('d', 'e', 's', 'c'), // description
647 BOX_clyr = FOUR_CHAR_INT('\xa9', 'l', 'y', 'r'), // lyrics (may be > 255 bytes)
648 BOX_tven = FOUR_CHAR_INT('t', 'v', 'e', 'n'), // tv episode number
649 BOX_tves = FOUR_CHAR_INT('t', 'v', 'e', 's'), // tv episode (byte)
650 BOX_tvnn = FOUR_CHAR_INT('t', 'v', 'n', 'n'), // tv network name
651 BOX_tvsh = FOUR_CHAR_INT('t', 'v', 's', 'h'), // tv show name
652 BOX_tvsn = FOUR_CHAR_INT('t', 'v', 's', 'n'), // tv season (byte)
653 BOX_purd = FOUR_CHAR_INT('p', 'u', 'r', 'd'), // purchase date
654 BOX_pgap = FOUR_CHAR_INT('p', 'g', 'a', 'p'), // Gapless Playback (byte)
655
656 //BOX_aart = FOUR_CHAR_INT( 'a', 'a', 'r', 't' ), // Album artist
657 BOX_cART = FOUR_CHAR_INT('\xa9', 'A', 'R', 'T'), // artist
658 BOX_gnre = FOUR_CHAR_INT('g', 'n', 'r', 'e'),
659
660 // 3GPP metatags (http://cpansearch.perl.org/src/JHAR/MP4-Info-1.12/Info.pm)
661 BOX_auth = FOUR_CHAR_INT('a', 'u', 't', 'h'), // author
662 BOX_titl = FOUR_CHAR_INT('t', 'i', 't', 'l'), // title
663 BOX_dscp = FOUR_CHAR_INT('d', 's', 'c', 'p'), // description
664 BOX_perf = FOUR_CHAR_INT('p', 'e', 'r', 'f'), // performer
665 BOX_mean = FOUR_CHAR_INT('m', 'e', 'a', 'n'), //
666 BOX_name = FOUR_CHAR_INT('n', 'a', 'm', 'e'), //
667 BOX_data = FOUR_CHAR_INT('d', 'a', 't', 'a'), //
668
669 // these from http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2008-September/053151.html
670 BOX_albm = FOUR_CHAR_INT('a', 'l', 'b', 'm'), // album
671 BOX_yrrc = FOUR_CHAR_INT('y', 'r', 'r', 'c') // album
672};
673
674// Video track : 'vide'
675#define MP4E_HANDLER_TYPE_VIDE 0x76696465
676// Audio track : 'soun'
677#define MP4E_HANDLER_TYPE_SOUN 0x736F756E
678// General MPEG-4 systems streams (without specific handler).
679// Used for private stream, as suggested in http://www.mp4ra.org/handler.html
680#define MP4E_HANDLER_TYPE_GESM 0x6765736D
681
682typedef struct {
685 unsigned duration;
686 unsigned flag_random_access;
687} sample_t;
688
689typedef struct {
690 unsigned char* data;
691 int bytes;
692 int capacity;
693} minimp4_vector_t;
694
695typedef struct {
696 MP4E_track_t info;
697 minimp4_vector_t smpl; // sample descriptor
698 minimp4_vector_t pending_sample;
699
700 minimp4_vector_t vsps; // or dsi for audio
701 minimp4_vector_t vpps; // not used for audio
702 minimp4_vector_t vvps; // used for HEVC
703
704} track_t;
705
706typedef struct MP4E_mux_tag {
707 minimp4_vector_t tracks;
708
709 int64_t write_pos;
710 int (*write_callback)(int64_t offset, const void* buffer, size_t size, void* token);
711 void* token;
712 char* text_comment;
713
714 int sequential_mode_flag;
715 int enable_fragmentation; // flag, indicating streaming-friendly 'fragmentation' mode
716 int fragments_count; // # of fragments in 'fragmentation' mode
717
718} MP4E_mux_t;
719
720static const unsigned char box_ftyp[] = {
721#if 1
722 0, 0, 0, 0x18, 'f', 't', 'y', 'p', 'm', 'p', '4', '2',
723 0, 0, 0, 0, 'm', 'p', '4', '2', 'i', 's', 'o', 'm',
724#else
725 // as in ffmpeg
726 0, 0, 0, 0x20, 'f', 't', 'y', 'p', 'i', 's', 'o', 'm', 0, 0, 2, 0,
727 'm', 'p', '4', '1', 'i', 's', 'o', 'm', 'i', 's', 'o', '2', 'a', 'v', 'c', '1',
728#endif
729};
730
734#define WR(x, n) *p++ = (unsigned char)((x) >> 8 * n)
735#define WRITE_1(x) WR(x, 0);
736#define WRITE_2(x) \
737 WR(x, 1); \
738 WR(x, 0);
739#define WRITE_3(x) \
740 WR(x, 2); \
741 WR(x, 1); \
742 WR(x, 0);
743#define WRITE_4(x) \
744 WR(x, 3); \
745 WR(x, 2); \
746 WR(x, 1); \
747 WR(x, 0);
748#define WR4(p, x) \
749 (p)[0] = (char)((x) >> 8 * 3); \
750 (p)[1] = (char)((x) >> 8 * 2); \
751 (p)[2] = (char)((x) >> 8 * 1); \
752 (p)[3] = (char)((x));
753
754// Finish atom: update atom size field
755#define END_ATOM \
756 --stack; \
757 WR4((unsigned char*)*stack, p - *stack);
758
759// Initiate atom: save position of size field on stack
760#define ATOM(x) \
761 *stack++ = p; \
762 p += 4; \
763 WRITE_4(x);
764
765// Atom with 'FullAtomVersionFlags' field
766#define ATOM_FULL(x, flag) \
767 ATOM(x); \
768 WRITE_4(flag);
769
770#define ERR(func) \
771 { \
772 int err = func; \
773 if (err) \
774 return err; \
775 }
776
780static int minimp4_vector_init(minimp4_vector_t* h, int capacity) {
781 h->bytes = 0;
782 h->capacity = capacity;
783 h->data = capacity ? (unsigned char*)malloc(capacity) : NULL;
784 return !capacity || !!h->data;
785}
786
790static void minimp4_vector_reset(minimp4_vector_t* h) {
791 if (h->data)
792 free(h->data);
793 memset(h, 0, sizeof(minimp4_vector_t));
794}
795
799static int minimp4_vector_grow(minimp4_vector_t* h, int bytes) {
800 void* p;
801 int new_size = h->capacity * 2 + 1024;
802 if (new_size < h->capacity + bytes)
803 new_size = h->capacity + bytes + 1024;
804 p = realloc(h->data, new_size);
805 if (!p)
806 return 0;
807 h->data = (unsigned char*)p;
808 h->capacity = new_size;
809 return 1;
810}
811
817static unsigned char* minimp4_vector_alloc_tail(minimp4_vector_t* h, int bytes) {
818 unsigned char* p;
819 if (!h->data && !minimp4_vector_init(h, 2 * bytes + 1024))
820 return NULL;
821 if ((h->capacity - h->bytes) < bytes && !minimp4_vector_grow(h, bytes))
822 return NULL;
823 assert(h->data);
824 assert((h->capacity - h->bytes) >= bytes);
825 p = h->data + h->bytes;
826 h->bytes += bytes;
827 return p;
828}
829
833static unsigned char* minimp4_vector_put(minimp4_vector_t* h, const void* buf, int bytes) {
834 unsigned char* tail = minimp4_vector_alloc_tail(h, bytes);
835 if (tail)
836 memcpy(tail, (void*)buf, bytes);
837 return tail;
838}
839
845MP4E_open(int sequential_mode_flag,
846 int enable_fragmentation,
847 void* token,
848 int (*write_callback)(int64_t offset, const void* buffer, size_t size, void* token)) {
849 if (write_callback(0, box_ftyp, sizeof(box_ftyp), token)) // Write fixed header: 'ftyp' box
850 return 0;
851 MP4E_mux_t* mux = (MP4E_mux_t*)malloc(sizeof(MP4E_mux_t));
852 if (!mux)
853 return mux;
854 mux->sequential_mode_flag = sequential_mode_flag || enable_fragmentation;
855 mux->enable_fragmentation = enable_fragmentation;
856 mux->fragments_count = 0;
857 mux->write_callback = write_callback;
858 mux->token = token;
859 mux->text_comment = NULL;
860 mux->write_pos = sizeof(box_ftyp);
861
862 if (!mux->sequential_mode_flag) { // Write filler, which would be updated later
863 if (mux->write_callback(mux->write_pos, box_ftyp, 8, mux->token)) {
864 free(mux);
865 return 0;
866 }
867 mux->write_pos += 16; // box_ftyp + box_free for 32bit or 64bit size encoding
868 }
869 minimp4_vector_init(&mux->tracks, 2 * sizeof(track_t));
870 return mux;
871}
872
876int MP4E_add_track(MP4E_mux_t* mux, const MP4E_track_t* track_data) {
877 track_t* tr;
878 int ntr = mux->tracks.bytes / sizeof(track_t);
879
880 if (!mux || !track_data)
882
883 tr = (track_t*)minimp4_vector_alloc_tail(&mux->tracks, sizeof(track_t));
884 if (!tr)
886 memset(tr, 0, sizeof(track_t));
887 memcpy(&tr->info, (void*)track_data, sizeof(*track_data));
888 if (!minimp4_vector_init(&tr->smpl, 256))
890 minimp4_vector_init(&tr->vsps, 0);
891 minimp4_vector_init(&tr->vpps, 0);
892 minimp4_vector_init(&tr->pending_sample, 0);
893 return ntr;
894}
895
896static const unsigned char* next_dsi(const unsigned char* p, const unsigned char* end, int* bytes) {
897 if (p < end + 2) {
898 *bytes = p[0] * 256 + p[1];
899 return p + 2;
900 } else
901 return NULL;
902}
903
904static int append_mem(minimp4_vector_t* v, const void* mem, int bytes) {
905 int i;
906 unsigned char size[2];
907 const unsigned char* p = v->data;
908 for (i = 0; i + 2 < v->bytes;) {
909 int cb = p[i] * 256 + p[i + 1];
910 if (cb == bytes && !memcmp(p + i + 2, mem, cb))
911 return 1;
912 i += 2 + cb;
913 }
914 size[0] = bytes >> 8;
915 size[1] = bytes;
916 return minimp4_vector_put(v, size, 2) && minimp4_vector_put(v, mem, bytes);
917}
918
919static int items_count(minimp4_vector_t* v) {
920 int i, count = 0;
921 const unsigned char* p = v->data;
922 for (i = 0; i + 2 < v->bytes;) {
923 int cb = p[i] * 256 + p[i + 1];
924 count++;
925 i += 2 + cb;
926 }
927 return count;
928}
929
930int MP4E_set_dsi(MP4E_mux_t* mux, int track_id, const void* dsi, int bytes) {
931 track_t* tr = ((track_t*)mux->tracks.data) + track_id;
932 assert(tr->info.track_media_kind == e_audio || tr->info.track_media_kind == e_private);
933 if (tr->vsps.bytes)
934 return MP4E_STATUS_ONLY_ONE_DSI_ALLOWED; // only one DSI allowed
935 return append_mem(&tr->vsps, dsi, bytes) ? MP4E_STATUS_OK : MP4E_STATUS_NO_MEMORY;
936}
937
938int MP4E_set_vps(MP4E_mux_t* mux, int track_id, const void* vps, int bytes) {
939 track_t* tr = ((track_t*)mux->tracks.data) + track_id;
940 assert(tr->info.track_media_kind == e_video);
941 return append_mem(&tr->vvps, vps, bytes) ? MP4E_STATUS_OK : MP4E_STATUS_NO_MEMORY;
942}
943
944int MP4E_set_sps(MP4E_mux_t* mux, int track_id, const void* sps, int bytes) {
945 track_t* tr = ((track_t*)mux->tracks.data) + track_id;
946 assert(tr->info.track_media_kind == e_video);
947 return append_mem(&tr->vsps, sps, bytes) ? MP4E_STATUS_OK : MP4E_STATUS_NO_MEMORY;
948}
949
950int MP4E_set_pps(MP4E_mux_t* mux, int track_id, const void* pps, int bytes) {
951 track_t* tr = ((track_t*)mux->tracks.data) + track_id;
952 assert(tr->info.track_media_kind == e_video);
953 return append_mem(&tr->vpps, pps, bytes) ? MP4E_STATUS_OK : MP4E_STATUS_NO_MEMORY;
954}
955
956static unsigned get_duration(const track_t* tr) {
957 unsigned i, sum_duration = 0;
958 const sample_t* s = (const sample_t*)tr->smpl.data;
959 for (i = 0; i < tr->smpl.bytes / sizeof(sample_t); i++) {
960 sum_duration += s[i].duration;
961 }
962 return sum_duration;
963}
964
965static int write_pending_data(MP4E_mux_t* mux, track_t* tr) {
966 // if have pending sample && have at least one sample in the index
967 if (tr->pending_sample.bytes > 0 && tr->smpl.bytes >= sizeof(sample_t)) {
968 // Complete pending sample
969 sample_t* smpl_desc;
970 unsigned char base[8], *p = base;
971
972 assert(mux->sequential_mode_flag);
973
974 // Write each sample to a separate atom
975 assert(mux->sequential_mode_flag); // Separate atom needed for sequential_mode only
976 WRITE_4(tr->pending_sample.bytes + 8);
977 WRITE_4(BOX_mdat);
978 ERR(mux->write_callback(mux->write_pos, base, p - base, mux->token));
979 mux->write_pos += p - base;
980
981 // Update sample descriptor with size and offset
982 smpl_desc = ((sample_t*)minimp4_vector_alloc_tail(&tr->smpl, 0)) - 1;
983 smpl_desc->size = tr->pending_sample.bytes;
984 smpl_desc->offset = (boxsize_t)mux->write_pos;
985
986 // Write data
987 ERR(mux->write_callback(
988 mux->write_pos, tr->pending_sample.data, tr->pending_sample.bytes, mux->token));
989 mux->write_pos += tr->pending_sample.bytes;
990
991 // reset buffer
992 tr->pending_sample.bytes = 0;
993 }
994 return MP4E_STATUS_OK;
995}
996
997static int
998add_sample_descriptor(MP4E_mux_t* mux, track_t* tr, int data_bytes, int duration, int kind) {
999 sample_t smp;
1000 smp.size = data_bytes;
1001 smp.offset = (boxsize_t)mux->write_pos;
1002 smp.duration = (duration ? duration : tr->info.default_duration);
1003 smp.flag_random_access = (kind == MP4E_SAMPLE_RANDOM_ACCESS);
1004 return NULL != minimp4_vector_put(&tr->smpl, &smp, sizeof(sample_t));
1005}
1006
1007static int mp4e_flush_index(MP4E_mux_t* mux);
1008
1012static int mp4e_write_fragment_header(MP4E_mux_t* mux,
1013 int track_num,
1014 int data_bytes,
1015 int duration,
1016 int kind
1018 ,
1019 uint64_t timestamp
1020#endif
1021) {
1022 unsigned char base[888], *p = base;
1023 unsigned char* stack_base[20]; // atoms nesting stack
1024 unsigned char** stack = stack_base;
1025 unsigned char* pdata_offset;
1026 unsigned flags;
1027 enum {
1028 default_sample_duration_present = 0x000008,
1029 default_sample_flags_present = 0x000020,
1030 } e;
1031
1032 track_t* tr = ((track_t*)mux->tracks.data) + track_num;
1033
1034 ATOM(BOX_moof)
1035 ATOM_FULL(BOX_mfhd, 0)
1036 WRITE_4(mux->fragments_count); // start from 1
1037 END_ATOM
1038 ATOM(BOX_traf)
1039 flags = 0;
1040 if (tr->info.track_media_kind == e_video)
1041 flags |= 0x20; // default-sample-flags-present
1042 else
1043 flags |= 0x08; // default-sample-duration-present
1044 flags = (tr->info.track_media_kind == e_video) ? 0x20020 : 0x20008;
1045
1046 ATOM_FULL(BOX_tfhd, flags)
1047 WRITE_4(track_num + 1); // track_ID
1048 if (tr->info.track_media_kind == e_video) {
1049 WRITE_4(0x1010000); // default_sample_flags
1050 } else {
1051 WRITE_4(duration);
1052 }
1053 END_ATOM
1054#if MP4D_TFDT_SUPPORT
1055 ATOM_FULL(BOX_tfdt, 0x01000000) // version 1
1056 WRITE_4(timestamp >> 32); // upper timestamp
1057 WRITE_4(timestamp & 0xffffffff); // lower timestamp
1058 END_ATOM
1059#endif
1060 if (tr->info.track_media_kind == e_audio) {
1061 flags = 0;
1062 flags |= 0x001; // data-offset-present
1063 flags |= 0x200; // sample-size-present
1064 ATOM_FULL(BOX_trun, flags)
1065 WRITE_4(1); // sample_count
1066 pdata_offset = p;
1067 p += 4; // save ptr to data_offset
1068 WRITE_4(data_bytes); // sample_size
1069 END_ATOM
1070 } else if (kind == MP4E_SAMPLE_RANDOM_ACCESS) {
1071 flags = 0;
1072 flags |= 0x001; // data-offset-present
1073 flags |= 0x004; // first-sample-flags-present
1074 flags |= 0x100; // sample-duration-present
1075 flags |= 0x200; // sample-size-present
1076 ATOM_FULL(BOX_trun, flags)
1077 WRITE_4(1); // sample_count
1078 pdata_offset = p;
1079 p += 4; // save ptr to data_offset
1080 WRITE_4(0x2000000); // first_sample_flags
1081 WRITE_4(duration); // sample_duration
1082 WRITE_4(data_bytes); // sample_size
1083 END_ATOM
1084 } else {
1085 flags = 0;
1086 flags |= 0x001; // data-offset-present
1087 flags |= 0x100; // sample-duration-present
1088 flags |= 0x200; // sample-size-present
1089 ATOM_FULL(BOX_trun, flags)
1090 WRITE_4(1); // sample_count
1091 pdata_offset = p;
1092 p += 4; // save ptr to data_offset
1093 WRITE_4(duration); // sample_duration
1094 WRITE_4(data_bytes); // sample_size
1095 END_ATOM
1096 }
1097 END_ATOM
1098 END_ATOM
1099 WR4(pdata_offset, (p - base) + 8);
1100
1101 ERR(mux->write_callback(mux->write_pos, base, p - base, mux->token));
1102 mux->write_pos += p - base;
1103 return MP4E_STATUS_OK;
1104}
1105
1106static int mp4e_write_mdat_box(MP4E_mux_t* mux, uint32_t size) {
1107 unsigned char base[8], *p = base;
1108 WRITE_4(size);
1109 WRITE_4(BOX_mdat);
1110 ERR(mux->write_callback(mux->write_pos, base, p - base, mux->token));
1111 mux->write_pos += p - base;
1112 return MP4E_STATUS_OK;
1113}
1114
1118int MP4E_put_sample(
1119 MP4E_mux_t* mux, int track_num, const void* data, int data_bytes, int duration, int kind) {
1120 track_t* tr;
1121 if (!mux || !data)
1123 tr = ((track_t*)mux->tracks.data) + track_num;
1124
1125 if (mux->enable_fragmentation) {
1126#if MP4D_TFDT_SUPPORT
1127 // NOTE: assume a constant `duration` to calculate current timestamp
1128 uint64_t timestamp = (uint64_t)mux->fragments_count * duration;
1129#endif
1130 if (!mux->fragments_count++)
1131 ERR(mp4e_flush_index(mux)); // write file headers before 1st sample
1132// write MOOF + MDAT + sample data
1133#if MP4D_TFDT_SUPPORT
1134 ERR(mp4e_write_fragment_header(mux, track_num, data_bytes, duration, kind, timestamp));
1135#else
1136 ERR(mp4e_write_fragment_header(mux, track_num, data_bytes, duration, kind));
1137#endif
1138 // write MDAT box for each sample
1139 ERR(mp4e_write_mdat_box(mux, data_bytes + 8));
1140 ERR(mux->write_callback(mux->write_pos, data, data_bytes, mux->token));
1141 mux->write_pos += data_bytes;
1142 return MP4E_STATUS_OK;
1143 }
1144
1145 if (kind != MP4E_SAMPLE_CONTINUATION) {
1146 if (mux->sequential_mode_flag)
1147 ERR(write_pending_data(mux, tr));
1148 if (!add_sample_descriptor(mux, tr, data_bytes, duration, kind))
1149 return MP4E_STATUS_NO_MEMORY;
1150 } else {
1151 if (!mux->sequential_mode_flag) {
1152 sample_t* smpl_desc;
1153 if (tr->smpl.bytes < sizeof(sample_t))
1154 return MP4E_STATUS_NO_MEMORY; // write continuation, but there are no samples in the index
1155 // Accumulate size of the continuation in the sample descriptor
1156 smpl_desc = (sample_t*)(tr->smpl.data + tr->smpl.bytes) - 1;
1157 smpl_desc->size += data_bytes;
1158 }
1159 }
1160
1161 if (mux->sequential_mode_flag) {
1162 if (!minimp4_vector_put(&tr->pending_sample, data, data_bytes))
1163 return MP4E_STATUS_NO_MEMORY;
1164 } else {
1165 ERR(mux->write_callback(mux->write_pos, data, data_bytes, mux->token));
1166 mux->write_pos += data_bytes;
1167 }
1168 return MP4E_STATUS_OK;
1169}
1170
1174static int od_size_of_size(int size) {
1175 int i, size_of_size = 1;
1176 for (i = size; i > 0x7F; i -= 0x7F)
1177 size_of_size++;
1178 return size_of_size;
1179}
1180
1187int MP4E_set_text_comment(MP4E_mux_t* mux, const char* comment) {
1188 if (!mux || !comment)
1190 if (mux->text_comment)
1191 free(mux->text_comment);
1192 mux->text_comment = strdup(comment);
1193 if (!mux->text_comment)
1194 return MP4E_STATUS_NO_MEMORY;
1195 return MP4E_STATUS_OK;
1196}
1197
1201static int mp4e_flush_index(MP4E_mux_t* mux) {
1202 unsigned char* stack_base[20]; // atoms nesting stack
1203 unsigned char** stack = stack_base;
1204 unsigned char *base, *p;
1205 unsigned int ntr, index_bytes, ntracks = mux->tracks.bytes / sizeof(track_t);
1206 int i, err;
1207
1208 // How much memory needed for indexes
1209 // Experimental data:
1210 // file with 1 track = 560 bytes
1211 // file with 2 tracks = 972 bytes
1212 // track size = 412 bytes;
1213 // file header size = 148 bytes
1214#define FILE_HEADER_BYTES 256
1215#define TRACK_HEADER_BYTES 512
1216 index_bytes = FILE_HEADER_BYTES;
1217 if (mux->text_comment)
1218 index_bytes += 128 + strlen(mux->text_comment);
1219 for (ntr = 0; ntr < ntracks; ntr++) {
1220 track_t* tr = ((track_t*)mux->tracks.data) + ntr;
1221 index_bytes += TRACK_HEADER_BYTES; // fixed amount (implementation-dependent)
1222 // may need extra 4 bytes for duration field + 4 bytes for worst-case random access box
1223 index_bytes += tr->smpl.bytes * (sizeof(sample_t) + 4 + 4) / sizeof(sample_t);
1224 index_bytes += tr->vsps.bytes;
1225 index_bytes += tr->vpps.bytes;
1226
1227 ERR(write_pending_data(mux, tr));
1228 }
1229
1230 base = (unsigned char*)malloc(index_bytes);
1231 if (!base)
1232 return MP4E_STATUS_NO_MEMORY;
1233 p = base;
1234
1235 if (!mux->sequential_mode_flag) {
1236 // update size of mdat box.
1237 // One of 2 points, which requires random file access.
1238 // Second is optional duration update at beginning of file in fragmentation mode.
1239 // This can be avoided using "till eof" size code, but in this case indexes must be
1240 // written before the mdat....
1241 int64_t size = mux->write_pos - sizeof(box_ftyp);
1242 const int64_t size_limit = (int64_t)(uint64_t)0xfffffffe;
1243 if (size > size_limit) {
1244 WRITE_4(1);
1245 WRITE_4(BOX_mdat);
1246 WRITE_4((size >> 32) & 0xffffffff);
1247 WRITE_4(size & 0xffffffff);
1248 } else {
1249 WRITE_4(8);
1250 WRITE_4(BOX_free);
1251 WRITE_4(size - 8);
1252 WRITE_4(BOX_mdat);
1253 }
1254 ERR(mux->write_callback(sizeof(box_ftyp), base, p - base, mux->token));
1255 p = base;
1256 }
1257
1258 // Write index atoms; order taken from Table 1 of [1]
1259#define MOOV_TIMESCALE 1000
1260 ATOM(BOX_moov);
1261 ATOM_FULL(BOX_mvhd, 0);
1262 WRITE_4(0); // creation_time
1263 WRITE_4(0); // modification_time
1264
1265 if (ntracks) {
1266 track_t* tr = ((track_t*)mux->tracks.data) + 0; // take 1st track
1267 unsigned duration = get_duration(tr);
1268 duration = (unsigned)(duration * 1LL * MOOV_TIMESCALE / tr->info.time_scale);
1269 WRITE_4(MOOV_TIMESCALE); // duration
1270 WRITE_4(duration); // duration
1271 }
1272
1273 WRITE_4(0x00010000); // rate
1274 WRITE_2(0x0100); // volume
1275 WRITE_2(0); // reserved
1276 WRITE_4(0); // reserved
1277 WRITE_4(0); // reserved
1278
1279 // matrix[9]
1280 WRITE_4(0x00010000);
1281 WRITE_4(0);
1282 WRITE_4(0);
1283 WRITE_4(0);
1284 WRITE_4(0x00010000);
1285 WRITE_4(0);
1286 WRITE_4(0);
1287 WRITE_4(0);
1288 WRITE_4(0x40000000);
1289
1290 // pre_defined[6]
1291 WRITE_4(0);
1292 WRITE_4(0);
1293 WRITE_4(0);
1294 WRITE_4(0);
1295 WRITE_4(0);
1296 WRITE_4(0);
1297
1298 //next_track_ID is a non-zero integer that indicates a value to use for the track ID of the next track to be
1299 //added to this presentation. Zero is not a valid track ID value. The value of next_track_ID shall be
1300 //larger than the largest track-ID in use.
1301 WRITE_4(ntracks + 1);
1302 END_ATOM;
1303
1304 for (ntr = 0; ntr < ntracks; ntr++) {
1305 track_t* tr = ((track_t*)mux->tracks.data) + ntr;
1306 unsigned duration = get_duration(tr);
1307 int samples_count = tr->smpl.bytes / sizeof(sample_t);
1308 const sample_t* sample = (const sample_t*)tr->smpl.data;
1309 unsigned handler_type;
1310 const char* handler_ascii = NULL;
1311
1312 if (mux->enable_fragmentation)
1313 samples_count = 0;
1314 else if (samples_count <= 0)
1315 continue; // skip empty track
1316
1317 switch (tr->info.track_media_kind) {
1318 case e_audio:
1319 handler_type = MP4E_HANDLER_TYPE_SOUN;
1320 handler_ascii = "SoundHandler";
1321 break;
1322 case e_video:
1323 handler_type = MP4E_HANDLER_TYPE_VIDE;
1324 handler_ascii = "VideoHandler";
1325 break;
1326 case e_private:
1327 handler_type = MP4E_HANDLER_TYPE_GESM;
1328 break;
1329 default:
1331 }
1332
1333 ATOM(BOX_trak);
1334 ATOM_FULL(BOX_tkhd, 7); // flag: 1=trak enabled; 2=track in movie; 4=track in preview
1335 WRITE_4(0); // creation_time
1336 WRITE_4(0); // modification_time
1337 WRITE_4(ntr + 1); // track_ID
1338 WRITE_4(0); // reserved
1339 WRITE_4((unsigned)(duration * 1LL * MOOV_TIMESCALE / tr->info.time_scale));
1340 WRITE_4(0);
1341 WRITE_4(0); // reserved[2]
1342 WRITE_2(0); // layer
1343 WRITE_2(0); // alternate_group
1344 WRITE_2(0x0100); // volume {if track_is_audio 0x0100 else 0};
1345 WRITE_2(0); // reserved
1346
1347 // matrix[9]
1348 WRITE_4(0x00010000);
1349 WRITE_4(0);
1350 WRITE_4(0);
1351 WRITE_4(0);
1352 WRITE_4(0x00010000);
1353 WRITE_4(0);
1354 WRITE_4(0);
1355 WRITE_4(0);
1356 WRITE_4(0x40000000);
1357
1358 if (tr->info.track_media_kind == e_audio || tr->info.track_media_kind == e_private) {
1359 WRITE_4(0); // width
1360 WRITE_4(0); // height
1361 } else {
1362 WRITE_4(tr->info.u.v.width * 0x10000); // width
1363 WRITE_4(tr->info.u.v.height * 0x10000); // height
1364 }
1365 END_ATOM;
1366
1367 ATOM(BOX_mdia);
1368 ATOM_FULL(BOX_mdhd, 0);
1369 WRITE_4(0); // creation_time
1370 WRITE_4(0); // modification_time
1371 WRITE_4(tr->info.time_scale);
1372 WRITE_4(duration); // duration
1373 {
1374 int lang_code = ((tr->info.language[0] & 31) << 10) |
1375 ((tr->info.language[1] & 31) << 5) | (tr->info.language[2] & 31);
1376 WRITE_2(lang_code); // language
1377 }
1378 WRITE_2(0); // pre_defined
1379 END_ATOM;
1380
1381 ATOM_FULL(BOX_hdlr, 0);
1382 WRITE_4(0); // pre_defined
1383 WRITE_4(handler_type); // handler_type
1384 WRITE_4(0);
1385 WRITE_4(0);
1386 WRITE_4(0); // reserved[3]
1387 // name is a null-terminated string in UTF-8 characters which gives a human-readable name for the track type (for debugging and inspection purposes).
1388 // set mdia hdlr name field to what quicktime uses.
1389 // Sony smartphone may fail to decode short files w/o handler name
1390 if (handler_ascii) {
1391 for (i = 0; i < (int)strlen(handler_ascii) + 1; i++) {
1392 WRITE_1(handler_ascii[i]);
1393 }
1394 } else {
1395 WRITE_4(0);
1396 }
1397 END_ATOM;
1398
1399 ATOM(BOX_minf);
1400
1401 if (tr->info.track_media_kind == e_audio) {
1402 // Sound Media Header Box
1403 ATOM_FULL(BOX_smhd, 0);
1404 WRITE_2(0); // balance
1405 WRITE_2(0); // reserved
1406 END_ATOM;
1407 }
1408 if (tr->info.track_media_kind == e_video) {
1409 // mandatory Video Media Header Box
1410 ATOM_FULL(BOX_vmhd, 1);
1411 WRITE_2(0); // graphicsmode
1412 WRITE_2(0);
1413 WRITE_2(0);
1414 WRITE_2(0); // opcolor[3]
1415 END_ATOM;
1416 }
1417
1418 ATOM(BOX_dinf);
1419 ATOM_FULL(BOX_dref, 0);
1420 WRITE_4(1); // entry_count
1421 // If the flag is set indicating that the data is in the same file as this box, then no string (not even an empty one)
1422 // shall be supplied in the entry field.
1423
1424 // ASP the correct way to avoid supply the string, is to use flag 1
1425 // otherwise ISO reference demux crashes
1426 ATOM_FULL(BOX_url, 1);
1427 END_ATOM;
1428 END_ATOM;
1429 END_ATOM;
1430
1431 ATOM(BOX_stbl);
1432 ATOM_FULL(BOX_stsd, 0);
1433 WRITE_4(1); // entry_count;
1434
1435 if (tr->info.track_media_kind == e_audio || tr->info.track_media_kind == e_private) {
1436 // AudioSampleEntry() assume MP4E_HANDLER_TYPE_SOUN
1437 if (tr->info.track_media_kind == e_audio) {
1438 ATOM(BOX_mp4a);
1439 } else {
1440 ATOM(BOX_mp4s);
1441 }
1442
1443 // SampleEntry
1444 WRITE_4(0);
1445 WRITE_2(0); // reserved[6]
1446 WRITE_2(1); // data_reference_index; - this is a tag for descriptor below
1447
1448 if (tr->info.track_media_kind == e_audio) {
1449 // AudioSampleEntry
1450 WRITE_4(0);
1451 WRITE_4(0); // reserved[2]
1452 WRITE_2(tr->info.u.a.channelcount); // channelcount
1453 WRITE_2(16); // samplesize
1454 WRITE_4(0); // pre_defined+reserved
1455 WRITE_4((tr->info.time_scale << 16)); // samplerate == = {timescale of media}<<16;
1456 }
1457
1458 ATOM_FULL(BOX_esds, 0);
1459 if (tr->vsps.bytes > 0) {
1460 int dsi_bytes = tr->vsps.bytes - 2; // - two bytes size field
1461 int dsi_size_size = od_size_of_size(dsi_bytes);
1462 int dcd_bytes = dsi_bytes + dsi_size_size + 1 + (1 + 1 + 3 + 4 + 4);
1463 int dcd_size_size = od_size_of_size(dcd_bytes);
1464 int esd_bytes = dcd_bytes + dcd_size_size + 1 + 3;
1465
1466#define WRITE_OD_LEN(size) \
1467 if (size > 0x7F) \
1468 do { \
1469 size -= 0x7F; \
1470 WRITE_1(0x00ff); \
1471 } while (size > 0x7F); \
1472 WRITE_1(size)
1473 WRITE_1(3); // OD_ESD
1474 WRITE_OD_LEN(esd_bytes);
1475 WRITE_2(0); // ES_ID(2) // TODO - what is this?
1476 WRITE_1(0); // flags(1)
1477
1478 WRITE_1(4); // OD_DCD
1479 WRITE_OD_LEN(dcd_bytes);
1480 if (tr->info.track_media_kind == e_audio) {
1481 WRITE_1(MP4_OBJECT_TYPE_AUDIO_ISO_IEC_14496_3); // OD_DCD
1482 WRITE_1(5 << 2); // stream_type == AudioStream
1483 } else {
1484 // http://xhelmboyx.tripod.com/formats/mp4-layout.txt
1485 WRITE_1(208); // 208 = private video
1486 WRITE_1(32 << 2); // stream_type == user private
1487 }
1488 WRITE_3(tr->info.u.a.channelcount * 6144 /
1489 8); // bufferSizeDB in bytes, constant as in reference decoder
1490 WRITE_4(0); // maxBitrate TODO
1491 WRITE_4(0); // avg_bitrate_bps TODO
1492
1493 WRITE_1(5); // OD_DSI
1494 WRITE_OD_LEN(dsi_bytes);
1495 for (i = 0; i < dsi_bytes; i++) {
1496 WRITE_1(tr->vsps.data[2 + i]);
1497 }
1498 }
1499 END_ATOM;
1500 END_ATOM;
1501 }
1502
1503 if (tr->info.track_media_kind == e_video &&
1504 (MP4_OBJECT_TYPE_AVC == tr->info.object_type_indication ||
1505 MP4_OBJECT_TYPE_HEVC == tr->info.object_type_indication)) {
1506 int numOfSequenceParameterSets = items_count(&tr->vsps);
1507 int numOfPictureParameterSets = items_count(&tr->vpps);
1508 if (MP4_OBJECT_TYPE_AVC == tr->info.object_type_indication) {
1509 ATOM(BOX_avc1);
1510 } else {
1511 ATOM(BOX_hvc1);
1512 }
1513 // VisualSampleEntry 8.16.2
1514 // extends SampleEntry
1515 WRITE_2(0); // reserved
1516 WRITE_2(0); // reserved
1517 WRITE_2(0); // reserved
1518 WRITE_2(1); // data_reference_index
1519
1520 WRITE_2(0); // pre_defined
1521 WRITE_2(0); // reserved
1522 WRITE_4(0); // pre_defined
1523 WRITE_4(0); // pre_defined
1524 WRITE_4(0); // pre_defined
1525 WRITE_2(tr->info.u.v.width);
1526 WRITE_2(tr->info.u.v.height);
1527 WRITE_4(0x00480000); // horizresolution = 72 dpi
1528 WRITE_4(0x00480000); // vertresolution = 72 dpi
1529 WRITE_4(0); // reserved
1530 WRITE_2(1); // frame_count
1531 for (i = 0; i < 32; i++) {
1532 WRITE_1(0); // compressorname
1533 }
1534 WRITE_2(24); // depth
1535 WRITE_2(-1); // pre_defined
1536
1537 if (MP4_OBJECT_TYPE_AVC == tr->info.object_type_indication) {
1538 ATOM(BOX_avcC);
1539 // AVCDecoderConfigurationRecord 5.2.4.1.1
1540 WRITE_1(1); // configurationVersion
1541 WRITE_1(tr->vsps.data[2 + 1]);
1542 WRITE_1(tr->vsps.data[2 + 2]);
1543 WRITE_1(tr->vsps.data[2 + 3]);
1544 WRITE_1(255); // 0xfc + NALU_len - 1
1545 WRITE_1(0xe0 | numOfSequenceParameterSets);
1546 for (i = 0; i < tr->vsps.bytes; i++) {
1547 WRITE_1(tr->vsps.data[i]);
1548 }
1549 WRITE_1(numOfPictureParameterSets);
1550 for (i = 0; i < tr->vpps.bytes; i++) {
1551 WRITE_1(tr->vpps.data[i]);
1552 }
1553 } else {
1554 int numOfVPS = items_count(&tr->vpps);
1555 ATOM(BOX_hvcC);
1556 // TODO: read actual params from stream
1557 WRITE_1(1); // configurationVersion
1558 WRITE_1(1); // Profile Space (2), Tier (1), Profile (5)
1559 WRITE_4(0x60000000); // Profile Compatibility
1560 WRITE_2(
1561 0); // progressive, interlaced, non packed constraint, frame only constraint flags
1562 WRITE_4(0); // constraint indicator flags
1563 WRITE_1(0); // level_idc
1564 WRITE_2(0xf000); // Min Spatial Segmentation
1565 WRITE_1(0xfc); // Parallelism Type
1566 WRITE_1(0xfc); // Chroma Format
1567 WRITE_1(0xf8); // Luma Depth
1568 WRITE_1(0xf8); // Chroma Depth
1569 WRITE_2(0); // Avg Frame Rate
1570 WRITE_1(
1571 3); // ConstantFrameRate (2), NumTemporalLayers (3), TemporalIdNested (1), LengthSizeMinusOne (2)
1572
1573 WRITE_1(3); // Num Of Arrays
1574 WRITE_1((1 << 7) | (HEVC_NAL_VPS & 0x3f)); // Array Completeness + NAL Unit Type
1575 WRITE_2(numOfVPS);
1576 for (i = 0; i < tr->vvps.bytes; i++) {
1577 WRITE_1(tr->vvps.data[i]);
1578 }
1579 WRITE_1((1 << 7) | (HEVC_NAL_SPS & 0x3f));
1580 WRITE_2(numOfSequenceParameterSets);
1581 for (i = 0; i < tr->vsps.bytes; i++) {
1582 WRITE_1(tr->vsps.data[i]);
1583 }
1584 WRITE_1((1 << 7) | (HEVC_NAL_PPS & 0x3f));
1585 WRITE_2(numOfPictureParameterSets);
1586 for (i = 0; i < tr->vpps.bytes; i++) {
1587 WRITE_1(tr->vpps.data[i]);
1588 }
1589 }
1590
1591 END_ATOM;
1592 END_ATOM;
1593 }
1594 END_ATOM;
1595
1596 /************************************************************************/
1597 /* indexes */
1598 /************************************************************************/
1599
1600 // Time to Sample Box
1601 ATOM_FULL(BOX_stts, 0);
1602 {
1603 unsigned char* pentry_count = p;
1604 int cnt = 1, entry_count = 0;
1605 WRITE_4(0);
1606 for (i = 0; i < samples_count; i++, cnt++) {
1607 if (i == (samples_count - 1) || sample[i].duration != sample[i + 1].duration) {
1608 WRITE_4(cnt);
1609 WRITE_4(sample[i].duration);
1610 cnt = 0;
1611 entry_count++;
1612 }
1613 }
1614 WR4(pentry_count, entry_count);
1615 }
1616 END_ATOM;
1617
1618 // Sample To Chunk Box
1619 ATOM_FULL(BOX_stsc, 0);
1620 if (mux->enable_fragmentation) {
1621 WRITE_4(0); // entry_count
1622 } else {
1623 WRITE_4(1); // entry_count
1624 WRITE_4(1); // first_chunk;
1625 WRITE_4(1); // samples_per_chunk;
1626 WRITE_4(1); // sample_description_index;
1627 }
1628 END_ATOM;
1629
1630 // Sample Size Box
1631 ATOM_FULL(BOX_stsz, 0);
1632 WRITE_4(
1633 0); // sample_size If this field is set to 0, then the samples have different sizes, and those sizes
1634 // are stored in the sample size table.
1635 WRITE_4(samples_count); // sample_count;
1636 for (i = 0; i < samples_count; i++) {
1637 WRITE_4(sample[i].size);
1638 }
1639 END_ATOM;
1640
1641 // Chunk Offset Box
1642 int is_64_bit = 0;
1643 if (samples_count && sample[samples_count - 1].offset > 0xffffffff)
1644 is_64_bit = 1;
1645 if (!is_64_bit) {
1646 ATOM_FULL(BOX_stco, 0);
1647 WRITE_4(samples_count);
1648 for (i = 0; i < samples_count; i++) {
1649 WRITE_4(sample[i].offset);
1650 }
1651 } else {
1652 ATOM_FULL(BOX_co64, 0);
1653 WRITE_4(samples_count);
1654 for (i = 0; i < samples_count; i++) {
1655 WRITE_4((sample[i].offset >> 32) & 0xffffffff);
1656 WRITE_4(sample[i].offset & 0xffffffff);
1657 }
1658 }
1659 END_ATOM;
1660
1661 // Sync Sample Box
1662 {
1663 int ra_count = 0;
1664 for (i = 0; i < samples_count; i++) {
1665 ra_count += !!sample[i].flag_random_access;
1666 }
1667 if (ra_count != samples_count) {
1668 // If the sync sample box is not present, every sample is a random access point.
1669 ATOM_FULL(BOX_stss, 0);
1670 WRITE_4(ra_count);
1671 for (i = 0; i < samples_count; i++) {
1672 if (sample[i].flag_random_access) {
1673 WRITE_4(i + 1);
1674 }
1675 }
1676 END_ATOM;
1677 }
1678 }
1679 END_ATOM;
1680 END_ATOM;
1681 END_ATOM;
1682 END_ATOM;
1683 } // tracks loop
1684
1685 if (mux->text_comment) {
1686 ATOM(BOX_udta);
1687 ATOM_FULL(BOX_meta, 0);
1688 ATOM_FULL(BOX_hdlr, 0);
1689 WRITE_4(0); // pre_defined
1690#define MP4E_HANDLER_TYPE_MDIR 0x6d646972
1691 WRITE_4(MP4E_HANDLER_TYPE_MDIR); // handler_type
1692 WRITE_4(0);
1693 WRITE_4(0);
1694 WRITE_4(0); // reserved[3]
1695 WRITE_4(
1696 0); // name is a null-terminated string in UTF-8 characters which gives a human-readable name for the track type (for debugging and inspection purposes).
1697 END_ATOM;
1698 ATOM(BOX_ilst);
1699 ATOM(BOX_ccmt);
1700 ATOM(BOX_data);
1701 WRITE_4(1); // type
1702 WRITE_4(0); // lang
1703 for (i = 0; i < (int)strlen(mux->text_comment) + 1; i++) {
1704 WRITE_1(mux->text_comment[i]);
1705 }
1706 END_ATOM;
1707 END_ATOM;
1708 END_ATOM;
1709 END_ATOM;
1710 END_ATOM;
1711 }
1712
1713 if (mux->enable_fragmentation) {
1714 track_t* tr = ((track_t*)mux->tracks.data) + 0;
1715 uint32_t movie_duration = get_duration(tr);
1716
1717 ATOM(BOX_mvex);
1718 ATOM_FULL(BOX_mehd, 0);
1719 WRITE_4(movie_duration); // duration
1720 END_ATOM;
1721 for (ntr = 0; ntr < ntracks; ntr++) {
1722 ATOM_FULL(BOX_trex, 0);
1723 WRITE_4(ntr + 1); // track_ID
1724 WRITE_4(1); // default_sample_description_index
1725 WRITE_4(0); // default_sample_duration
1726 WRITE_4(0); // default_sample_size
1727 WRITE_4(0); // default_sample_flags
1728 END_ATOM;
1729 }
1730 END_ATOM;
1731 }
1732 END_ATOM; // moov atom
1733
1734 assert((unsigned)(p - base) <= index_bytes);
1735
1736 err = mux->write_callback(mux->write_pos, base, p - base, mux->token);
1737 mux->write_pos += p - base;
1738 free(base);
1739 return err;
1740}
1741
1742int MP4E_close(MP4E_mux_t* mux) {
1743 int err = MP4E_STATUS_OK;
1744 unsigned ntr, ntracks;
1745 if (!mux)
1747 if (!mux->enable_fragmentation)
1748 err = mp4e_flush_index(mux);
1749 if (mux->text_comment)
1750 free(mux->text_comment);
1751 ntracks = mux->tracks.bytes / sizeof(track_t);
1752 for (ntr = 0; ntr < ntracks; ntr++) {
1753 track_t* tr = ((track_t*)mux->tracks.data) + ntr;
1754 minimp4_vector_reset(&tr->vsps);
1755 minimp4_vector_reset(&tr->vpps);
1756 minimp4_vector_reset(&tr->smpl);
1757 minimp4_vector_reset(&tr->pending_sample);
1758 }
1759 minimp4_vector_reset(&mux->tracks);
1760 free(mux);
1761 return err;
1762}
1763
1764typedef uint32_t bs_item_t;
1765#define BS_BITS 32
1766
1767typedef struct {
1768 // Look-ahead bit cache: MSB aligned, 17 bits guaranteed, zero stuffing
1769 unsigned int cache;
1770
1771 // Bit counter = 16 - (number of bits in wCache)
1772 // cache refilled when cache_free_bits >= 0
1773 int cache_free_bits;
1774
1775 // Current read position
1776 const uint16_t* buf;
1777
1778 // original data buffer
1779 const uint16_t* origin;
1780
1781 // original data buffer length, bytes
1782 unsigned origin_bytes;
1783} bit_reader_t;
1784
1785#define LOAD_SHORT(x) ((uint16_t)(x << 8) | (x >> 8))
1786
1787static unsigned int show_bits(bit_reader_t* bs, int n) {
1788 unsigned int retval;
1789 assert(n > 0 && n <= 16);
1790 retval = (unsigned int)(bs->cache >> (32 - n));
1791 return retval;
1792}
1793
1794static void flush_bits(bit_reader_t* bs, int n) {
1795 assert(n >= 0 && n <= 16);
1796 bs->cache <<= n;
1797 bs->cache_free_bits += n;
1798 if (bs->cache_free_bits >= 0) {
1799 bs->cache |= ((uint32_t)LOAD_SHORT(*bs->buf)) << bs->cache_free_bits;
1800 bs->buf++;
1801 bs->cache_free_bits -= 16;
1802 }
1803}
1804
1805static unsigned int get_bits(bit_reader_t* bs, int n) {
1806 unsigned int retval = show_bits(bs, n);
1807 flush_bits(bs, n);
1808 return retval;
1809}
1810
1811static void set_pos_bits(bit_reader_t* bs, unsigned pos_bits) {
1812 assert((int)pos_bits >= 0);
1813
1814 bs->buf = bs->origin + pos_bits / 16;
1815 bs->cache = 0;
1816 bs->cache_free_bits = 16;
1817 flush_bits(bs, 0);
1818 flush_bits(bs, pos_bits & 15);
1819}
1820
1821static unsigned get_pos_bits(const bit_reader_t* bs) {
1822 // Current bitbuffer position =
1823 // position of next wobits in the internal buffer
1824 // minus bs, available in bit cache wobits
1825 unsigned pos_bits = (unsigned)(bs->buf - bs->origin) * 16;
1826 pos_bits -= 16 - bs->cache_free_bits;
1827 assert((int)pos_bits >= 0);
1828 return pos_bits;
1829}
1830
1831static int remaining_bits(const bit_reader_t* bs) {
1832 return bs->origin_bytes * 8 - get_pos_bits(bs);
1833}
1834
1835static void init_bits(bit_reader_t* bs, const void* data, unsigned data_bytes) {
1836 bs->origin = (const uint16_t*)data;
1837 bs->origin_bytes = data_bytes;
1838 set_pos_bits(bs, 0);
1839}
1840
1841#define GetBits(n) get_bits(bs, n)
1842
1846static int ue_bits(bit_reader_t* bs) {
1847 int clz;
1848 int val;
1849 for (clz = 0; !get_bits(bs, 1); clz++) {}
1850 //get_bits(bs, clz + 1);
1851 val = (1 << clz) - 1 + (clz ? get_bits(bs, clz) : 0);
1852 return val;
1853}
1854
1855#if MINIMP4_TRANSCODE_SPS_ID
1856
1860typedef struct {
1861 int shift; // bit position in the cache
1862 uint32_t cache; // bit cache
1863 bs_item_t* buf; // current position
1864 bs_item_t* origin; // initial position
1865} bs_t;
1866
1867#define SWAP32(x) \
1868 (uint32_t)((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) << 8) & 0xFF0000) | \
1869 ((x & 0xFF) << 24))
1870
1871static void h264e_bs_put_bits(bs_t* bs, unsigned n, unsigned val) {
1872 assert(!(val >> n));
1873 bs->shift -= n;
1874 assert((unsigned)n <= 32);
1875 if (bs->shift < 0) {
1876 assert(-bs->shift < 32);
1877 bs->cache |= val >> -bs->shift;
1878 *bs->buf++ = SWAP32(bs->cache);
1879 bs->shift = 32 + bs->shift;
1880 bs->cache = 0;
1881 }
1882 bs->cache |= val << bs->shift;
1883}
1884
1885static void h264e_bs_flush(bs_t* bs) {
1886 *bs->buf = SWAP32(bs->cache);
1887}
1888
1889static unsigned h264e_bs_get_pos_bits(const bs_t* bs) {
1890 unsigned pos_bits = (unsigned)((bs->buf - bs->origin) * BS_BITS);
1891 pos_bits += BS_BITS - bs->shift;
1892 assert((int)pos_bits >= 0);
1893 return pos_bits;
1894}
1895
1896static unsigned h264e_bs_byte_align(bs_t* bs) {
1897 int pos = h264e_bs_get_pos_bits(bs);
1898 h264e_bs_put_bits(bs, -pos & 7, 0);
1899 return pos + (-pos & 7);
1900}
1901
1916static void h264e_bs_put_golomb(bs_t* bs, unsigned val) {
1917 int size = 0;
1918 unsigned t = val + 1;
1919 do {
1920 size++;
1921 } while (t >>= 1);
1922
1923 h264e_bs_put_bits(bs, 2 * size - 1, val + 1);
1924}
1925
1926static void h264e_bs_init_bits(bs_t* bs, void* data) {
1927 bs->origin = (bs_item_t*)data;
1928 bs->buf = bs->origin;
1929 bs->shift = BS_BITS;
1930 bs->cache = 0;
1931}
1932
1933static int find_mem_cache(void* cache[], int cache_bytes[], int cache_size, void* mem, int bytes) {
1934 int i;
1935 if (!bytes)
1936 return -1;
1937 for (i = 0; i < cache_size; i++) {
1938 if (cache_bytes[i] == bytes && !memcmp(mem, cache[i], bytes))
1939 return i; // found
1940 }
1941 for (i = 0; i < cache_size; i++) {
1942 if (!cache_bytes[i]) {
1943 cache[i] = malloc(bytes);
1944 if (cache[i]) {
1945 memcpy(cache[i], mem, bytes);
1946 cache_bytes[i] = bytes;
1947 }
1948 return i; // put in
1949 }
1950 }
1951 return -1; // no room
1952}
1953
1957static int remove_nal_escapes(unsigned char* dst, const unsigned char* src, int h264_data_bytes) {
1958 int i = 0, j = 0, zero_cnt = 0;
1959 for (j = 0; j < h264_data_bytes; j++) {
1960 if (zero_cnt == 2 && src[j] <= 3) {
1961 if (src[j] == 3) {
1962 if (j == h264_data_bytes - 1) {
1963 // cabac_zero_word: no action
1964 } else if (src[j + 1] <= 3) {
1965 j++;
1966 zero_cnt = 0;
1967 } else {
1968 // TODO: assume end-of-nal
1969 //return 0;
1970 }
1971 } else
1972 return 0;
1973 }
1974 dst[i++] = src[j];
1975 if (src[j])
1976 zero_cnt = 0;
1977 else
1978 zero_cnt++;
1979 }
1980 //while (--j > i) src[j] = 0;
1981 return i;
1982}
1983
1987static int nal_put_esc(uint8_t* d, const uint8_t* s, int n) {
1988 int i, j = 4, cntz = 0;
1989 d[0] = d[1] = d[2] = 0;
1990 d[3] = 1; // start code
1991 for (i = 0; i < n; i++) {
1992 uint8_t byte = *s++;
1993 if (cntz == 2 && byte <= 3) {
1994 d[j++] = 3;
1995 cntz = 0;
1996 }
1997 if (byte)
1998 cntz = 0;
1999 else
2000 cntz++;
2001 d[j++] = byte;
2002 }
2003 return j;
2004}
2005
2006static void copy_bits(bit_reader_t* bs, bs_t* bd) {
2007 unsigned cb, bits;
2008 int bit_count = remaining_bits(bs);
2009 while (bit_count > 7) {
2010 cb = MINIMP4_MIN(bit_count - 7, 8);
2011 bits = GetBits(cb);
2012 h264e_bs_put_bits(bd, cb, bits);
2013 bit_count -= cb;
2014 }
2015
2016 // cut extra zeros after stop-bit
2017 bits = GetBits(bit_count);
2018 for (; bit_count && ~bits & 1; bit_count--) {
2019 bits >>= 1;
2020 }
2021 if (bit_count) {
2022 h264e_bs_put_bits(bd, bit_count, bits);
2023 }
2024}
2025
2026static int change_sps_id(bit_reader_t* bs, bs_t* bd, int new_id, int* old_id) {
2027 unsigned bits, sps_id, i, bytes;
2028 for (i = 0; i < 3; i++) {
2029 bits = GetBits(8);
2030 h264e_bs_put_bits(bd, 8, bits);
2031 }
2032 sps_id = ue_bits(bs); // max = 31
2033
2034 *old_id = sps_id;
2035 sps_id = new_id;
2036 assert(sps_id <= 31);
2037
2038 h264e_bs_put_golomb(bd, sps_id);
2039 copy_bits(bs, bd);
2040
2041 bytes = h264e_bs_byte_align(bd) / 8;
2042 h264e_bs_flush(bd);
2043 return bytes;
2044}
2045
2046static int
2047patch_pps(h264_sps_id_patcher_t* h, bit_reader_t* bs, bs_t* bd, int new_pps_id, int* old_id) {
2048 int bytes;
2049 unsigned pps_id = ue_bits(bs); // max = 255
2050 unsigned sps_id = ue_bits(bs); // max = 31
2051
2052 *old_id = pps_id;
2053 sps_id = h->map_sps[sps_id];
2054 pps_id = new_pps_id;
2055
2056 assert(sps_id <= 31);
2057 assert(pps_id <= 255);
2058
2059 h264e_bs_put_golomb(bd, pps_id);
2060 h264e_bs_put_golomb(bd, sps_id);
2061 copy_bits(bs, bd);
2062
2063 bytes = h264e_bs_byte_align(bd) / 8;
2064 h264e_bs_flush(bd);
2065 return bytes;
2066}
2067
2068static void patch_slice_header(h264_sps_id_patcher_t* h, bit_reader_t* bs, bs_t* bd) {
2069 unsigned first_mb_in_slice = ue_bits(bs);
2070 unsigned slice_type = ue_bits(bs);
2071 unsigned pps_id = ue_bits(bs);
2072
2073 pps_id = h->map_pps[pps_id];
2074
2075 assert(pps_id <= 255);
2076
2077 h264e_bs_put_golomb(bd, first_mb_in_slice);
2078 h264e_bs_put_golomb(bd, slice_type);
2079 h264e_bs_put_golomb(bd, pps_id);
2080 copy_bits(bs, bd);
2081}
2082
2083static int transcode_nalu(h264_sps_id_patcher_t* h,
2084 const unsigned char* src,
2085 int nalu_bytes,
2086 unsigned char* dst) {
2087 int old_id;
2088
2089 bit_reader_t bst[1];
2090 bs_t bdt[1];
2091
2092 bit_reader_t bs[1];
2093 bs_t bd[1];
2094 int payload_type = src[0] & 31;
2095
2096 *dst = *src;
2097 h264e_bs_init_bits(bd, dst + 1);
2098 init_bits(bs, src + 1, nalu_bytes - 1);
2099 h264e_bs_init_bits(bdt, dst + 1);
2100 init_bits(bst, src + 1, nalu_bytes - 1);
2101
2102 switch (payload_type) {
2103 case 7: {
2104 int cb = change_sps_id(bst, bdt, 0, &old_id);
2105 int id = find_mem_cache(h->sps_cache, h->sps_bytes, MINIMP4_MAX_SPS, dst + 1, cb);
2106 if (id == -1)
2107 return 0;
2108 h->map_sps[old_id] = id;
2109 change_sps_id(bs, bd, id, &old_id);
2110 } break;
2111 case 8: {
2112 int cb = patch_pps(h, bst, bdt, 0, &old_id);
2113 int id = find_mem_cache(h->pps_cache, h->pps_bytes, MINIMP4_MAX_PPS, dst + 1, cb);
2114 if (id == -1)
2115 return 0;
2116 h->map_pps[old_id] = id;
2117 patch_pps(h, bs, bd, id, &old_id);
2118 } break;
2119 case 1:
2120 case 2:
2121 case 5:
2122 patch_slice_header(h, bs, bd);
2123 break;
2124 default:
2125 memcpy(dst, (void*)src, nalu_bytes);
2126 return nalu_bytes;
2127 }
2128
2129 nalu_bytes = 1 + h264e_bs_byte_align(bd) / 8;
2130 h264e_bs_flush(bd);
2131
2132 return nalu_bytes;
2133}
2134
2135#endif
2136
2145static const uint8_t* find_start_code(const uint8_t* h264_data, int h264_data_bytes, int* zcount) {
2146 const uint8_t* eof = h264_data + h264_data_bytes;
2147 const uint8_t* p = h264_data;
2148 do {
2149 int zero_cnt = 1;
2150 const uint8_t* found = (uint8_t*)memchr(p, 0, eof - p);
2151 p = found ? found : eof;
2152 while (p + zero_cnt < eof && !p[zero_cnt])
2153 zero_cnt++;
2154 if (zero_cnt >= 2 && p[zero_cnt] == 1) {
2155 *zcount = zero_cnt + 1;
2156 return p + zero_cnt + 1;
2157 }
2158 p += zero_cnt;
2159 } while (p < eof);
2160 *zcount = 0;
2161 return eof;
2162}
2163
2167static const uint8_t*
2168find_nal_unit(const uint8_t* h264_data, int h264_data_bytes, int* pnal_unit_bytes) {
2169 const uint8_t* eof = h264_data + h264_data_bytes;
2170 int zcount;
2171 const uint8_t* start = find_start_code(h264_data, h264_data_bytes, &zcount);
2172 const uint8_t* stop = start;
2173 if (start) {
2174 stop = find_start_code(start, (int)(eof - start), &zcount);
2175 while (stop > start && !stop[-1]) {
2176 stop--;
2177 }
2178 }
2179
2180 *pnal_unit_bytes = (int)(stop - start - zcount);
2181 return start;
2182}
2183
2184int mp4_h26x_write_init(mp4_h26x_writer_t* h, MP4E_mux_t* mux, int width, int height, int is_hevc) {
2185 MP4E_track_t tr;
2187 tr.language[0] = 'u';
2188 tr.language[1] = 'n';
2189 tr.language[2] = 'd';
2190 tr.language[3] = 0;
2192 tr.time_scale = 90000;
2193 tr.default_duration = 0;
2194 tr.u.v.width = width;
2195 tr.u.v.height = height;
2196 h->mux_track_id = MP4E_add_track(mux, &tr);
2197 h->mux = mux;
2198
2199 h->is_hevc = is_hevc;
2200 h->need_vps = is_hevc;
2201 h->need_sps = 1;
2202 h->need_pps = 1;
2203 h->need_idr = 1;
2204#if MINIMP4_TRANSCODE_SPS_ID
2205 memset(&h->sps_patcher, 0, sizeof(h264_sps_id_patcher_t));
2206#endif
2207 return MP4E_STATUS_OK;
2208}
2209
2211#if MINIMP4_TRANSCODE_SPS_ID
2212 h264_sps_id_patcher_t* p = &h->sps_patcher;
2213 int i;
2214 for (i = 0; i < MINIMP4_MAX_SPS; i++) {
2215 if (p->sps_cache[i])
2216 free(p->sps_cache[i]);
2217 }
2218 for (i = 0; i < MINIMP4_MAX_PPS; i++) {
2219 if (p->pps_cache[i])
2220 free(p->pps_cache[i]);
2221 }
2222#endif
2223 memset(h, 0, sizeof(*h));
2224}
2225
2226static int mp4_h265_write_nal(mp4_h26x_writer_t* h,
2227 const unsigned char* nal,
2228 int sizeof_nal,
2229 unsigned timeStamp90kHz_next) {
2230 int payload_type = (nal[0] >> 1) & 0x3f;
2231 int is_intra = payload_type >= HEVC_NAL_BLA_W_LP && payload_type <= HEVC_NAL_CRA_NUT;
2232 int err = MP4E_STATUS_OK;
2233 //printf("payload_type=%d, intra=%d\n", payload_type, is_intra);
2234
2235 if (is_intra && !h->need_sps && !h->need_pps && !h->need_vps)
2236 h->need_idr = 0;
2237 switch (payload_type) {
2238 case HEVC_NAL_VPS:
2239 MP4E_set_vps(h->mux, h->mux_track_id, nal, sizeof_nal);
2240 h->need_vps = 0;
2241 break;
2242 case HEVC_NAL_SPS:
2243 MP4E_set_sps(h->mux, h->mux_track_id, nal, sizeof_nal);
2244 h->need_sps = 0;
2245 break;
2246 case HEVC_NAL_PPS:
2247 MP4E_set_pps(h->mux, h->mux_track_id, nal, sizeof_nal);
2248 h->need_pps = 0;
2249 break;
2250 default:
2251 if (h->need_vps || h->need_sps || h->need_pps || h->need_idr)
2253 {
2254 unsigned char* tmp = (unsigned char*)malloc(4 + sizeof_nal);
2255 if (!tmp)
2256 return MP4E_STATUS_NO_MEMORY;
2257 int sample_kind = MP4E_SAMPLE_DEFAULT;
2258 tmp[0] = (unsigned char)(sizeof_nal >> 24);
2259 tmp[1] = (unsigned char)(sizeof_nal >> 16);
2260 tmp[2] = (unsigned char)(sizeof_nal >> 8);
2261 tmp[3] = (unsigned char)(sizeof_nal);
2262 memcpy(tmp + 4, (void*)nal, sizeof_nal);
2263 if (is_intra)
2264 sample_kind = MP4E_SAMPLE_RANDOM_ACCESS;
2265 err = MP4E_put_sample(
2266 h->mux, h->mux_track_id, tmp, 4 + sizeof_nal, timeStamp90kHz_next, sample_kind);
2267 free(tmp);
2268 }
2269 break;
2270 }
2271 return err;
2272}
2273
2275 const unsigned char* nal,
2276 int length,
2277 unsigned timeStamp90kHz_next) {
2278 const unsigned char* eof = nal + length;
2279 int payload_type, sizeof_nal, err = MP4E_STATUS_OK;
2280 for (;; nal++) {
2281#if MINIMP4_TRANSCODE_SPS_ID
2282 unsigned char *nal1, *nal2;
2283#endif
2284 nal = find_nal_unit(nal, (int)(eof - nal), &sizeof_nal);
2285 if (!sizeof_nal)
2286 break;
2287 if (h->is_hevc) {
2288 ERR(mp4_h265_write_nal(h, nal, sizeof_nal, timeStamp90kHz_next));
2289 continue;
2290 }
2291 payload_type = nal[0] & 31;
2292 if (9 == payload_type)
2293 continue; // access unit delimiter, nothing to be done
2294#if MINIMP4_TRANSCODE_SPS_ID
2295 // Transcode SPS, PPS and slice headers, reassigning ID's for SPS and PPS:
2296 // - assign unique ID's to different SPS and PPS
2297 // - assign same ID's to equal (except ID) SPS and PPS
2298 // - save all different SPS and PPS
2299 nal1 = (unsigned char*)malloc(sizeof_nal * 17 / 16 + 32);
2300 if (!nal1)
2301 return MP4E_STATUS_NO_MEMORY;
2302 nal2 = (unsigned char*)malloc(sizeof_nal * 17 / 16 + 32);
2303 if (!nal2) {
2304 free(nal1);
2305 return MP4E_STATUS_NO_MEMORY;
2306 }
2307 sizeof_nal = remove_nal_escapes(nal2, nal, sizeof_nal);
2308 if (!sizeof_nal) {
2309 exit_with_free:
2310 free(nal1);
2311 free(nal2);
2313 }
2314
2315 sizeof_nal = transcode_nalu(&h->sps_patcher, nal2, sizeof_nal, nal1);
2316 sizeof_nal = nal_put_esc(nal2, nal1, sizeof_nal);
2317
2318 switch (payload_type) {
2319 case 7:
2320 MP4E_set_sps(h->mux, h->mux_track_id, nal2 + 4, sizeof_nal - 4);
2321 h->need_sps = 0;
2322 break;
2323 case 8:
2324 if (h->need_sps)
2325 goto exit_with_free;
2326 MP4E_set_pps(h->mux, h->mux_track_id, nal2 + 4, sizeof_nal - 4);
2327 h->need_pps = 0;
2328 break;
2329 case 5:
2330 if (h->need_sps)
2331 goto exit_with_free;
2332 h->need_idr = 0;
2333 // flow through
2334 default:
2335 if (h->need_sps)
2336 goto exit_with_free;
2337 if (!h->need_pps && !h->need_idr) {
2338 bit_reader_t bs[1];
2339 init_bits(bs, nal + 1, sizeof_nal - 4 - 1);
2340 unsigned first_mb_in_slice = ue_bits(bs);
2341 //unsigned slice_type = ue_bits(bs);
2342 int sample_kind = MP4E_SAMPLE_DEFAULT;
2343 nal2[0] = (unsigned char)((sizeof_nal - 4) >> 24);
2344 nal2[1] = (unsigned char)((sizeof_nal - 4) >> 16);
2345 nal2[2] = (unsigned char)((sizeof_nal - 4) >> 8);
2346 nal2[3] = (unsigned char)((sizeof_nal - 4));
2347 if (first_mb_in_slice)
2348 sample_kind = MP4E_SAMPLE_CONTINUATION;
2349 else if (payload_type == 5)
2350 sample_kind = MP4E_SAMPLE_RANDOM_ACCESS;
2351 err = MP4E_put_sample(
2352 h->mux, h->mux_track_id, nal2, sizeof_nal, timeStamp90kHz_next, sample_kind);
2353 }
2354 break;
2355 }
2356 free(nal1);
2357 free(nal2);
2358#else
2359 // No SPS/PPS transcoding
2360 // This branch assumes that encoder use correct SPS/PPS ID's
2361 switch (payload_type) {
2362 case 7:
2363 MP4E_set_sps(h->mux, h->mux_track_id, nal, sizeof_nal);
2364 h->need_sps = 0;
2365 break;
2366 case 8:
2367 MP4E_set_pps(h->mux, h->mux_track_id, nal, sizeof_nal);
2368 h->need_pps = 0;
2369 break;
2370 case 5:
2371 if (h->need_sps)
2373 h->need_idr = 0;
2374 // flow through
2375 default:
2376 if (h->need_sps)
2378 if (!h->need_pps && !h->need_idr) {
2379 bit_reader_t bs[1];
2380 unsigned char* tmp = (unsigned char*)malloc(4 + sizeof_nal);
2381 if (!tmp)
2382 return MP4E_STATUS_NO_MEMORY;
2383 init_bits(bs, nal + 1, sizeof_nal - 1);
2384 unsigned first_mb_in_slice = ue_bits(bs);
2385 int sample_kind = MP4E_SAMPLE_DEFAULT;
2386 tmp[0] = (unsigned char)(sizeof_nal >> 24);
2387 tmp[1] = (unsigned char)(sizeof_nal >> 16);
2388 tmp[2] = (unsigned char)(sizeof_nal >> 8);
2389 tmp[3] = (unsigned char)(sizeof_nal);
2390 memcpy(tmp + 4, nal, sizeof_nal);
2391 if (first_mb_in_slice)
2392 sample_kind = MP4E_SAMPLE_CONTINUATION;
2393 else if (payload_type == 5)
2394 sample_kind = MP4E_SAMPLE_RANDOM_ACCESS;
2395 err = MP4E_put_sample(
2396 h->mux, h->mux_track_id, tmp, 4 + sizeof_nal, timeStamp90kHz_next, sample_kind);
2397 free(tmp);
2398 }
2399 break;
2400 }
2401#endif
2402 if (err)
2403 break;
2404 }
2405 return err;
2406}
2407
2408#if MP4D_TRACE_SUPPORTED
2409#define TRACE(x) printf x
2410#else
2411#define TRACE(x)
2412#endif
2413
2414#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
2415
2416static int minimp4_fgets(MP4D_demux_t* mp4) {
2417 uint8_t c;
2418 if (mp4->read_callback(mp4->read_pos, &c, 1, mp4->token))
2419 return -1;
2420 mp4->read_pos++;
2421 return c;
2422}
2423
2428static unsigned minimp4_read(MP4D_demux_t* mp4, int nb, int* eof_flag) {
2429 uint32_t v = 0;
2430 int last_byte;
2431 switch (nb) {
2432 case 4:
2433 v = (v << 8) | minimp4_fgets(mp4);
2434 case 3:
2435 v = (v << 8) | minimp4_fgets(mp4);
2436 case 2:
2437 v = (v << 8) | minimp4_fgets(mp4);
2438 default:
2439 case 1:
2440 v = (v << 8) | (last_byte = minimp4_fgets(mp4));
2441 }
2442 if (last_byte < 0) {
2443 *eof_flag = 1;
2444 }
2445 return v;
2446}
2447
2452static uint32_t
2453read_payload(MP4D_demux_t* mp4, unsigned nb, boxsize_t* payload_bytes, int* eof_flag) {
2454 if (*payload_bytes < nb) {
2455 *eof_flag = 1;
2456 nb = (int)*payload_bytes;
2457 }
2458 *payload_bytes -= nb;
2459
2460 return minimp4_read(mp4, nb, eof_flag);
2461}
2462
2467static void my_fseek(MP4D_demux_t* mp4, boxsize_t pos, int* eof_flag) {
2468 mp4->read_pos += pos;
2469 if (mp4->read_pos >= mp4->read_size)
2470 *eof_flag = 1;
2471}
2472
2473#define READ(n) read_payload(mp4, n, &payload_bytes, &eof_flag)
2474#define SKIP(n) \
2475 { \
2476 boxsize_t t = MINIMP4_MIN(payload_bytes, n); \
2477 my_fseek(mp4, t, &eof_flag); \
2478 payload_bytes -= t; \
2479 }
2480
2492enum { MINIMP4_MAX_ALLOC_BYTES = 256u * 1024u * 1024u };
2493
2494static void* minimp4_bounded_malloc(size_t size) {
2495 if (size > MINIMP4_MAX_ALLOC_BYTES)
2496 return NULL;
2497 return malloc(size);
2498}
2499
2500// A malformed file can carry the same table box (stsc, stco/co64, ...)
2501// twice for one track; re-running a MALLOC for a field that's already
2502// populated would leak the earlier block. free() is a no-op on NULL, so
2503// this is free for the (common) single-occurrence case.
2504#define MALLOC(t, p, size) \
2505 { \
2506 free(p); \
2507 p = (t)minimp4_bounded_malloc(size); \
2508 if (!(p)) { \
2509 ERROR("out of memory"); \
2510 } \
2511 }
2512
2513/*
2514* On error: release resources.
2515*/
2516#define RETURN_ERROR(mess) \
2517 { \
2518 TRACE(("\nMP4 ERROR: " mess)); \
2519 MP4D_close(mp4); \
2520 return 0; \
2521 }
2522
2523/*
2524* Any errors, occurred on top-level hierarchy is passed to exit check: 'if (!mp4->track_count) ... '
2525*/
2526#define ERROR(mess) \
2527 if (!depth) \
2528 break; \
2529 else \
2530 RETURN_ERROR(mess);
2531
2532typedef enum { BOX_ATOM, BOX_OD } boxtype_t;
2533
2534int MP4D_open(MP4D_demux_t* mp4,
2535 int (*read_callback)(int64_t offset, void* buffer, size_t size, void* token),
2536 void* token,
2537 int64_t file_size) {
2538 // box stack size
2539 int depth = 0;
2540
2541 struct {
2542 // remaining bytes for box in the stack
2543 boxsize_t bytes;
2544
2545 // kind of box children's: OD chunks handled in the same manner as name chunks
2546 boxtype_t format;
2547
2548 } stack[MAX_CHUNKS_DEPTH];
2549
2550#if MP4D_TRACE_SUPPORTED
2551 // path of current element: List0/List1/... etc
2552 uint32_t box_path[MAX_CHUNKS_DEPTH];
2553#endif
2554
2555 int eof_flag = 0;
2556 unsigned i;
2557 MP4D_track_t* tr = NULL;
2558
2559 if (!mp4 || !read_callback) {
2560 TRACE(("\nERROR: invlaid arguments!"));
2561 return 0;
2562 }
2563
2564 memset(mp4, 0, sizeof(MP4D_demux_t));
2566 mp4->token = token;
2567 mp4->read_size = file_size;
2568
2569 stack[0].format = BOX_ATOM; // start with atom box
2570 stack[0].bytes = 0; // never accessed
2571
2572 do {
2573 // List of boxes, derived from 'FullBox'
2574 // ~~~~~~~~~~~~~~~~~~~~~
2575 // need read version field and check version for these boxes
2576 static const struct {
2577 uint32_t name;
2578 unsigned max_version;
2579 unsigned use_track_flag;
2580 } g_fullbox[] = {
2581#if MP4D_INFO_SUPPORTED
2582 {BOX_mdhd, 1, 1},
2583 {BOX_mvhd, 1, 0},
2584 {BOX_hdlr, 0, 0},
2585 {BOX_meta,
2586 0,
2587 0}, // Android can produce meta box without 'FullBox' field, comment this line to simulate the bug
2588#endif
2589#if MP4D_TRACE_TIMESTAMPS
2590 {BOX_stts, 0, 0},
2591 {BOX_ctts, 0, 0},
2592#endif
2593 {BOX_stz2, 0, 1},
2594 {BOX_stsz, 0, 1},
2595 {BOX_stsc, 0, 1},
2596 {BOX_stco, 0, 1},
2597 {BOX_co64, 0, 1},
2598 {BOX_stsd, 0, 0},
2599 {BOX_esds, 0, 1}
2600 // esds does not use track, but switches to OD mode. Check here, to avoid OD check
2601 };
2602
2603 // List of boxes, which contains other boxes ('envelopes')
2604 // Parser will descend down for boxes in this list, otherwise parsing will proceed to
2605 // the next sibling box
2606 // OD boxes handled in the same way as atom boxes...
2607 static const struct {
2608 uint32_t name;
2609 boxtype_t type;
2610 } g_envelope_box[] = {
2611 {BOX_esds,
2612 BOX_OD}, // TODO: BOX_esds can be used for both audio and video, but this code supports audio only!
2613 {OD_ESD, BOX_OD},
2614 {OD_DCD, BOX_OD},
2615 {OD_DSI, BOX_OD},
2616 {BOX_trak, BOX_ATOM},
2617 {BOX_moov, BOX_ATOM},
2618 //{BOX_moof, BOX_ATOM},
2619 {BOX_mdia, BOX_ATOM},
2620 {BOX_tref, BOX_ATOM},
2621 {BOX_minf, BOX_ATOM},
2622 {BOX_dinf, BOX_ATOM},
2623 {BOX_stbl, BOX_ATOM},
2624 {BOX_stsd, BOX_ATOM},
2625 {BOX_mp4a, BOX_ATOM},
2626 {BOX_mp4s, BOX_ATOM},
2627#if MP4D_AVC_SUPPORTED
2628 {BOX_mp4v, BOX_ATOM},
2629 {BOX_avc1, BOX_ATOM},
2630 //{BOX_avc2, BOX_ATOM},
2631 //{BOX_svc1, BOX_ATOM},
2632#endif
2633#if MP4D_HEVC_SUPPORTED
2634 {BOX_hvc1, BOX_ATOM},
2635#endif
2636 {BOX_udta, BOX_ATOM},
2637 {BOX_meta, BOX_ATOM},
2638 {BOX_ilst, BOX_ATOM}};
2639
2640 uint32_t FullAtomVersionAndFlags = 0;
2641 boxsize_t payload_bytes;
2642 boxsize_t box_bytes;
2643 uint32_t box_name;
2644#if MP4D_INFO_SUPPORTED
2645 unsigned char** ptag = NULL;
2646#endif
2647 int read_bytes = 0;
2648
2649 // Read header box type and it's length
2650 if (stack[depth].format == BOX_ATOM) {
2651 box_bytes = minimp4_read(mp4, 4, &eof_flag);
2652#if FIX_BAD_ANDROID_META_BOX
2653 broken_android_meta_hack:
2654#endif
2655 if (eof_flag)
2656 break; // normal exit
2657
2658 if (box_bytes >= 2 && box_bytes < 8) {
2659 ERROR("invalid box size (broken file?)");
2660 }
2661
2662 box_name = minimp4_read(mp4, 4, &eof_flag);
2663 read_bytes = 8;
2664
2665 // Decode box size
2666 if (box_bytes == 0 || // standard indication of 'till eof' size
2667 box_bytes ==
2668 (boxsize_t)0xFFFFFFFFU // some files uses non-standard 'till eof' signaling
2669 ) {
2670 box_bytes = ~(boxsize_t)0;
2671 }
2672
2673 payload_bytes = box_bytes - 8;
2674
2675 if (box_bytes == 1) // 64-bit sizes
2676 {
2677 TRACE(("\n64-bit chunk encountered"));
2678
2679 box_bytes = minimp4_read(mp4, 4, &eof_flag);
2680#if MP4D_64BIT_SUPPORTED
2681 box_bytes <<= 32;
2682 box_bytes |= minimp4_read(mp4, 4, &eof_flag);
2683#else
2684 if (box_bytes) {
2685 ERROR("UNSUPPORTED FEATURE: MP4BoxHeader(): 64-bit boxes not supported!");
2686 }
2687 box_bytes = minimp4_read(mp4, 4, &eof_flag);
2688#endif
2689 if (box_bytes < 16) {
2690 ERROR("invalid box size (broken file?)");
2691 }
2692 payload_bytes = box_bytes - 16;
2693 }
2694
2695 // Read and check box version for some boxes
2696 for (i = 0; i < NELEM(g_fullbox); i++) {
2697 if (box_name == g_fullbox[i].name) {
2698 FullAtomVersionAndFlags = READ(4);
2699 read_bytes += 4;
2700
2701#if FIX_BAD_ANDROID_META_BOX
2702 // Fix invalid BOX_meta, found in some Android-produced MP4
2703 // This branch is optional: bad box would be skipped
2704 if (box_name == BOX_meta) {
2705 if (FullAtomVersionAndFlags >= 8 &&
2706 FullAtomVersionAndFlags < payload_bytes) {
2707 if (box_bytes > stack[depth].bytes) {
2708 ERROR("broken file structure!");
2709 }
2710 stack[depth].bytes -= box_bytes;
2711 ;
2712 depth++;
2713 stack[depth].bytes = payload_bytes + 4; // +4 need for missing header
2714 stack[depth].format = BOX_ATOM;
2715 box_bytes = FullAtomVersionAndFlags;
2716 TRACE(("Bad metadata box detected (Android bug?)!\n"));
2717 goto broken_android_meta_hack;
2718 }
2719 }
2720#endif // FIX_BAD_ANDROID_META_BOX
2721
2722 if ((FullAtomVersionAndFlags >> 24) > g_fullbox[i].max_version) {
2723 ERROR("unsupported box version!");
2724 }
2725 if (g_fullbox[i].use_track_flag && !tr) {
2726 ERROR("broken file structure!");
2727 }
2728 }
2729 }
2730 } else // stack[depth].format == BOX_OD
2731 {
2732 int val;
2733 box_name = OD_BASE + minimp4_read(mp4, 1, &eof_flag); // 1-byte box type
2734 read_bytes += 1;
2735 if (eof_flag)
2736 break;
2737
2738 payload_bytes = 0;
2739 box_bytes = 1;
2740 do {
2741 val = minimp4_read(mp4, 1, &eof_flag);
2742 read_bytes += 1;
2743 if (eof_flag) {
2744 ERROR("premature EOF!");
2745 }
2746 payload_bytes = (payload_bytes << 7) | (val & 0x7F);
2747 box_bytes++;
2748 } while (val & 0x80);
2749 box_bytes += payload_bytes;
2750 }
2751
2752#if MP4D_TRACE_SUPPORTED
2753 box_path[depth] = (box_name >> 24) | (box_name << 24) | ((box_name >> 8) & 0x0000FF00) |
2754 ((box_name << 8) & 0x00FF0000);
2755 TRACE(("%2d %8d %.*s (%d bytes remains for sibilings) \n",
2756 depth,
2757 (int)box_bytes,
2758 depth * 4,
2759 (char*)box_path,
2760 (int)stack[depth].bytes));
2761#endif
2762
2763 // Check that box size <= parent size
2764 if (depth) {
2765 // Skip box with bad size
2766 assert(box_bytes > 0);
2767 if (box_bytes > stack[depth].bytes) {
2768 TRACE(("Wrong %c%c%c%c box size: broken file?\n",
2769 (box_name >> 24) & 255,
2770 (box_name >> 16) & 255,
2771 (box_name >> 8) & 255,
2772 box_name & 255));
2773 box_bytes = stack[depth].bytes;
2774 box_name = 0;
2775 payload_bytes = box_bytes - read_bytes;
2776 }
2777 stack[depth].bytes -= box_bytes;
2778 }
2779
2780 // Read box header
2781 switch (box_name) {
2782 case BOX_stz2: //ISO/IEC 14496-1 Page 38. Section 8.17.2 - Sample Size Box.
2783 case BOX_stsz: {
2784 int size = 0;
2785 uint32_t sample_size;
2786 // Hardening fix: g_fullbox[]'s use_track_flag check only
2787 // hard-aborts via RETURN_ERROR at depth > 0 -- at depth 0
2788 // (this box appearing with no enclosing moov/trak) ERROR()
2789 // just breaks out of that unrelated lookup loop and parsing
2790 // continues into this case with tr still NULL. Fuzzer
2791 // found this as a null-pointer deref from a lone top-level
2792 // "stsz" box.
2793 if (!tr)
2794 break;
2795 sample_size = READ(4);
2796 tr->sample_count = READ(4);
2797 // (uint64_t) cast: sample_count*4 as native 32-bit
2798 // arithmetic can itself overflow/wrap before reaching
2799 // minimp4_bounded_malloc's size check, allocating far
2800 // fewer bytes than the loop below then writes -- a
2801 // fuzzer-found heap-buffer-overflow.
2802 MALLOC(unsigned int*, tr->entry_size, (uint64_t)tr->sample_count * 4);
2803 for (i = 0; i < tr->sample_count; i++) {
2804 if (box_name == BOX_stsz) {
2805 tr->entry_size[i] = (sample_size ? sample_size : READ(4));
2806 } else {
2807 switch (sample_size & 0xFF) {
2808 case 16:
2809 tr->entry_size[i] = READ(2);
2810 break;
2811 case 8:
2812 tr->entry_size[i] = READ(1);
2813 break;
2814 case 4:
2815 if (i & 1) {
2816 tr->entry_size[i] = size & 15;
2817 } else {
2818 size = READ(1);
2819 tr->entry_size[i] = (size >> 4);
2820 }
2821 break;
2822 }
2823 }
2824 }
2825 } break;
2826
2827 case BOX_stsc: //ISO/IEC 14496-12 Page 38. Section 8.18 - Sample To Chunk Box.
2828 // Same depth-0 use_track_flag gap as BOX_stsz above.
2829 if (!tr)
2830 break;
2831 tr->sample_to_chunk_count = READ(4);
2832 MALLOC(MP4D_sample_to_chunk_t*,
2833 tr->sample_to_chunk,
2834 tr->sample_to_chunk_count * sizeof(tr->sample_to_chunk[0]));
2835 for (i = 0; i < tr->sample_to_chunk_count; i++) {
2836 tr->sample_to_chunk[i].first_chunk = READ(4);
2837 tr->sample_to_chunk[i].samples_per_chunk = READ(4);
2838 SKIP(4); // sample_description_index
2839 }
2840 break;
2841#if MP4D_TRACE_TIMESTAMPS || MP4D_TIMESTAMPS_SUPPORTED
2842 case BOX_stts: {
2843 unsigned count, j, k = 0, ts = 0, ts_capacity;
2844 // Hardening fix: g_fullbox[] registers BOX_stts with
2845 // use_track_flag=0 (no active-track requirement enforced
2846 // before this case runs), but the MP4D_TIMESTAMPS_SUPPORTED
2847 // branch below unconditionally writes through tr -- a
2848 // top-level "stts" box with no enclosing trak (tr still
2849 // NULL) reaches this with no track allocated yet. Fuzzer
2850 // found this as a null-pointer deref from an 8-byte file.
2851 if (!tr)
2852 break;
2853 count = READ(4);
2854 ts_capacity = count;
2855#if MP4D_TIMESTAMPS_SUPPORTED
2856 // (uint64_t) cast: same native-arithmetic-overflow gap as
2857 // BOX_stsz's entry_size MALLOC above, on this box's own
2858 // unbounded, file-declared count.
2859 MALLOC(unsigned int*, tr->timestamp, (uint64_t)ts_capacity * 4);
2860 MALLOC(unsigned int*, tr->duration, (uint64_t)ts_capacity * 4);
2861 tr->timestamp_count = 0;
2862#endif
2863
2864 for (i = 0; i < count; i++) {
2865 unsigned sc = READ(4);
2866 int d = READ(4);
2867 uint64_t new_k = (uint64_t)k + sc; // avoid 32-bit wraparound below
2868 TRACE(("sample %8d count %8d duration %8d\n", i, sc, d));
2869#if MP4D_TIMESTAMPS_SUPPORTED
2870 if (new_k > ts_capacity) {
2871 // sc is an attacker-controlled per-entry sample
2872 // count; k + sc as plain "unsigned" arithmetic can
2873 // wrap past ts_capacity, skipping this resize while
2874 // the write loop below still walks `sc` entries --
2875 // a fuzzer-found heap-buffer-overflow. Widening the
2876 // addition avoids the wrap.
2877 //
2878 // Growing to exactly new_k on every entry (rather
2879 // than with slack) meant a file with many entries
2880 // that each grow the running total by only a
2881 // little forced a full realloc -- and full copy --
2882 // on every single one: a fuzzer-found multi-second
2883 // "realloc thrashing" hang distinct from a single
2884 // oversized allocation. Double capacity instead
2885 // (still bounded to MINIMP4_MAX_ALLOC_BYTES, which
2886 // is what catches the ~16GB single-request case
2887 // fuzzing also found), same amortized-growth
2888 // rationale as std::vector.
2889 //
2890 // Checking the bound *before* reallocating matters
2891 // too: rejecting after the fact would mean
2892 // overwriting one perfectly good pointer (from the
2893 // MALLOC above) with the other realloc's NULL
2894 // result, leaking the one that had succeeded.
2895 // Leaving both pointers untouched on rejection lets
2896 // MP4D_close() free them normally, same as any
2897 // other error path.
2898 uint64_t new_capacity = (uint64_t)ts_capacity * 2;
2899 if (new_capacity < new_k)
2900 new_capacity = new_k;
2901 if (new_capacity * sizeof(unsigned) > MINIMP4_MAX_ALLOC_BYTES)
2902 new_capacity = MINIMP4_MAX_ALLOC_BYTES / sizeof(unsigned);
2903 if (new_capacity < new_k) {
2904 ERROR("out of memory");
2905 }
2906 ts_capacity = (unsigned)new_capacity;
2907 tr->timestamp =
2908 (unsigned int*)realloc(tr->timestamp, ts_capacity * sizeof(unsigned));
2909 tr->duration =
2910 (unsigned int*)realloc(tr->duration, ts_capacity * sizeof(unsigned));
2911 if (!tr->timestamp || !tr->duration) {
2912 ERROR("out of memory");
2913 }
2914 }
2915 for (j = 0; j < sc; j++) {
2916 tr->duration[k] = d;
2917 tr->timestamp[k++] = ts;
2918 ts += d;
2919 }
2920 tr->timestamp_count = k;
2921#endif
2922 }
2923 } break;
2924 case BOX_ctts: {
2925 unsigned count = READ(4);
2926 for (i = 0; i < count; i++) {
2927 int sc, d;
2928 // count is an unbounded, file-declared value with no
2929 // backing allocation to size-check against (unlike
2930 // stsz/stsc/stco/stts above); once the box's actual
2931 // payload is exhausted, READ() keeps returning
2932 // zero-padding forever rather than stopping the loop,
2933 // so a file can claim ~4 billion entries in a few
2934 // bytes on disk. Fuzzer found this as a multi-second
2935 // hang (pure wasted CPU, not memory-unsafe on its own).
2936 if (payload_bytes == 0)
2937 break;
2938 sc = READ(4);
2939 d = READ(4);
2940 (void)sc;
2941 (void)d;
2942 TRACE(("sample %8d count %8d decoding to composition offset %8d\n", i, sc, d));
2943 }
2944 } break;
2945#endif
2946 case BOX_stco: //ISO/IEC 14496-12 Page 39. Section 8.19 - Chunk Offset Box.
2947 case BOX_co64:
2948 // Same depth-0 use_track_flag gap as BOX_stsz above.
2949 if (!tr)
2950 break;
2951 tr->chunk_count = READ(4);
2952 MALLOC(MP4D_file_offset_t*,
2953 tr->chunk_offset,
2954 tr->chunk_count * sizeof(MP4D_file_offset_t));
2955 for (i = 0; i < tr->chunk_count; i++) {
2956 tr->chunk_offset[i] = READ(4);
2957 if (box_name == BOX_co64) {
2958#if !MP4D_64BIT_SUPPORTED
2959 if (tr->chunk_offset[i]) {
2960 ERROR("UNSUPPORTED FEATURE: 64-bit chunk_offset not supported!");
2961 }
2962#endif
2963 tr->chunk_offset[i] <<= 32;
2964 tr->chunk_offset[i] |= READ(4);
2965 }
2966 }
2967 break;
2968
2969#if MP4D_INFO_SUPPORTED
2970 case BOX_mvhd:
2971 SKIP(((FullAtomVersionAndFlags >> 24) == 1) ? 8 + 8 : 4 + 4);
2972 mp4->timescale = READ(4);
2973 mp4->duration_hi = ((FullAtomVersionAndFlags >> 24) == 1) ? READ(4) : 0;
2974 mp4->duration_lo = READ(4);
2975 SKIP(4 + 2 + 2 + 4 * 2 + 4 * 9 + 4 * 6 + 4);
2976 break;
2977
2978 case BOX_mdhd:
2979 // Same depth-0 use_track_flag gap as BOX_stsz above.
2980 if (!tr)
2981 break;
2982 SKIP(((FullAtomVersionAndFlags >> 24) == 1) ? 8 + 8 : 4 + 4);
2983 tr->timescale = READ(4);
2984 tr->duration_hi = ((FullAtomVersionAndFlags >> 24) == 1) ? READ(4) : 0;
2985 tr->duration_lo = READ(4);
2986
2987 {
2988 int ISO_639_2_T = READ(2);
2989 tr->language[2] = (ISO_639_2_T & 31) + 0x60;
2990 ISO_639_2_T >>= 5;
2991 tr->language[1] = (ISO_639_2_T & 31) + 0x60;
2992 ISO_639_2_T >>= 5;
2993 tr->language[0] = (ISO_639_2_T & 31) + 0x60;
2994 }
2995 // the rest of this box is skipped by default ...
2996 break;
2997
2998 case BOX_hdlr:
2999 if (tr) // When this box is within 'meta' box, the track may not be avaialable
3000 {
3001 SKIP(4); // pre_defined
3002 tr->handler_type = READ(4);
3003 }
3004 // typically hdlr box does not contain any useful info.
3005 // the rest of this box is skipped by default ...
3006 break;
3007
3008 case BOX_btrt:
3009 if (!tr) {
3010 ERROR("broken file structure!");
3011 }
3012
3013 SKIP(4 + 4);
3014 tr->avg_bitrate_bps = READ(4);
3015 break;
3016
3017 // Set pointer to tag to be read...
3018 case BOX_calb:
3019 ptag = &mp4->tag.album;
3020 break;
3021 case BOX_cART:
3022 ptag = &mp4->tag.artist;
3023 break;
3024 case BOX_cnam:
3025 ptag = &mp4->tag.title;
3026 break;
3027 case BOX_cday:
3028 ptag = &mp4->tag.year;
3029 break;
3030 case BOX_ccmt:
3031 ptag = &mp4->tag.comment;
3032 break;
3033 case BOX_cgen:
3034 ptag = &mp4->tag.genre;
3035 break;
3036
3037#endif
3038
3039 case BOX_stsd:
3040 SKIP(4); // entry_count, BOX_mp4a & BOX_mp4v boxes follows immediately
3041 break;
3042
3043 case BOX_mp4s: // private stream
3044 if (!tr) {
3045 ERROR("broken file structure!");
3046 }
3047 SKIP(6 * 1 + 2 /*Base SampleEntry*/);
3048 break;
3049
3050 case BOX_mp4a:
3051 if (!tr) {
3052 ERROR("broken file structure!");
3053 }
3054#if MP4D_INFO_SUPPORTED
3055 SKIP(6 * 1 + 2 /*Base SampleEntry*/ + 4 * 2);
3056 tr->SampleDescription.audio.channelcount = READ(2);
3057 SKIP(2 /*samplesize*/ + 2 + 2);
3058 tr->SampleDescription.audio.samplerate_hz = READ(4) >> 16;
3059#else
3060 SKIP(28);
3061#endif
3062 break;
3063
3064#if MP4D_AVC_SUPPORTED
3065 case BOX_avc1: // AVCSampleEntry extends VisualSampleEntry
3066 // case BOX_avc2: - no test
3067 // case BOX_svc1: - no test
3068 case BOX_mp4v:
3069 if (!tr) {
3070 ERROR("broken file structure!");
3071 }
3072#if MP4D_INFO_SUPPORTED
3073 SKIP(6 * 1 + 2 /*Base SampleEntry*/ + 2 + 2 + 4 * 3);
3074 tr->SampleDescription.video.width = READ(2);
3075 tr->SampleDescription.video.height = READ(2);
3076 // frame_count is always 1
3077 // compressorname is rarely set..
3078 SKIP(4 + 4 + 4 + 2 /*frame_count*/ + 32 /*compressorname*/ + 2 + 2);
3079#else
3080 SKIP(78);
3081#endif
3082 // ^^^ end of VisualSampleEntry
3083 // now follows for BOX_avc1:
3084 // BOX_avcC
3085 // BOX_btrt (optional)
3086 // BOX_m4ds (optional)
3087 // for BOX_mp4v:
3088 // BOX_esds
3089 break;
3090
3091 case BOX_avcC: // AVCDecoderConfigurationRecord()
3092 // hack: AAC-specific DSI field reused (for it have same purpoose as sps/pps)
3093 // TODO: check this hack if BOX_esds co-exist with BOX_avcC
3094 // Hardening fix: unlike its sibling cases (mp4s/mp4a/avc1/mp4v),
3095 // this one had no tr-null guard at all -- a lone top-level
3096 // "avcC" box reaches this with tr still NULL.
3097 if (!tr)
3098 break;
3100 tr->dsi = (unsigned char*)minimp4_bounded_malloc((size_t)box_bytes);
3101 if (!tr->dsi) {
3102 ERROR("out of memory");
3103 }
3104 tr->dsi_bytes = (unsigned)box_bytes;
3105 {
3106 int spspps;
3107 unsigned char* p = tr->dsi;
3108 unsigned int configurationVersion = READ(1);
3109 unsigned int AVCProfileIndication = READ(1);
3110 unsigned int profile_compatibility = READ(1);
3111 unsigned int AVCLevelIndication = READ(1);
3112 //bit(6) reserved =
3113 unsigned int lengthSizeMinusOne = READ(1) & 3;
3114
3115 (void)configurationVersion;
3116 (void)AVCProfileIndication;
3117 (void)profile_compatibility;
3118 (void)AVCLevelIndication;
3119 (void)lengthSizeMinusOne;
3120
3121 for (spspps = 0; spspps < 2; spspps++) {
3122 unsigned int numOfSequenceParameterSets = READ(1);
3123 if (!spspps) {
3124 numOfSequenceParameterSets &= 31; // clears 3 msb for SPS
3125 }
3126 *p++ = numOfSequenceParameterSets;
3127 for (i = 0; i < numOfSequenceParameterSets; i++) {
3128 unsigned k, sequenceParameterSetLength = READ(2);
3129 *p++ = sequenceParameterSetLength >> 8;
3130 *p++ = sequenceParameterSetLength;
3131 for (k = 0; k < sequenceParameterSetLength; k++) {
3132 *p++ = READ(1);
3133 }
3134 }
3135 }
3136 }
3137 break;
3138#endif // MP4D_AVC_SUPPORTED
3139
3140 case OD_ESD: {
3141 unsigned flags = READ(3); // ES_ID(2) + flags(1)
3142
3143 if (flags & 0x80) // steamdependflag
3144 {
3145 SKIP(2); // dependsOnESID
3146 }
3147 if (flags & 0x40) // urlflag
3148 {
3149 unsigned bytecount = READ(1);
3150 SKIP(bytecount); // skip URL
3151 }
3152 if (flags & 0x20) // ocrflag (was reserved in MPEG-4 v.1)
3153 {
3154 SKIP(2); // OCRESID
3155 }
3156 break;
3157 }
3158
3159 case OD_DCD: //ISO/IEC 14496-1 Page 28. Section 8.6.5 - DecoderConfigDescriptor.
3160 // g_fullbox[] doesn't actually gate OD_DCD/OD_DSI (that table
3161 // covers ISOBMFF full boxes, not MPEG-4 object descriptors), so
3162 // a DecoderConfigDescriptor/DecSpecificInfo can be reached with
3163 // no active track (asserts are compiled out under NDEBUG) --
3164 // hardening fix for a fuzzer-found null-pointer deref.
3165 if (!tr)
3166 break;
3167 tr->object_type_indication = READ(1);
3168#if MP4D_INFO_SUPPORTED
3169 tr->stream_type = READ(1) >> 2;
3170 SKIP(3 /*bufferSizeDB*/ + 4 /*maxBitrate*/);
3171 tr->avg_bitrate_bps = READ(4);
3172#else
3173 SKIP(1 + 3 + 4 + 4);
3174#endif
3175 break;
3176
3177 case OD_DSI: //ISO/IEC 14496-1 Page 28. Section 8.6.5 - DecoderConfigDescriptor.
3178 if (!tr)
3179 break;
3180 if (!tr->dsi && payload_bytes) {
3181 // (uint64_t) cast, not (int): truncating a large
3182 // payload_bytes to int before minimp4_bounded_malloc's
3183 // size check can produce a small (or, if negative,
3184 // implementation-defined-but-typically-huge-when-
3185 // reinterpreted-as-size_t) allocation while the write loop
3186 // below still walks the untruncated payload_bytes count --
3187 // a fuzzer-found heap-buffer-overflow.
3188 MALLOC(unsigned char*, tr->dsi, (uint64_t)payload_bytes);
3189 for (i = 0; i < payload_bytes; i++) {
3190 tr->dsi[i] =
3191 minimp4_read(mp4, 1, &eof_flag); // These bytes available due to check above
3192 }
3193 tr->dsi_bytes = i;
3194 payload_bytes -= i;
3195 break;
3196 }
3197
3198 default:
3199 TRACE(("[%c%c%c%c] %d\n",
3200 box_name >> 24,
3201 box_name >> 16,
3202 box_name >> 8,
3203 box_name,
3204 (int)payload_bytes));
3205 }
3206
3207#if MP4D_INFO_SUPPORTED
3208 // Read tag is tag pointer is set
3209 if (ptag && !*ptag && payload_bytes > 16) {
3210#if 0
3211 uint32_t size = READ(4);
3212 uint32_t data = READ(4);
3213 uint32_t class = READ(4);
3214 uint32_t x1 = READ(4);
3215 TRACE(("%2d %2d %2d ", size, class, x1));
3216#else
3217 SKIP(4 + 4 + 4 + 4);
3218#endif
3219 // (uint64_t) cast: same truncate-before-size-check gap as
3220 // OD_DSI's dsi buffer above.
3221 MALLOC(unsigned char*, *ptag, (uint64_t)payload_bytes + 1);
3222 for (i = 0; payload_bytes != 0; i++) {
3223 (*ptag)[i] = READ(1);
3224 }
3225 (*ptag)[i] = 0; // zero-terminated string
3226 }
3227#endif
3228
3229 if (box_name == BOX_trak) {
3230 // New track found: allocate memory using realloc()
3231 // Typically there are 1 audio track for AAC audio file,
3232 // 4 tracks for movie file,
3233 // 3-5 tracks for scalable audio (CELP+AAC)
3234 // and up to 50 tracks for BSAC scalable audio
3235 void* mem = realloc(mp4->track, (mp4->track_count + 1) * sizeof(MP4D_track_t));
3236 if (!mem) {
3237 // if realloc fails, it does not deallocate old pointer!
3238 ERROR("out of memory");
3239 }
3240 mp4->track = (MP4D_track_t*)mem;
3241 tr = mp4->track + mp4->track_count++;
3242 memset(tr, 0, sizeof(MP4D_track_t));
3243 } else if (box_name == BOX_meta) {
3244 tr = NULL; // Avoid update of 'hdlr' box, which may contains in the 'meta' box
3245 }
3246
3247 // If this box is envelope, save it's size in box stack
3248 for (i = 0; i < NELEM(g_envelope_box); i++) {
3249 if (box_name == g_envelope_box[i].name) {
3250 if (++depth >= MAX_CHUNKS_DEPTH) {
3251 ERROR("too deep atoms nesting!");
3252 }
3253 stack[depth].bytes = payload_bytes;
3254 stack[depth].format = g_envelope_box[i].type;
3255 break;
3256 }
3257 }
3258
3259 // if box is not envelope, just skip it
3260 if (i == NELEM(g_envelope_box)) {
3261 if (payload_bytes > file_size) {
3262 eof_flag = 1;
3263 } else {
3264 SKIP(payload_bytes);
3265 }
3266 }
3267
3268 // remove empty boxes from stack
3269 // don't touch box with index 0 (which indicates whole file)
3270 while (depth > 0 && !stack[depth].bytes) {
3271 depth--;
3272 }
3273
3274 } while (!eof_flag);
3275
3276 if (!mp4->track_count) {
3277 RETURN_ERROR("no tracks found");
3278 }
3279 return 1;
3280}
3281
3286static int sample_to_chunk(MP4D_track_t* tr, unsigned nsample, unsigned* nfirst_sample_in_chunk) {
3287 unsigned chunk_group, nc, sum;
3288 *nfirst_sample_in_chunk = 0;
3289 if (tr->chunk_count == 0) {
3290 // Hardening fix: a track can declare samples (stsz) with no chunk
3291 // offset table (missing/empty stco/co64) in a malformed file. The
3292 // original "<= 1" fast path treated this the same as the legitimate
3293 // single-chunk case and returned chunk 0, which made callers index
3294 // into a chunk_offset array that was never allocated.
3295 return -1;
3296 }
3297 if (tr->chunk_count == 1) {
3298 return 0;
3299 }
3300 if (!tr->sample_to_chunk || tr->sample_to_chunk_count == 0) {
3301 // Hardening fix: a track can have a stco/co64 (chunk_count > 1)
3302 // with no stsc box at all (tr->sample_to_chunk NULL), or a stsc
3303 // box declaring zero entries. The loop below dereferences
3304 // tr->sample_to_chunk[chunk_group] unconditionally on its very
3305 // first iteration regardless of tr->sample_to_chunk_count --
3306 // fuzzer found the NULL case as a null-pointer deref.
3307 return -1;
3308 }
3309
3310 // Sequential demuxing queries nsample in strictly increasing order,
3311 // once per sample -- rescanning from nc=0 every time (the original
3312 // behavior, and its own "TODO: this can be calculated once per file"
3313 // above) makes a full demux O(chunk_count * sample_count). Fuzzing
3314 // found this as a multi-second hang from a crafted file with a
3315 // large-but-not-otherwise-invalid chunk count. Resume from the last
3316 // call's stopping point whenever this query doesn't need to look
3317 // earlier than it did.
3318 if (nsample >= tr->stc_cache_sum && tr->stc_cache_nc < tr->chunk_count) {
3319 chunk_group = tr->stc_cache_group;
3320 nc = tr->stc_cache_nc;
3321 sum = tr->stc_cache_sum;
3322 *nfirst_sample_in_chunk = sum;
3323 } else {
3324 chunk_group = 0;
3325 nc = 0;
3326 sum = 0;
3327 }
3328
3329 for (; nc < tr->chunk_count; nc++) {
3330 if (chunk_group + 1 < tr->sample_to_chunk_count // stuck at last entry till EOF
3331 && nc + 1 == // Chunks counted starting with '1'
3332 tr->sample_to_chunk[chunk_group + 1].first_chunk) // next group?
3333 {
3334 chunk_group++;
3335 }
3336
3337 sum += tr->sample_to_chunk[chunk_group].samples_per_chunk;
3338 if (nsample < sum) {
3339 tr->stc_cache_group = chunk_group;
3340 tr->stc_cache_nc = nc + 1;
3341 tr->stc_cache_sum = sum;
3342 return nc;
3343 }
3344
3345 *nfirst_sample_in_chunk = sum;
3346 }
3347
3348 tr->stc_cache_group = chunk_group;
3349 tr->stc_cache_nc = nc;
3350 tr->stc_cache_sum = sum;
3351 return -1;
3352}
3353
3354// Exported API function
3356 unsigned ntrack,
3357 unsigned nsample,
3358 unsigned* frame_bytes,
3359 unsigned* timestamp,
3360 unsigned* duration) {
3361 MP4D_track_t* tr = mp4->track + ntrack;
3362 unsigned ns;
3363 int nchunk = sample_to_chunk(tr, nsample, &ns);
3365
3366 if (nchunk < 0 || !tr->chunk_offset || !tr->entry_size) {
3367 // Hardening fix: chunk_count/sample_count and their matching
3368 // chunk_offset/entry_size arrays are set together within a single
3369 // box handler, but a malformed file can hit that handler's
3370 // out-of-memory ERROR() path (e.g. a duplicate stco/stsz declaring
3371 // an oversized count the second time around) after already
3372 // free()-ing the previous, valid allocation -- and, at depth 0,
3373 // ERROR() doesn't actually abort the parse (see the box handlers'
3374 // own comments on this), so a later chunk_count/sample_count can
3375 // end up numerically valid while its array stayed NULL. Fuzzer
3376 // found this as a null-pointer deref.
3377 *frame_bytes = 0;
3378 return 0;
3379 }
3380
3381 // Resuming from a per-track cache the same way sample_to_chunk() does
3382 // above: summing entry_size from the chunk's first sample up to
3383 // `nsample` on every single call makes a demux with a few large chunks
3384 // (e.g. one giant chunk holding every sample) O(chunk_size^2) even
3385 // though sample_to_chunk() itself never has to rescan in that case.
3386 // Fuzzing found this as a multi-second hang distinct from (and not
3387 // fixed by) the sample_to_chunk() memoization.
3388 if (tr->fo_cache_valid && nsample == tr->fo_cache_nsample + 1 && ns <= tr->fo_cache_nsample) {
3389 offset = tr->fo_cache_offset;
3390 ns = nsample;
3391 } else {
3392 offset = tr->chunk_offset[nchunk];
3393 }
3394
3395 for (; ns < nsample; ns++) {
3396 offset += tr->entry_size[ns];
3397 }
3398
3399 *frame_bytes = tr->entry_size[ns];
3400
3401 tr->fo_cache_valid = 1;
3402 tr->fo_cache_nsample = nsample;
3403 tr->fo_cache_offset = offset + tr->entry_size[ns];
3404
3405 if (timestamp) {
3406#if MP4D_TIMESTAMPS_SUPPORTED
3407 // Hardening fix: a track can have samples (from stsz) but no stts
3408 // box at all, leaving tr->timestamp/tr->duration NULL from the
3409 // MP4D_track_t's zero-init; or a malformed file's stsz sample_count
3410 // can simply exceed the total sample count its own stts box
3411 // declared, leaving `ns` past the end of both arrays even though
3412 // they're non-NULL. Fuzzer found both as reads on a malformed file.
3413 *timestamp = (tr->timestamp && ns < tr->timestamp_count) ? tr->timestamp[ns] : 0;
3414#else
3415 *timestamp = 0;
3416#endif
3417 }
3418 if (duration) {
3419#if MP4D_TIMESTAMPS_SUPPORTED
3420 *duration = (tr->duration && ns < tr->timestamp_count) ? tr->duration[ns] : 0;
3421#else
3422 *duration = 0;
3423#endif
3424 }
3425
3426 return offset;
3427}
3428
3429#define FREE(x) \
3430 if (x) { \
3431 free(x); \
3432 x = NULL; \
3433 }
3434
3435// Exported API function
3436void MP4D_close(MP4D_demux_t* mp4) {
3437 while (mp4->track_count) {
3438 MP4D_track_t* tr = mp4->track + --mp4->track_count;
3439 FREE(tr->entry_size);
3440#if MP4D_TIMESTAMPS_SUPPORTED
3441 FREE(tr->timestamp);
3442 FREE(tr->duration);
3443#endif
3444 FREE(tr->sample_to_chunk);
3445 FREE(tr->chunk_offset);
3446 FREE(tr->dsi);
3447 }
3448 FREE(mp4->track);
3449#if MP4D_INFO_SUPPORTED
3450 FREE(mp4->tag.title);
3451 FREE(mp4->tag.artist);
3452 FREE(mp4->tag.album);
3453 FREE(mp4->tag.year);
3454 FREE(mp4->tag.comment);
3455 FREE(mp4->tag.genre);
3456#endif
3457}
3458
3459static int skip_spspps(const unsigned char* p, int nbytes, int nskip) {
3460 int i, k = 0;
3461 for (i = 0; i < nskip; i++) {
3462 unsigned segmbytes;
3463 if (k > nbytes - 2)
3464 return -1;
3465 segmbytes = p[k] * 256 + p[k + 1];
3466 k += 2 + segmbytes;
3467 }
3468 return k;
3469}
3470
3471static const void* MP4D_read_spspps(
3472 const MP4D_demux_t* mp4, unsigned int ntrack, int pps_flag, int nsps, int* sps_bytes) {
3473 int sps_count, skip_bytes;
3474 int bytepos = 0;
3475 unsigned char* p = mp4->track[ntrack].dsi;
3476 if (ntrack >= mp4->track_count)
3477 return NULL;
3479 return NULL; // SPS/PPS are specific for AVC format only
3480
3481 if (pps_flag) {
3482 // Skip all SPS
3483 sps_count = p[bytepos++];
3484 skip_bytes = skip_spspps(p + bytepos, mp4->track[ntrack].dsi_bytes - bytepos, sps_count);
3485 if (skip_bytes < 0)
3486 return NULL;
3487 bytepos += skip_bytes;
3488 }
3489
3490 // Skip sps/pps before the given target
3491 sps_count = p[bytepos++];
3492 if (nsps >= sps_count)
3493 return NULL;
3494 skip_bytes = skip_spspps(p + bytepos, mp4->track[ntrack].dsi_bytes - bytepos, nsps);
3495 if (skip_bytes < 0)
3496 return NULL;
3497 bytepos += skip_bytes;
3498 *sps_bytes = p[bytepos] * 256 + p[bytepos + 1];
3499 return p + bytepos + 2;
3500}
3501
3502const void* MP4D_read_sps(const MP4D_demux_t* mp4, unsigned int ntrack, int nsps, int* sps_bytes) {
3503 return MP4D_read_spspps(mp4, ntrack, 0, nsps, sps_bytes);
3504}
3505
3506const void* MP4D_read_pps(const MP4D_demux_t* mp4, unsigned int ntrack, int npps, int* pps_bytes) {
3507 return MP4D_read_spspps(mp4, ntrack, 1, npps, pps_bytes);
3508}
3509
3510#if MP4D_PRINT_INFO_SUPPORTED
3511/************************************************************************/
3512/* Purely informational part, may be removed for embedded applications */
3513/************************************************************************/
3514
3515//
3516// Decodes ISO/IEC 14496 MP4 stream type to ASCII string
3517//
3518static const char* GetMP4StreamTypeName(int streamType) {
3519 switch (streamType) {
3520 case 0x00:
3521 return "Forbidden";
3522 case 0x01:
3523 return "ObjectDescriptorStream";
3524 case 0x02:
3525 return "ClockReferenceStream";
3526 case 0x03:
3527 return "SceneDescriptionStream";
3528 case 0x04:
3529 return "VisualStream";
3530 case 0x05:
3531 return "AudioStream";
3532 case 0x06:
3533 return "MPEG7Stream";
3534 case 0x07:
3535 return "IPMPStream";
3536 case 0x08:
3537 return "ObjectContentInfoStream";
3538 case 0x09:
3539 return "MPEGJStream";
3540 default:
3541 if (streamType >= 0x20 && streamType <= 0x3F) {
3542 return "User private";
3543 } else {
3544 return "Reserved for ISO use";
3545 }
3546 }
3547}
3548
3549//
3550// Decodes ISO/IEC 14496 MP4 object type to ASCII string
3551//
3552static const char* GetMP4ObjectTypeName(int objectTypeIndication) {
3553 switch (objectTypeIndication) {
3554 case 0x00:
3555 return "Forbidden";
3556 case 0x01:
3557 return "Systems ISO/IEC 14496-1";
3558 case 0x02:
3559 return "Systems ISO/IEC 14496-1";
3560 case 0x20:
3561 return "Visual ISO/IEC 14496-2";
3562 case 0x40:
3563 return "Audio ISO/IEC 14496-3";
3564 case 0x60:
3565 return "Visual ISO/IEC 13818-2 Simple Profile";
3566 case 0x61:
3567 return "Visual ISO/IEC 13818-2 Main Profile";
3568 case 0x62:
3569 return "Visual ISO/IEC 13818-2 SNR Profile";
3570 case 0x63:
3571 return "Visual ISO/IEC 13818-2 Spatial Profile";
3572 case 0x64:
3573 return "Visual ISO/IEC 13818-2 High Profile";
3574 case 0x65:
3575 return "Visual ISO/IEC 13818-2 422 Profile";
3576 case 0x66:
3577 return "Audio ISO/IEC 13818-7 Main Profile";
3578 case 0x67:
3579 return "Audio ISO/IEC 13818-7 LC Profile";
3580 case 0x68:
3581 return "Audio ISO/IEC 13818-7 SSR Profile";
3582 case 0x69:
3583 return "Audio ISO/IEC 13818-3";
3584 case 0x6A:
3585 return "Visual ISO/IEC 11172-2";
3586 case 0x6B:
3587 return "Audio ISO/IEC 11172-3";
3588 case 0x6C:
3589 return "Visual ISO/IEC 10918-1";
3590 case 0xFF:
3591 return "no object type specified";
3592 default:
3593 if (objectTypeIndication >= 0xC0 && objectTypeIndication <= 0xFE)
3594 return "User private";
3595 else
3596 return "Reserved for ISO use";
3597 }
3598}
3599
3629void MP4D_printf_info(const MP4D_demux_t* mp4) {
3630 unsigned i;
3631 printf("\nMP4 FILE: %d tracks found. Movie time %.2f sec\n",
3632 mp4->track_count,
3633 (4294967296.0 * mp4->duration_hi + mp4->duration_lo) / mp4->timescale);
3634#define STR_TAG(name) \
3635 if (mp4->tag.name) \
3636 printf("%10s = %s\n", #name, mp4->tag.name)
3637 STR_TAG(title);
3638 STR_TAG(artist);
3639 STR_TAG(album);
3640 STR_TAG(year);
3641 STR_TAG(comment);
3642 STR_TAG(genre);
3643 printf("\nNo|type|lng| duration | bitrate| %-23s| Object type", "Stream type");
3644 for (i = 0; i < mp4->track_count; i++) {
3645 MP4D_track_t* tr = mp4->track + i;
3646
3647 printf("\n%2d|%c%c%c%c|%c%c%c|%7.2f s %6d frm| %7d|",
3648 i,
3649 (tr->handler_type >> 24),
3650 (tr->handler_type >> 16),
3651 (tr->handler_type >> 8),
3652 (tr->handler_type >> 0),
3653 tr->language[0],
3654 tr->language[1],
3655 tr->language[2],
3656 (65536.0 * 65536.0 * tr->duration_hi + tr->duration_lo) / tr->timescale,
3657 tr->sample_count,
3658 tr->avg_bitrate_bps);
3659
3660 printf(" %-23s|", GetMP4StreamTypeName(tr->stream_type));
3661 printf(" %-23s", GetMP4ObjectTypeName(tr->object_type_indication));
3662
3664 printf(" - %d ch %d hz",
3667 } else if (tr->handler_type == MP4D_HANDLER_TYPE_VIDE) {
3668 printf(" - %dx%d",
3671 }
3672 }
3673 printf("\n");
3674}
3675
3676#endif // MP4D_PRINT_INFO_SUPPORTED
3677#endif
const void * MP4D_read_sps(const MP4D_demux_t *mp4, unsigned int ntrack, int nsps, int *sps_bytes)
boxsize_t MP4D_file_offset_t
Definition minimp4.h:102
struct MP4E_mux_tag MP4E_mux_t
Definition minimp4.h:125
#define MP4E_SAMPLE_DEFAULT
Definition minimp4.h:89
#define MP4_OBJECT_TYPE_AVC
Definition minimp4.h:71
#define MP4E_STATUS_NO_MEMORY
Definition minimp4.h:82
int mp4_h26x_write_init(mp4_h26x_writer_t *h, MP4E_mux_t *mux, int width, int height, int is_hevc)
#define MINIMP4_MAX_SPS
Definition minimp4.h:32
void MP4D_close(MP4D_demux_t *mp4)
int MP4E_set_text_comment(MP4E_mux_t *mux, const char *comment)
MP4E_mux_t * MP4E_open(int sequential_mode_flag, int enable_fragmentation, void *token, int(*write_callback)(int64_t offset, const void *buffer, size_t size, void *token))
int MP4D_open(MP4D_demux_t *mp4, int(*read_callback)(int64_t offset, void *buffer, size_t size, void *token), void *token, int64_t file_size)
void mp4_h26x_write_close(mp4_h26x_writer_t *h)
struct MP4D_demux_tag MP4D_demux_t
#define MP4D_TFDT_SUPPORT
Definition minimp4.h:57
#define HEVC_NAL_CRA_NUT
Definition minimp4.h:119
int mp4_h26x_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, int length, unsigned timeStamp90kHz_next)
#define MP4E_HANDLER_TYPE_GESM
Definition minimp4.h:113
int MP4E_put_sample(MP4E_mux_t *mux, int track_num, const void *data, int data_bytes, int duration, int kind)
uint64_t boxsize_t
Definition minimp4.h:98
#define MP4E_STATUS_BAD_ARGUMENTS
Definition minimp4.h:81
#define MP4D_HANDLER_TYPE_SOUN
Definition minimp4.h:110
int MP4E_close(MP4E_mux_t *mux)
int MP4E_set_dsi(MP4E_mux_t *mux, int track_id, const void *dsi, int bytes)
int MP4E_set_sps(MP4E_mux_t *mux, int track_id, const void *sps, int bytes)
#define HEVC_NAL_VPS
Definition minimp4.h:115
#define MP4E_SAMPLE_RANDOM_ACCESS
Definition minimp4.h:90
#define MINIMP4_MAX_PPS
Definition minimp4.h:33
#define MP4E_STATUS_OK
Definition minimp4.h:80
#define MINIMP4_MIN(x, y)
Definition minimp4.h:22
int MP4E_add_track(MP4E_mux_t *mux, const MP4E_track_t *track_data)
MP4D_file_offset_t MP4D_frame_offset(const MP4D_demux_t *mp4, unsigned int ntrack, unsigned int nsample, unsigned int *frame_bytes, unsigned *timestamp, unsigned *duration)
track_media_kind_t
Definition minimp4.h:127
@ e_private
Definition minimp4.h:127
@ e_video
Definition minimp4.h:127
@ e_audio
Definition minimp4.h:127
struct mp4_h26x_writer_tag mp4_h26x_writer_t
int MP4E_set_vps(MP4E_mux_t *mux, int track_id, const void *vps, int bytes)
#define MAX_CHUNKS_DEPTH
Definition minimp4.h:30
const void * MP4D_read_pps(const MP4D_demux_t *mp4, unsigned int ntrack, int npps, int *pps_bytes)
#define HEVC_NAL_SPS
Definition minimp4.h:116
#define MP4E_STATUS_ONLY_ONE_DSI_ALLOWED
Definition minimp4.h:84
#define MP4_OBJECT_TYPE_AUDIO_ISO_IEC_14496_3
Definition minimp4.h:63
#define MP4_OBJECT_TYPE_HEVC
Definition minimp4.h:73
int MP4E_set_pps(MP4E_mux_t *mux, int track_id, const void *pps, int bytes)
#define HEVC_NAL_BLA_W_LP
Definition minimp4.h:118
#define MP4D_HANDLER_TYPE_VIDE
Definition minimp4.h:108
#define MP4E_SAMPLE_CONTINUATION
Definition minimp4.h:91
#define HEVC_NAL_PPS
Definition minimp4.h:117
AU_EXTERN AU_EXPORT void printf(const char *format,...)
Definition stdio.cpp:121
AU_EXPORT char * strdup(const char *c)
Definition string.cpp:237
#define RETURN_ERROR(StatusCode)
Definition Base.h:1000
#define assert(expr)
Definition assert.h:32
uint8_t flags
Definition virtio.h:0
XE_LIB void * memchr(const void *src, int c, size_t n)
Definition string.cpp:883
XETime t
Definition main.cpp:53
size_t a
Definition main.cpp:156
boxsize_t MP4D_file_offset_t
Definition minimp4.h:102
unsigned int uint32_t
Definition acefiex.h:163
COMPILER_DEPENDENT_INT64 int64_t
Definition acefiex.h:164
unsigned char uint8_t
Definition acefiex.h:161
COMPILER_DEPENDENT_UINT64 uint64_t
Definition acefiex.h:165
unsigned short int uint16_t
Definition acefiex.h:162
#define NULL
Definition actypes.h:561
#define GetBits
Definition bitstream.h:53
char title[128]
Definition d_main.c:877
uint8_t byte
Definition doomtype.h:83
size_t size
Definition drm_bridge.h:1299
size_t size_t offset
Definition drm_bridge.h:1299
struct drm_crtc struct drm_plane struct drm_plane const struct drm_crtc_funcs const char * name
Definition drm_crtc.h:1242
const char const char * format
Definition drm_print.h:516
int sample
Definition h264bsd_deblocking.c:642
#define FREE(ptr)
Definition h264bsd_util.h:150
struct i915_user_extension base
Definition i915_drm.h:0
void memcmp(void)
void strlen(void)
void memset(void)
void memcpy(void)
void * data
Definition kthread.h:30
int h
Definition layout.c:118
#define d
Definition libunicode.c:1833
char end[]
#define realloc(p, s)
Definition quickjs.c:2292
#define malloc(s)
Definition quickjs.c:2290
#define free(p)
Definition quickjs.c:2291
Definition minimp4.h:264
unsigned duration_hi
Definition minimp4.h:281
unsigned char * album
Definition minimp4.h:292
unsigned timescale
Definition minimp4.h:285
int64_t read_size
Definition minimp4.h:269
void * token
Definition minimp4.h:272
struct MP4D_demux_tag::@753 tag
unsigned char * title
Definition minimp4.h:290
MP4D_track_t * track
Definition minimp4.h:270
int64_t read_pos
Definition minimp4.h:268
unsigned char * year
Definition minimp4.h:293
unsigned duration_lo
Definition minimp4.h:282
unsigned char * artist
Definition minimp4.h:291
unsigned char * comment
Definition minimp4.h:294
unsigned char * genre
Definition minimp4.h:295
unsigned track_count
Definition minimp4.h:274
int(* read_callback)(int64_t offset, void *buffer, size_t size, void *token)
Definition minimp4.h:271
Definition minimp4.h:301
unsigned first_chunk
Definition minimp4.h:302
unsigned samples_per_chunk
Definition minimp4.h:303
Definition minimp4.h:159
unsigned sample_count
Definition minimp4.h:165
MP4D_file_offset_t * chunk_offset
Definition minimp4.h:255
unsigned channelcount
Definition minimp4.h:234
unsigned stc_cache_group
Definition minimp4.h:260
unsigned timestamp_count
Definition minimp4.h:281
unsigned fo_cache_nsample
Definition minimp4.h:270
unsigned sample_to_chunk_count
Definition minimp4.h:251
unsigned chunk_count
Definition minimp4.h:254
unsigned width
Definition minimp4.h:240
struct MP4D_track_t::@750::@751 audio
unsigned height
Definition minimp4.h:241
unsigned * timestamp
Definition minimp4.h:258
unsigned samplerate_hz
Definition minimp4.h:235
struct MP4D_track_t::@750::@752 video
unsigned object_type_indication
Definition minimp4.h:192
unsigned timescale
Definition minimp4.h:210
unsigned stc_cache_sum
Definition minimp4.h:262
struct MP4D_sample_to_chunk_t_tag * sample_to_chunk
Definition minimp4.h:252
unsigned * entry_size
Definition minimp4.h:249
unsigned char * dsi
Definition minimp4.h:168
unsigned duration_lo
Definition minimp4.h:207
union MP4D_track_t::@750 SampleDescription
unsigned fo_cache_valid
Definition minimp4.h:269
unsigned stc_cache_nc
Definition minimp4.h:261
unsigned handler_type
Definition minimp4.h:203
MP4D_file_offset_t fo_cache_offset
Definition minimp4.h:271
unsigned * duration
Definition minimp4.h:259
unsigned dsi_bytes
Definition minimp4.h:171
unsigned char language[4]
Definition minimp4.h:216
unsigned duration_hi
Definition minimp4.h:206
unsigned stream_type
Definition minimp4.h:229
unsigned avg_bitrate_bps
Definition minimp4.h:213
Definition minimp4.h:129
int width
Definition minimp4.h:150
track_media_kind_t track_media_kind
Definition minimp4.h:137
unsigned time_scale
Definition minimp4.h:140
unsigned char language[4]
Definition minimp4.h:135
int height
Definition minimp4.h:151
unsigned object_type_indication
Definition minimp4.h:132
union MP4E_track_t::@747 u
unsigned default_duration
Definition minimp4.h:141
struct MP4E_track_t::@747::@749 v
Definition minimp4.h:306
void * sps_cache[MINIMP4_MAX_SPS]
Definition minimp4.h:307
void * pps_cache[MINIMP4_MAX_PPS]
Definition minimp4.h:308
Definition minimp4.h:317
int need_sps
Definition minimp4.h:322
MP4E_mux_t * mux
Definition minimp4.h:321
int need_pps
Definition minimp4.h:322
int need_vps
Definition minimp4.h:322
int is_hevc
Definition minimp4.h:322
int need_idr
Definition minimp4.h:322
h264_sps_id_patcher_t sps_patcher
Definition minimp4.h:319
int mux_track_id
Definition minimp4.h:322
size_t(* write_callback)(struct __VFS_NODE__ *node, struct __VFS_NODE__ *file, uint64_t *buffer, uint32_t length)
Definition vfs.h:103
size_t(* read_callback)(struct __VFS_NODE__ *node, struct __VFS_NODE__ *file, uint64_t *buffer, uint32_t length)
Definition vfs.h:96