mp4.c 53 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.21 2003/04/14 03:23:30 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 "codecs.h"
34 35 36 37 38 39 40 41 42 43
#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 * );

44 45 46
/* New input could have something like that... */
static int   MP4Seek     ( input_thread_t *, mtime_t );

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

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

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

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

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

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

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

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

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

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

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

104
    demux_sys_t     *p_demux;
105

106
    MP4_Box_t       *p_ftyp;
107 108


109 110
    MP4_Box_t       *p_mvhd;
    MP4_Box_t       *p_trak;
111

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

    }
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
    /* 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 );
    }
135

136

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

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

163 164

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

171
    MP4_BoxDumpStructure( p_input, &p_demux->box_root );
172

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

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

204
    if( !(p_mvhd = MP4_BoxGet( &p_demux->box_root, "/moov/mvhd" ) ) )
205
    {
206
        msg_Err( p_input, "cannot find /moov/mvhd" );
207 208 209 210 211 212
        MP4End( p_input );
        return( -1 );
    }
    else
    {
        p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
213
        p_demux->i_duration = p_mvhd->data.p_mvhd->i_duration;
214
    }
215

216
    if( !( p_demux->i_tracks =
217
                MP4_BoxCount( &p_demux->box_root, "/moov/trak" ) ) )
218
    {
219
        msg_Err( p_input, "cannot find any /moov/trak" );
220 221 222
        MP4End( p_input );
        return( -1 );
    }
223 224 225
    msg_Dbg( p_input, "find %d track%c",
                        p_demux->i_tracks,
                        p_demux->i_tracks ? 's':' ' );
226

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
    /*  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 );


259 260 261 262 263 264
    /* 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++ )
    {
265
        p_trak = MP4_BoxGet( &p_demux->box_root, "/moov/trak[%d]", i );
266
        MP4_TrackCreate( p_input, &p_demux->track[i], p_trak );
267 268 269 270 271 272 273 274 275 276 277 278 279

        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:
280
                    psz_cat = "unknown";
281 282
                    break;
            }
283

284 285
            msg_Dbg( p_input, "adding track[Id 0x%x] %s (%s) language %c%c%c",
                            p_demux->track[i].i_track_ID,
286 287 288
                            psz_cat,
                            p_demux->track[i].b_enable ? "enable":"disable",
                            p_demux->track[i].i_language[0],
289
                            p_demux->track[i].i_language[1],
290 291 292 293
                            p_demux->track[i].i_language[2] );
        }
        else
        {
294
            msg_Dbg( p_input, "ignoring track[Id 0x%x]", p_demux->track[i].i_track_ID );
295 296 297
        }

    }
298

299 300 301
    for( i = 0; i < p_demux->i_tracks; i++ )
    {
        /* start decoder for this track if enable by default*/
302
        if( p_demux->track[i].b_ok && p_demux->track[i].b_enable )
303
        {
304
            MP4_TrackSelect( p_input, &p_demux->track[i], 0 );
305 306 307 308 309 310
        }
    }

    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 );
311 312

    return( 0 );
313 314 315 316

}

/*****************************************************************************
317
 * MP4Demux: read packet and send them to decoders
318 319
 *****************************************************************************
 * TODO check for newly selected track (ie audio upt to now )
320 321 322
 *****************************************************************************/
static int MP4Demux( input_thread_t *p_input )
{
323
    demux_sys_t *p_demux = p_input->p_demux_data;
324
    unsigned int i_track;
325

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371

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


372
    /* XXX beurk, beuRK and BEURK,
373 374 375 376
       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;
377

378 379 380 381
        /* first wait for empty buffer, arbitrary time FIXME */
        msleep( DEFAULT_PTS_DELAY );
        /* *** calculate new date *** */

382
        i_date = (mtime_t)1000000 *
383
                 (mtime_t)p_demux->i_duration /
384
                 (mtime_t)p_demux->i_timescale *
385 386 387 388
                 (mtime_t)MP4_TellAbsolute( p_input ) /
                 (mtime_t)p_input->stream.p_selected_area->i_size;
        MP4Seek( p_input, i_date );
    }
389

390 391 392 393 394 395 396 397
    /* 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;
398

399 400 401

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

403

404 405 406 407 408 409 410 411 412 413 414 415
    /* *** 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 );

416 417
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
418 419 420 421
#define track p_demux->track[i_track]
        if( !track.b_ok ||
            !track.b_selected ||
            MP4_GetTrackPTS( &track ) >= MP4_GetMoviePTS( p_demux ) )
422
        {
423
            continue;
424
        }
425
        while( MP4_GetTrackPTS( &track ) < MP4_GetMoviePTS( p_demux ) )
426 427
        {

428
            if( !b_play_audio && track.i_cat == AUDIO_ES )
429
            {
430 431 432 433
                if( MP4_TrackNextSample( p_input, &track ) )
                {
                    break;
                }
434
            }
435 436 437 438
            else
            {
                size_t i_size;
                off_t i_pos;
439

440 441
                data_packet_t *p_data;
                pes_packet_t *p_pes;
442

443 444
                /* caculate size and position for this sample */
                i_size = MP4_TrackSampleSize( &track );
445

446
                i_pos  = MP4_GetTrackPos( &track );
447

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
                /* 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;
                }
468 469
                p_data->p_payload_end = p_data->p_payload_start + i_size;

470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
                /* 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;
                }
            }
506
        }
507
#undef track
508 509
    }

510
    return( 1 );
511
}
512 513 514 515 516 517
/*****************************************************************************
 * 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;
518
    unsigned int i_track;
519 520
    /* First update update global time */
    p_demux->i_time = i_date * p_demux->i_timescale / 1000000;
521
    p_demux->i_pcr  = i_date* 9 / 100;
522

523 524 525
    /* Now for each stream try to go to this time */
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
526 527 528 529 530 531
#define track p_demux->track[i_track]
        if( track.b_ok && track.b_selected )
        {
            MP4_TrackSeek( p_input, &track, i_date );
        }
#undef  track
532 533 534
    }
    return( 1 );
}
535 536 537 538 539

/*****************************************************************************
 * MP4End: frees unused data
 *****************************************************************************/
static void __MP4End ( vlc_object_t * p_this )
540 541
{
    unsigned int i_track;
542
    input_thread_t *  p_input = (input_thread_t *)p_this;
543
    demux_sys_t *p_demux = p_input->p_demux_data;
544

545
    msg_Dbg( p_input, "freeing all memory" );
546
    MP4_BoxFree( p_input, &p_demux->box_root );
547 548
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
549
        MP4_TrackDestroy( p_input, &p_demux->track[i_track] );
550 551
    }
    FREE( p_demux->track );
552 553

    FREE( p_input->p_demux_data );
554 555 556 557 558 559 560
}


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

561 562 563
/* 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 )
564
{
565 566
    MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
    MP4_Box_t *p_stsc;
567

568 569 570 571 572 573
    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" ) ) ))
574
    {
575
        return( VLC_EGENERIC );
576
    }
577 578 579

    p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
    if( !p_demux_track->i_chunk_count )
580
    {
581 582
        msg_Warn( p_input, "no chunk defined" );
        return( VLC_EGENERIC );
583
    }
584 585 586 587 588
    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++ )
589
    {
590 591
        p_demux_track->chunk[i_chunk].i_offset =
                p_co64->data.p_co64->i_chunk_offset[i_chunk];
592 593
    }

594 595 596 597 598 599
    /* 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 )
600
    {
601 602
        msg_Warn( p_input, "cannot read chunk table or table empty" );
        return( VLC_EGENERIC );
603
    }
604 605

    while( i_index )
606
    {
607 608 609 610 611 612 613 614 615 616
        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;
617 618
    }

619 620
    p_demux_track->chunk[0].i_sample_first = 0;
    for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
621
    {
622 623 624
        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;
625
    }
626

627 628 629 630
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d chunk",
             p_demux_track->i_track_ID,
            p_demux_track->i_chunk_count );
631

632
    return( VLC_SUCCESS );
633
}
634 635
static int TrackCreateSamplesIndex( input_thread_t *p_input,
                                    track_data_mp4_t *p_demux_track )
636 637
{
    MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
638
                          ctts make same mapping but for composition time,
639
                          not yet used and probably not usefull */
640 641
    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
642 643 644
                          as a unique type */
    /* TODO use also stss and stsh table for seeking */
    /* FIXME use edit table */
645 646
    int64_t i_sample;
    int64_t i_chunk;
647

648 649
    int64_t i_index;
    int64_t i_index_sample_used;
650

651 652
    int64_t i_last_dts;

653 654
    p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
    p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */
655 656 657 658

    if( ( !p_stts )||( !p_stsz ) )
    {
        msg_Warn( p_input, "cannot read sample table" );
659
        return( VLC_EGENERIC );
660
    }
661

662 663 664 665 666 667 668 669 670 671 672 673 674 675
    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;
676
        p_demux_track->p_sample_size =
677
            calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
678

679 680
        for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
        {
681
            p_demux_track->p_sample_size[i_sample] =
682 683 684 685 686 687 688
                    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
689
       the box !, so each chunk will contain an "extract" of this table
690
       for fast research */
691

692 693
    i_last_dts = 0;
    i_index = 0; i_index_sample_used =0;
694

695 696 697 698
    /* create and init last data for each chunk */
    for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
    {

699
        int64_t i_entry, i_sample_count, i;
700 701
        /* save last dts */
        p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
702
    /* count how many entries needed for this chunk
703 704 705
       for p_sample_delta_dts and p_sample_count_dts */

        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
706 707

        i_entry = 0;
708 709 710 711 712
        while( i_sample_count > 0 )
        {
            i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];
            if( i_entry == 0 )
            {
713
                i_sample_count += i_index_sample_used; /* don't count already used sample
714 715 716 717
                                                   int this entry */
            }
            i_entry++;
        }
718

719
        /* allocate them */
720
        p_demux_track->chunk[i_chunk].p_sample_count_dts =
721
            calloc( i_entry, sizeof( uint32_t ) );
722
        p_demux_track->chunk[i_chunk].p_sample_delta_dts =
723
            calloc( i_entry, sizeof( uint32_t ) );
724 725 726 727 728

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

732 733 734 735 736
            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;
737
            i_sample_count -= i_used;
738 739 740 741 742

            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];
743 744

            i_last_dts += i_used *
745 746 747 748 749
                    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] )
            {
750

751 752 753 754
                i_index++;
                i_index_sample_used = 0;
            }
        }
755

756 757
    }

758 759
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d samples length:"I64Fd"s",
760
             p_demux_track->i_track_ID,
761 762
             p_demux_track->i_sample_count,
             i_last_dts / p_demux_track->i_timescale );
763

764
    return( VLC_SUCCESS );
765 766
}

767 768 769 770 771 772 773 774 775
/*
 * 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 )
776
{
777 778
    MP4_Box_t *  p_sample;
    unsigned int i;
779

780 781
    unsigned int i_decoder_specific_info_len;
    uint8_t *    p_decoder_specific_info;
782 783 784

    es_descriptor_t *p_es;
    pes_packet_t    *p_pes_init;
785

786 787
    uint8_t             *p_init;
    BITMAPINFOHEADER    *p_bih;
788
    WAVEFORMATEX        *p_wf;
789

790
    MP4_Box_t   *p_esds;
791

792
    if( !p_track->chunk[i_chunk].i_sample_description_index )
793
    {
794
        msg_Warn( p_input,
795
                  "invalid SampleEntry index (track[Id 0x%x])",
796 797
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
798
    }
799 800

    p_sample = MP4_BoxGet(  p_track->p_stsd,
801
                            "[%d]",
802
                p_track->chunk[i_chunk].i_sample_description_index - 1 );
803

804
    if( !p_sample || !p_sample->data.p_data )
805
    {
806
        msg_Warn( p_input,
807
                  "cannot find SampleEntry (track[Id 0x%x])",
808 809
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
810 811
    }

812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
    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;
            }
        }
    }


838
    vlc_mutex_lock( &p_input->stream.stream_lock );
839 840 841 842
    p_es = input_AddES( p_input,
                        p_input->stream.p_selected_program,
                        p_track->i_track_ID,
                        0 );
843 844 845 846
    vlc_mutex_unlock( &p_input->stream.stream_lock );
    /* Initialise ES, first language as description */
    for( i = 0; i < 3; i++ )
    {
847
        p_es->psz_desc[i] = p_track->i_language[i];
848
    }
849
    p_es->psz_desc[3] = '\0';
850

851
    p_es->i_stream_id = p_track->i_track_ID;
852 853 854 855 856 857

    /* 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 ) ):
858 859 860 861
            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' );
862 863
            break;
        default:
864
            p_es->i_fourcc = p_sample->i_type;
865 866
            break;
    }
867

868
    p_es->i_cat = p_track->i_cat;
869

870 871
    i_decoder_specific_info_len = 0;
    p_decoder_specific_info = NULL;
872
    p_pes_init = NULL;
873

874
    /* now see if esds is present and if so create a data packet
875 876
        with decoder_specific_info  */
#define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr
877
    if( ( p_esds = MP4_BoxGet( p_sample, "esds" ) )&&
878 879 880 881 882 883 884
        ( p_esds->data.p_esds )&&
        ( p_decconfig ) )
    {
        /* First update information based on i_objectTypeIndication */
        switch( p_decconfig->i_objectTypeIndication )
        {
            case( 0x20 ): /* MPEG4 VIDEO */
885
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','v' );
886 887
                break;
            case( 0x40):
888
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
889 890 891 892 893 894 895
                break;
            case( 0x60):
            case( 0x61):
            case( 0x62):
            case( 0x63):
            case( 0x64):
            case( 0x65): /* MPEG2 video */
896
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
897
                break;
898
            /* Theses are MPEG2-AAC */
899 900 901
            case( 0x66): /* main profile */
            case( 0x67): /* Low complexity profile */
            case( 0x68): /* Scaleable Sampling rate profile */
902
                p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
903 904
                break;
            /* true MPEG 2 audio */
905
            case( 0x69):
906
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
907 908
                break;
            case( 0x6a): /* MPEG1 video */
909
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
910 911
                break;
            case( 0x6b): /* MPEG1 audio */
912
                p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
913 914
                break;
            case( 0x6c ): /* jpeg */
915
                p_es->i_fourcc = VLC_FOURCC( 'j','p','e','g' );
916 917 918
                break;
            default:
                /* Unknown entry, but don't touch i_fourcc */
919
                msg_Warn( p_input,
920
                          "unknown objectTypeIndication(0x%x) (Track[ID 0x%x])",
921
                          p_decconfig->i_objectTypeIndication,
922
                          p_track->i_track_ID );
923 924
                break;
        }
925
        i_decoder_specific_info_len =
926
                p_decconfig->i_decoder_specific_info_len;
927
        p_decoder_specific_info =
928 929 930 931 932 933
                p_decconfig->p_decoder_specific_info;
    }

#undef p_decconfig

    /* some last initialisation */
934 935 936
    /* 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
937 938 939
       like adding some new fields in p_es ...

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

944
        TODO set more values
945

946 947
     */

948
    switch( p_track->i_cat )
949
    {
950 951
        case( VIDEO_ES ):
            /* now create a bitmapinfoheader_t for decoder and
952
               add information found in p_esds */
953 954
            /* XXX XXX + 16 are for avoid segfault when ffmpeg access beyong the data */
            p_init = malloc( sizeof( BITMAPINFOHEADER ) + i_decoder_specific_info_len + 16 );
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
            p_bih = (BITMAPINFOHEADER*)p_init;

            p_bih->biSize     = sizeof( BITMAPINFOHEADER ) + i_decoder_specific_info_len;
            p_bih->biWidth    = p_sample->data.p_sample_vide->i_width;
            p_bih->biHeight   = p_sample->data.p_sample_vide->i_height;
            p_bih->biPlanes   = 1;      // FIXME
            p_bih->biBitCount = 0;      // FIXME
            p_bih->biCompression   = 0; // FIXME
            p_bih->biSizeImage     = 0; // FIXME
            p_bih->biXPelsPerMeter = 0; // FIXME
            p_bih->biYPelsPerMeter = 0; // FIXME
            p_bih->biClrUsed       = 0; // FIXME
            p_bih->biClrImportant  = 0; // FIXME

            if( p_bih->biWidth == 0 )
970
            {
971
                // fall on display size
972
                p_bih->biWidth = p_track->i_width;
973
            }
Laurent Aimar's avatar