mp4.c 60.3 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.35 2003/09/07 22:48:29 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
 * 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 <vlc/vlc.h>
#include <vlc/input.h>
30
#include <vlc_playlist.h>
31
#include "codecs.h"
32 33 34 35 36 37
#include "libmp4.h"
#include "mp4.h"

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
38 39 40
static int  Open    ( vlc_object_t * );
static void Close     ( vlc_object_t * );

41
vlc_module_begin();
Gildas Bazin's avatar
 
Gildas Bazin committed
42
    set_description( _("MP4 demuxer") );
43
    set_capability( "demux", 242 );
44
    set_callbacks( Open, Close );
45 46
vlc_module_end();

47 48 49 50 51 52 53 54 55 56 57 58

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int    Demux   ( input_thread_t * );
static int    DemuxRef( input_thread_t *p_input )
{
    return 0;
}
static int   Seek     ( input_thread_t *, mtime_t );
static int   Control  ( input_thread_t *, int, va_list );

59
/*****************************************************************************
60
 * Declaration of local function
61
 *****************************************************************************/
62

63 64
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 * );
65

66 67
static int  MP4_TrackSelect ( input_thread_t *, track_data_mp4_t *, mtime_t );
static void MP4_TrackUnselect(input_thread_t *, track_data_mp4_t * );
68

69
static int  MP4_TrackSeek   ( input_thread_t *, track_data_mp4_t *, mtime_t );
70

71 72 73
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 * );
74 75

#define MP4_Set4BytesLE( p, dw ) \
76 77 78 79
    *((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 )
80 81

#define MP4_Set2BytesLE( p, dw ) \
82 83
    *((uint8_t*)p) = ( (dw)&0xff ); \
    *((uint8_t*)p+1) = ( ((dw)>> 8)&0xff )
84

85 86
#define FREE( p ) \
    if( p ) { free( p ); (p) = NULL;}
87

88
/*****************************************************************************
89
 * Open: check file and initializes MP4 structures
90
 *****************************************************************************/
91
static int Open( vlc_object_t * p_this )
92
{
93 94
    input_thread_t  *p_input = (input_thread_t *)p_this;
    uint8_t         *p_peek;
95

96
    demux_sys_t     *p_demux;
97

98
    MP4_Box_t       *p_ftyp;
99

100
    MP4_Box_t       *p_rmra;
101

102 103
    MP4_Box_t       *p_mvhd;
    MP4_Box_t       *p_trak;
104

105
    unsigned int    i;
106 107
    vlc_bool_t      b_audio;

108 109 110 111
    /* 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)" );
112
        return VLC_EGENERIC;
113
    }
114
    switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) )
115
    {
116 117 118 119 120 121 122 123 124
        case FOURCC_ftyp:
        case FOURCC_moov:
        case FOURCC_foov:
        case FOURCC_moof:
        case FOURCC_mdat:
        case FOURCC_udta:
        case FOURCC_free:
        case FOURCC_skip:
        case FOURCC_wide:
125 126 127
            break;
         default:
            msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
128
            return VLC_EGENERIC;
129
    }
130 131
    /* I need to seek */
    if( !p_input->stream.b_seekable )
132
    {
133 134
        msg_Warn( p_input, "MP4 plugin discarded (unseekable)" );
        return VLC_EGENERIC;
135
    }
136

137 138 139 140 141 142 143 144
    /*Set exported functions */
    p_input->pf_demux = Demux;
    p_input->pf_demux_control = Control;


    /* create our structure that will contains all data */
    p_input->p_demux_data = p_demux = malloc( sizeof( demux_sys_t ) );
    memset( p_demux, 0, sizeof( demux_sys_t ) );
145 146

    /* Now load all boxes ( except raw data ) */
147
    if( !MP4_BoxGetRoot( p_input, &p_demux->box_root ) )
148 149
    {
        msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
150
        return VLC_EGENERIC;
151 152
    }

153
    MP4_BoxDumpStructure( p_input, &p_demux->box_root );
154

155
    if( ( p_ftyp = MP4_BoxGet( &p_demux->box_root, "/ftyp" ) ) )
156 157 158 159
    {
        switch( p_ftyp->data.p_ftyp->i_major_brand )
        {
            case( FOURCC_isom ):
160
                msg_Dbg( p_input,
161 162
                         "ISO Media file (isom) version %d.",
                         p_ftyp->data.p_ftyp->i_minor_version );
163 164
                break;
            default:
165
                msg_Dbg( p_input,
166 167
                         "unrecognized major file specification (%4.4s).",
                          (char*)&p_ftyp->data.p_ftyp->i_major_brand );
168 169 170 171 172
                break;
        }
    }
    else
    {
173
        msg_Dbg( p_input, "file type box missing (assuming ISO Media file)" );
174 175 176
    }

    /* the file need to have one moov box */
177
    if( MP4_BoxCount( &p_demux->box_root, "/moov" ) <= 0 )
178
    {
179 180 181 182 183
        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)" );
184
            goto error;
185 186 187
        }
        /* we have a free box as a moov, rename it */
        p_foov->i_type = FOURCC_moov;
188 189
    }

190 191 192 193 194 195 196 197 198 199 200 201 202 203
    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 )
        {
204
            //p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
            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;
                    }
227 228
                    if( !strncmp( psz_ref, "http://", 7 ) ||
                        !strncmp( psz_ref, "rtsp://", 7 ) )
229 230
                    {
                        msg_Dbg( p_input, "adding ref = `%s'", psz_ref );
Gildas Bazin's avatar
 
Gildas Bazin committed
231 232
                        playlist_Add( p_playlist, psz_ref, 0, 0,
                                      PLAYLIST_APPEND, PLAYLIST_END );
233 234 235 236
                    }
                    else
                    {
                        /* msg dbg relative ? */
237 238
                        char *psz_absolute = alloca( strlen( p_input->psz_source ) + strlen( psz_ref ) + 1);
                        char *end = strrchr( p_input->psz_source, '/' );
239 240 241

                        if( end )
                        {
242
                            int i_len = end + 1 - p_input->psz_source;
243

244
                            strncpy( psz_absolute, p_input->psz_source, i_len);
245
                            psz_absolute[i_len] = '\0';
246 247 248 249 250 251 252
                        }
                        else
                        {
                            strcpy( psz_absolute, "" );
                        }
                        strcat( psz_absolute, psz_ref );
                        msg_Dbg( p_input, "adding ref = `%s'", psz_absolute );
Gildas Bazin's avatar
 
Gildas Bazin committed
253 254
                        playlist_Add( p_playlist, psz_absolute, 0, 0,
                                      PLAYLIST_APPEND, PLAYLIST_END );
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
                    }
                }
                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" );
        }
    }

270
    if( !(p_mvhd = MP4_BoxGet( &p_demux->box_root, "/moov/mvhd" ) ) )
271
    {
272 273 274
        if( !p_rmra )
        {
            msg_Err( p_input, "cannot find /moov/mvhd" );
275
            goto error;
276 277 278 279
        }
        else
        {
            msg_Warn( p_input, "cannot find /moov/mvhd (pure ref file)" );
280
            p_input->pf_demux = DemuxRef;
281
            return VLC_SUCCESS;
282
        }
283 284 285 286
    }
    else
    {
        p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
287
        p_demux->i_duration = p_mvhd->data.p_mvhd->i_duration;
288
    }
289

290
    if( !( p_demux->i_tracks =
291
                MP4_BoxCount( &p_demux->box_root, "/moov/trak" ) ) )
292
    {
293
        msg_Err( p_input, "cannot find any /moov/trak" );
294
        goto error;
295
    }
296 297 298
    msg_Dbg( p_input, "find %d track%c",
                        p_demux->i_tracks,
                        p_demux->i_tracks ? 's':' ' );
299

300 301 302 303 304 305
    /*  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" );
306
        goto error;
307 308 309 310 311 312
    }
    /* 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" );
313
        goto error;
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
    }
    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
    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 );


329 330 331 332 333 334
    /* 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++ )
    {
335
        p_trak = MP4_BoxGet( &p_demux->box_root, "/moov/trak[%d]", i );
336
        MP4_TrackCreate( p_input, &p_demux->track[i], p_trak );
337 338 339 340 341 342 343 344 345 346 347 348 349

        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:
350
                    psz_cat = "unknown";
351 352
                    break;
            }
353

354 355
            msg_Dbg( p_input, "adding track[Id 0x%x] %s (%s) language %c%c%c",
                            p_demux->track[i].i_track_ID,
356 357 358
                            psz_cat,
                            p_demux->track[i].b_enable ? "enable":"disable",
                            p_demux->track[i].i_language[0],
359
                            p_demux->track[i].i_language[1],
360 361 362 363
                            p_demux->track[i].i_language[2] );
        }
        else
        {
364
            msg_Dbg( p_input, "ignoring track[Id 0x%x]", p_demux->track[i].i_track_ID );
365 366 367
        }

    }
368

369
    for( i = 0, b_audio = VLC_FALSE; i < p_demux->i_tracks; i++ )
370
    {
371
#define track p_demux->track[i]
372
        /* start decoder for this track if enable by default*/
373 374
        if( track.b_ok && track.b_enable &&
            ( track.i_cat != AUDIO_ES || !b_audio ) )
375
        {
376 377 378 379 380 381 382
            if( !MP4_TrackSelect( p_input, &track, 0 ) )
            {
                if(track.i_cat == AUDIO_ES )
                {
                    b_audio = VLC_TRUE;
                }
            }
383
        }
384
#undef track
385 386 387 388 389
    }

    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 );
390

391 392 393 394 395
    return VLC_SUCCESS;

error:
    Close( VLC_OBJECT( p_input ) );
    return VLC_EGENERIC;
396 397 398
}

/*****************************************************************************
399
 * Demux: read packet and send them to decoders
400 401
 *****************************************************************************
 * TODO check for newly selected track (ie audio upt to now )
402
 *****************************************************************************/
403
static int Demux( input_thread_t *p_input )
404
{
405
    demux_sys_t *p_demux = p_input->p_demux_data;
406
    unsigned int i_track;
407

408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452

    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 );
    }

453 454 455 456 457 458 459 460
    /* 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;
461

462 463 464

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

466

Gildas Bazin's avatar
 
Gildas Bazin committed
467 468
    /* Check if we need to send the audio data to decoder */
    b_play_audio = !p_input->stream.control.b_mute;
469

470 471
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
472 473 474 475
#define track p_demux->track[i_track]
        if( !track.b_ok ||
            !track.b_selected ||
            MP4_GetTrackPTS( &track ) >= MP4_GetMoviePTS( p_demux ) )
476
        {
477
            continue;
478
        }
479
        while( MP4_GetTrackPTS( &track ) < MP4_GetMoviePTS( p_demux ) )
480 481
        {

482
            if( !b_play_audio && track.i_cat == AUDIO_ES )
483
            {
484 485 486 487
                if( MP4_TrackNextSample( p_input, &track ) )
                {
                    break;
                }
488
            }
489 490 491 492
            else
            {
                size_t i_size;
                off_t i_pos;
493

494 495
                data_packet_t *p_data;
                pes_packet_t *p_pes;
496

497 498
                /* caculate size and position for this sample */
                i_size = MP4_TrackSampleSize( &track );
499

500
                i_pos  = MP4_GetTrackPos( &track );
501

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

504
                /* go,go go ! */
505
                if( MP4_SeekAbsolute( p_input, i_pos ) )
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
                {
                    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;
                }
524 525
                p_data->p_payload_end = p_data->p_payload_start + i_size;

526 527 528 529 530 531 532
                /* 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 )
                {
533
                    if( MP4_ReadData( p_input, p_data->p_payload_start, i_size ) )
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
                    {
                        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 )
                {
Gildas Bazin's avatar
 
Gildas Bazin committed
550 551

                    p_pes->i_rate = p_input->stream.control.i_rate;
552 553 554 555 556 557 558 559 560 561 562 563
                    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;
                }
            }
564
        }
565
#undef track
566 567
    }

568
    return( 1 );
569
}
570
/*****************************************************************************
571
 * Seek: Got to i_date
572
 ******************************************************************************/
573
static int   Seek     ( input_thread_t *p_input, mtime_t i_date )
574 575
{
    demux_sys_t *p_demux = p_input->p_demux_data;
576
    unsigned int i_track;
577 578
    /* First update update global time */
    p_demux->i_time = i_date * p_demux->i_timescale / 1000000;
579
    p_demux->i_pcr  = i_date* 9 / 100;
580

581 582 583
    /* Now for each stream try to go to this time */
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
584 585 586 587 588 589
#define track p_demux->track[i_track]
        if( track.b_ok && track.b_selected )
        {
            MP4_TrackSeek( p_input, &track, i_date );
        }
#undef  track
590 591 592
    }
    return( 1 );
}
593 594

/*****************************************************************************
595
 * Control:
596
 *****************************************************************************/
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
static int   Control  ( input_thread_t *p_input, int i_query, va_list args )
{
    demux_sys_t *p_sys = p_input->p_demux_data;

    double   f, *pf;
    int64_t i64, *pi64;

    switch( i_query )
    {
        case DEMUX_GET_POSITION:
            pf = (double*)va_arg( args, double * );
            if( p_sys->i_duration > 0 )
            {
                *pf = (double)p_sys->i_time / (double)p_sys->i_duration;
            }
            else
            {
                *pf = 0.0;
            }
            return VLC_SUCCESS;

        case DEMUX_SET_POSITION:
            f = (double)va_arg( args, double );
            i64 = (int64_t)( f *
                             (double)1000000 *
                             (double)p_sys->i_duration /
                             (double)p_sys->i_timescale );
            return Seek( p_input, i64 );

        case DEMUX_GET_TIME:
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = (mtime_t)1000000 *
                    (mtime_t)p_sys->i_time /
                    (mtime_t)p_sys->i_timescale;
            return VLC_SUCCESS;

        case DEMUX_SET_TIME:
            i64 = (int64_t)va_arg( args, int64_t );
            return Seek( p_input, i64 );

        case DEMUX_GET_LENGTH:
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = (mtime_t)1000000 *
                    (mtime_t)p_sys->i_duration /
                    (mtime_t)p_sys->i_timescale;
            return VLC_SUCCESS;

        default:
            msg_Err( p_input, "control query unimplemented !!!" );
            return demux_vaControlDefault( p_input, i_query, args );
    }
}

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

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

    FREE( p_input->p_demux_data );
668 669 670
}


671

672 673 674 675
/****************************************************************************
 * Local functions, specific to vlc
 ****************************************************************************/

676 677 678
/* 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 )
679
{
680 681
    MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
    MP4_Box_t *p_stsc;
682

683 684 685 686 687 688
    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" ) ) ))
689
    {
690
        return( VLC_EGENERIC );
691
    }
692 693 694

    p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
    if( !p_demux_track->i_chunk_count )
695
    {
696 697
        msg_Warn( p_input, "no chunk defined" );
        return( VLC_EGENERIC );
698
    }
699 700 701 702 703
    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++ )
704
    {
705 706
        p_demux_track->chunk[i_chunk].i_offset =
                p_co64->data.p_co64->i_chunk_offset[i_chunk];
707 708
    }

709 710 711 712 713 714
    /* 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 )
715
    {
716 717
        msg_Warn( p_input, "cannot read chunk table or table empty" );
        return( VLC_EGENERIC );
718
    }
719 720

    while( i_index )
721
    {
722 723 724 725 726 727 728 729 730 731
        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;
732 733
    }

734 735
    p_demux_track->chunk[0].i_sample_first = 0;
    for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
736
    {
737 738 739
        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;
740
    }
741

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

747
    return( VLC_SUCCESS );
748
}
749 750
static int TrackCreateSamplesIndex( input_thread_t *p_input,
                                    track_data_mp4_t *p_demux_track )
751 752
{
    MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
753
                          ctts make same mapping but for composition time,
754
                          not yet used and probably not usefull */
755 756
    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
757 758 759
                          as a unique type */
    /* TODO use also stss and stsh table for seeking */
    /* FIXME use edit table */
760 761
    int64_t i_sample;
    int64_t i_chunk;
762

763 764
    int64_t i_index;
    int64_t i_index_sample_used;
765

766 767
    int64_t i_last_dts;

768 769
    p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
    p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */
770 771 772 773

    if( ( !p_stts )||( !p_stsz ) )
    {
        msg_Warn( p_input, "cannot read sample table" );
774
        return( VLC_EGENERIC );
775
    }
776

777 778 779 780 781 782 783 784 785 786 787 788 789 790
    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;
791
        p_demux_track->p_sample_size =
792
            calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
793

794 795
        for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
        {
796
            p_demux_track->p_sample_size[i_sample] =
797 798 799 800 801 802 803
                    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
804
       the box !, so each chunk will contain an "extract" of this table
805
       for fast research */
806

807 808
    i_last_dts = 0;
    i_index = 0; i_index_sample_used =0;
809

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

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

        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
821 822

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

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

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

847 848 849 850 851
            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;
852
            i_sample_count -= i_used;
853 854 855 856 857

            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];
858 859

            i_last_dts += i_used *
860 861 862 863 864
                    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] )
            {
865

866 867 868 869
                i_index++;
                i_index_sample_used = 0;
            }
        }
870

871 872
    }

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

879
    return( VLC_SUCCESS );
880 881
}

882 883 884 885 886 887 888 889 890
/*
 * 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 )
891
{
892 893
    MP4_Box_t *  p_sample;
    unsigned int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
894
    char psz_lang[4];
895

896 897
    unsigned int i_decoder_specific_info_len;
    uint8_t *    p_decoder_specific_info;
898 899 900

    es_descriptor_t *p_es;
    pes_packet_t    *p_pes_init;
901

902 903
    uint8_t             *p_init;
    BITMAPINFOHEADER    *p_bih;
904
    WAVEFORMATEX        *p_wf;
905

906
    MP4_Box_t   *p_esds;
907

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

    p_sample = MP4_BoxGet(  p_track->p_stsd,
917
                            "[%d]",
918
                p_track->chunk[i_chunk].i_sample_description_index - 1 );
919

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

928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
    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;
947 948 949 950 951 952 953 954 955 956 957 958 959 960
                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;
961 962 963 964 965 966
                default:
                    break;
            }
        }
    }

967 968 969
    /* Initialise ES, first language as description */
    for( i = 0; i < 3; i++ )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
970
        psz_lang[i] = p_track->i_language[i];
971
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
972 973 974 975 976 977
    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 );
978

979
    p_es->i_stream_id = p_track->i_track_ID;
980 981 982 983 984 985

    /* 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 ) ):
986 987 988 989
            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' );
990