mp4.c 57 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.24 2003/04/22 16:28:24 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
/* New input could have something like that... */
static int   MP4Seek     ( input_thread_t *, mtime_t );

48 49 50 51 52 53
#define MP4End(a) __MP4End(VLC_OBJECT(a))

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
vlc_module_begin();
Gildas Bazin's avatar
 
Gildas Bazin committed
54
    set_description( _("MP4 demuxer") );
55 56 57 58 59
    set_capability( "demux", 242 );
    set_callbacks( MP4Init, __MP4End );
vlc_module_end();

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

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

69 70 71 72 73
static int  MP4_TrackSelect ( input_thread_t *,
                              track_data_mp4_t *,
                              mtime_t );
static void MP4_TrackUnselect(input_thread_t *,
                              track_data_mp4_t * );
74

75 76 77
static int  MP4_TrackSeek   ( input_thread_t *,
                              track_data_mp4_t *,
                              mtime_t );
78

79 80 81 82
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 * );
83 84

#define MP4_Set4BytesLE( p, dw ) \
85 86 87 88
    *((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 )
89 90

#define MP4_Set2BytesLE( p, dw ) \
91 92
    *((uint8_t*)p) = ( (dw)&0xff ); \
    *((uint8_t*)p+1) = ( ((dw)>> 8)&0xff )
93

94 95
#define FREE( p ) \
    if( p ) { free( p ); (p) = NULL;}
96

97 98 99 100
/*****************************************************************************
 * MP4Init: check file and initializes MP4 structures
 *****************************************************************************/
static int MP4Init( vlc_object_t * p_this )
101
{
102 103
    input_thread_t  *p_input = (input_thread_t *)p_this;
    uint8_t         *p_peek;
104

105
    demux_sys_t     *p_demux;
106

107
    MP4_Box_t       *p_ftyp;
108

109
    MP4_Box_t       *p_rmra;
110

111 112
    MP4_Box_t       *p_mvhd;
    MP4_Box_t       *p_trak;
113

114
    unsigned int    i;
115 116 117 118 119
    /* I need to seek */
    if( !p_input->stream.b_seekable )
    {
        msg_Warn( p_input, "MP4 plugin discarded (unseekable)" );
        return( -1 );
120 121

    }
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
    /* 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)" );
        return( -1 );
    }
137

138

139
    switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) )
140 141 142 143 144
    {
        case( FOURCC_ftyp ):
        case( FOURCC_moov ):
        case( FOURCC_moof ):
        case( FOURCC_mdat ):
145
        case( FOURCC_udta ):
146 147
        case( FOURCC_free ):
        case( FOURCC_skip ):
148
        case( FOURCC_wide ):
149 150 151 152 153 154 155
            break;
         default:
            msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
            return( -1 );
    }

    /* create our structure that will contains all data */
156
    if( !( p_input->p_demux_data =
157
                p_demux = malloc( sizeof( demux_sys_t ) ) ) )
158 159 160 161
    {
        msg_Err( p_input, "out of memory" );
        return( -1 );
    }
162
    memset( p_demux, 0, sizeof( demux_sys_t ) );
163
    p_input->p_demux_data = p_demux;
164

165 166

    /* Now load all boxes ( except raw data ) */
167
    if( !MP4_BoxGetRoot( p_input, &p_demux->box_root ) )
168 169 170 171 172
    {
        msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
        return( -1 );
    }

173
    MP4_BoxDumpStructure( p_input, &p_demux->box_root );
174

175
    if( ( p_ftyp = MP4_BoxGet( &p_demux->box_root, "/ftyp" ) ) )
176 177 178 179
    {
        switch( p_ftyp->data.p_ftyp->i_major_brand )
        {
            case( FOURCC_isom ):
180
                msg_Dbg( p_input,
181 182
                         "ISO Media file (isom) version %d.",
                         p_ftyp->data.p_ftyp->i_minor_version );
183 184
                break;
            default:
185
                msg_Dbg( p_input,
186 187
                         "unrecognized major file specification (%4.4s).",
                          (char*)&p_ftyp->data.p_ftyp->i_major_brand );
188 189 190 191 192
                break;
        }
    }
    else
    {
193
        msg_Dbg( p_input, "file type box missing (assuming ISO Media file)" );
194 195 196
    }

    /* the file need to have one moov box */
197
    if( MP4_BoxCount( &p_demux->box_root, "/moov" ) != 1 )
198
    {
199
        msg_Err( p_input,
200
                 "MP4 plugin discarded (%d moov boxes)",
201
                 MP4_BoxCount( &p_demux->box_root, "/moov" ) );
202 203
//        MP4End( p_input );
//        return( -1 );
204 205
    }

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
    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 )
        {
            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;
                    }
242 243
                    if( !strncmp( psz_ref, "http://", 7 ) ||
                        !strncmp( psz_ref, "rtsp://", 7 ) )
244 245 246 247 248 249 250 251 252 253 254 255
                    {
                        msg_Dbg( p_input, "adding ref = `%s'", psz_ref );
                        playlist_Add( p_playlist, psz_ref, PLAYLIST_APPEND, PLAYLIST_END );
                    }
                    else
                    {
                        /* msg dbg relative ? */
                        char *psz_absolute = alloca( strlen( p_input->psz_name ) + strlen( psz_ref ) + 1);
                        char *end = strrchr( p_input->psz_name, '/' );

                        if( end )
                        {
256 257 258 259
                            int i_len = end + 1 - p_input->psz_name;

                            strncpy( psz_absolute, p_input->psz_name, i_len);
                            psz_absolute[i_len] = '\0';
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
                        }
                        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" );
        }
    }

283
    if( !(p_mvhd = MP4_BoxGet( &p_demux->box_root, "/moov/mvhd" ) ) )
284
    {
285 286 287 288 289 290 291 292
        if( !p_rmra )
        {
            msg_Err( p_input, "cannot find /moov/mvhd" );
        }
        else
        {
            msg_Warn( p_input, "cannot find /moov/mvhd (pure ref file)" );
        }
293 294 295 296 297 298
        MP4End( p_input );
        return( -1 );
    }
    else
    {
        p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
299
        p_demux->i_duration = p_mvhd->data.p_mvhd->i_duration;
300
    }
301

302
    if( !( p_demux->i_tracks =
303
                MP4_BoxCount( &p_demux->box_root, "/moov/trak" ) ) )
304
    {
305
        msg_Err( p_input, "cannot find any /moov/trak" );
306 307 308
        MP4End( p_input );
        return( -1 );
    }
309 310 311
    msg_Dbg( p_input, "find %d track%c",
                        p_demux->i_tracks,
                        p_demux->i_tracks ? 's':' ' );
312

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
    /*  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 );
        return( -1 );
    }
    /* 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 );
        return( -1 );
    }
    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 );


345 346 347 348 349 350
    /* 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++ )
    {
351
        p_trak = MP4_BoxGet( &p_demux->box_root, "/moov/trak[%d]", i );
352
        MP4_TrackCreate( p_input, &p_demux->track[i], p_trak );
353 354 355 356 357 358 359 360 361 362 363 364 365

        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:
366
                    psz_cat = "unknown";
367 368
                    break;
            }
369

370 371
            msg_Dbg( p_input, "adding track[Id 0x%x] %s (%s) language %c%c%c",
                            p_demux->track[i].i_track_ID,
372 373 374
                            psz_cat,
                            p_demux->track[i].b_enable ? "enable":"disable",
                            p_demux->track[i].i_language[0],
375
                            p_demux->track[i].i_language[1],
376 377 378 379
                            p_demux->track[i].i_language[2] );
        }
        else
        {
380
            msg_Dbg( p_input, "ignoring track[Id 0x%x]", p_demux->track[i].i_track_ID );
381 382 383
        }

    }
384

385 386 387
    for( i = 0; i < p_demux->i_tracks; i++ )
    {
        /* start decoder for this track if enable by default*/
388
        if( p_demux->track[i].b_ok && p_demux->track[i].b_enable )
389
        {
390
            MP4_TrackSelect( p_input, &p_demux->track[i], 0 );
391 392 393 394 395 396
        }
    }

    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 );
397 398

    return( 0 );
399 400 401 402

}

/*****************************************************************************
403
 * MP4Demux: read packet and send them to decoders
404 405
 *****************************************************************************
 * TODO check for newly selected track (ie audio upt to now )
406 407 408
 *****************************************************************************/
static int MP4Demux( input_thread_t *p_input )
{
409
    demux_sys_t *p_demux = p_input->p_demux_data;
410
    unsigned int i_track;
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 453 454 455 456 457

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


458
    /* XXX beurk, beuRK and BEURK,
459 460 461 462
       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;
463

464 465 466 467
        /* first wait for empty buffer, arbitrary time FIXME */
        msleep( DEFAULT_PTS_DELAY );
        /* *** calculate new date *** */

468
        i_date = (mtime_t)1000000 *
469
                 (mtime_t)p_demux->i_duration /
470
                 (mtime_t)p_demux->i_timescale *
471 472 473 474
                 (mtime_t)MP4_TellAbsolute( p_input ) /
                 (mtime_t)p_input->stream.p_selected_area->i_size;
        MP4Seek( p_input, i_date );
    }
475

476 477 478 479 480 481 482 483
    /* 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;
484

485 486 487

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

489

490 491 492 493 494 495 496 497 498 499 500 501
    /* *** 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 );

502 503
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
504 505 506 507
#define track p_demux->track[i_track]
        if( !track.b_ok ||
            !track.b_selected ||
            MP4_GetTrackPTS( &track ) >= MP4_GetMoviePTS( p_demux ) )
508
        {
509
            continue;
510
        }
511
        while( MP4_GetTrackPTS( &track ) < MP4_GetMoviePTS( p_demux ) )
512 513
        {

514
            if( !b_play_audio && track.i_cat == AUDIO_ES )
515
            {
516 517 518 519
                if( MP4_TrackNextSample( p_input, &track ) )
                {
                    break;
                }
520
            }
521 522 523 524
            else
            {
                size_t i_size;
                off_t i_pos;
525

526 527
                data_packet_t *p_data;
                pes_packet_t *p_pes;
528

529 530
                /* caculate size and position for this sample */
                i_size = MP4_TrackSampleSize( &track );
531

532
                i_pos  = MP4_GetTrackPos( &track );
533

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

536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
                /* go,go go ! */
                if( ! MP4_SeekAbsolute( p_input, i_pos ) )
                {
                    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;
                }
556 557
                p_data->p_payload_end = p_data->p_payload_start + i_size;

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
                /* 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 )
                {
                    if( !MP4_ReadData( p_input, p_data->p_payload_start, i_size ) )
                    {
                        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;
                }
            }
594
        }
595
#undef track
596 597
    }

598
    return( 1 );
599
}
600 601 602 603 604 605
/*****************************************************************************
 * 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;
606
    unsigned int i_track;
607 608
    /* First update update global time */
    p_demux->i_time = i_date * p_demux->i_timescale / 1000000;
609
    p_demux->i_pcr  = i_date* 9 / 100;
610

611 612 613
    /* Now for each stream try to go to this time */
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
614 615 616 617 618 619
#define track p_demux->track[i_track]
        if( track.b_ok && track.b_selected )
        {
            MP4_TrackSeek( p_input, &track, i_date );
        }
#undef  track
620 621 622
    }
    return( 1 );
}
623 624 625 626 627

/*****************************************************************************
 * MP4End: frees unused data
 *****************************************************************************/
static void __MP4End ( vlc_object_t * p_this )
628 629
{
    unsigned int i_track;
630
    input_thread_t *  p_input = (input_thread_t *)p_this;
631
    demux_sys_t *p_demux = p_input->p_demux_data;
632

633
    msg_Dbg( p_input, "freeing all memory" );
634
    MP4_BoxFree( p_input, &p_demux->box_root );
635 636
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
637
        MP4_TrackDestroy( p_input, &p_demux->track[i_track] );
638 639
    }
    FREE( p_demux->track );
640 641

    FREE( p_input->p_demux_data );
642 643 644 645 646 647 648
}


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

649 650 651
/* 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 )
652
{
653 654
    MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
    MP4_Box_t *p_stsc;
655

656 657 658 659 660 661
    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" ) ) ))
662
    {
663
        return( VLC_EGENERIC );
664
    }
665 666 667

    p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
    if( !p_demux_track->i_chunk_count )
668
    {
669 670
        msg_Warn( p_input, "no chunk defined" );
        return( VLC_EGENERIC );
671
    }
672 673 674 675 676
    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++ )
677
    {
678 679
        p_demux_track->chunk[i_chunk].i_offset =
                p_co64->data.p_co64->i_chunk_offset[i_chunk];
680 681
    }

682 683 684 685 686 687
    /* 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 )
688
    {
689 690
        msg_Warn( p_input, "cannot read chunk table or table empty" );
        return( VLC_EGENERIC );
691
    }
692 693

    while( i_index )
694
    {
695 696 697 698 699 700 701 702 703 704
        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;
705 706
    }

707 708
    p_demux_track->chunk[0].i_sample_first = 0;
    for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
709
    {
710 711 712
        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;
713
    }
714

715 716 717 718
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d chunk",
             p_demux_track->i_track_ID,
            p_demux_track->i_chunk_count );
719

720
    return( VLC_SUCCESS );
721
}
722 723
static int TrackCreateSamplesIndex( input_thread_t *p_input,
                                    track_data_mp4_t *p_demux_track )
724 725
{
    MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
726
                          ctts make same mapping but for composition time,
727
                          not yet used and probably not usefull */
728 729
    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
730 731 732
                          as a unique type */
    /* TODO use also stss and stsh table for seeking */
    /* FIXME use edit table */
733 734
    int64_t i_sample;
    int64_t i_chunk;
735

736 737
    int64_t i_index;
    int64_t i_index_sample_used;
738

739 740
    int64_t i_last_dts;

741 742
    p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
    p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */
743 744 745 746

    if( ( !p_stts )||( !p_stsz ) )
    {
        msg_Warn( p_input, "cannot read sample table" );
747
        return( VLC_EGENERIC );
748
    }
749

750 751 752 753 754 755 756 757 758 759 760 761 762 763
    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;
764
        p_demux_track->p_sample_size =
765
            calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
766

767 768
        for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
        {
769
            p_demux_track->p_sample_size[i_sample] =
770 771 772 773 774 775 776
                    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
777
       the box !, so each chunk will contain an "extract" of this table
778
       for fast research */
779

780 781
    i_last_dts = 0;
    i_index = 0; i_index_sample_used =0;
782

783 784 785 786
    /* create and init last data for each chunk */
    for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
    {

787
        int64_t i_entry, i_sample_count, i;
788 789
        /* save last dts */
        p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
790
    /* count how many entries needed for this chunk
791 792 793
       for p_sample_delta_dts and p_sample_count_dts */

        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
794 795

        i_entry = 0;
796 797 798 799 800
        while( i_sample_count > 0 )
        {
            i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];
            if( i_entry == 0 )
            {
801
                i_sample_count += i_index_sample_used; /* don't count already used sample
802 803 804 805
                                                   int this entry */
            }
            i_entry++;
        }
806

807
        /* allocate them */
808
        p_demux_track->chunk[i_chunk].p_sample_count_dts =
809
            calloc( i_entry, sizeof( uint32_t ) );
810
        p_demux_track->chunk[i_chunk].p_sample_delta_dts =
811
            calloc( i_entry, sizeof( uint32_t ) );
812 813 814 815 816

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

820 821 822 823 824
            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;
825
            i_sample_count -= i_used;
826 827 828 829 830

            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];
831 832

            i_last_dts += i_used *
833 834 835 836 837
                    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] )
            {
838

839 840 841 842
                i_index++;
                i_index_sample_used = 0;
            }
        }
843

844 845
    }

846 847
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d samples length:"I64Fd"s",
848
             p_demux_track->i_track_ID,
849 850
             p_demux_track->i_sample_count,
             i_last_dts / p_demux_track->i_timescale );
851

852
    return( VLC_SUCCESS );
853 854
}

855 856 857 858 859 860 861 862 863
/*
 * 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 )
864
{
865 866
    MP4_Box_t *  p_sample;
    unsigned int i;
867

868 869
    unsigned int i_decoder_specific_info_len;
    uint8_t *    p_decoder_specific_info;
870 871 872

    es_descriptor_t *p_es;
    pes_packet_t    *p_pes_init;
873

874 875
    uint8_t             *p_init;
    BITMAPINFOHEADER    *p_bih;
876
    WAVEFORMATEX        *p_wf;
877

878
    MP4_Box_t   *p_esds;
879

880
    if( !p_track->chunk[i_chunk].i_sample_description_index )
881
    {
882
        msg_Warn( p_input,
883
                  "invalid SampleEntry index (track[Id 0x%x])",
884 885
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
886
    }
887 888

    p_sample = MP4_BoxGet(  p_track->p_stsd,
889
                            "[%d]",
890
                p_track->chunk[i_chunk].i_sample_description_index - 1 );
891

892
    if( !p_sample || !p_sample->data.p_data )
893
    {
894
        msg_Warn( p_input,
895
                  "cannot find SampleEntry (track[Id 0x%x])",
896 897
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
898 899
    }

900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
    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;
                default:
                    break;
            }
        }
    }


926
    vlc_mutex_lock( &p_input->stream.stream_lock );
927 928 929 930
    p_es = input_AddES( p_input,
                        p_input->stream.p_selected_program,
                        p_track->i_track_ID,
                        0 );
931 932 933 934
    vlc_mutex_unlock( &p_input->stream.stream_lock );
    /* Initialise ES, first language as description */
    for( i = 0; i < 3; i++ )
    {
935
        p_es->psz_desc[i] = p_track->i_language[i];
936
    }
937
    p_es->psz_desc[3] = '\0';
938

939
    p_es->i_stream_id = p_track->i_track_ID;
940 941 942 943 944 945

    /* 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 ) ):
946 947 948 949
            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' );
950 951
            break;
        default:
952
            p_es->i_fourcc = p_sample->i_type;
953 954
            break;
    }
955

956
    p_es->i_cat = p_track->i_cat;
957

958 959
    i_decoder_specific_info_len = 0;
    p_decoder_specific_info = NULL;
960
    p_pes_init = NULL;
961

962
    /* now see if esds is present and if so create a data packet
963 964
        with decoder_specific_info  */
#define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr
965
    if( ( p_esds = MP4_BoxGet( p_sample, "esds" ) )&&
966 967 968 969 970 971 972
        ( p_esds->data.p_esds )&&
        ( p_decconfig ) )
    {
        /* First update information based on i_objectTypeIndication */
        switch( p_decconfig->i_objectTypeIndication )
        {
            case( 0x20 ): /* MPEG4 VIDEO */
973
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','v' );
974 975
                break;
            case( 0x40):
976
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
977 978 979 980 981 982 983
                break;
            case( 0x60):
            case( 0x61):
            case( 0x62):
            case( 0x63):
            case( 0x64):
            case( 0x65): /* MPEG2 video */
984
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
985
                break;
986
            /* Theses are MPEG2-AAC */
987 988 989
            case( 0x66): /* main profile */
            case( 0x67): /* Low complexity profile */
            case( 0x68): /* Scaleable Sampling rate profile */
990
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
991 992
                break;
            /* true MPEG 2 audio */
993
            case( 0x69):
994
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
995 996
                break;
            case( 0x6a): /* MPEG1 video */
997
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
998 999
                break;
            case( 0x6b): /* MPEG1 audio */
1000
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
1001 1002
                break;
            case( 0x6c ): /* jpeg */
1003
                p_es->i_fourcc = VLC_FOURCC( 'j','p','e','g' );
1004 1005 1006
                break;
            default:
                /* Unknown entry, but don't touch i_fourcc */
1007
                msg_Warn( p_input,
1008
                          "unknown objectTypeIndication(0x%x) (Track[ID 0x%x])",
1009
                          p_decconfig->i_objectTypeIndication,
1010
                          p_track->i_track_ID );
1011 1012
                break;
        }
1013
        i_decoder_specific_info_len =
1014
                p_decconfig->i_decoder_specific_info_len;
1015
        p_decoder_specific_info =
1016 1017
                p_decconfig->p_decoder_specific_info;
    }
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
    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;
        }
    }
1038 1039 1040 1041

#undef p_decconfig

    /* some last initialisation */
1042 1043 1044
    /* 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
1045 1046 1047
       like adding some new fields in p_es ...

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

1052
        TODO set more values
1053

1054 1055