1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#include <stdlib.h>
28#include <string.h>
29
30/* Work-around for MSVC debugger issue */
31#define VC_CONTAINER_MODULE_T VC_CONTAINER_MODULE_MP4_READER_T
32#define VC_CONTAINER_TRACK_MODULE_T VC_CONTAINER_TRACK_MODULE_MP4_READER_T
33
34#define CONTAINER_IS_BIG_ENDIAN
35#include "containers/core/containers_private.h"
36#include "containers/core/containers_io_helpers.h"
37#include "containers/core/containers_utils.h"
38#include "containers/core/containers_logging.h"
39#include "containers/mp4/mp4_common.h"
40#undef CONTAINER_HELPER_LOG_INDENT
41#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->box_level
42
43VC_CONTAINER_STATUS_T mp4_reader_open( VC_CONTAINER_T *p_ctx );
44
45/******************************************************************************
46TODO:
47- aspect ratio
48- itunes gapless
49- edit list
50- subpicture track
51******************************************************************************/
52
53/******************************************************************************
54Defines.
55******************************************************************************/
56#define MP4_TRACKS_MAX 16
57
58#define MP4_BOX_MIN_HEADER_SIZE 8
59#define MP4_MAX_BOX_SIZE (1<<29) /* Does not apply to the mdat box */
60#define MP4_MAX_BOX_LEVEL 10
61
62#define MP4_MAX_SAMPLES_BATCH_SIZE (16*1024)
63
64#define MP4_SKIP_U8(ctx,n) (size -= 1, SKIP_U8(ctx,n))
65#define MP4_SKIP_U16(ctx,n) (size -= 2, SKIP_U16(ctx,n))
66#define MP4_SKIP_U24(ctx,n) (size -= 3, SKIP_U24(ctx,n))
67#define MP4_SKIP_U32(ctx,n) (size -= 4, SKIP_U32(ctx,n))
68#define MP4_SKIP_U64(ctx,n) (size -= 8, SKIP_U64(ctx,n))
69#define MP4_READ_U8(ctx,n) (size -= 1, READ_U8(ctx,n))
70#define MP4_READ_U16(ctx,n) (size -= 2, READ_U16(ctx,n))
71#define MP4_READ_U24(ctx,n) (size -= 3, READ_U24(ctx,n))
72#define MP4_READ_U32(ctx,n) (size -= 4, READ_U32(ctx,n))
73#define MP4_READ_U64(ctx,n) (size -= 8, READ_U64(ctx,n))
74#define MP4_READ_FOURCC(ctx,n) (size -= 4, READ_FOURCC(ctx,n))
75#define MP4_SKIP_FOURCC(ctx,n) (size -= 4, SKIP_FOURCC(ctx,n))
76#define MP4_READ_BYTES(ctx,buffer,sz) (size -= sz, READ_BYTES(ctx,buffer,sz))
77#define MP4_SKIP_BYTES(ctx,sz) (size -= sz, SKIP_BYTES(ctx,sz))
78#define MP4_SKIP_STRING(ctx,sz,n) (size -= sz, SKIP_STRING(ctx,sz,n))
79
80/******************************************************************************
81Type definitions.
82******************************************************************************/
83typedef struct
84{
85 VC_CONTAINER_STATUS_T status;
86
87 int64_t duration;
88 int64_t pts;
89 int64_t dts;
90
91 uint32_t sample;
92 int64_t offset;
93 unsigned int sample_offset;
94 unsigned int sample_size;
95
96 uint32_t sample_duration;
97 uint32_t sample_duration_count;
98 int32_t sample_composition_offset;
99 uint32_t sample_composition_count;
100
101 uint32_t next_sync_sample;
102 bool keyframe;
103
104 uint32_t samples_per_chunk;
105 uint32_t chunks;
106 uint32_t samples_in_chunk;
107
108 struct {
109 uint32_t entry;
110 } sample_table[MP4_SAMPLE_TABLE_NUM];
111
112} MP4_READER_STATE_T;
113
114typedef struct VC_CONTAINER_TRACK_MODULE_T
115{
116 MP4_READER_STATE_T state;
117
118 int64_t timescale;
119 uint8_t object_type_indication;
120
121 uint32_t sample_size;
122 struct {
123 int64_t offset;
124 uint32_t entries;
125 uint32_t entry_size;
126 } sample_table[MP4_SAMPLE_TABLE_NUM];
127
128 uint32_t samples_batch_size;
129
130} VC_CONTAINER_TRACK_MODULE_T;
131
132typedef struct VC_CONTAINER_MODULE_T
133{
134 int64_t box_offset;
135 int box_level;
136
137 MP4_BRAND_T brand;
138
139 int64_t timescale;
140
141 VC_CONTAINER_TRACK_T *tracks[MP4_TRACKS_MAX];
142 unsigned int current_track;
143
144 bool found_moov;
145 int64_t data_offset;
146 int64_t data_size;
147
148} VC_CONTAINER_MODULE_T;
149
150/******************************************************************************
151Static functions within this file.
152******************************************************************************/
153static VC_CONTAINER_STATUS_T mp4_read_box( VC_CONTAINER_T *p_ctx, int64_t size, MP4_BOX_TYPE_T parent_type );
154static VC_CONTAINER_STATUS_T mp4_read_boxes( VC_CONTAINER_T *p_ctx, int64_t size, MP4_BOX_TYPE_T type );
155static VC_CONTAINER_STATUS_T mp4_read_box_ftyp( VC_CONTAINER_T *p_ctx, int64_t size );
156static VC_CONTAINER_STATUS_T mp4_read_box_moov( VC_CONTAINER_T *p_ctx, int64_t size );
157static VC_CONTAINER_STATUS_T mp4_read_box_mvhd( VC_CONTAINER_T *p_ctx, int64_t size );
158static VC_CONTAINER_STATUS_T mp4_read_box_trak( VC_CONTAINER_T *p_ctx, int64_t size );
159static VC_CONTAINER_STATUS_T mp4_read_box_tkhd( VC_CONTAINER_T *p_ctx, int64_t size );
160static VC_CONTAINER_STATUS_T mp4_read_box_mdia( VC_CONTAINER_T *p_ctx, int64_t size );
161static VC_CONTAINER_STATUS_T mp4_read_box_mdhd( VC_CONTAINER_T *p_ctx, int64_t size );
162static VC_CONTAINER_STATUS_T mp4_read_box_hdlr( VC_CONTAINER_T *p_ctx, int64_t size );
163static VC_CONTAINER_STATUS_T mp4_read_box_minf( VC_CONTAINER_T *p_ctx, int64_t size );
164static VC_CONTAINER_STATUS_T mp4_read_box_vmhd( VC_CONTAINER_T *p_ctx, int64_t size );
165static VC_CONTAINER_STATUS_T mp4_read_box_smhd( VC_CONTAINER_T *p_ctx, int64_t size );
166static VC_CONTAINER_STATUS_T mp4_read_box_dinf( VC_CONTAINER_T *p_ctx, int64_t size );
167static VC_CONTAINER_STATUS_T mp4_read_box_dref( VC_CONTAINER_T *p_ctx, int64_t size );
168static VC_CONTAINER_STATUS_T mp4_read_box_stbl( VC_CONTAINER_T *p_ctx, int64_t size );
169static VC_CONTAINER_STATUS_T mp4_read_box_stsd( VC_CONTAINER_T *p_ctx, int64_t size );
170static VC_CONTAINER_STATUS_T mp4_read_box_stts( VC_CONTAINER_T *p_ctx, int64_t size );
171static VC_CONTAINER_STATUS_T mp4_read_box_ctts( VC_CONTAINER_T *p_ctx, int64_t size );
172static VC_CONTAINER_STATUS_T mp4_read_box_stsc( VC_CONTAINER_T *p_ctx, int64_t size );
173static VC_CONTAINER_STATUS_T mp4_read_box_stsz( VC_CONTAINER_T *p_ctx, int64_t size );
174static VC_CONTAINER_STATUS_T mp4_read_box_stco( VC_CONTAINER_T *p_ctx, int64_t size );
175static VC_CONTAINER_STATUS_T mp4_read_box_co64( VC_CONTAINER_T *p_ctx, int64_t size );
176static VC_CONTAINER_STATUS_T mp4_read_box_stss( VC_CONTAINER_T *p_ctx, int64_t size );
177static VC_CONTAINER_STATUS_T mp4_read_box_vide( VC_CONTAINER_T *p_ctx, int64_t size );
178static VC_CONTAINER_STATUS_T mp4_read_box_soun( VC_CONTAINER_T *p_ctx, int64_t size );
179static VC_CONTAINER_STATUS_T mp4_read_box_text( VC_CONTAINER_T *p_ctx, int64_t size );
180
181static VC_CONTAINER_STATUS_T mp4_read_box_esds( VC_CONTAINER_T *p_ctx, int64_t size );
182static VC_CONTAINER_STATUS_T mp4_read_box_vide_avcC( VC_CONTAINER_T *p_ctx, int64_t size );
183static VC_CONTAINER_STATUS_T mp4_read_box_vide_d263( VC_CONTAINER_T *p_ctx, int64_t size );
184static VC_CONTAINER_STATUS_T mp4_read_box_soun_damr( VC_CONTAINER_T *p_ctx, int64_t size );
185static VC_CONTAINER_STATUS_T mp4_read_box_soun_dawp( VC_CONTAINER_T *p_ctx, int64_t size );
186static VC_CONTAINER_STATUS_T mp4_read_box_soun_devc( VC_CONTAINER_T *p_ctx, int64_t size );
187static VC_CONTAINER_STATUS_T mp4_read_box_soun_wave( VC_CONTAINER_T *p_ctx, int64_t size );
188
189static struct {
190 const MP4_BOX_TYPE_T type;
191 VC_CONTAINER_STATUS_T (*pf_func)( VC_CONTAINER_T *, int64_t );
192 const MP4_BOX_TYPE_T parent_type;
193} mp4_box_list[] =
194{
195 {MP4_BOX_TYPE_FTYP, mp4_read_box_ftyp, MP4_BOX_TYPE_ROOT},
196 {MP4_BOX_TYPE_MDAT, 0, MP4_BOX_TYPE_ROOT},
197 {MP4_BOX_TYPE_MOOV, mp4_read_box_moov, MP4_BOX_TYPE_ROOT},
198 {MP4_BOX_TYPE_MVHD, mp4_read_box_mvhd, MP4_BOX_TYPE_MOOV},
199 {MP4_BOX_TYPE_TRAK, mp4_read_box_trak, MP4_BOX_TYPE_MOOV},
200 {MP4_BOX_TYPE_TKHD, mp4_read_box_tkhd, MP4_BOX_TYPE_TRAK},
201 {MP4_BOX_TYPE_MDIA, mp4_read_box_mdia, MP4_BOX_TYPE_TRAK},
202 {MP4_BOX_TYPE_MDHD, mp4_read_box_mdhd, MP4_BOX_TYPE_MDIA},
203 {MP4_BOX_TYPE_HDLR, mp4_read_box_hdlr, MP4_BOX_TYPE_MDIA},
204 {MP4_BOX_TYPE_MINF, mp4_read_box_minf, MP4_BOX_TYPE_MDIA},
205 {MP4_BOX_TYPE_VMHD, mp4_read_box_vmhd, MP4_BOX_TYPE_MINF},
206 {MP4_BOX_TYPE_SMHD, mp4_read_box_smhd, MP4_BOX_TYPE_MINF},
207 {MP4_BOX_TYPE_DINF, mp4_read_box_dinf, MP4_BOX_TYPE_MINF},
208 {MP4_BOX_TYPE_DREF, mp4_read_box_dref, MP4_BOX_TYPE_DINF},
209 {MP4_BOX_TYPE_STBL, mp4_read_box_stbl, MP4_BOX_TYPE_MINF},
210 {MP4_BOX_TYPE_STSD, mp4_read_box_stsd, MP4_BOX_TYPE_STBL},
211 {MP4_BOX_TYPE_STTS, mp4_read_box_stts, MP4_BOX_TYPE_STBL},
212 {MP4_BOX_TYPE_CTTS, mp4_read_box_ctts, MP4_BOX_TYPE_STBL},
213 {MP4_BOX_TYPE_STSC, mp4_read_box_stsc, MP4_BOX_TYPE_STBL},
214 {MP4_BOX_TYPE_STSZ, mp4_read_box_stsz, MP4_BOX_TYPE_STBL},
215 {MP4_BOX_TYPE_STCO, mp4_read_box_stco, MP4_BOX_TYPE_STBL},
216 {MP4_BOX_TYPE_CO64, mp4_read_box_co64, MP4_BOX_TYPE_STBL},
217 {MP4_BOX_TYPE_STSS, mp4_read_box_stss, MP4_BOX_TYPE_STBL},
218 {MP4_BOX_TYPE_VIDE, mp4_read_box_vide, MP4_BOX_TYPE_STSD},
219 {MP4_BOX_TYPE_SOUN, mp4_read_box_soun, MP4_BOX_TYPE_STSD},
220 {MP4_BOX_TYPE_TEXT, mp4_read_box_text, MP4_BOX_TYPE_STSD},
221
222 /* Codec specific boxes */
223 {MP4_BOX_TYPE_AVCC, mp4_read_box_vide_avcC, MP4_BOX_TYPE_VIDE},
224 {MP4_BOX_TYPE_D263, mp4_read_box_vide_d263, MP4_BOX_TYPE_VIDE},
225 {MP4_BOX_TYPE_ESDS, mp4_read_box_esds, MP4_BOX_TYPE_VIDE},
226 {MP4_BOX_TYPE_DAMR, mp4_read_box_soun_damr, MP4_BOX_TYPE_SOUN},
227 {MP4_BOX_TYPE_DAWP, mp4_read_box_soun_dawp, MP4_BOX_TYPE_SOUN},
228 {MP4_BOX_TYPE_DEVC, mp4_read_box_soun_devc, MP4_BOX_TYPE_SOUN},
229 {MP4_BOX_TYPE_WAVE, mp4_read_box_soun_wave, MP4_BOX_TYPE_SOUN},
230 {MP4_BOX_TYPE_ESDS, mp4_read_box_esds, MP4_BOX_TYPE_SOUN},
231
232 {MP4_BOX_TYPE_UNKNOWN, 0, MP4_BOX_TYPE_UNKNOWN}
233};
234
235static struct {
236 const VC_CONTAINER_FOURCC_T type;
237 const VC_CONTAINER_FOURCC_T codec;
238 bool batch;
239} mp4_codec_mapping[] =
240{
241 {VC_FOURCC('a','v','c','1'), VC_CONTAINER_CODEC_H264, 0},
242 {VC_FOURCC('m','p','4','v'), VC_CONTAINER_CODEC_MP4V, 0},
243 {VC_FOURCC('s','2','6','3'), VC_CONTAINER_CODEC_H263, 0},
244 {VC_FOURCC('m','p','e','g'), VC_CONTAINER_CODEC_MP2V, 0},
245 {VC_FOURCC('m','j','p','a'), VC_CONTAINER_CODEC_MJPEGA, 0},
246 {VC_FOURCC('m','j','p','b'), VC_CONTAINER_CODEC_MJPEGB, 0},
247
248 {VC_FOURCC('j','p','e','g'), VC_CONTAINER_CODEC_JPEG, 0},
249
250 {VC_FOURCC('m','p','4','a'), VC_CONTAINER_CODEC_MP4A, 0},
251 {VC_FOURCC('s','a','m','r'), VC_CONTAINER_CODEC_AMRNB, 0},
252 {VC_FOURCC('s','a','w','b'), VC_CONTAINER_CODEC_AMRWB, 0},
253 {VC_FOURCC('s','a','w','p'), VC_CONTAINER_CODEC_AMRWBP, 0},
254 {VC_FOURCC('a','c','-','3'), VC_CONTAINER_CODEC_AC3, 0},
255 {VC_FOURCC('e','c','-','3'), VC_CONTAINER_CODEC_EAC3, 0},
256 {VC_FOURCC('s','e','v','c'), VC_CONTAINER_CODEC_EVRC, 0},
257 {VC_FOURCC('e','v','r','c'), VC_CONTAINER_CODEC_EVRC, 0},
258 {VC_FOURCC('s','q','c','p'), VC_CONTAINER_CODEC_QCELP, 0},
259 {VC_FOURCC('a','l','a','w'), VC_CONTAINER_CODEC_ALAW, 1},
260 {VC_FOURCC('u','l','a','w'), VC_CONTAINER_CODEC_MULAW, 1},
261 {VC_FOURCC('t','w','o','s'), VC_CONTAINER_CODEC_PCM_SIGNED_BE, 1},
262 {VC_FOURCC('s','o','w','t'), VC_CONTAINER_CODEC_PCM_SIGNED_LE, 1},
263
264 {0, 0},
265};
266static VC_CONTAINER_FOURCC_T mp4_box_type_to_codec(VC_CONTAINER_FOURCC_T type)
267{
268 int i;
269 for(i = 0; mp4_codec_mapping[i].type; i++ )
270 if(mp4_codec_mapping[i].type == type) break;
271 return mp4_codec_mapping[i].codec;
272}
273
274static bool codec_needs_batch_mode(VC_CONTAINER_FOURCC_T codec)
275{
276 int i;
277 for(i = 0; mp4_codec_mapping[i].codec; i++ )
278 if(mp4_codec_mapping[i].codec == codec) break;
279 return mp4_codec_mapping[i].batch;
280}
281
282/*****************************************************************************/
283static VC_CONTAINER_STATUS_T mp4_read_box_header( VC_CONTAINER_T *p_ctx, int64_t size,
284 MP4_BOX_TYPE_T *box_type, int64_t *box_size )
285{
286 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
287 int64_t offset = STREAM_POSITION(p_ctx);
288
289 module->box_offset = offset;
290
291 *box_size = _READ_U32(p_ctx);
292 *box_type = _READ_FOURCC(p_ctx);
293 if(!*box_type) return VC_CONTAINER_ERROR_CORRUPTED;
294
295 if(*box_size == 1) *box_size = _READ_U64(p_ctx);
296 LOG_FORMAT(p_ctx, "- Box %4.4s, Size: %"PRIi64", Offset: %"PRIi64,
297 (const char *)box_type, *box_size, offset);
298
299 /* Sanity check the box size */
300 if(*box_size < 0 /* Shouldn't ever get that big */ ||
301 /* Only the mdat box can really be massive */
302 (*box_type != MP4_BOX_TYPE_MDAT && *box_size > MP4_MAX_BOX_SIZE))
303 {
304 LOG_DEBUG(p_ctx, "box %4.4s has an invalid size (%"PRIi64")",
305 (const char *)box_type, *box_size);
306 return VC_CONTAINER_ERROR_CORRUPTED;
307 }
308
309#if 0
310 /* It is valid for a box to have a zero size (i.e unknown) if it is the last one */
311 if(*box_size == 0 && size >= 0) *box_size = size;
312 else if(*box_size == 0) *box_size = INT64_C(-1);
313#else
314 if(*box_size <= 0)
315 {
316 LOG_DEBUG(p_ctx, "box %4.4s has an invalid size (%"PRIi64")",
317 (const char *)box_type, *box_size);
318 return VC_CONTAINER_ERROR_CORRUPTED;
319 }
320#endif
321
322 /* Sanity check box size against parent */
323 if(size >= 0 && *box_size > size)
324 {
325 LOG_DEBUG(p_ctx, "box %4.4s is bigger than it should (%"PRIi64" > %"PRIi64")",
326 (const char *)box_type, *box_size, size);
327 return VC_CONTAINER_ERROR_CORRUPTED;
328 }
329
330 *box_size -= (STREAM_POSITION(p_ctx) - offset);
331 return STREAM_STATUS(p_ctx);
332}
333
334/*****************************************************************************/
335static VC_CONTAINER_STATUS_T mp4_read_box_data( VC_CONTAINER_T *p_ctx,
336 MP4_BOX_TYPE_T box_type, int64_t box_size, MP4_BOX_TYPE_T parent_type )
337{
338 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
339 int64_t offset = STREAM_POSITION(p_ctx);
340 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
341 unsigned int i;
342
343 /* Check if the box is a recognised one */
344 for(i = 0; mp4_box_list[i].type; i++)
345 if(mp4_box_list[i].type == box_type &&
346 mp4_box_list[i].parent_type == parent_type) break;
347 if(mp4_box_list[i].type == MP4_BOX_TYPE_UNKNOWN)
348 for(i = 0; mp4_box_list[i].type; i++)
349 if(mp4_box_list[i].type == box_type) break;
350
351 /* Sanity check that the box has the right parent */
352 if(mp4_box_list[i].type != MP4_BOX_TYPE_UNKNOWN &&
353 mp4_box_list[i].parent_type != MP4_BOX_TYPE_UNKNOWN &&
354 parent_type != MP4_BOX_TYPE_UNKNOWN && parent_type != mp4_box_list[i].parent_type)
355 {
356 LOG_FORMAT(p_ctx, "Ignoring mis-placed box %4.4s", (const char *)&box_type);
357 goto skip;
358 }
359
360 /* Sanity check that the element isn't too deeply nested */
361 if(module->box_level >= 2 * MP4_MAX_BOX_LEVEL)
362 {
363 LOG_DEBUG(p_ctx, "box %4.4s is too deep. skipping", (const char *)&box_type);
364 goto skip;
365 }
366
367 module->box_level++;
368
369 /* Call the box specific parsing function */
370 if(mp4_box_list[i].pf_func)
371 status = mp4_box_list[i].pf_func(p_ctx, box_size);
372
373 module->box_level--;
374
375 if(status != VC_CONTAINER_SUCCESS)
376 LOG_DEBUG(p_ctx, "box %4.4s appears to be corrupted (%i)", (const char *)&box_type, status);
377
378 skip:
379 /* Skip the rest of the box */
380 box_size -= (STREAM_POSITION(p_ctx) - offset);
381 if(box_size < 0) /* Check for overruns */
382 {
383 /* Things have gone really bad here and we ended up reading past the end of the
384 * box. We could maybe try to be clever and recover by seeking back to the end
385 * of the box. However if we get there, the file is clearly corrupted so there's
386 * no guarantee it would work anyway. */
387 LOG_DEBUG(p_ctx, "%"PRIi64" bytes overrun past the end of box %4.4s",
388 -box_size, (const char *)&box_type);
389 return VC_CONTAINER_ERROR_CORRUPTED;
390 }
391
392 if(box_size)
393 LOG_FORMAT(p_ctx, "%"PRIi64" bytes left unread in box %4.4s",
394 box_size, (const char *)&box_type );
395
396 if(box_size < MP4_MAX_BOX_SIZE) box_size = SKIP_BYTES(p_ctx, box_size);
397 else SEEK(p_ctx, STREAM_POSITION(p_ctx) + box_size);
398
399 return STREAM_STATUS(p_ctx);
400}
401
402/*****************************************************************************/
403static VC_CONTAINER_STATUS_T mp4_read_box( VC_CONTAINER_T *p_ctx, int64_t size,
404 MP4_BOX_TYPE_T parent_type )
405{
406 VC_CONTAINER_STATUS_T status;
407 MP4_BOX_TYPE_T box_type;
408 int64_t box_size;
409
410 status = mp4_read_box_header( p_ctx, size, &box_type, &box_size );
411 if(status != VC_CONTAINER_SUCCESS) return status;
412 return mp4_read_box_data( p_ctx, box_type, box_size, parent_type );
413}
414
415/*****************************************************************************/
416static VC_CONTAINER_STATUS_T mp4_read_boxes( VC_CONTAINER_T *p_ctx, int64_t size,
417 MP4_BOX_TYPE_T type)
418{
419 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
420 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
421 int64_t offset = STREAM_POSITION(p_ctx);
422 bool unknown_size = size < 0;
423
424 /* Read contained boxes */
425 module->box_level++;
426 while(status == VC_CONTAINER_SUCCESS &&
427 (unknown_size || size >= MP4_BOX_MIN_HEADER_SIZE))
428 {
429 offset = STREAM_POSITION(p_ctx);
430 status = mp4_read_box(p_ctx, size, type);
431 if(!unknown_size) size -= (STREAM_POSITION(p_ctx) - offset);
432 }
433 module->box_level--;
434 return status;
435}
436
437/*****************************************************************************/
438static VC_CONTAINER_STATUS_T mp4_read_box_ftyp( VC_CONTAINER_T *p_ctx, int64_t size )
439{
440 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
441
442 module->brand = MP4_READ_FOURCC(p_ctx, "major_brand");
443 MP4_SKIP_U32(p_ctx, "minor_version");
444 while(size >= 4) MP4_SKIP_FOURCC(p_ctx, "compatible_brands");
445
446 return STREAM_STATUS(p_ctx);
447}
448
449/*****************************************************************************/
450static VC_CONTAINER_STATUS_T mp4_read_box_moov( VC_CONTAINER_T *p_ctx, int64_t size )
451{
452 return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_MOOV);
453}
454
455/*****************************************************************************/
456static VC_CONTAINER_STATUS_T mp4_read_box_mvhd( VC_CONTAINER_T *p_ctx, int64_t size )
457{
458 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
459 uint32_t version, i;
460 int64_t duration;
461
462 version = MP4_READ_U8(p_ctx, "version");
463 MP4_SKIP_U24(p_ctx, "flags");
464
465 if(version)
466 {
467 MP4_SKIP_U64(p_ctx, "creation_time");
468 MP4_SKIP_U64(p_ctx, "modification_time");
469 module->timescale = MP4_READ_U32(p_ctx, "timescale");
470 duration = MP4_READ_U64(p_ctx, "duration");
471 }
472 else
473 {
474 MP4_SKIP_U32(p_ctx, "creation_time");
475 MP4_SKIP_U32(p_ctx, "modification_time");
476 module->timescale = MP4_READ_U32(p_ctx, "timescale");
477 duration = MP4_READ_U32(p_ctx, "duration");
478 }
479
480 if(module->timescale)
481 p_ctx->duration = duration * 1000000 / module->timescale;
482
483 MP4_SKIP_U32(p_ctx, "rate");
484 MP4_SKIP_U16(p_ctx, "volume");
485 MP4_SKIP_U16(p_ctx, "reserved");
486 for(i = 0; i < 2; i++) MP4_SKIP_U32(p_ctx, "reserved");
487 for(i = 0; i < 9; i++) MP4_SKIP_U32(p_ctx, "matrix");
488 for(i = 0; i < 6; i++) MP4_SKIP_U32(p_ctx, "pre_defined");
489 MP4_SKIP_U32(p_ctx, "next_track_ID");
490
491 return STREAM_STATUS(p_ctx);
492}
493
494/*****************************************************************************/
495static VC_CONTAINER_STATUS_T mp4_read_box_trak( VC_CONTAINER_T *p_ctx, int64_t size )
496{
497 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
498 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
499 VC_CONTAINER_TRACK_T *track;
500
501 /* We have a new track. Allocate and initialise our track context */
502 if(p_ctx->tracks_num >= MP4_TRACKS_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
503 p_ctx->tracks[p_ctx->tracks_num] = track =
504 vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
505 if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
506
507 track->priv->module->sample_table[MP4_SAMPLE_TABLE_STTS].entry_size = 8;
508 track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSZ].entry_size = 4;
509 track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSC].entry_size = 12;
510 track->priv->module->sample_table[MP4_SAMPLE_TABLE_STCO].entry_size = 4;
511 track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSS].entry_size = 4;
512 track->priv->module->sample_table[MP4_SAMPLE_TABLE_CO64].entry_size = 8;
513 track->priv->module->sample_table[MP4_SAMPLE_TABLE_CTTS].entry_size = 8;
514
515 status = mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_TRAK);
516
517 /* TODO: Sanity check track */
518
519 track->is_enabled = true;
520 track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
521 module->current_track++;
522 p_ctx->tracks_num++;
523
524 return status;
525}
526
527/*****************************************************************************/
528static VC_CONTAINER_STATUS_T mp4_read_box_tkhd( VC_CONTAINER_T *p_ctx, int64_t size )
529{
530 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
531 uint32_t i, version;
532 int64_t duration;
533
534 version = MP4_READ_U8(p_ctx, "version");
535 MP4_SKIP_U24(p_ctx, "flags");
536
537 if(version)
538 {
539 MP4_SKIP_U64(p_ctx, "creation_time");
540 MP4_SKIP_U64(p_ctx, "modification_time");
541 MP4_SKIP_U32(p_ctx, "track_ID");
542 MP4_SKIP_U32(p_ctx, "reserved");
543 duration = MP4_READ_U64(p_ctx, "duration");
544 }
545 else
546 {
547 MP4_SKIP_U32(p_ctx, "creation_time");
548 MP4_SKIP_U32(p_ctx, "modification_time");
549 MP4_SKIP_U32(p_ctx, "track_ID");
550 MP4_SKIP_U32(p_ctx, "reserved");
551 duration = MP4_READ_U32(p_ctx, "duration");
552 }
553
554 if(module->timescale)
555 duration = duration * 1000000 / module->timescale;
556
557 for(i = 0; i < 2; i++) MP4_SKIP_U32(p_ctx, "reserved");
558 MP4_SKIP_U16(p_ctx, "layer");
559 MP4_SKIP_U16(p_ctx, "alternate_group");
560 MP4_SKIP_U16(p_ctx, "volume");
561 MP4_SKIP_U16(p_ctx, "reserved");
562 for(i = 0; i < 9; i++) MP4_SKIP_U32(p_ctx, "matrix");
563
564 MP4_SKIP_U32(p_ctx, "width");
565 MP4_SKIP_U32(p_ctx, "height");
566
567 return STREAM_STATUS(p_ctx);
568}
569
570/*****************************************************************************/
571static VC_CONTAINER_STATUS_T mp4_read_box_mdia( VC_CONTAINER_T *p_ctx, int64_t size )
572{
573 return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_MDIA);
574}
575
576/*****************************************************************************/
577static VC_CONTAINER_STATUS_T mp4_read_box_mdhd( VC_CONTAINER_T *p_ctx, int64_t size )
578{
579 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
580 VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
581 uint32_t version, timescale;
582 int64_t duration;
583
584 version = MP4_READ_U8(p_ctx, "version");
585 MP4_SKIP_U24(p_ctx, "flags");
586
587 if(version)
588 {
589 MP4_SKIP_U64(p_ctx, "creation_time");
590 MP4_SKIP_U64(p_ctx, "modification_time");
591 timescale = MP4_READ_U32(p_ctx, "timescale");
592 duration = MP4_READ_U64(p_ctx, "duration");
593 }
594 else
595 {
596 MP4_SKIP_U32(p_ctx, "creation_time");
597 MP4_SKIP_U32(p_ctx, "modification_time");
598 timescale = MP4_READ_U32(p_ctx, "timescale");
599 duration = MP4_READ_U32(p_ctx, "duration");
600 }
601
602 if(timescale) duration = duration * 1000000 / timescale;
603 track_module->timescale = timescale;
604
605 MP4_SKIP_U16(p_ctx, "language"); /* ISO-639-2/T language code */
606 MP4_SKIP_U16(p_ctx, "pre_defined");
607
608 return STREAM_STATUS(p_ctx);
609}
610
611/*****************************************************************************/
612static VC_CONTAINER_STATUS_T mp4_read_box_hdlr( VC_CONTAINER_T *p_ctx, int64_t size )
613{
614 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
615 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
616 uint32_t i, fourcc, string_size;
617 VC_CONTAINER_ES_TYPE_T es_type = VC_CONTAINER_ES_TYPE_UNKNOWN;
618
619 if(size <= 24) return VC_CONTAINER_ERROR_CORRUPTED;
620
621 MP4_SKIP_U8(p_ctx, "version");
622 MP4_SKIP_U24(p_ctx, "flags");
623
624 MP4_SKIP_U32(p_ctx, "pre-defined");
625
626 fourcc = MP4_READ_FOURCC(p_ctx, "handler_type");
627 if(fourcc == MP4_BOX_TYPE_VIDE) es_type = VC_CONTAINER_ES_TYPE_VIDEO;
628 if(fourcc == MP4_BOX_TYPE_SOUN) es_type = VC_CONTAINER_ES_TYPE_AUDIO;
629 if(fourcc == MP4_BOX_TYPE_TEXT) es_type = VC_CONTAINER_ES_TYPE_SUBPICTURE;
630 track->format->es_type = es_type;
631
632 for(i = 0; i < 3; i++) MP4_SKIP_U32(p_ctx, "reserved");
633
634 string_size = size;
635 if(module->brand == MP4_BRAND_QT)
636 string_size = MP4_READ_U8(p_ctx, "string_size");
637
638 if(size < 0) return VC_CONTAINER_ERROR_CORRUPTED;
639 if(string_size > size) string_size = size;
640
641 MP4_SKIP_STRING(p_ctx, string_size, "name");
642
643 return STREAM_STATUS(p_ctx);
644}
645
646/*****************************************************************************/
647static VC_CONTAINER_STATUS_T mp4_read_box_minf( VC_CONTAINER_T *p_ctx, int64_t size )
648{
649 return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_MINF);
650}
651
652/*****************************************************************************/
653static VC_CONTAINER_STATUS_T mp4_read_box_vmhd( VC_CONTAINER_T *p_ctx, int64_t size )
654{
655 MP4_SKIP_U8(p_ctx, "version");
656 MP4_SKIP_U24(p_ctx, "flags");
657
658 MP4_SKIP_U16(p_ctx, "graphicsmode");
659 MP4_SKIP_U16(p_ctx, "opcolor");
660 MP4_SKIP_U16(p_ctx, "opcolor");
661 MP4_SKIP_U16(p_ctx, "opcolor");
662
663 return STREAM_STATUS(p_ctx);
664}
665
666/*****************************************************************************/
667static VC_CONTAINER_STATUS_T mp4_read_box_smhd( VC_CONTAINER_T *p_ctx, int64_t size )
668{
669 MP4_SKIP_U8(p_ctx, "version");
670 MP4_SKIP_U24(p_ctx, "flags");
671
672 MP4_SKIP_U16(p_ctx, "balance");
673 MP4_SKIP_U16(p_ctx, "reserved");
674
675 return STREAM_STATUS(p_ctx);
676}
677
678/*****************************************************************************/
679static VC_CONTAINER_STATUS_T mp4_read_box_dinf( VC_CONTAINER_T *p_ctx, int64_t size )
680{
681 return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_DINF);
682}
683
684/*****************************************************************************/
685static VC_CONTAINER_STATUS_T mp4_read_box_dref( VC_CONTAINER_T *p_ctx, int64_t size )
686{
687 MP4_SKIP_U8(p_ctx, "version");
688 MP4_SKIP_U24(p_ctx, "flags");
689
690 MP4_SKIP_U32(p_ctx, "entry_count");
691
692 return STREAM_STATUS(p_ctx);
693}
694
695/*****************************************************************************/
696static VC_CONTAINER_STATUS_T mp4_read_box_stbl( VC_CONTAINER_T *p_ctx, int64_t size )
697{
698 return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_STBL);
699}
700
701/*****************************************************************************/
702static VC_CONTAINER_STATUS_T mp4_read_box_stsd( VC_CONTAINER_T *p_ctx, int64_t size )
703{
704 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
705 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
706 VC_CONTAINER_STATUS_T status;
707 MP4_BOX_TYPE_T box_type;
708 int64_t box_size;
709 uint32_t count;
710
711 MP4_SKIP_U8(p_ctx, "version");
712 MP4_SKIP_U24(p_ctx, "flags");
713
714 count = MP4_READ_U32(p_ctx, "entry_count");
715 if(!count) return VC_CONTAINER_ERROR_CORRUPTED;
716
717 status = mp4_read_box_header( p_ctx, size, &box_type, &box_size );
718 if(status != VC_CONTAINER_SUCCESS) return status;
719
720 track->format->codec = mp4_box_type_to_codec(box_type);
721 if(!track->format->codec) track->format->codec = box_type;
722
723 if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO) box_type = MP4_BOX_TYPE_VIDE;
724 if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO) box_type = MP4_BOX_TYPE_SOUN;
725 if(track->format->es_type == VC_CONTAINER_ES_TYPE_SUBPICTURE) box_type = MP4_BOX_TYPE_TEXT;
726 status = mp4_read_box_data( p_ctx, box_type, box_size, MP4_BOX_TYPE_STSD );
727 if(status != VC_CONTAINER_SUCCESS) return status;
728
729 /* Special treatment for MPEG4 */
730 if(track->format->codec == VC_CONTAINER_CODEC_MP4A)
731 {
732 switch (track->priv->module->object_type_indication)
733 {
734 case MP4_MPEG4_AAC_LC_OBJECT_TYPE:
735 case MP4_MPEG2_AAC_LC_OBJECT_TYPE:
736 track->format->codec = VC_CONTAINER_CODEC_MP4A; break;
737 case MP4_MP3_OBJECT_TYPE:
738 case MP4_MPEG1_AUDIO_OBJECT_TYPE:
739 case MP4_KTF_MP3_OBJECT_TYPE:
740 track->format->codec = VC_CONTAINER_CODEC_MPGA; break;
741 case MP4_SKT_EVRC_2V1_OBJECT_TYPE:
742 case MP4_SKT_EVRC_OBJECT_TYPE:
743 track->format->codec = VC_CONTAINER_CODEC_EVRC; break;
744 case MP4_3GPP2_QCELP_OBJECT_TYPE:
745 track->format->codec = VC_CONTAINER_CODEC_QCELP; break;
746 default:
747 track->format->codec = VC_CONTAINER_CODEC_UNKNOWN; break;
748 }
749 }
750 else if(track->format->codec == VC_CONTAINER_CODEC_MP4V)
751 {
752 switch (track->priv->module->object_type_indication)
753 {
754 case MP4_MPEG4_VISUAL_OBJECT_TYPE:
755 track->format->codec = VC_CONTAINER_CODEC_MP4V; break;
756 case MP4_JPEG_OBJECT_TYPE:
757 track->format->codec = VC_CONTAINER_CODEC_JPEG; break;
758 case MP4_MPEG2_SP_OBJECT_TYPE:
759 case MP4_MPEG2_SNR_OBJECT_TYPE:
760 case MP4_MPEG2_AAC_LC_OBJECT_TYPE:
761 case MP4_MPEG2_MP_OBJECT_TYPE:
762 track->format->codec = VC_CONTAINER_CODEC_MP2V; break;
763 case MP4_MPEG1_VISUAL_OBJECT_TYPE:
764 track->format->codec = VC_CONTAINER_CODEC_MP1V; break;
765 default:
766 track->format->codec = VC_CONTAINER_CODEC_UNKNOWN; break;
767 }
768 }
769
770 /* For some codecs we process the samples in batches to be more efficient */
771 if(codec_needs_batch_mode(track->format->codec))
772 track->priv->module->samples_batch_size = MP4_MAX_SAMPLES_BATCH_SIZE;
773
774 /* Fix-up some of the data */
775 switch(track->format->codec)
776 {
777 case VC_CONTAINER_CODEC_ALAW:
778 case VC_CONTAINER_CODEC_MULAW:
779 track->format->type->audio.bits_per_sample = 8;
780 track->priv->module->sample_size = track->format->type->audio.channels;
781 break;
782 case VC_CONTAINER_CODEC_PCM_SIGNED_LE:
783 case VC_CONTAINER_CODEC_PCM_SIGNED_BE:
784 track->priv->module->sample_size = (track->format->type->audio.bits_per_sample + 7) /
785 8 * track->format->type->audio.channels;
786 break;
787 case VC_CONTAINER_CODEC_MP4A:
788 /* samplerate / channels is sometimes invalid so sanity check it using the codec config data */
789 if(track->format->extradata_size >= 2)
790 {
791 static unsigned int rate[] =
792 { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
793 16000, 12000, 11025, 8000, 7350 };
794 unsigned int samplerate = 0, channels = 0;
795 uint8_t *p = track->format->extradata;
796 uint32_t index = (p[0] & 7) << 1 | (p[1] >> 7);
797 if(index == 15 && track->format->extradata_size >= 5)
798 {
799 samplerate = (p[1] & 0x7f) << 17 | (p[2] << 9) | (p[3] << 1) | (p[4] >> 7);
800 channels = (p[4] >> 3) & 15;
801 }
802 else if(index < 13)
803 {
804 samplerate = rate[index];
805 channels = (p[1] >> 3) & 15;;
806 }
807
808 if(samplerate && samplerate != track->format->type->audio.sample_rate &&
809 2 * samplerate != track->format->type->audio.sample_rate)
810 track->format->type->audio.sample_rate = samplerate;
811 if(channels && channels != track->format->type->audio.channels &&
812 2 * channels != track->format->type->audio.channels)
813 track->format->type->audio.channels = channels;
814 }
815 break;
816 default: break;
817 }
818
819 return VC_CONTAINER_SUCCESS;
820}
821
822/*****************************************************************************/
823static VC_CONTAINER_STATUS_T mp4_cache_table( VC_CONTAINER_T *p_ctx, MP4_SAMPLE_TABLE_T table,
824 uint32_t entries, int64_t size )
825{
826 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
827 VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
828 uint32_t available_entries, entries_size;
829
830 if(size < 0) return VC_CONTAINER_ERROR_CORRUPTED;
831
832 track_module->sample_table[table].offset = STREAM_POSITION(p_ctx);
833 track_module->sample_table[table].entries = entries;
834
835 available_entries = size / track_module->sample_table[table].entry_size;
836 if(available_entries < entries)
837 {
838 LOG_DEBUG(p_ctx, "table has less entries than advertised (%i/%i)", available_entries, entries);
839 entries = available_entries;
840 }
841
842 entries_size = entries * track_module->sample_table[table].entry_size;
843 size = vc_container_io_cache(p_ctx->priv->io, entries_size );
844 if(size != entries_size)
845 {
846 available_entries = size / track_module->sample_table[table].entry_size;
847 LOG_DEBUG(p_ctx, "cached less table entries than advertised (%i/%i)", available_entries, entries);
848 track_module->sample_table[table].entries = available_entries;
849 }
850
851 return STREAM_STATUS(p_ctx);
852}
853
854/*****************************************************************************/
855static VC_CONTAINER_STATUS_T mp4_read_box_stts( VC_CONTAINER_T *p_ctx, int64_t size )
856{
857 uint32_t entries;
858
859 MP4_SKIP_U8(p_ctx, "version");
860 MP4_SKIP_U24(p_ctx, "flags");
861
862 entries = MP4_READ_U32(p_ctx, "entry_count");
863 return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STTS, entries, size );
864}
865
866/*****************************************************************************/
867static VC_CONTAINER_STATUS_T mp4_read_box_ctts( VC_CONTAINER_T *p_ctx, int64_t size )
868{
869 uint32_t entries;
870
871 MP4_SKIP_U8(p_ctx, "version");
872 MP4_SKIP_U24(p_ctx, "flags");
873
874 entries = MP4_READ_U32(p_ctx, "entry_count");
875 return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_CTTS, entries, size );
876}
877
878/*****************************************************************************/
879static VC_CONTAINER_STATUS_T mp4_read_box_stsc( VC_CONTAINER_T *p_ctx, int64_t size )
880{
881 uint32_t entries;
882
883 MP4_SKIP_U8(p_ctx, "version");
884 MP4_SKIP_U24(p_ctx, "flags");
885
886 entries = MP4_READ_U32(p_ctx, "entry_count");
887 return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STSC, entries, size );
888}
889
890/*****************************************************************************/
891static VC_CONTAINER_STATUS_T mp4_read_box_stsz( VC_CONTAINER_T *p_ctx, int64_t size )
892{
893 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
894 VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
895 uint32_t entries;
896
897 MP4_SKIP_U8(p_ctx, "version");
898 MP4_SKIP_U24(p_ctx, "flags");
899
900 track_module->sample_size = READ_U32(p_ctx, "sample_size");
901 if(track_module->sample_size) return STREAM_STATUS(p_ctx);
902
903 entries = MP4_READ_U32(p_ctx, "sample_count");
904 return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STSZ, entries, size );
905}
906
907/*****************************************************************************/
908static VC_CONTAINER_STATUS_T mp4_read_box_stco( VC_CONTAINER_T *p_ctx, int64_t size )
909{
910 uint32_t entries;
911
912 MP4_SKIP_U8(p_ctx, "version");
913 MP4_SKIP_U24(p_ctx, "flags");
914
915 entries = MP4_READ_U32(p_ctx, "entry_count");
916 return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STCO, entries, size );
917}
918
919/*****************************************************************************/
920static VC_CONTAINER_STATUS_T mp4_read_box_co64( VC_CONTAINER_T *p_ctx, int64_t size )
921{
922 uint32_t entries;
923
924 MP4_SKIP_U8(p_ctx, "version");
925 MP4_SKIP_U24(p_ctx, "flags");
926
927 entries = MP4_READ_U32(p_ctx, "entry_count");
928 return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_CO64, entries, size );
929}
930
931/*****************************************************************************/
932static VC_CONTAINER_STATUS_T mp4_read_box_stss( VC_CONTAINER_T *p_ctx, int64_t size )
933{
934 uint32_t entries;
935
936 MP4_SKIP_U8(p_ctx, "version");
937 MP4_SKIP_U24(p_ctx, "flags");
938
939 entries = MP4_READ_U32(p_ctx, "entry_count");
940 return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STSS, entries, size );
941}
942
943/*****************************************************************************/
944static VC_CONTAINER_STATUS_T mp4_read_esds_descriptor_header(VC_CONTAINER_T *p_ctx, int64_t *size,
945 uint32_t *descriptor_length, uint8_t *descriptor_type)
946{
947 uint32_t byte, length = 0;
948
949 if(*size <= 0) return VC_CONTAINER_ERROR_CORRUPTED;
950
951 *descriptor_type = _READ_U8(p_ctx);
952 (*size)--;
953
954 /* Read descriptor size */
955 while(*size)
956 {
957 byte = _READ_U8(p_ctx);
958 (*size)--;
959 length = (length << 7) | (byte&0x7F);
960 if(!(byte & 0x80)) break;
961 }
962
963 if(*size <= 0 || length > *size)
964 {
965 LOG_FORMAT(p_ctx, "esds descriptor is corrupted");
966 return VC_CONTAINER_ERROR_CORRUPTED;
967 }
968
969 *descriptor_length = length;
970 LOG_FORMAT(p_ctx, "esds descriptor %x, size %i", *descriptor_type, *descriptor_length);
971 return VC_CONTAINER_SUCCESS;
972}
973
974/*****************************************************************************/
975static VC_CONTAINER_STATUS_T mp4_read_box_esds( VC_CONTAINER_T *p_ctx, int64_t size )
976{
977 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
978 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
979 VC_CONTAINER_STATUS_T status;
980 uint32_t descriptor_length;
981 uint8_t descriptor_type;
982
983 MP4_SKIP_U8(p_ctx, "version");
984 MP4_SKIP_U24(p_ctx, "flags");
985
986 status = mp4_read_esds_descriptor_header(p_ctx, &size, &descriptor_length, &descriptor_type);
987 if(status != VC_CONTAINER_SUCCESS) return status;
988
989 if(descriptor_type == 0x3) /* ES descriptor */
990 {
991 uint8_t flags;
992
993 MP4_SKIP_U16(p_ctx, "es_id");
994 flags = MP4_READ_U8(p_ctx, "flags");
995
996 if(flags & 0x80) /* Stream dependence */
997 MP4_SKIP_U16(p_ctx, "depend_on_es_id");
998
999 if(flags & 0x40) /* URL */
1000 {
1001 uint32_t url_size = MP4_READ_U8(p_ctx, "url_size");
1002 MP4_SKIP_STRING(p_ctx, url_size, "url");
1003 }
1004
1005 if(flags & 0x20) /* OCR_stream*/
1006 MP4_SKIP_U16(p_ctx, "OCR_es_id");
1007
1008 status = mp4_read_esds_descriptor_header(p_ctx, &size, &descriptor_length, &descriptor_type);
1009 if(status != VC_CONTAINER_SUCCESS) return status;
1010 }
1011
1012 if(descriptor_type == 0x4) /* Decoder Config descriptor */
1013 {
1014 track->priv->module->object_type_indication = MP4_READ_U8(p_ctx, "object_type_indication");
1015 MP4_SKIP_U8(p_ctx, "stream_type");
1016 MP4_SKIP_U24(p_ctx, "buffer_size_db");
1017 MP4_SKIP_U32(p_ctx, "max_bitrate");
1018 track->format->bitrate = MP4_READ_U32(p_ctx, "avg_bitrate");
1019
1020 if(size <= 0 || descriptor_length <= 13) return STREAM_STATUS(p_ctx);
1021
1022 status = mp4_read_esds_descriptor_header(p_ctx, &size, &descriptor_length, &descriptor_type);
1023 if(status != VC_CONTAINER_SUCCESS) return status;
1024 if(descriptor_type == 0x05 && descriptor_length)
1025 {
1026 status = vc_container_track_allocate_extradata(p_ctx, track, descriptor_length);
1027 if(status != VC_CONTAINER_SUCCESS) return status;
1028 track->format->extradata_size = MP4_READ_BYTES(p_ctx, track->format->extradata, descriptor_length);
1029 }
1030 }
1031
1032 return STREAM_STATUS(p_ctx);
1033}
1034
1035/*****************************************************************************/
1036static VC_CONTAINER_STATUS_T mp4_read_box_vide( VC_CONTAINER_T *p_ctx, int64_t size )
1037{
1038 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1039 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
1040 unsigned int i;
1041
1042 for(i = 0; i < 6; i++) MP4_SKIP_U8(p_ctx, "reserved");
1043 MP4_SKIP_U16(p_ctx, "data_reference_index");
1044
1045 MP4_SKIP_U16(p_ctx, "pre_defined");
1046 MP4_SKIP_U16(p_ctx, "reserved");
1047 for(i = 0; i < 3; i++) MP4_SKIP_U32(p_ctx, "pre_defined");
1048 track->format->type->video.width = MP4_READ_U16(p_ctx, "width");
1049 track->format->type->video.height = MP4_READ_U16(p_ctx, "height");
1050 MP4_SKIP_U32(p_ctx, "horizresolution"); /* dpi */
1051 MP4_SKIP_U32(p_ctx, "vertresolution"); /* dpi */
1052 MP4_SKIP_U32(p_ctx, "reserved");
1053 MP4_SKIP_U16(p_ctx, "frame_count");
1054 MP4_SKIP_BYTES(p_ctx, 32);
1055 MP4_SKIP_U16(p_ctx, "depth");
1056 MP4_SKIP_U16(p_ctx, "pre_defined");
1057
1058 if(size > 0)
1059 return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_VIDE );
1060
1061 return STREAM_STATUS(p_ctx);
1062}
1063
1064/*****************************************************************************/
1065static VC_CONTAINER_STATUS_T mp4_read_box_vide_avcC( VC_CONTAINER_T *p_ctx, int64_t size )
1066{
1067 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1068 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
1069 VC_CONTAINER_STATUS_T status;
1070
1071 if(track->format->codec != VC_CONTAINER_CODEC_H264 || size <= 0)
1072 return VC_CONTAINER_ERROR_CORRUPTED;
1073
1074 track->format->codec_variant = VC_FOURCC('a','v','c','C');
1075
1076 status = vc_container_track_allocate_extradata(p_ctx, track, (unsigned int)size);
1077 if(status != VC_CONTAINER_SUCCESS) return status;
1078 track->format->extradata_size = READ_BYTES(p_ctx, track->format->extradata, size);
1079
1080 return STREAM_STATUS(p_ctx);
1081}
1082
1083/*****************************************************************************/
1084static VC_CONTAINER_STATUS_T mp4_read_box_vide_d263( VC_CONTAINER_T *p_ctx, int64_t size )
1085{
1086 MP4_SKIP_FOURCC(p_ctx, "vendor");
1087 MP4_SKIP_U8(p_ctx, "version");
1088 MP4_SKIP_U8(p_ctx, "level");
1089 MP4_SKIP_U8(p_ctx, "profile");
1090 return STREAM_STATUS(p_ctx);
1091}
1092
1093/*****************************************************************************/
1094static VC_CONTAINER_STATUS_T mp4_read_box_soun( VC_CONTAINER_T *p_ctx, int64_t size )
1095{
1096 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1097 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
1098 unsigned int i, version = 0;
1099
1100 for(i = 0; i < 6; i++) MP4_SKIP_U8(p_ctx, "reserved");
1101 MP4_SKIP_U16(p_ctx, "data_reference_index");
1102
1103 version = MP4_READ_U16(p_ctx, "version");
1104 MP4_SKIP_U16(p_ctx, "revision_level");
1105 MP4_SKIP_U32(p_ctx, "vendor");
1106
1107 track->format->type->audio.channels = MP4_READ_U16(p_ctx, "channelcount");
1108 track->format->type->audio.bits_per_sample = MP4_READ_U16(p_ctx, "samplesize");
1109 MP4_SKIP_U16(p_ctx, "pre_defined");
1110 MP4_SKIP_U16(p_ctx, "reserved");
1111 track->format->type->audio.sample_rate = MP4_READ_U16(p_ctx, "samplerate");
1112 MP4_SKIP_U16(p_ctx, "samplerate_fp_low");
1113
1114 if(version == 1)
1115 {
1116 MP4_SKIP_U32(p_ctx, "samples_per_packet");
1117 MP4_SKIP_U32(p_ctx, "bytes_per_packet");
1118 MP4_SKIP_U32(p_ctx, "bytes_per_frame");
1119 MP4_SKIP_U32(p_ctx, "bytes_per_sample");
1120 }
1121
1122 if(size > 0)
1123 return mp4_read_box( p_ctx, size, MP4_BOX_TYPE_SOUN );
1124
1125 return STREAM_STATUS(p_ctx);
1126}
1127
1128/*****************************************************************************/
1129static VC_CONTAINER_STATUS_T mp4_read_box_soun_damr( VC_CONTAINER_T *p_ctx, int64_t size )
1130{
1131 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1132 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
1133
1134 MP4_SKIP_FOURCC(p_ctx, "vendor");
1135 MP4_SKIP_U8(p_ctx, "version");
1136 MP4_SKIP_U8(p_ctx, "mode_set");
1137 MP4_SKIP_U8(p_ctx, "mode_change_period");
1138 MP4_SKIP_U8(p_ctx, "frame_per_second");
1139
1140 track->format->type->audio.channels = 1;
1141 if(track->format->codec == VC_CONTAINER_CODEC_AMRNB)
1142 track->format->type->audio.sample_rate = 8000;
1143 else if(track->format->codec == VC_CONTAINER_CODEC_AMRWB)
1144 track->format->type->audio.sample_rate = 16000;
1145
1146 return STREAM_STATUS(p_ctx);
1147}
1148
1149/*****************************************************************************/
1150static VC_CONTAINER_STATUS_T mp4_read_box_soun_dawp( VC_CONTAINER_T *p_ctx, int64_t size )
1151{
1152 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1153 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
1154
1155 MP4_SKIP_FOURCC(p_ctx, "vendor");
1156 MP4_SKIP_U8(p_ctx, "version");
1157
1158 track->format->type->audio.channels = 2;
1159 track->format->type->audio.sample_rate = 16000;
1160
1161 return STREAM_STATUS(p_ctx);
1162}
1163
1164/*****************************************************************************/
1165static VC_CONTAINER_STATUS_T mp4_read_box_soun_devc( VC_CONTAINER_T *p_ctx, int64_t size )
1166{
1167 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1168 VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
1169
1170 MP4_SKIP_FOURCC(p_ctx, "vendor");
1171 MP4_SKIP_U8(p_ctx, "version");
1172 MP4_SKIP_U8(p_ctx, "samples_per_frame");
1173
1174 track->format->type->audio.channels = 1;
1175 track->format->type->audio.sample_rate = 8000;
1176
1177 return STREAM_STATUS(p_ctx);
1178}
1179
1180/*****************************************************************************/
1181static VC_CONTAINER_STATUS_T mp4_read_box_soun_wave( VC_CONTAINER_T *p_ctx, int64_t size )
1182{
1183 return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_SOUN);
1184}
1185
1186/*****************************************************************************/
1187static VC_CONTAINER_STATUS_T mp4_read_box_text( VC_CONTAINER_T *p_ctx, int64_t size )
1188{
1189 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1190 VC_CONTAINER_PARAM_UNUSED(module);
1191
1192 /* TODO */if(1) return VC_CONTAINER_ERROR_FAILED;
1193
1194 if(size > 0)
1195 return mp4_read_box( p_ctx, size, MP4_BOX_TYPE_TEXT );
1196
1197 return STREAM_STATUS(p_ctx);
1198}
1199
1200/*****************************************************************************/
1201static VC_CONTAINER_STATUS_T mp4_reader_close( VC_CONTAINER_T *p_ctx )
1202{
1203 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1204 unsigned int i;
1205
1206 for(i = 0; i < p_ctx->tracks_num; i++)
1207 vc_container_free_track(p_ctx, p_ctx->tracks[i]);
1208 free(module);
1209 return VC_CONTAINER_SUCCESS;
1210}
1211
1212/*****************************************************************************/
1213#ifdef ENABLE_MP4_READER_LOG_STATE
1214static void mp4_log_state( VC_CONTAINER_T *p_ctx, MP4_READER_STATE_T *state )
1215{
1216 VC_CONTAINER_PARAM_UNUSED(p_ctx);
1217
1218 LOG_DEBUG(p_ctx, "state:");
1219 LOG_DEBUG(p_ctx, "duration: %i, pts %i, dts %i", (int)state->duration,
1220 (int)state->pts, (int)state->dts);
1221 LOG_DEBUG(p_ctx, "sample: %i, offset %i, sample_offset %i, sample_size %i",
1222 state->sample, (int)state->offset, state->sample_offset,
1223 state->sample_size);
1224 LOG_DEBUG(p_ctx, "sample_duration: %i, count %i",
1225 state->sample_duration, state->sample_duration_count);
1226 LOG_DEBUG(p_ctx, "sample_composition_offset: %i, count %i",
1227 state->sample_composition_offset, state->sample_composition_count);
1228 LOG_DEBUG(p_ctx, "next_sync_sample: %i, keyframe %i",
1229 state->next_sync_sample, state->keyframe);
1230 LOG_DEBUG(p_ctx, "samples_per_chunk: %i, chunks %i, samples_in_chunk %i",
1231 state->samples_per_chunk, state->chunks, state->samples_in_chunk);
1232 LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_STTS %i", state->sample_table[MP4_SAMPLE_TABLE_STTS].entry);
1233 LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_STSZ %i", state->sample_table[MP4_SAMPLE_TABLE_STSZ].entry);
1234 LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_STSC %i", state->sample_table[MP4_SAMPLE_TABLE_STSC].entry);
1235 LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_STCO %i", state->sample_table[MP4_SAMPLE_TABLE_STCO].entry);
1236 LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_CO64 %i", state->sample_table[MP4_SAMPLE_TABLE_CO64].entry);
1237 LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_CTTS %i", state->sample_table[MP4_SAMPLE_TABLE_CTTS].entry);
1238}
1239#endif /* ENABLE_MP4_READER_LOG_STATE */
1240
1241/*****************************************************************************/
1242static VC_CONTAINER_STATUS_T mp4_seek_sample_table( VC_CONTAINER_T *p_ctx,
1243 VC_CONTAINER_TRACK_MODULE_T *track_module, MP4_READER_STATE_T *state,
1244 MP4_SAMPLE_TABLE_T table)
1245{
1246 int64_t seek_offset;
1247
1248 /* Seek to the next entry in the table */
1249 if(state->sample_table[table].entry >= track_module->sample_table[table].entries)
1250 return VC_CONTAINER_ERROR_EOS;
1251
1252 seek_offset = track_module->sample_table[table].offset +
1253 track_module->sample_table[table].entry_size * state->sample_table[table].entry;
1254
1255 return SEEK(p_ctx, seek_offset);
1256}
1257
1258/*****************************************************************************/
1259static VC_CONTAINER_STATUS_T mp4_read_sample_table( VC_CONTAINER_T *p_ctx,
1260 VC_CONTAINER_TRACK_MODULE_T *track_module, MP4_READER_STATE_T *state,
1261 MP4_SAMPLE_TABLE_T table, unsigned int seek)
1262{
1263 uint32_t value;
1264
1265 if(table == MP4_SAMPLE_TABLE_STSZ && track_module->sample_size)
1266 {
1267 state->sample_size = track_module->sample_size;
1268 return state->status;
1269 }
1270
1271 /* CO64 support */
1272 if(table == MP4_SAMPLE_TABLE_STCO &&
1273 track_module->sample_table[MP4_SAMPLE_TABLE_CO64].entries)
1274 table = MP4_SAMPLE_TABLE_CO64;
1275
1276 /* Seek to the next entry in the table */
1277 if(seek)
1278 {
1279 state->status = mp4_seek_sample_table( p_ctx, track_module, state, table );
1280 if(state->status != VC_CONTAINER_SUCCESS) return state->status;
1281 }
1282
1283 switch(table)
1284 {
1285 case MP4_SAMPLE_TABLE_STSZ:
1286 state->sample_size = _READ_U32(p_ctx);
1287 state->status = STREAM_STATUS(p_ctx);
1288 break;
1289
1290 case MP4_SAMPLE_TABLE_STTS:
1291 state->sample_duration_count = _READ_U32(p_ctx);
1292 state->sample_duration = _READ_U32(p_ctx);
1293 state->status = STREAM_STATUS(p_ctx);
1294 if(state->status != VC_CONTAINER_SUCCESS) break;
1295 if(!state->sample_duration_count) state->status = VC_CONTAINER_ERROR_CORRUPTED;
1296 break;
1297
1298 case MP4_SAMPLE_TABLE_CTTS:
1299 state->sample_composition_count = _READ_U32(p_ctx);
1300 state->sample_composition_offset = _READ_U32(p_ctx); /* Converted to signed */
1301 state->status = STREAM_STATUS(p_ctx);
1302 if(state->status != VC_CONTAINER_SUCCESS) break;
1303 if(!state->sample_composition_count) state->status = VC_CONTAINER_ERROR_CORRUPTED;
1304 break;
1305
1306 case MP4_SAMPLE_TABLE_STSC:
1307 state->chunks = _READ_U32(p_ctx);
1308 state->samples_per_chunk = _READ_U32(p_ctx);
1309 _SKIP_U32(p_ctx);
1310 state->status = STREAM_STATUS(p_ctx);
1311 if(state->status != VC_CONTAINER_SUCCESS) break;
1312
1313 if(state->sample_table[table].entry + 1 <
1314 track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entries) value = _READ_U32(p_ctx);
1315 else value = -1;
1316
1317 if(!state->chunks || !state->samples_per_chunk || state->chunks >= value )
1318 {state->status = VC_CONTAINER_ERROR_CORRUPTED; break;}
1319 state->chunks = value - state->chunks;
1320 state->samples_in_chunk = state->samples_per_chunk;
1321 break;
1322
1323 case MP4_SAMPLE_TABLE_STCO:
1324 case MP4_SAMPLE_TABLE_CO64:
1325 state->offset = table == MP4_SAMPLE_TABLE_STCO ? _READ_U32(p_ctx) : _READ_U64(p_ctx);
1326 state->status = STREAM_STATUS(p_ctx);
1327 if(state->status != VC_CONTAINER_SUCCESS) break;
1328 if(!state->offset) state->status = VC_CONTAINER_ERROR_CORRUPTED;
1329 state->samples_in_chunk = state->samples_per_chunk;
1330 break;
1331
1332 case MP4_SAMPLE_TABLE_STSS:
1333 state->next_sync_sample = _READ_U32(p_ctx);
1334 state->status = STREAM_STATUS(p_ctx);
1335 break;
1336
1337 default: break;
1338 }
1339
1340 state->sample_table[table].entry++;
1341 return state->status;
1342}
1343
1344/*****************************************************************************/
1345static VC_CONTAINER_STATUS_T mp4_read_sample_header( VC_CONTAINER_T *p_ctx, uint32_t track,
1346 MP4_READER_STATE_T *state )
1347{
1348 VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[track]->priv->module;
1349
1350 if(state->status != VC_CONTAINER_SUCCESS) return state->status;
1351
1352 if(state->sample_offset < state->sample_size)
1353 return state->status; /* We still have data left from the current sample */
1354
1355 /* Switch to the next sample */
1356 state->offset += state->sample_size;
1357 state->sample_offset = 0;
1358 state->sample_size = 0;
1359 state->sample++;
1360
1361 if(!state->samples_in_chunk)
1362 {
1363 /* We're switching to the next chunk */
1364 if(!state->chunks)
1365 {
1366 /* Seek to the next entry in the STSC */
1367 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSC, 1 );
1368 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1369 }
1370
1371 /* Get the offset of the new chunk */
1372 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STCO, 1 );
1373 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1374
1375 state->chunks--;
1376 }
1377 state->samples_in_chunk--;
1378
1379 /* Get the new sample size */
1380 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSZ, 1 );
1381 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1382
1383 /* Get the timestamp */
1384 if(track_module->timescale)
1385 state->pts = state->dts = state->duration * 1000000 / track_module->timescale;
1386 if(!state->sample_duration_count)
1387 {
1388 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STTS, 1 );
1389 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1390 }
1391 state->sample_duration_count--;
1392
1393 /* Get the composition time */
1394 if(track_module->sample_table[MP4_SAMPLE_TABLE_CTTS].entries)
1395 {
1396 if(!state->sample_composition_count)
1397 {
1398 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_CTTS, 1 );
1399 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1400 }
1401 if(track_module->timescale)
1402 state->pts = (state->duration + state->sample_composition_offset) * 1000000 / track_module->timescale;
1403 state->sample_composition_count--;
1404 }
1405 state->duration += state->sample_duration;
1406
1407 /* Get the keyframe flag */
1408 if(state->sample_table[MP4_SAMPLE_TABLE_STSS].entry <
1409 track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries &&
1410 !state->next_sync_sample)
1411 {
1412 mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSS, 1 );
1413 state->status = VC_CONTAINER_SUCCESS; /* This isn't a critical error */
1414 }
1415
1416 state->keyframe =
1417 track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries &&
1418 state->sample == state->next_sync_sample;
1419 if(state->keyframe)
1420 state->next_sync_sample = 0;
1421
1422 /* Try to batch several samples together if requested. We'll always stop at the chunk boundary */
1423 if(track_module->samples_batch_size)
1424 {
1425 uint32_t size = state->sample_size;
1426 while(state->samples_in_chunk && size < track_module->samples_batch_size)
1427 {
1428 if(mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSZ, 1 )) break;
1429
1430 if(!state->sample_duration_count)
1431 if(mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STTS, 1 )) break;
1432
1433 state->sample_duration_count--;
1434 state->duration += state->sample_duration;
1435
1436 size += state->sample_size;
1437 state->samples_in_chunk--;
1438 state->sample++;
1439 }
1440 state->sample_size = size;
1441 }
1442
1443#ifdef ENABLE_MP4_READER_LOG_STATE
1444 mp4_log_state(p_ctx, state);
1445#endif
1446
1447 error:
1448 return state->status;
1449}
1450
1451/*****************************************************************************/
1452static VC_CONTAINER_STATUS_T mp4_read_sample_data( VC_CONTAINER_T *p_ctx, uint32_t track,
1453 MP4_READER_STATE_T *state, uint8_t *data, unsigned int *data_size )
1454{
1455 VC_CONTAINER_STATUS_T status;
1456 unsigned int size = state->sample_size - state->sample_offset;
1457
1458 if(state->status != VC_CONTAINER_SUCCESS) return state->status;
1459
1460 if(data_size && *data_size < size) size = *data_size;
1461
1462 if(data)
1463 {
1464 state->status = SEEK(p_ctx, state->offset + state->sample_offset);
1465 if(state->status != VC_CONTAINER_SUCCESS) return state->status;
1466
1467 size = READ_BYTES(p_ctx, data, size);
1468 }
1469 state->sample_offset += size;
1470
1471 if(data_size) *data_size = size;
1472 state->status = STREAM_STATUS(p_ctx);
1473 if(state->status != VC_CONTAINER_SUCCESS) return state->status;
1474
1475 status = state->status;
1476
1477 /* Switch to the start of the next sample */
1478 if(state->sample_offset >= state->sample_size)
1479 mp4_read_sample_header(p_ctx, track, state);
1480
1481 return status;
1482}
1483
1484/*****************************************************************************/
1485static VC_CONTAINER_STATUS_T mp4_reader_read( VC_CONTAINER_T *p_ctx,
1486 VC_CONTAINER_PACKET_T *packet, uint32_t flags )
1487{
1488 VC_CONTAINER_TRACK_MODULE_T *track_module;
1489 VC_CONTAINER_STATUS_T status;
1490 MP4_READER_STATE_T *state;
1491 uint32_t i, track;
1492 unsigned int data_size;
1493 uint8_t *data = 0;
1494 int64_t offset;
1495
1496 /* Select the track to read from. If no specific track is requested by the caller, this
1497 * will be the track to which the next bit of data in the mdat belongs to */
1498 if(!(flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK))
1499 {
1500 for(i = 0, track = 0, offset = -1; i < p_ctx->tracks_num; i++)
1501 {
1502 track_module = p_ctx->tracks[i]->priv->module;
1503
1504 /* Ignore tracks which have no more readable data */
1505 if(track_module->state.status != VC_CONTAINER_SUCCESS) continue;
1506
1507 if(offset >= 0 && track_module->state.offset >= offset) continue;
1508 offset = track_module->state.offset;
1509 track = i;
1510 }
1511 }
1512 else track = packet->track;
1513
1514 if(track >= p_ctx->tracks_num) return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
1515
1516 track_module = p_ctx->tracks[track]->priv->module;
1517 state = &track_module->state;
1518
1519 status = mp4_read_sample_header(p_ctx, track, state);
1520 if(status != VC_CONTAINER_SUCCESS) return status;
1521
1522 if(!packet) /* Skip packet */
1523 return mp4_read_sample_data(p_ctx, track, state, 0, 0);
1524
1525 packet->dts = state->dts;
1526 packet->pts = state->pts;
1527 packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
1528 if(state->keyframe) packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
1529 if(!state->sample_offset) packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
1530 packet->track = track;
1531 packet->frame_size = state->sample_size;
1532 packet->size = state->sample_size - state->sample_offset;
1533
1534 if(flags & VC_CONTAINER_READ_FLAG_SKIP)
1535 return mp4_read_sample_data(p_ctx, track, state, 0, 0);
1536 else if((flags & VC_CONTAINER_READ_FLAG_INFO) || !packet->data)
1537 return VC_CONTAINER_SUCCESS;
1538
1539 data = packet->data;
1540 data_size = packet->buffer_size;
1541
1542 status = mp4_read_sample_data(p_ctx, track, state, data, &data_size);
1543 if(status != VC_CONTAINER_SUCCESS)
1544 {
1545 /* FIXME */
1546 return status;
1547 }
1548
1549 packet->size = data_size;
1550 if(state->sample_offset) //?
1551 packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
1552
1553 return status;
1554}
1555
1556/*****************************************************************************/
1557static uint32_t mp4_find_sample( VC_CONTAINER_T *p_ctx, uint32_t track,
1558 MP4_READER_STATE_T *state, int64_t seek_time, VC_CONTAINER_STATUS_T *p_status )
1559{
1560 VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[track]->priv->module;
1561 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
1562 uint32_t sample = 0, sample_duration_count;
1563 int64_t sample_duration, seek_time_up = seek_time + 1;
1564 unsigned int i;
1565 VC_CONTAINER_PARAM_UNUSED(state);
1566
1567 seek_time = seek_time * track_module->timescale / 1000000;
1568 /* We also need to check against the time rounded up to account for
1569 * rounding errors in the timestamp (because of the timescale conversion) */
1570 seek_time_up = seek_time_up * track_module->timescale / 1000000;
1571
1572 status = SEEK(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_STTS].offset);
1573 if(status != VC_CONTAINER_SUCCESS) goto end;
1574
1575 /* Find the sample which corresponds to the requested time */
1576 for(i = 0; i < track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entries; i++)
1577 {
1578 sample_duration_count = _READ_U32(p_ctx);
1579 sample_duration = _READ_U32(p_ctx);
1580 status = STREAM_STATUS(p_ctx);
1581 if(status != VC_CONTAINER_SUCCESS) break;
1582
1583 if(sample_duration_count * sample_duration <= seek_time)
1584 {
1585 seek_time -= sample_duration_count * sample_duration;
1586 seek_time_up -= sample_duration_count * sample_duration;
1587 sample += sample_duration_count;
1588 continue;
1589 }
1590 if(!sample_duration) break;
1591
1592 seek_time /= sample_duration;
1593 seek_time_up /= sample_duration;
1594 sample += MAX(seek_time, seek_time_up);
1595 break;
1596 }
1597
1598 end:
1599 if(p_status) *p_status = status;
1600 return sample;
1601}
1602
1603/*****************************************************************************/
1604static VC_CONTAINER_STATUS_T mp4_seek_track( VC_CONTAINER_T *p_ctx, uint32_t track,
1605 MP4_READER_STATE_T *state, uint32_t sample )
1606{
1607 VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[track]->priv->module;
1608 uint32_t chunk = 0, samples;
1609 unsigned int i;
1610
1611 memset(state, 0, sizeof(*state));
1612
1613 /* Find the right chunk */
1614 for(i = 0, samples = sample; i < track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entries; i++)
1615 {
1616 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSC, 1 );
1617 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1618
1619 if(state->chunks * state->samples_per_chunk <= samples)
1620 {
1621 samples -= state->chunks * state->samples_per_chunk;
1622 chunk += state->chunks;
1623 continue;
1624 }
1625
1626 while(samples >= state->samples_per_chunk)
1627 {
1628 samples -= state->samples_per_chunk;
1629 state->chunks--;
1630 chunk++;
1631 }
1632
1633 state->chunks--;
1634 break;
1635 }
1636
1637 /* Get the offset of the selected chunk */
1638 state->sample_table[MP4_SAMPLE_TABLE_STCO].entry = chunk;
1639 state->sample_table[MP4_SAMPLE_TABLE_CO64].entry = chunk;
1640 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STCO, 1 );
1641 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1642
1643 /* Find the sample offset within the chunk */
1644 state->sample_table[MP4_SAMPLE_TABLE_STSZ].entry = sample - samples;
1645 for(i = 0; i < samples; i++)
1646 {
1647 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSZ, !i );
1648 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1649 state->offset += state->sample_size;
1650 state->samples_in_chunk--;
1651 }
1652
1653 /* Get the timestamp */
1654 for(i = 0, samples = sample; i < track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entries; i++)
1655 {
1656 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STTS, !i );
1657 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1658
1659 if(state->sample_duration_count <= samples)
1660 {
1661 samples -= state->sample_duration_count;
1662 state->duration += state->sample_duration * state->sample_duration_count;
1663 continue;
1664 }
1665
1666 state->sample_duration_count -= samples;
1667 state->duration += samples * state->sample_duration;
1668 break;
1669 }
1670
1671 /* Find the right place in the sample composition table */
1672 for(i = 0, samples = sample; i < track_module->sample_table[MP4_SAMPLE_TABLE_CTTS].entries; i++)
1673 {
1674 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_CTTS, !i );
1675 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1676
1677 if(state->sample_composition_count <= samples)
1678 {
1679 samples -= state->sample_composition_count;
1680 continue;
1681 }
1682
1683 state->sample_composition_count -= samples;
1684 break;
1685 }
1686
1687 /* Find the right place in the synchronisation table */
1688 for(i = 0; i < track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries; i++)
1689 {
1690 state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSS, !i );
1691 if(state->status != VC_CONTAINER_SUCCESS) goto error;
1692
1693 if(state->next_sync_sample >= sample + 1) break;
1694 }
1695
1696 state->sample = sample;
1697 state->sample_size = 0;
1698 mp4_read_sample_header(p_ctx, track, state);
1699
1700 error:
1701 return state->status;
1702}
1703
1704/*****************************************************************************/
1705static VC_CONTAINER_STATUS_T mp4_reader_seek(VC_CONTAINER_T *p_ctx,
1706 int64_t *offset, VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
1707{
1708 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
1709 VC_CONTAINER_TRACK_MODULE_T *track_module;
1710 VC_CONTAINER_STATUS_T status;
1711 uint32_t i, track, sample, prev_sample, next_sample;
1712 int64_t seek_time = *offset;
1713 VC_CONTAINER_PARAM_UNUSED(module);
1714 VC_CONTAINER_PARAM_UNUSED(mode);
1715
1716 /* Reset the states */
1717 for(i = 0; i < p_ctx->tracks_num; i++)
1718 memset(&p_ctx->tracks[i]->priv->module->state, 0, sizeof(p_ctx->tracks[i]->priv->module->state));
1719
1720 /* Deal with the easy case first */
1721 if(!*offset)
1722 {
1723 /* Initialise tracks */
1724 for(i = 0; i < p_ctx->tracks_num; i++)
1725 {
1726 /* FIXME: we should check we've got at least one success */
1727 mp4_read_sample_header(p_ctx, i, &p_ctx->tracks[i]->priv->module->state);
1728 }
1729 return VC_CONTAINER_SUCCESS;
1730 }
1731
1732 /* Find the first enabled video track */
1733 for(track = 0; track < p_ctx->tracks_num; track++)
1734 if(p_ctx->tracks[track]->is_enabled &&
1735 p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO) break;
1736 if(track == p_ctx->tracks_num) goto seek_time_found; /* No video track found */
1737 track_module = p_ctx->tracks[track]->priv->module;
1738
1739 /* Find the sample number for the requested time */
1740 sample = mp4_find_sample( p_ctx, track, &track_module->state, seek_time, &status );
1741 if(status != VC_CONTAINER_SUCCESS) goto seek_time_found;
1742
1743 /* Find the closest sync sample */
1744 status = mp4_seek_sample_table( p_ctx, track_module, &track_module->state, MP4_SAMPLE_TABLE_STSS );
1745 if(status != VC_CONTAINER_SUCCESS) goto seek_time_found;
1746 for(i = 0, prev_sample = 0, next_sample = 0;
1747 i < track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries; i++)
1748 {
1749 next_sample = _READ_U32(p_ctx) - 1;
1750 if(next_sample > sample)
1751 {
1752 sample = (flags & VC_CONTAINER_SEEK_FLAG_FORWARD) ? next_sample : prev_sample;
1753 break;
1754 }
1755 prev_sample = next_sample;
1756 }
1757
1758 /* Do the seek on this track and use its timestamp as the new seek point */
1759 status = mp4_seek_track(p_ctx, track, &track_module->state, sample);
1760 if(status != VC_CONTAINER_SUCCESS) goto seek_time_found;
1761 seek_time = track_module->state.pts;
1762
1763 seek_time_found:
1764
1765 for(i = 0; i < p_ctx->tracks_num; i++)
1766 {
1767 uint32_t sample;
1768 track_module = p_ctx->tracks[i]->priv->module;
1769 if(track_module->state.offset) continue;
1770 sample = mp4_find_sample( p_ctx, i, &track_module->state, seek_time, &status );
1771 if(status != VC_CONTAINER_SUCCESS) return status; //FIXME
1772
1773 status = mp4_seek_track(p_ctx, i, &track_module->state, sample);
1774 }
1775
1776 *offset = seek_time;
1777 return VC_CONTAINER_SUCCESS;
1778}
1779
1780/******************************************************************************
1781Global function definitions.
1782******************************************************************************/
1783
1784VC_CONTAINER_STATUS_T mp4_reader_open( VC_CONTAINER_T *p_ctx )
1785{
1786 VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
1787 VC_CONTAINER_MODULE_T *module = 0;
1788 unsigned int i;
1789 uint8_t h[8];
1790
1791 /* Check for a known box type to see if we're dealing with mp4 */
1792 if( PEEK_BYTES(p_ctx, h, 8) != 8 )
1793 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
1794 switch(VC_FOURCC(h[4],h[5],h[6],h[7]))
1795 {
1796 case MP4_BOX_TYPE_FTYP:
1797 case MP4_BOX_TYPE_MDAT:
1798 case MP4_BOX_TYPE_MOOV:
1799 case MP4_BOX_TYPE_FREE:
1800 case MP4_BOX_TYPE_SKIP:
1801 case MP4_BOX_TYPE_WIDE:
1802 case MP4_BOX_TYPE_PNOT:
1803 case MP4_BOX_TYPE_PICT:
1804 case MP4_BOX_TYPE_UDTA:
1805 case MP4_BOX_TYPE_UUID:
1806 break;
1807 default:
1808 /* Couldn't recognize the box type. This doesn't look like an mp4. */
1809 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
1810 }
1811
1812 /*
1813 * We are dealing with an MP4 file
1814 */
1815
1816 LOG_DEBUG(p_ctx, "using mp4 reader");
1817
1818 /* Allocate our context */
1819 module = malloc(sizeof(*module));
1820 if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
1821 memset(module, 0, sizeof(*module));
1822 p_ctx->priv->module = module;
1823 p_ctx->tracks = module->tracks;
1824
1825 while(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS)
1826 {
1827 MP4_BOX_TYPE_T box_type;
1828 int64_t box_size;
1829
1830 status = mp4_read_box_header( p_ctx, INT64_C(-1), &box_type, &box_size );
1831 if(status != VC_CONTAINER_SUCCESS) goto error;
1832
1833 if(box_type == MP4_BOX_TYPE_MDAT)
1834 {
1835 module->data_offset = STREAM_POSITION(p_ctx);
1836 module->data_size = box_size;
1837 if(module->found_moov) break; /* We've got everything we want */
1838 }
1839 else if(box_type == MP4_BOX_TYPE_MOOV)
1840 module->found_moov = true;
1841
1842 status = mp4_read_box_data( p_ctx, box_type, box_size, MP4_BOX_TYPE_ROOT );
1843 if(status != VC_CONTAINER_SUCCESS) goto error;
1844
1845 if(module->found_moov && module->data_offset) break; /* We've got everything we want */
1846 }
1847
1848 /* Initialise tracks */
1849 for(i = 0; i < p_ctx->tracks_num; i++)
1850 {
1851 /* FIXME: we should check we've got at least one success */
1852 status = mp4_read_sample_header(p_ctx, i, &p_ctx->tracks[i]->priv->module->state);
1853 }
1854
1855 status = SEEK(p_ctx, module->data_offset);
1856 if(status != VC_CONTAINER_SUCCESS) goto error;
1857
1858 p_ctx->priv->pf_close = mp4_reader_close;
1859 p_ctx->priv->pf_read = mp4_reader_read;
1860 p_ctx->priv->pf_seek = mp4_reader_seek;
1861
1862 if(STREAM_SEEKABLE(p_ctx))
1863 p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
1864
1865 return VC_CONTAINER_SUCCESS;
1866
1867 error:
1868 LOG_DEBUG(p_ctx, "mp4: error opening stream");
1869 if(module) mp4_reader_close(p_ctx);
1870 return status;
1871}
1872
1873/********************************************************************************
1874 Entrypoint function
1875 ********************************************************************************/
1876
1877#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
1878# pragma weak reader_open mp4_reader_open
1879#endif
1880