mp4.c 59.4 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.37 2003/09/12 16:26:40 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
    /*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 ) );
144 145

    /* Now load all boxes ( except raw data ) */
Laurent Aimar's avatar
Laurent Aimar committed
146
    if( ( p_demux->p_root = MP4_BoxGetRoot( p_input ) ) == NULL )
147 148
    {
        msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
Laurent Aimar's avatar
Laurent Aimar committed
149
        goto error;
150 151
    }

Laurent Aimar's avatar
Laurent Aimar committed
152
    MP4_BoxDumpStructure( p_input, p_demux->p_root );
153

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

    /* the file need to have one moov box */
Laurent Aimar's avatar
Laurent Aimar committed
176
    if( MP4_BoxCount( p_demux->p_root, "/moov" ) <= 0 )
177
    {
Laurent Aimar's avatar
Laurent Aimar committed
178
        MP4_Box_t *p_foov = MP4_BoxGet( p_demux->p_root, "/foov" );
179 180 181 182

        if( !p_foov )
        {
            msg_Err( p_input, "MP4 plugin discarded (no moov box)" );
183
            goto error;
184 185 186
        }
        /* we have a free box as a moov, rename it */
        p_foov->i_type = FOURCC_moov;
187 188
    }

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

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

243
                            strncpy( psz_absolute, p_input->psz_source, i_len);
244
                            psz_absolute[i_len] = '\0';
245 246 247 248 249 250 251
                        }
                        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
252 253
                        playlist_Add( p_playlist, psz_absolute, 0, 0,
                                      PLAYLIST_APPEND, PLAYLIST_END );
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
                    }
                }
                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" );
        }
    }

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

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

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


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

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

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

    }
367

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

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

390 391 392
    return VLC_SUCCESS;

error:
Laurent Aimar's avatar
Laurent Aimar committed
393 394 395 396 397
    if( p_demux->p_root )
    {
        MP4_BoxFree( p_input, p_demux->p_root );
    }
    free( p_demux );
398
    return VLC_EGENERIC;
399 400 401
}

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

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

456 457 458 459 460 461 462 463
    /* 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;
464

465 466 467

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

469

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

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

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

497
                pes_packet_t *p_pes;
498

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

502
                i_pos  = MP4_GetTrackPos( &track );
503

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

506
                /* go,go go ! */
507
                if( stream_Seek( p_input->s, i_pos ) )
508 509 510 511 512 513
                {
                    msg_Warn( p_input, "track[0x%x] will be disabled (eof?)", track.i_track_ID );
                    MP4_TrackUnselect( p_input, &track );
                    break;
                }

Laurent Aimar's avatar
Laurent Aimar committed
514
                /* now read pes */
515
                if( ( p_pes = stream_PesPacket( p_input->s, i_size ) ) == NULL )
516
                {
Laurent Aimar's avatar
Laurent Aimar committed
517 518
                    msg_Warn( p_input, "track[0x%x] will be disabled (eof?)", track.i_track_ID );
                    MP4_TrackUnselect( p_input, &track );
519 520 521 522 523 524 525 526 527
                    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
528 529

                    p_pes->i_rate = p_input->stream.control.i_rate;
530 531 532 533 534 535 536 537 538 539 540 541
                    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;
                }
            }
542
        }
543
#undef track
544 545
    }

546
    return( 1 );
547
}
548
/*****************************************************************************
549
 * Seek: Got to i_date
550
 ******************************************************************************/
551
static int   Seek     ( input_thread_t *p_input, mtime_t i_date )
552 553
{
    demux_sys_t *p_demux = p_input->p_demux_data;
554
    unsigned int i_track;
555 556
    /* First update update global time */
    p_demux->i_time = i_date * p_demux->i_timescale / 1000000;
557
    p_demux->i_pcr  = i_date* 9 / 100;
558

559 560 561
    /* Now for each stream try to go to this time */
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
562 563 564 565 566 567
#define track p_demux->track[i_track]
        if( track.b_ok && track.b_selected )
        {
            MP4_TrackSeek( p_input, &track, i_date );
        }
#undef  track
568 569 570
    }
    return( 1 );
}
571 572

/*****************************************************************************
573
 * Control:
574
 *****************************************************************************/
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
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 )
632 633
{
    unsigned int i_track;
634
    input_thread_t *  p_input = (input_thread_t *)p_this;
635
    demux_sys_t *p_demux = p_input->p_demux_data;
636

637
    msg_Dbg( p_input, "freeing all memory" );
Laurent Aimar's avatar
Laurent Aimar committed
638 639

    MP4_BoxFree( p_input, p_demux->p_root );
640 641
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
642
        MP4_TrackDestroy( p_input, &p_demux->track[i_track] );
643 644
    }
    FREE( p_demux->track );
645 646

    FREE( p_input->p_demux_data );
647 648 649
}


650

651 652 653 654
/****************************************************************************
 * Local functions, specific to vlc
 ****************************************************************************/

655 656 657
/* 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 )
658
{
659 660
    MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
    MP4_Box_t *p_stsc;
661

662 663 664 665 666 667
    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" ) ) ))
668
    {
669
        return( VLC_EGENERIC );
670
    }
671 672 673

    p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
    if( !p_demux_track->i_chunk_count )
674
    {
675 676
        msg_Warn( p_input, "no chunk defined" );
        return( VLC_EGENERIC );
677
    }
678 679 680 681 682
    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++ )
683
    {
684 685
        p_demux_track->chunk[i_chunk].i_offset =
                p_co64->data.p_co64->i_chunk_offset[i_chunk];
686 687
    }

688 689 690 691 692 693
    /* 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 )
694
    {
695 696
        msg_Warn( p_input, "cannot read chunk table or table empty" );
        return( VLC_EGENERIC );
697
    }
698 699

    while( i_index )
700
    {
701 702 703 704 705 706 707 708 709 710
        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;
711 712
    }

713 714
    p_demux_track->chunk[0].i_sample_first = 0;
    for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
715
    {
716 717 718
        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;
719
    }
720

721 722 723 724
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d chunk",
             p_demux_track->i_track_ID,
            p_demux_track->i_chunk_count );
725

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

742 743
    int64_t i_index;
    int64_t i_index_sample_used;
744

745 746
    int64_t i_last_dts;

747 748
    p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
    p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */
749 750 751 752

    if( ( !p_stts )||( !p_stsz ) )
    {
        msg_Warn( p_input, "cannot read sample table" );
753
        return( VLC_EGENERIC );
754
    }
755

756 757 758 759 760 761 762 763 764 765 766 767 768 769
    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;
770
        p_demux_track->p_sample_size =
771
            calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
772

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

786 787
    i_last_dts = 0;
    i_index = 0; i_index_sample_used =0;
788

789 790 791 792
    /* create and init last data for each chunk */
    for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
    {

793
        int64_t i_entry, i_sample_count, i;
794 795
        /* save last dts */
        p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
796
    /* count how many entries needed for this chunk
797 798 799
       for p_sample_delta_dts and p_sample_count_dts */

        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
800 801

        i_entry = 0;
802 803 804 805 806
        while( i_sample_count > 0 )
        {
            i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];
            if( i_entry == 0 )
            {
807
                i_sample_count += i_index_sample_used; /* don't count already used sample
808 809 810 811
                                                   int this entry */
            }
            i_entry++;
        }
812

813
        /* allocate them */
814
        p_demux_track->chunk[i_chunk].p_sample_count_dts =
815
            calloc( i_entry, sizeof( uint32_t ) );
816
        p_demux_track->chunk[i_chunk].p_sample_delta_dts =
817
            calloc( i_entry, sizeof( uint32_t ) );
818 819 820 821 822

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

826 827 828 829 830
            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;
831
            i_sample_count -= i_used;
832 833 834 835 836

            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];
837 838

            i_last_dts += i_used *
839 840 841 842 843
                    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] )
            {
844

845 846 847 848
                i_index++;
                i_index_sample_used = 0;
            }
        }
849

850 851
    }

852 853
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d samples length:"I64Fd"s",
854
             p_demux_track->i_track_ID,
855 856
             p_demux_track->i_sample_count,
             i_last_dts / p_demux_track->i_timescale );
857

858
    return( VLC_SUCCESS );
859 860
}

861 862 863 864 865 866 867 868 869
/*
 * 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 )
870
{
871 872
    MP4_Box_t *  p_sample;
    unsigned int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
873
    char psz_lang[4];
874

875 876
    unsigned int i_decoder_specific_info_len;
    uint8_t *    p_decoder_specific_info;
877 878 879

    es_descriptor_t *p_es;
    pes_packet_t    *p_pes_init;
880

881 882
    uint8_t             *p_init;
    BITMAPINFOHEADER    *p_bih;
883
    WAVEFORMATEX        *p_wf;
884

885
    MP4_Box_t   *p_esds;
886

887
    if( !p_track->chunk[i_chunk].i_sample_description_index )
888
    {
889
        msg_Warn( p_input,
890
                  "invalid SampleEntry index (track[Id 0x%x])",
891 892
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
893
    }
894 895

    p_sample = MP4_BoxGet(  p_track->p_stsd,
896
                            "[%d]",
897
                p_track->chunk[i_chunk].i_sample_description_index - 1 );
898

899
    if( !p_sample || !p_sample->data.p_data )
900
    {
901
        msg_Warn( p_input,
902
                  "cannot find SampleEntry (track[Id 0x%x])",
903 904
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
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;
926 927 928 929 930 931 932 933 934 935 936 937 938 939
                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;
940 941 942 943 944 945
                default:
                    break;
            }
        }
    }

946 947 948
    /* Initialise ES, first language as description */
    for( i = 0; i < 3; i++ )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
949
        psz_lang[i] = p_track->i_language[i];
950
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
951 952 953 954 955 956
    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 );
957

958
    p_es->i_stream_id = p_track->i_track_ID;
959 960 961 962 963 964

    /* 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 ) ):
965 966 967 968
            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' );
969
            break;
970 971 972
        case( VLC_FOURCC( 's', '2', '6', '3' ) <