mp4.c 59.9 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * mp4.c : MP4 file input module for vlc
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
5
 * $Id: mp4.c,v 1.31 2003/05/09 19:29:57 fenrir Exp $
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *
8
9
10
11
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
12
 *
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
#include <string.h>                                              /* strdup() */
#include <errno.h>
#include <sys/types.h>

#include <vlc/vlc.h>
#include <vlc/input.h>
33
#include <vlc_playlist.h>
34
#include "codecs.h"
35
36
37
38
39
40
41
42
43
44
#include "libmp4.h"
#include "mp4.h"

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int    MP4Init    ( vlc_object_t * );
static void __MP4End     ( vlc_object_t * );
static int    MP4Demux   ( input_thread_t * );

45
46
47
48
49
static int    MP4DemuxRef( input_thread_t *p_input )
{
    return 0;
}

50
51
52
/* New input could have something like that... */
static int   MP4Seek     ( input_thread_t *, mtime_t );

53
54
55
56
57
58
#define MP4End(a) __MP4End(VLC_OBJECT(a))

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
vlc_module_begin();
gbazin's avatar
   
gbazin committed
59
    set_description( _("MP4 demuxer") );
60
61
62
63
64
    set_capability( "demux", 242 );
    set_callbacks( MP4Init, __MP4End );
vlc_module_end();

/*****************************************************************************
65
 * Declaration of local function
66
 *****************************************************************************/
67

68
69
70
71
72
static void MP4_TrackCreate ( input_thread_t *,
                              track_data_mp4_t *,
                              MP4_Box_t  * );
static void MP4_TrackDestroy( input_thread_t *,
                              track_data_mp4_t * );
73

74
75
76
77
78
static int  MP4_TrackSelect ( input_thread_t *,
                              track_data_mp4_t *,
                              mtime_t );
static void MP4_TrackUnselect(input_thread_t *,
                              track_data_mp4_t * );
79

80
81
82
static int  MP4_TrackSeek   ( input_thread_t *,
                              track_data_mp4_t *,
                              mtime_t );
83

84
85
86
87
static uint64_t MP4_GetTrackPos( track_data_mp4_t * );
static int  MP4_TrackSampleSize( track_data_mp4_t * );
static int  MP4_TrackNextSample( input_thread_t *,
                                 track_data_mp4_t * );
88
89

#define MP4_Set4BytesLE( p, dw ) \
90
91
92
93
    *((uint8_t*)p)   = ( (dw)&0xff ); \
    *((uint8_t*)p+1) = ( ((dw)>> 8)&0xff ); \
    *((uint8_t*)p+2) = ( ((dw)>>16)&0xff ); \
    *((uint8_t*)p+3) = ( ((dw)>>24)&0xff )
94
95

#define MP4_Set2BytesLE( p, dw ) \
96
97
    *((uint8_t*)p) = ( (dw)&0xff ); \
    *((uint8_t*)p+1) = ( ((dw)>> 8)&0xff )
98

99
100
#define FREE( p ) \
    if( p ) { free( p ); (p) = NULL;}
101

102
103
104
105
/*****************************************************************************
 * MP4Init: check file and initializes MP4 structures
 *****************************************************************************/
static int MP4Init( vlc_object_t * p_this )
106
{
107
108
    input_thread_t  *p_input = (input_thread_t *)p_this;
    uint8_t         *p_peek;
109

110
    demux_sys_t     *p_demux;
111

112
    MP4_Box_t       *p_ftyp;
113

114
    MP4_Box_t       *p_rmra;
115

116
117
    MP4_Box_t       *p_mvhd;
    MP4_Box_t       *p_trak;
118

119
    unsigned int    i;
120
121
    vlc_bool_t      b_audio;

122
123
124
125
    /* I need to seek */
    if( !p_input->stream.b_seekable )
    {
        msg_Warn( p_input, "MP4 plugin discarded (unseekable)" );
126
        return( VLC_EGENERIC );
127
128

    }
129
130
131
132
133
134
135
136
137
138
139
140
141
    /* Initialize access plug-in structures. */
    if( p_input->i_mtu == 0 )
    {
        /* Improve speed. */
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
    }

    p_input->pf_demux = MP4Demux;

    /* a little test to see if it could be a mp4 */
    if( input_Peek( p_input, &p_peek, 8 ) < 8 )
    {
        msg_Warn( p_input, "MP4 plugin discarded (cannot peek)" );
142
        return( VLC_EGENERIC );
143
    }
144

145

146
    switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) )
147
148
149
    {
        case( FOURCC_ftyp ):
        case( FOURCC_moov ):
150
        case( FOURCC_foov ):
151
152
        case( FOURCC_moof ):
        case( FOURCC_mdat ):
153
        case( FOURCC_udta ):
154
155
        case( FOURCC_free ):
        case( FOURCC_skip ):
156
        case( FOURCC_wide ):
157
158
159
            break;
         default:
            msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
160
            return( VLC_EGENERIC );
161
162
163
    }

    /* create our structure that will contains all data */
164
    if( !( p_input->p_demux_data =
165
                p_demux = malloc( sizeof( demux_sys_t ) ) ) )
166
167
    {
        msg_Err( p_input, "out of memory" );
168
        return( VLC_EGENERIC );
169
    }
170
    memset( p_demux, 0, sizeof( demux_sys_t ) );
171
    p_input->p_demux_data = p_demux;
172

173
174

    /* Now load all boxes ( except raw data ) */
175
    if( !MP4_BoxGetRoot( p_input, &p_demux->box_root ) )
176
177
    {
        msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
178
        return( VLC_EGENERIC );
179
180
    }

181
    MP4_BoxDumpStructure( p_input, &p_demux->box_root );
182

183
    if( ( p_ftyp = MP4_BoxGet( &p_demux->box_root, "/ftyp" ) ) )
184
185
186
187
    {
        switch( p_ftyp->data.p_ftyp->i_major_brand )
        {
            case( FOURCC_isom ):
188
                msg_Dbg( p_input,
189
190
                         "ISO Media file (isom) version %d.",
                         p_ftyp->data.p_ftyp->i_minor_version );
191
192
                break;
            default:
193
                msg_Dbg( p_input,
194
195
                         "unrecognized major file specification (%4.4s).",
                          (char*)&p_ftyp->data.p_ftyp->i_major_brand );
196
197
198
199
200
                break;
        }
    }
    else
    {
201
        msg_Dbg( p_input, "file type box missing (assuming ISO Media file)" );
202
203
204
    }

    /* the file need to have one moov box */
205
    if( MP4_BoxCount( &p_demux->box_root, "/moov" ) <= 0 )
206
    {
207
208
209
210
211
212
213
214
215
216
        MP4_Box_t *p_foov = MP4_BoxGet( &p_demux->box_root, "/foov" );

        if( !p_foov )
        {
            msg_Err( p_input, "MP4 plugin discarded (no moov box)" );
            MP4End( p_input );
            return( VLC_EGENERIC );
        }
        /* we have a free box as a moov, rename it */
        p_foov->i_type = FOURCC_moov;
217
218
    }

219
220
221
222
223
224
225
226
227
228
229
230
231
232
    if( ( p_rmra = MP4_BoxGet( &p_demux->box_root,  "/moov/rmra" ) ) )
    {
        playlist_t *p_playlist;
        int        i_count = MP4_BoxCount( p_rmra, "rmda" );
        int        i;

        msg_Dbg( p_input, "detected playlist mov file (%d ref)", i_count );

        p_playlist =
            (playlist_t *)vlc_object_find( p_input,
                                           VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
        if( p_playlist )
        {
233
            //p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
            for( i = 0; i < i_count; i++ )
            {
                MP4_Box_t *p_rdrf = MP4_BoxGet( p_rmra, "rmda[%d]/rdrf", i );
                char      *psz_ref;
                uint32_t  i_ref_type;

                if( !p_rdrf || !( psz_ref = p_rdrf->data.p_rdrf->psz_ref ) )
                {
                    continue;
                }
                i_ref_type = p_rdrf->data.p_rdrf->i_ref_type;

                msg_Dbg( p_input, "new ref=`%s' type=%4.4s",
                         psz_ref, (char*)&i_ref_type );

                if( i_ref_type == VLC_FOURCC( 'u', 'r', 'l', ' ' ) )
                {
                    if( strstr( psz_ref, "qt5gateQT" ) )
                    {
                        msg_Dbg( p_input, "ignoring pseudo ref =`%s'", psz_ref );
                        continue;
                    }
256
257
                    if( !strncmp( psz_ref, "http://", 7 ) ||
                        !strncmp( psz_ref, "rtsp://", 7 ) )
258
259
260
261
262
263
264
                    {
                        msg_Dbg( p_input, "adding ref = `%s'", psz_ref );
                        playlist_Add( p_playlist, psz_ref, PLAYLIST_APPEND, PLAYLIST_END );
                    }
                    else
                    {
                        /* msg dbg relative ? */
265
266
                        char *psz_absolute = alloca( strlen( p_input->psz_source ) + strlen( psz_ref ) + 1);
                        char *end = strrchr( p_input->psz_source, '/' );
267
268
269

                        if( end )
                        {
270
                            int i_len = end + 1 - p_input->psz_source;
271

272
                            strncpy( psz_absolute, p_input->psz_source, i_len);
273
                            psz_absolute[i_len] = '\0';
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
                        }
                        else
                        {
                            strcpy( psz_absolute, "" );
                        }
                        strcat( psz_absolute, psz_ref );
                        msg_Dbg( p_input, "adding ref = `%s'", psz_absolute );
                        playlist_Add( p_playlist, psz_absolute, PLAYLIST_APPEND, PLAYLIST_END );
                    }
                }
                else
                {
                    msg_Err( p_input, "unknown ref type=%4.4s FIXME (send a bug report)", (char*)&p_rdrf->data.p_rdrf->i_ref_type );
                }
            }
            vlc_object_release( p_playlist );
        }
        else
        {
            msg_Err( p_input, "can't find playlist" );
        }
    }

297
    if( !(p_mvhd = MP4_BoxGet( &p_demux->box_root, "/moov/mvhd" ) ) )
298
    {
299
300
301
        if( !p_rmra )
        {
            msg_Err( p_input, "cannot find /moov/mvhd" );
302
303
            MP4End( p_input );
            return VLC_EGENERIC;
304
305
306
307
        }
        else
        {
            msg_Warn( p_input, "cannot find /moov/mvhd (pure ref file)" );
308
309
            p_input->pf_demux = MP4DemuxRef;
            return VLC_SUCCESS;
310
        }
311
312
313
314
    }
    else
    {
        p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
315
        p_demux->i_duration = p_mvhd->data.p_mvhd->i_duration;
316
    }
317

318
    if( !( p_demux->i_tracks =
319
                MP4_BoxCount( &p_demux->box_root, "/moov/trak" ) ) )
320
    {
321
        msg_Err( p_input, "cannot find any /moov/trak" );
322
        MP4End( p_input );
323
        return( VLC_EGENERIC );
324
    }
325
326
327
    msg_Dbg( p_input, "find %d track%c",
                        p_demux->i_tracks,
                        p_demux->i_tracks ? 's':' ' );
328

329
330
331
332
333
334
335
    /*  create one program */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    if( input_InitStream( p_input, 0 ) == -1)
    {
        vlc_mutex_unlock( &p_input->stream.stream_lock );
        msg_Err( p_input, "cannot init stream" );
        MP4End( p_input );
336
        return( VLC_EGENERIC );
337
338
339
340
341
342
343
    }
    /* Needed to create program _before_ MP4_TrackCreate */
    if( input_AddProgram( p_input, 0, 0) == NULL )
    {
        vlc_mutex_unlock( &p_input->stream.stream_lock );
        msg_Err( p_input, "cannot add program" );
        MP4End( p_input );
344
        return( VLC_EGENERIC );
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
    }
    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
    /* XXX beurk and beurk, see MP4Demux and MP4Seek */
    if( p_demux->i_duration/p_demux->i_timescale > 0 )
    {
        p_input->stream.i_mux_rate =
            p_input->stream.p_selected_area->i_size / 50 /
            ( p_demux->i_duration / p_demux->i_timescale );
    }
    else
    {
        p_input->stream.i_mux_rate = 0;
    }
    vlc_mutex_unlock( &p_input->stream.stream_lock );


361
362
363
364
365
366
    /* allocate memory */
    p_demux->track = calloc( p_demux->i_tracks, sizeof( track_data_mp4_t ) );

    /* now process each track and extract all usefull informations */
    for( i = 0; i < p_demux->i_tracks; i++ )
    {
367
        p_trak = MP4_BoxGet( &p_demux->box_root, "/moov/trak[%d]", i );
368
        MP4_TrackCreate( p_input, &p_demux->track[i], p_trak );
369
370
371
372
373
374
375
376
377
378
379
380
381

        if( p_demux->track[i].b_ok )
        {
            char *psz_cat;
            switch( p_demux->track[i].i_cat )
            {
                case( VIDEO_ES ):
                    psz_cat = "video";
                    break;
                case( AUDIO_ES ):
                    psz_cat = "audio";
                    break;
                default:
382
                    psz_cat = "unknown";
383
384
                    break;
            }
385

386
387
            msg_Dbg( p_input, "adding track[Id 0x%x] %s (%s) language %c%c%c",
                            p_demux->track[i].i_track_ID,
388
389
390
                            psz_cat,
                            p_demux->track[i].b_enable ? "enable":"disable",
                            p_demux->track[i].i_language[0],
391
                            p_demux->track[i].i_language[1],
392
393
394
395
                            p_demux->track[i].i_language[2] );
        }
        else
        {
396
            msg_Dbg( p_input, "ignoring track[Id 0x%x]", p_demux->track[i].i_track_ID );
397
398
399
        }

    }
400

401
    for( i = 0, b_audio = VLC_FALSE; i < p_demux->i_tracks; i++ )
402
    {
403
#define track p_demux->track[i]
404
        /* start decoder for this track if enable by default*/
405
406
        if( track.b_ok && track.b_enable &&
            ( track.i_cat != AUDIO_ES || !b_audio ) )
407
        {
408
409
410
411
412
413
414
            if( !MP4_TrackSelect( p_input, &track, 0 ) )
            {
                if(track.i_cat == AUDIO_ES )
                {
                    b_audio = VLC_TRUE;
                }
            }
415
        }
416
#undef track
417
418
419
420
421
    }

    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_input->stream.p_selected_program->b_is_ok = 1;
    vlc_mutex_unlock( &p_input->stream.stream_lock );
422

423
    return( VLC_SUCCESS );
424
425
426
}

/*****************************************************************************
427
 * MP4Demux: read packet and send them to decoders
428
429
 *****************************************************************************
 * TODO check for newly selected track (ie audio upt to now )
430
431
432
 *****************************************************************************/
static int MP4Demux( input_thread_t *p_input )
{
433
    demux_sys_t *p_demux = p_input->p_demux_data;
434
    unsigned int i_track;
435

436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481

    unsigned int i_track_selected;
    vlc_bool_t   b_video;
    vlc_bool_t   b_play_audio;

    /* check for newly selected/unselected track */
    for( i_track = 0, i_track_selected = 0, b_video = VLC_FALSE;
            i_track <  p_demux->i_tracks; i_track++ )
    {
#define track   p_demux->track[i_track]
        if( track.b_selected && track.i_sample >= track.i_sample_count )
        {
            msg_Warn( p_input, "track[0x%x] will be disabled", track.i_track_ID );
            MP4_TrackUnselect( p_input, &track );
        }
        else if( track.b_ok )
        {
            if( track.b_selected && track.p_es->p_decoder_fifo == NULL )
            {
                MP4_TrackUnselect( p_input, &track );
            }
            else if( !track.b_selected && track.p_es->p_decoder_fifo != NULL )
            {
                MP4_TrackSelect( p_input, &track, MP4_GetMoviePTS( p_demux ) );
            }

            if( track.b_selected )
            {
                i_track_selected++;

                if( track.i_cat == VIDEO_ES )
                {
                    b_video = VLC_TRUE;
                }
            }
        }
#undef  track
    }

    if( i_track_selected <= 0 )
    {
        msg_Warn( p_input, "no track selected, exiting..." );
        return( 0 );
    }


482
    /* XXX beurk, beuRK and BEURK,
483
484
485
486
       but only way I've found to detect seek from interface */
    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
    {
        mtime_t i_date;
487

488
489
490
491
        /* first wait for empty buffer, arbitrary time FIXME */
        msleep( DEFAULT_PTS_DELAY );
        /* *** calculate new date *** */

492
        i_date = (mtime_t)1000000 *
493
                 (mtime_t)p_demux->i_duration /
494
                 (mtime_t)p_demux->i_timescale *
495
496
497
498
                 (mtime_t)MP4_TellAbsolute( p_input ) /
                 (mtime_t)p_input->stream.p_selected_area->i_size;
        MP4Seek( p_input, i_date );
    }
499

500
501
502
503
504
505
506
507
    /* first wait for the good time to read a packet */
    input_ClockManageRef( p_input,
                          p_input->stream.p_selected_program,
                          p_demux->i_pcr );


    /* update pcr XXX in mpeg scale so in 90000 unit/s */
    p_demux->i_pcr = MP4_GetMoviePTS( p_demux ) * 9 / 100;
508

509
510
511

    /* we will read 100ms for each stream so ...*/
    p_demux->i_time += __MAX( p_demux->i_timescale / 10 , 1 );
512

513

514
515
516
517
518
519
520
521
522
523
524
525
    /* *** send audio data to decoder if rate == DEFAULT_RATE or no video *** */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    if( p_input->stream.control.i_rate == DEFAULT_RATE || !b_video )
    {
        b_play_audio = VLC_TRUE;
    }
    else
    {
        b_play_audio = VLC_FALSE;
    }
    vlc_mutex_unlock( &p_input->stream.stream_lock );

526
527
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
528
529
530
531
#define track p_demux->track[i_track]
        if( !track.b_ok ||
            !track.b_selected ||
            MP4_GetTrackPTS( &track ) >= MP4_GetMoviePTS( p_demux ) )
532
        {
533
            continue;
534
        }
535
        while( MP4_GetTrackPTS( &track ) < MP4_GetMoviePTS( p_demux ) )
536
537
        {

538
            if( !b_play_audio && track.i_cat == AUDIO_ES )
539
            {
540
541
542
543
                if( MP4_TrackNextSample( p_input, &track ) )
                {
                    break;
                }
544
            }
545
546
547
548
            else
            {
                size_t i_size;
                off_t i_pos;
549

550
551
                data_packet_t *p_data;
                pes_packet_t *p_pes;
552

553
554
                /* caculate size and position for this sample */
                i_size = MP4_TrackSampleSize( &track );
555

556
                i_pos  = MP4_GetTrackPos( &track );
557

558
559
                //msg_Dbg( p_input, "stream %d size=%6d pos=%8lld",  i_track, i_size, i_pos );

560
                /* go,go go ! */
561
                if( MP4_SeekAbsolute( p_input, i_pos ) )
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
                {
                    msg_Warn( p_input, "track[0x%x] will be disabled (eof?)", track.i_track_ID );
                    MP4_TrackUnselect( p_input, &track );
                    break;
                }


                /* now create a pes */
                if( !(p_pes = input_NewPES( p_input->p_method_data ) ) )
                {
                    break;
                }
                /* and a data packet for the data */
                if( !(p_data = input_NewPacket( p_input->p_method_data, i_size ) ) )
                {
                    input_DeletePES( p_input->p_method_data, p_pes );
                    break;
                }
580
581
                p_data->p_payload_end = p_data->p_payload_start + i_size;

582
583
584
585
586
587
588
                /* initialisation of all the field */
                p_pes->i_dts = p_pes->i_pts = 0;
                p_pes->p_first = p_pes->p_last  = p_data;
                p_pes->i_nb_data = 1;
                p_pes->i_pes_size = i_size;
                if( i_size > 0 )
                {
589
                    if( MP4_ReadData( p_input, p_data->p_payload_start, i_size ) )
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
                    {
                        input_DeletePES( p_input->p_method_data, p_pes );

                        msg_Warn( p_input, "track[0x%x] will be disabled (eof?)", track.i_track_ID );
                        MP4_TrackUnselect( p_input, &track );
                        break;
                    }
                }

                p_pes->i_dts =
                    p_pes->i_pts = input_ClockGetTS( p_input,
                                                     p_input->stream.p_selected_program,
                                                     MP4_GetTrackPTS( &track ) * 9/100);

                if( track.p_es->p_decoder_fifo )
                {
                    input_DecodePES( track.p_es->p_decoder_fifo, p_pes );
                }
                else
                {
                    input_DeletePES( p_input->p_method_data, p_pes );
                }

                if( MP4_TrackNextSample( p_input, &track ) )
                {
                    break;
                }
            }
618
        }
619
#undef track
620
621
    }

622
    return( 1 );
623
}
624
625
626
627
628
629
/*****************************************************************************
 * MP4Seek: Got to i_date
 ******************************************************************************/
static int   MP4Seek     ( input_thread_t *p_input, mtime_t i_date )
{
    demux_sys_t *p_demux = p_input->p_demux_data;
630
    unsigned int i_track;
631
632
    /* First update update global time */
    p_demux->i_time = i_date * p_demux->i_timescale / 1000000;
633
    p_demux->i_pcr  = i_date* 9 / 100;
634

635
636
637
    /* Now for each stream try to go to this time */
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
638
639
640
641
642
643
#define track p_demux->track[i_track]
        if( track.b_ok && track.b_selected )
        {
            MP4_TrackSeek( p_input, &track, i_date );
        }
#undef  track
644
645
646
    }
    return( 1 );
}
647
648
649
650
651

/*****************************************************************************
 * MP4End: frees unused data
 *****************************************************************************/
static void __MP4End ( vlc_object_t * p_this )
652
653
{
    unsigned int i_track;
654
    input_thread_t *  p_input = (input_thread_t *)p_this;
655
    demux_sys_t *p_demux = p_input->p_demux_data;
656

657
    msg_Dbg( p_input, "freeing all memory" );
658
    MP4_BoxFree( p_input, &p_demux->box_root );
659
660
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
661
        MP4_TrackDestroy( p_input, &p_demux->track[i_track] );
662
663
    }
    FREE( p_demux->track );
664
665

    FREE( p_input->p_demux_data );
666
667
668
669
670
671
672
}


/****************************************************************************
 * Local functions, specific to vlc
 ****************************************************************************/

673
674
675
/* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
static int TrackCreateChunksIndex( input_thread_t *p_input,
                                   track_data_mp4_t *p_demux_track )
676
{
677
678
    MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
    MP4_Box_t *p_stsc;
679

680
681
682
683
684
685
    unsigned int i_chunk;
    unsigned int i_index, i_last;

    if( ( !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "stco" ) )&&
          !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "co64" ) ) )||
        ( !(p_stsc = MP4_BoxGet( p_demux_track->p_stbl, "stsc" ) ) ))
686
    {
687
        return( VLC_EGENERIC );
688
    }
689
690
691

    p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
    if( !p_demux_track->i_chunk_count )
692
    {
693
694
        msg_Warn( p_input, "no chunk defined" );
        return( VLC_EGENERIC );
695
    }
696
697
698
699
700
    p_demux_track->chunk = calloc( p_demux_track->i_chunk_count,
                                   sizeof( chunk_data_mp4_t ) );

    /* first we read chunk offset */
    for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
701
    {
702
703
        p_demux_track->chunk[i_chunk].i_offset =
                p_co64->data.p_co64->i_chunk_offset[i_chunk];
704
705
    }

706
707
708
709
710
711
    /* now we read index for SampleEntry( soun vide mp4a mp4v ...)
        to be used for the sample XXX begin to 1
        We construct it begining at the end */
    i_last = p_demux_track->i_chunk_count; /* last chunk proceded */
    i_index = p_stsc->data.p_stsc->i_entry_count;
    if( !i_index )
712
    {
713
714
        msg_Warn( p_input, "cannot read chunk table or table empty" );
        return( VLC_EGENERIC );
715
    }
716
717

    while( i_index )
718
    {
719
720
721
722
723
724
725
726
727
728
        i_index--;
        for( i_chunk = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
                i_chunk < i_last; i_chunk++ )
        {
            p_demux_track->chunk[i_chunk].i_sample_description_index =
                    p_stsc->data.p_stsc->i_sample_description_index[i_index];
            p_demux_track->chunk[i_chunk].i_sample_count =
                    p_stsc->data.p_stsc->i_samples_per_chunk[i_index];
        }
        i_last = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
729
730
    }

731
732
    p_demux_track->chunk[0].i_sample_first = 0;
    for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
733
    {
734
735
736
        p_demux_track->chunk[i_chunk].i_sample_first =
            p_demux_track->chunk[i_chunk-1].i_sample_first +
                p_demux_track->chunk[i_chunk-1].i_sample_count;
737
    }
738

739
740
741
742
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d chunk",
             p_demux_track->i_track_ID,
            p_demux_track->i_chunk_count );
743

744
    return( VLC_SUCCESS );
745
}
746
747
static int TrackCreateSamplesIndex( input_thread_t *p_input,
                                    track_data_mp4_t *p_demux_track )
748
749
{
    MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
750
                          ctts make same mapping but for composition time,
751
                          not yet used and probably not usefull */
752
753
    MP4_Box_t *p_stsz; /* gives sample size of each samples, there is also stz2
                          that uses a compressed form FIXME make them in libmp4
754
755
756
                          as a unique type */
    /* TODO use also stss and stsh table for seeking */
    /* FIXME use edit table */
757
758
    int64_t i_sample;
    int64_t i_chunk;
759

760
761
    int64_t i_index;
    int64_t i_index_sample_used;
762

763
764
    int64_t i_last_dts;

765
766
    p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
    p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */
767
768
769
770

    if( ( !p_stts )||( !p_stsz ) )
    {
        msg_Warn( p_input, "cannot read sample table" );
771
        return( VLC_EGENERIC );
772
    }
773

774
775
776
777
778
779
780
781
782
783
784
785
786
787
    p_demux_track->i_sample_count = p_stsz->data.p_stsz->i_sample_count;


    /* for sample size, there are 2 case */
    if( p_stsz->data.p_stsz->i_sample_size )
    {
        /* 1: all sample have the same size, so no need to construct a table */
        p_demux_track->i_sample_size = p_stsz->data.p_stsz->i_sample_size;
        p_demux_track->p_sample_size = NULL;
    }
    else
    {
        /* 2: each sample can have a different size */
        p_demux_track->i_sample_size = 0;
788
        p_demux_track->p_sample_size =
789
            calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
790

791
792
        for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
        {
793
            p_demux_track->p_sample_size[i_sample] =
794
795
796
797
798
799
800
                    p_stsz->data.p_stsz->i_entry_size[i_sample];
        }
    }
    /* we have extract all information from stsz,
        now use stts */

    /* if we don't want to waste too much memory, we can't expand
801
       the box !, so each chunk will contain an "extract" of this table
802
       for fast research */
803

804
805
    i_last_dts = 0;
    i_index = 0; i_index_sample_used =0;
806

807
808
809
810
    /* create and init last data for each chunk */
    for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
    {

811
        int64_t i_entry, i_sample_count, i;
812
813
        /* save last dts */
        p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
814
    /* count how many entries needed for this chunk
815
816
817
       for p_sample_delta_dts and p_sample_count_dts */

        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
818
819

        i_entry = 0;
820
821
822
823
824
        while( i_sample_count > 0 )
        {
            i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];
            if( i_entry == 0 )
            {
825
                i_sample_count += i_index_sample_used; /* don't count already used sample
826
827
828
829
                                                   int this entry */
            }
            i_entry++;
        }
830

831
        /* allocate them */
832
        p_demux_track->chunk[i_chunk].p_sample_count_dts =
833
            calloc( i_entry, sizeof( uint32_t ) );
834
        p_demux_track->chunk[i_chunk].p_sample_delta_dts =
835
            calloc( i_entry, sizeof( uint32_t ) );
836
837
838
839
840

        /* now copy */
        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
        for( i = 0; i < i_entry; i++ )
        {
841
842
            int64_t i_used;
            int64_t i_rest;
843

844
845
846
847
848
            i_rest = p_stts->data.p_stts->i_sample_count[i_index] - i_index_sample_used;

            i_used = __MIN( i_rest, i_sample_count );

            i_index_sample_used += i_used;
849
            i_sample_count -= i_used;
850
851
852
853
854

            p_demux_track->chunk[i_chunk].p_sample_count_dts[i] = i_used;

            p_demux_track->chunk[i_chunk].p_sample_delta_dts[i] =
                        p_stts->data.p_stts->i_sample_delta[i_index];
855
856

            i_last_dts += i_used *
857
858
859
860
861
                    p_demux_track->chunk[i_chunk].p_sample_delta_dts[i];

            if( i_index_sample_used >=
                             p_stts->data.p_stts->i_sample_count[i_index] )
            {
862

863
864
865
866
                i_index++;
                i_index_sample_used = 0;
            }
        }
867

868
869
    }

870
871
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d samples length:"I64Fd"s",
872
             p_demux_track->i_track_ID,
873
874
             p_demux_track->i_sample_count,
             i_last_dts / p_demux_track->i_timescale );
875

876
    return( VLC_SUCCESS );
877
878
}

879
880
881
882
883
884
885
886
887
/*
 * TrackCreateES:
 *  Create ES and PES to init decoder if needed, for a track starting at i_chunk
 */
static int  TrackCreateES   ( input_thread_t   *p_input,
                              track_data_mp4_t *p_track,
                              unsigned int     i_chunk,
                              es_descriptor_t  **pp_es,
                              pes_packet_t     **pp_pes )
888
{
889
890
    MP4_Box_t *  p_sample;
    unsigned int i;
gbazin's avatar
   
gbazin committed
891
    char psz_lang[4];
892

893
894
    unsigned int i_decoder_specific_info_len;
    uint8_t *    p_decoder_specific_info;
895
896
897

    es_descriptor_t *p_es;
    pes_packet_t    *p_pes_init;
898

899
900
    uint8_t             *p_init;
    BITMAPINFOHEADER    *p_bih;
901
    WAVEFORMATEX        *p_wf;
902

903
    MP4_Box_t   *p_esds;
904

905
    if( !p_track->chunk[i_chunk].i_sample_description_index )
906
    {
907
        msg_Warn( p_input,
908
                  "invalid SampleEntry index (track[Id 0x%x])",
909
910
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
911
    }
912
913

    p_sample = MP4_BoxGet(  p_track->p_stsd,
914
                            "[%d]",
915
                p_track->chunk[i_chunk].i_sample_description_index - 1 );
916

917
    if( !p_sample || !p_sample->data.p_data )
918
    {
919
        msg_Warn( p_input,
920
                  "cannot find SampleEntry (track[Id 0x%x])",
921
922
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
923
924
    }

925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
    p_track->p_sample = p_sample;

    if( p_track->i_sample_size == 1 )
    {
        MP4_Box_data_sample_soun_t *p_soun;

        p_soun = p_sample->data.p_sample_soun;

        if( p_soun->i_qt_version == 0 )
        {
            switch( p_sample->i_type )
            {
                case VLC_FOURCC( 'i', 'm', 'a', '4' ):
                    p_soun->i_qt_version = 1;
                    p_soun->i_sample_per_packet = 64;
                    p_soun->i_bytes_per_packet  = 34;
                    p_soun->i_bytes_per_frame   = 34 * p_soun->i_channelcount;
                    p_soun->i_bytes_per_sample  = 2;
                    break;
944
945
946
947
948
949
950
951
952
953
954
955
956
957
                case VLC_FOURCC( 'M', 'A', 'C', '3' ):
                    p_soun->i_qt_version = 1;
                    p_soun->i_sample_per_packet = 6;
                    p_soun->i_bytes_per_packet  = 2;
                    p_soun->i_bytes_per_frame   = 2 * p_soun->i_channelcount;
                    p_soun->i_bytes_per_sample  = 2;
                    break;
                case VLC_FOURCC( 'M', 'A', 'C', '6' ):
                    p_soun->i_qt_version = 1;
                    p_soun->i_sample_per_packet = 12;
                    p_soun->i_bytes_per_packet  = 2;
                    p_soun->i_bytes_per_frame   = 2 * p_soun->i_channelcount;
                    p_soun->i_bytes_per_sample  = 2;
                    break;
958
959
960
961
962
963
                default:
                    break;
            }
        }
    }

964
965
966
    /* Initialise ES, first language as description */
    for( i = 0; i < 3; i++ )
    {
gbazin's avatar
   
gbazin committed
967
        psz_lang[i] = p_track->i_language[i];
968
    }
gbazin's avatar
   
gbazin committed
969
970
971
972
973
974
    psz_lang[3] = '\0';

    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_es = input_AddES( p_input, p_input->stream.p_selected_program,
                        p_track->i_track_ID, p_track->i_cat, psz_lang, 0 );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
975

976
    p_es->i_stream_id = p_track->i_track_ID;
977
978
979
980
981
982

    /* It's a little ugly but .. there are special cases */
    switch( p_sample->i_type )
    {
        case( VLC_FOURCC( '.', 'm', 'p', '3' ) ):
        case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ):
983
984
985
986
            p_es->i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
            break;
        case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ):
            p_es->i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
987
            break;
988
989
990
        case( VLC_FOURCC( 's', '2', '6', '3' ) ):
            p_es->i_fourcc = VLC_FOURCC( 'h', '2', '6', '3' );
            break;
991
        default:
992
            p_es->i_fourcc = p_sample->i_type;
993
994
            break;
    }
995

996
997
    i_decoder_specific_info_len = 0;
    p_decoder_specific_info = NULL;
998
    p_pes_init = NULL;
999

1000
    /* now see if esds is present and if so create a data packet
1001
1002
        with decoder_specific_info  */
#define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr
1003
    if( ( p_esds = MP4_BoxGet( p_sample, "esds" ) )&&
1004
1005
1006
1007
1008
1009
1010
        ( p_esds->data.p_esds )&&
        ( p_decconfig ) )
    {
        /* First update information based on i_objectTypeIndication */
        switch( p_decconfig->i_objectTypeIndication )
        {
            case( 0x20 ): /* MPEG4 VIDEO */
1011
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','v' );
1012
1013
                break;
            case( 0x40):
1014
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
1015
1016
1017
1018
1019
1020
1021
                break;
            case( 0x60):
            case( 0x61):
            case( 0x62):
            case( 0x63):
            case( 0x64):
            case( 0x65): /* MPEG2 video */
1022
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
1023
                break;
1024
            /* Theses are MPEG2-AAC */
1025
1026
1027
            case( 0x66): /* main profile */
            case( 0x67): /* Low complexity profile */
            case( 0x68): /* Scaleable Sampling rate profile */
1028
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
1029
1030
                break;
            /* true MPEG 2 audio */
1031
            case( 0x69):
1032
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
1033
1034
                break;
            case( 0x6a): /* MPEG1 video */
1035
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
1036
1037
                break;
            case( 0x6b): /* MPEG1 audio */
1038
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
1039
1040
                break;
            case( 0x6c ): /* jpeg */
1041
                p_es->i_fourcc = VLC_FOURCC( 'j','p','e','g' );
1042
1043
1044
                break;
            default:
                /* Unknown entry, but don't touch i_fourcc */
1045
                msg_Warn( p_input,
1046
                          "unknown objectTypeIndication(0x%x) (Track[ID 0x%x])",
1047
                          p_decconfig->i_objectTypeIndication,
1048
                          p_track->i_track_ID );
1049
1050
                break;
        }
1051
        i_decoder_specific_info_len =
1052
                p_decconfig->i_decoder_specific_info_len;
1053
        p_decoder_specific_info =
1054
1055
                p_decconfig->p_decoder_specific_info;
    }
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
    else
    {
        switch( p_sample->i_type )
        {
            /* qt decoder, send the complete chunk */
            case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
            case VLC_FOURCC( 'Z', 'y', 'G', 'o' ):
                i_decoder_specific_info_len = p_sample->data.p_sample_vide->i_qt_image_description;
                p_decoder_specific_info     = p_sample->data.p_sample_vide->p_qt_image_description;
                break;
            case VLC_FOURCC( 'Q', 'D', 'M', 'C' ):
            case VLC_FOURCC( 'Q', 'D', 'M', '2' ):
            case VLC_FOURCC( 'Q', 'c', 'l', 'p' ):
                i_decoder_specific_info_len = p_sample->data.p_sample_soun->i_qt_description;
                p_decoder_specific_info     = p_sample->data.p_sample_soun->p_qt_description;
                break;
            default:
                break;
        }
    }
1076
1077
1078
1079

#undef p_decconfig

    /* some last initialisation */
1080
1081
1082
    /* XXX I create a bitmapinfoheader_t or
       waveformatex_t for each stream, up to now it's the best thing
       I've found but it could exist a better solution :) as something
1083
1084
1085
       like adding some new fields in p_es ...

       XXX I don't set all values, only thoses that are interesting or known
1086
        --> bitmapinfoheader_t : width and height
1087
        --> waveformatex_t : channels, samplerate, bitspersample
1088
        and at the end I add p_decoder_specific_info
1089

1090
        TODO set more values
1091

1092
1093
     */

1094
    switch( p_track->i_cat )
1095
    {
1096
1097
        case( VIDEO_ES ):
            /* now create a bitmapinfoheader_t for decoder and
1098
               add information found in p_esds */
1099
1100