mp4.c 59.9 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * mp4.c : MP4 file input module for vlc
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
5
 * $Id: mp4.c,v 1.42 2003/11/24 00:39:01 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

    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 )
        {
428
            if( track.b_selected && track.p_es->p_dec == NULL )
429 430 431
            {
                MP4_TrackUnselect( p_input, &track );
            }
432
            else if( !track.b_selected && track.p_es->p_dec != NULL )
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
            {
                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
                    break;
                }
Gildas Bazin's avatar
 
Gildas Bazin committed
521 522 523 524 525 526 527 528 529 530 531 532 533

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

                if( track.i_cat != VIDEO_ES )
                    p_pes->i_dts = p_pes->i_pts;
                else
                {
                    p_pes->i_dts = p_pes->i_pts;
                    p_pes->i_pts = 0;
                }
534

535
                if( track.p_es->p_dec )
536
                {
Gildas Bazin's avatar
 
Gildas Bazin committed
537 538

                    p_pes->i_rate = p_input->stream.control.i_rate;
539
                    input_DecodePES( track.p_es->p_dec, p_pes );
540 541 542 543 544 545 546 547 548 549 550
                }
                else
                {
                    input_DeletePES( p_input->p_method_data, p_pes );
                }

                if( MP4_TrackNextSample( p_input, &track ) )
                {
                    break;
                }
            }
551
        }
552
#undef track
553 554
    }

555
    return( 1 );
556
}
557
/*****************************************************************************
558
 * Seek: Got to i_date
559
 ******************************************************************************/
560
static int   Seek     ( input_thread_t *p_input, mtime_t i_date )
561 562
{
    demux_sys_t *p_demux = p_input->p_demux_data;
563
    unsigned int i_track;
564 565
    /* First update update global time */
    p_demux->i_time = i_date * p_demux->i_timescale / 1000000;
566
    p_demux->i_pcr  = i_date* 9 / 100;
567

568 569 570
    /* Now for each stream try to go to this time */
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
571 572 573 574 575 576
#define track p_demux->track[i_track]
        if( track.b_ok && track.b_selected )
        {
            MP4_TrackSeek( p_input, &track, i_date );
        }
#undef  track
577 578 579
    }
    return( 1 );
}
580 581

/*****************************************************************************
582
 * Control:
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
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;
630 631 632
        case DEMUX_GET_FPS:
            msg_Warn( p_input, "DEMUX_GET_FPS unimplemented !!" );
            return VLC_EGENERIC;
633 634 635 636 637 638 639 640 641 642
        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 )
643 644
{
    unsigned int i_track;
645
    input_thread_t *  p_input = (input_thread_t *)p_this;
646
    demux_sys_t *p_demux = p_input->p_demux_data;
647

648
    msg_Dbg( p_input, "freeing all memory" );
Laurent Aimar's avatar
Laurent Aimar committed
649 650

    MP4_BoxFree( p_input, p_demux->p_root );
651 652
    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
    {
653
        MP4_TrackDestroy( p_input, &p_demux->track[i_track] );
654 655
    }
    FREE( p_demux->track );
656 657

    FREE( p_input->p_demux_data );
658 659 660
}


661

662 663 664 665
/****************************************************************************
 * Local functions, specific to vlc
 ****************************************************************************/

666 667 668
/* 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 )
669
{
670 671
    MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
    MP4_Box_t *p_stsc;
672

673 674 675 676 677 678
    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" ) ) ))
679
    {
680
        return( VLC_EGENERIC );
681
    }
682 683 684

    p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
    if( !p_demux_track->i_chunk_count )
685
    {
686 687
        msg_Warn( p_input, "no chunk defined" );
        return( VLC_EGENERIC );
688
    }
689 690 691 692 693
    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++ )
694
    {
695 696
        p_demux_track->chunk[i_chunk].i_offset =
                p_co64->data.p_co64->i_chunk_offset[i_chunk];
697 698
    }

699 700 701 702 703 704
    /* 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 )
705
    {
706 707
        msg_Warn( p_input, "cannot read chunk table or table empty" );
        return( VLC_EGENERIC );
708
    }
709 710

    while( i_index )
711
    {
712 713 714 715 716 717 718 719 720 721
        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;
722 723
    }

724 725
    p_demux_track->chunk[0].i_sample_first = 0;
    for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
726
    {
727 728 729
        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;
730
    }
731

732 733 734 735
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d chunk",
             p_demux_track->i_track_ID,
            p_demux_track->i_chunk_count );
736

737
    return( VLC_SUCCESS );
738
}
739 740
static int TrackCreateSamplesIndex( input_thread_t *p_input,
                                    track_data_mp4_t *p_demux_track )
741 742
{
    MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
743
                          ctts make same mapping but for composition time,
744
                          not yet used and probably not usefull */
745 746
    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
747 748 749
                          as a unique type */
    /* TODO use also stss and stsh table for seeking */
    /* FIXME use edit table */
750 751
    int64_t i_sample;
    int64_t i_chunk;
752

753 754
    int64_t i_index;
    int64_t i_index_sample_used;
755

756 757
    int64_t i_last_dts;

758 759
    p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
    p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */
760 761 762 763

    if( ( !p_stts )||( !p_stsz ) )
    {
        msg_Warn( p_input, "cannot read sample table" );
764
        return( VLC_EGENERIC );
765
    }
766

767 768 769 770 771 772 773 774 775 776 777 778 779 780
    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;
781
        p_demux_track->p_sample_size =
782
            calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
783

784 785
        for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
        {
786
            p_demux_track->p_sample_size[i_sample] =
787 788 789 790 791 792 793
                    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
794
       the box !, so each chunk will contain an "extract" of this table
795
       for fast research */
796

797 798
    i_last_dts = 0;
    i_index = 0; i_index_sample_used =0;
799

800 801 802 803
    /* create and init last data for each chunk */
    for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
    {

804
        int64_t i_entry, i_sample_count, i;
805 806
        /* save last dts */
        p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
807
    /* count how many entries needed for this chunk
808 809 810
       for p_sample_delta_dts and p_sample_count_dts */

        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
811 812

        i_entry = 0;
813 814 815 816 817
        while( i_sample_count > 0 )
        {
            i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];
            if( i_entry == 0 )
            {
818
                i_sample_count += i_index_sample_used; /* don't count already used sample
819 820 821 822
                                                   int this entry */
            }
            i_entry++;
        }
823

824
        /* allocate them */
825
        p_demux_track->chunk[i_chunk].p_sample_count_dts =
826
            calloc( i_entry, sizeof( uint32_t ) );
827
        p_demux_track->chunk[i_chunk].p_sample_delta_dts =
828
            calloc( i_entry, sizeof( uint32_t ) );
829 830 831 832 833

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

837 838 839 840 841
            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;
842
            i_sample_count -= i_used;
843 844 845 846 847

            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];
848 849

            i_last_dts += i_used *
850 851 852 853 854
                    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] )
            {
855

856 857 858 859
                i_index++;
                i_index_sample_used = 0;
            }
        }
860

861 862
    }

863 864
    msg_Dbg( p_input,
             "track[Id 0x%x] read %d samples length:"I64Fd"s",
865
             p_demux_track->i_track_ID,
866 867
             p_demux_track->i_sample_count,
             i_last_dts / p_demux_track->i_timescale );
868

869
    return( VLC_SUCCESS );
870 871
}

872 873 874 875 876 877 878 879 880
/*
 * 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 )
881
{
882 883
    MP4_Box_t *  p_sample;
    unsigned int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
884
    char psz_lang[4];
885

886 887
    unsigned int i_decoder_specific_info_len;
    uint8_t *    p_decoder_specific_info;
888 889 890

    es_descriptor_t *p_es;
    pes_packet_t    *p_pes_init;
891

892 893
    uint8_t             *p_init;
    BITMAPINFOHEADER    *p_bih;
894
    WAVEFORMATEX        *p_wf;
895

896
    MP4_Box_t   *p_esds;
897

898
    if( !p_track->chunk[i_chunk].i_sample_description_index )
899
    {
900
        msg_Warn( p_input,
901
                  "invalid SampleEntry index (track[Id 0x%x])",
902 903
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
904
    }
905 906

    p_sample = MP4_BoxGet(  p_track->p_stsd,
907
                            "[%d]",
908
                p_track->chunk[i_chunk].i_sample_description_index - 1 );
909

910
    if( !p_sample || !p_sample->data.p_data )
911
    {
912
        msg_Warn( p_input,
913
                  "cannot find SampleEntry (track[Id 0x%x])",
914 915
                  p_track->i_track_ID );
        return( VLC_EGENERIC );
916 917
    }

918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
    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;
937 938 939 940 941 942 943 944 945 946 947 948 949 950
                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;
951 952 953 954 955 956
                default:
                    break;
            }
        }
    }

957 958 959
    /* Initialise ES, first language as description */
    for( i = 0; i < 3; i++ )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
960
        psz_lang[i] = p_track->i_language[i];
961
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
962 963 964 965 966 967
    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 );
968

969
    p_es->i_stream_id = p_track->i_track_ID;
970 971 972 973 974 975

    /* 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 ) ):
976 977 978 979
            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' );
980
            break;
981 982 983
        case( VLC_FOURCC( 's', '2', '6', '3' ) ):
            p_es->i_fourcc = VLC_FOURCC( 'h', '2', '6', '3' );
            break;
984
        default:
985
            p_es->i_fourcc = p_sample->i_type;
986 987
            break;
    }
988

989 990
    i_decoder_specific_info_len = 0;
    p_decoder_specific_info = NULL;
991
    p_pes_init = NULL;
992