demux.c 26.9 KB
Newer Older
gbazin's avatar
 
gbazin committed
1 2 3
/*****************************************************************************
 * demux.c: demuxer using ffmpeg (libavformat).
 *****************************************************************************
ivoire's avatar
ivoire committed
4
 * Copyright (C) 2004-2009 the VideoLAN team
5
 * $Id$
gbazin's avatar
 
gbazin committed
6 7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
gbazin's avatar
 
gbazin committed
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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.
 *
 * 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
dionoea's avatar
dionoea committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
gbazin's avatar
 
gbazin committed
23 24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#include <vlc_common.h>
zorglub's avatar
zorglub committed
34 35
#include <vlc_demux.h>
#include <vlc_stream.h>
36
#include <vlc_meta.h>
37
#include <vlc_input.h>
hartman's avatar
hartman committed
38
#include <vlc_charset.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
39
#include <vlc_avcodec.h>
gbazin's avatar
 
gbazin committed
40 41

/* ffmpeg header */
42 43 44
#if defined(HAVE_LIBAVFORMAT_AVFORMAT_H)
#   include <libavformat/avformat.h>
#elif defined(HAVE_FFMPEG_AVFORMAT_H)
45
#   include <ffmpeg/avformat.h>
gbazin's avatar
 
gbazin committed
46 47
#endif

48
#include "../../codec/avcodec/avcodec.h"
49
#include "avformat.h"
50
#include "../xiph.h"
51
#include "../vobsub.h"
52

53 54
//#define AVFORMAT_DEBUG 1

gbazin's avatar
 
gbazin committed
55
/* Version checking */
56
#if defined(HAVE_FFMPEG_AVFORMAT_H) || defined(HAVE_LIBAVFORMAT_AVFORMAT_H)
57

58 59 60 61
#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(50<<8)+0) )
#   define HAVE_FFMPEG_CODEC_ATTACHMENT 1
#endif

hartman's avatar
hartman committed
62 63 64 65
#if (LIBAVFORMAT_VERSION_INT >= ((52<<16)+(15<<8)+0) )
#   define HAVE_FFMPEG_CHAPTERS 1
#endif

gbazin's avatar
 
gbazin committed
66 67 68 69 70 71 72 73 74 75 76
/*****************************************************************************
 * demux_sys_t: demux descriptor
 *****************************************************************************/
struct demux_sys_t
{
    ByteIOContext   io;
    int             io_buffer_size;
    uint8_t        *io_buffer;

    AVInputFormat  *fmt;
    AVFormatContext *ic;
gbazin's avatar
 
gbazin committed
77 78
    URLContext     url;
    URLProtocol    prot;
gbazin's avatar
 
gbazin committed
79 80 81 82 83 84 85

    int             i_tk;
    es_out_id_t     **tk;

    int64_t     i_pcr;
    int64_t     i_pcr_inc;
    int         i_pcr_tk;
86 87 88

    int                i_attachments;
    input_attachment_t **attachments;
hartman's avatar
hartman committed
89 90 91

    /* Only one title with seekpoints possible atm. */
    input_title_t *p_title;
gbazin's avatar
 
gbazin committed
92 93 94 95 96 97 98 99 100
};

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int Demux  ( demux_t *p_demux );
static int Control( demux_t *p_demux, int i_query, va_list args );

static int IORead( void *opaque, uint8_t *buf, int buf_size );
101
static int64_t IOSeek( void *opaque, int64_t offset, int whence );
gbazin's avatar
 
gbazin committed
102

hartman's avatar
hartman committed
103 104
static void UpdateSeekPoint( demux_t *p_demux, int64_t i_time );

gbazin's avatar
 
gbazin committed
105 106 107
/*****************************************************************************
 * Open
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
108
int OpenDemux( vlc_object_t *p_this )
gbazin's avatar
 
gbazin committed
109 110 111 112 113
{
    demux_t       *p_demux = (demux_t*)p_this;
    demux_sys_t   *p_sys;
    AVProbeData   pd;
    AVInputFormat *fmt;
hartman's avatar
hartman committed
114 115
    unsigned int  i;
    int64_t       i_start_time = -1;
gbazin's avatar
 
gbazin committed
116 117 118

    /* Init Probe data */
    pd.filename = p_demux->psz_path;
119
    if( ( pd.buf_size = stream_Peek( p_demux->s, &pd.buf, 2048 + 213 ) ) <= 0 )
gbazin's avatar
 
gbazin committed
120 121 122 123 124
    {
        msg_Warn( p_demux, "cannot peek" );
        return VLC_EGENERIC;
    }

125
    vlc_avcodec_lock();
126
    av_register_all(); /* Can be called several times */
127
    vlc_avcodec_unlock();
gbazin's avatar
 
gbazin committed
128 129 130 131 132 133 134 135 136

    /* Guess format */
    if( !( fmt = av_probe_input_format( &pd, 1 ) ) )
    {
        msg_Dbg( p_demux, "couldn't guess format" );
        return VLC_EGENERIC;
    }

    /* Don't try to handle MPEG unless forced */
137
    if( !p_demux->b_force &&
gbazin's avatar
 
gbazin committed
138 139 140
        ( !strcmp( fmt->name, "mpeg" ) ||
          !strcmp( fmt->name, "vcd" ) ||
          !strcmp( fmt->name, "vob" ) ||
141 142 143 144
          !strcmp( fmt->name, "mpegts" ) ||
          /* libavformat's redirector won't work */
          !strcmp( fmt->name, "redir" ) ||
          !strcmp( fmt->name, "sdp" ) ) )
gbazin's avatar
 
gbazin committed
145 146 147 148
    {
        return VLC_EGENERIC;
    }

149 150 151 152 153 154 155 156 157 158 159 160
    /* Don't trigger false alarms on bin files */
    if( !p_demux->b_force && !strcmp( fmt->name, "psxstr" ) )
    {
        int i_len;

        if( !p_demux->psz_path ) return VLC_EGENERIC;

        i_len = strlen( p_demux->psz_path );
        if( i_len < 4 ) return VLC_EGENERIC;

        if( strcasecmp( &p_demux->psz_path[i_len - 4], ".str" ) &&
            strcasecmp( &p_demux->psz_path[i_len - 4], ".xai" ) &&
161
            strcasecmp( &p_demux->psz_path[i_len - 3], ".xa" ) )
162 163 164 165 166
        {
            return VLC_EGENERIC;
        }
    }

167 168
    msg_Dbg( p_demux, "detected format: %s", fmt->name );

gbazin's avatar
 
gbazin committed
169 170 171 172
    /* Fill p_demux fields */
    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
173
    p_sys->ic = 0;
gbazin's avatar
 
gbazin committed
174 175 176 177
    p_sys->fmt = fmt;
    p_sys->i_tk = 0;
    p_sys->tk = NULL;
    p_sys->i_pcr_tk = -1;
178
    p_sys->i_pcr = -1;
179
    TAB_INIT( p_sys->i_attachments, p_sys->attachments);
hartman's avatar
hartman committed
180
    p_sys->p_title = NULL;
gbazin's avatar
 
gbazin committed
181 182 183 184

    /* Create I/O wrapper */
    p_sys->io_buffer_size = 32768;  /* FIXME */
    p_sys->io_buffer = malloc( p_sys->io_buffer_size );
gbazin's avatar
 
gbazin committed
185 186 187 188
    p_sys->url.priv_data = p_demux;
    p_sys->url.prot = &p_sys->prot;
    p_sys->url.prot->name = "VLC I/O wrapper";
    p_sys->url.prot->url_open = 0;
189 190
    p_sys->url.prot->url_read =
                    (int (*) (URLContext *, unsigned char *, int))IORead;
gbazin's avatar
 
gbazin committed
191
    p_sys->url.prot->url_write = 0;
192
    p_sys->url.prot->url_seek =
193
                    (int64_t (*) (URLContext *, int64_t, int))IOSeek;
gbazin's avatar
 
gbazin committed
194 195
    p_sys->url.prot->url_close = 0;
    p_sys->url.prot->next = 0;
gbazin's avatar
 
gbazin committed
196
    init_put_byte( &p_sys->io, p_sys->io_buffer, p_sys->io_buffer_size,
gbazin's avatar
 
gbazin committed
197
                   0, &p_sys->url, IORead, NULL, IOSeek );
gbazin's avatar
 
gbazin committed
198 199 200 201 202 203

    /* Open it */
    if( av_open_input_stream( &p_sys->ic, &p_sys->io, p_demux->psz_path,
                              p_sys->fmt, NULL ) )
    {
        msg_Err( p_demux, "av_open_input_stream failed" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
204
        CloseDemux( p_this );
gbazin's avatar
 
gbazin committed
205 206 207
        return VLC_EGENERIC;
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
208
    vlc_avcodec_lock(); /* avformat calls avcodec behind our back!!! */
209
    if( av_find_stream_info( p_sys->ic ) < 0 )
gbazin's avatar
 
gbazin committed
210
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
211
        vlc_avcodec_unlock();
gbazin's avatar
 
gbazin committed
212
        msg_Err( p_demux, "av_find_stream_info failed" );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
213
        CloseDemux( p_this );
gbazin's avatar
 
gbazin committed
214 215
        return VLC_EGENERIC;
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
216
    vlc_avcodec_unlock();
gbazin's avatar
 
gbazin committed
217 218 219

    for( i = 0; i < p_sys->ic->nb_streams; i++ )
    {
220
        AVCodecContext *cc = p_sys->ic->streams[i]->codec;
gbazin's avatar
 
gbazin committed
221 222 223
        es_out_id_t  *es;
        es_format_t  fmt;
        vlc_fourcc_t fcc;
224
        const char *psz_type = "unknown";
gbazin's avatar
 
gbazin committed
225

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
226
        if( !GetVlcFourcc( cc->codec_id, NULL, &fcc, NULL ) )
gbazin's avatar
 
gbazin committed
227 228 229 230 231 232
            fcc = VLC_FOURCC( 'u', 'n', 'd', 'f' );

        switch( cc->codec_type )
        {
        case CODEC_TYPE_AUDIO:
            es_format_Init( &fmt, AUDIO_ES, fcc );
233
            fmt.i_bitrate = cc->bit_rate;
gbazin's avatar
 
gbazin committed
234 235
            fmt.audio.i_channels = cc->channels;
            fmt.audio.i_rate = cc->sample_rate;
aballier's avatar
aballier committed
236
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0)
gbazin's avatar
 
gbazin committed
237
            fmt.audio.i_bitspersample = cc->bits_per_sample;
aballier's avatar
aballier committed
238 239 240
#else
            fmt.audio.i_bitspersample = cc->bits_per_coded_sample;
#endif
gbazin's avatar
 
gbazin committed
241
            fmt.audio.i_blockalign = cc->block_align;
242
            psz_type = "audio";
gbazin's avatar
 
gbazin committed
243
            break;
244

gbazin's avatar
 
gbazin committed
245 246
        case CODEC_TYPE_VIDEO:
            es_format_Init( &fmt, VIDEO_ES, fcc );
247 248 249 250 251 252 253 254 255 256 257 258 259

            /* Special case for raw video data */
            if( cc->codec_id == CODEC_ID_RAWVIDEO )
            {
                msg_Dbg( p_demux, "raw video, pixel format: %i", cc->pix_fmt );
                if( GetVlcChroma( &fmt.video, cc->pix_fmt ) != VLC_SUCCESS)
                {
                    msg_Err( p_demux, "was unable to find a FourCC match for raw video" );
                }
                else
                    fmt.i_codec = fmt.video.i_chroma;
            }

gbazin's avatar
 
gbazin committed
260 261
            fmt.video.i_width = cc->width;
            fmt.video.i_height = cc->height;
gbazin's avatar
 
gbazin committed
262 263 264 265 266
            if( cc->palctrl )
            {
                fmt.video.p_palette = malloc( sizeof(video_palette_t) );
                *fmt.video.p_palette = *(video_palette_t *)cc->palctrl;
            }
267
            psz_type = "video";
gbazin's avatar
 
gbazin committed
268
            break;
269

270 271
        case CODEC_TYPE_SUBTITLE:
            es_format_Init( &fmt, SPU_ES, fcc );
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
            if( strncmp( p_sys->ic->iformat->name, "matroska", 8 ) == 0 &&
                cc->codec_id == CODEC_ID_DVD_SUBTITLE &&
                cc->extradata != NULL &&
                cc->extradata_size > 0 )
            {
                char *psz_start;
                char *psz_buf = malloc( cc->extradata_size + 1);
                if( psz_buf != NULL )
                {
                    memcpy( psz_buf, cc->extradata , cc->extradata_size );
                    psz_buf[cc->extradata_size] = '\0';

                    psz_start = strstr( psz_buf, "size:" );
                    if( psz_start &&
                        vobsub_size_parse( psz_start,
                                           &fmt.subs.spu.i_original_frame_width,
                                           &fmt.subs.spu.i_original_frame_height ) == VLC_SUCCESS )
                    {
                        msg_Dbg( p_demux, "original frame size: %dx%d",
                                 fmt.subs.spu.i_original_frame_width,
                                 fmt.subs.spu.i_original_frame_height );
                    }
                    else
                    {
                        msg_Warn( p_demux, "reading original frame size failed" );
                    }

                    psz_start = strstr( psz_buf, "palette:" );
                    if( psz_start &&
                        vobsub_palette_parse( psz_start, &fmt.subs.spu.palette[1] ) == VLC_SUCCESS )
                    {
                        fmt.subs.spu.palette[0] =  0xBeef;
                        msg_Dbg( p_demux, "vobsub palette read" );
                    }
                    else
                    {
                        msg_Warn( p_demux, "reading original palette failed" );
                    }
                    free( psz_buf );
                }
            }

314
            psz_type = "subtitle";
315
            break;
316

gbazin's avatar
 
gbazin committed
317
        default:
318
            es_format_Init( &fmt, UNKNOWN_ES, 0 );
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
#ifdef HAVE_FFMPEG_CODEC_ATTACHMENT
            if( cc->codec_type == CODEC_TYPE_ATTACHMENT )
            {
                input_attachment_t *p_attachment;
                psz_type = "attachment";
                if( cc->codec_id == CODEC_ID_TTF )
                {
                    p_attachment = vlc_input_attachment_New( p_sys->ic->streams[i]->filename, "application/x-truetype-font", NULL,
                                             cc->extradata, (int)cc->extradata_size );
                    TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment );
                }
                else msg_Warn( p_demux, "unsupported attachment type in ffmpeg demux" );
            }
            break;
#endif

335 336
            if( cc->codec_type == CODEC_TYPE_DATA )
                psz_type = "data";
337

338
            msg_Warn( p_demux, "unsupported track type in ffmpeg demux" );
hartman's avatar
hartman committed
339
            break;
gbazin's avatar
 
gbazin committed
340
        }
341
        fmt.psz_language = strdup( p_sys->ic->streams[i]->language );
342 343 344 345 346

#ifdef HAVE_FFMPEG_CODEC_ATTACHMENT
        if( cc->codec_type != CODEC_TYPE_ATTACHMENT )
#endif
        {
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 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
            const uint8_t *p_extra = cc->extradata;
            unsigned      i_extra  = cc->extradata_size;

            if( cc->codec_id == CODEC_ID_THEORA )
            {
                unsigned pi_size[3];
                void     *pp_data[3];
                unsigned i_count;
                for( i_count = 0; i_count < 3; i_count++ )
                {
                    if( i_extra < 2 )
                        break;
                    pi_size[i_count] = GetWBE( p_extra );
                    pp_data[i_count] = (uint8_t*)&p_extra[2];
                    if( i_extra < pi_size[i_count] + 2 )
                        break;

                    p_extra += 2 + pi_size[i_count];
                    i_extra -= 2 + pi_size[i_count];
                }
                if( i_count > 0 && xiph_PackHeaders( &fmt.i_extra, &fmt.p_extra,
                                                     pi_size, pp_data, i_count ) )
                {
                    fmt.i_extra = 0;
                    fmt.p_extra = NULL;
                }
            }
            else if( cc->codec_id == CODEC_ID_SPEEX )
            {
                uint8_t p_dummy_comment[] = {
                    0, 0, 0, 0,
                    0, 0, 0, 0,
                };
                unsigned pi_size[2];
                void     *pp_data[2];

                pi_size[0] = i_extra;
                pp_data[0] = (uint8_t*)p_extra;

                pi_size[1] = sizeof(p_dummy_comment);
                pp_data[1] = p_dummy_comment;

                if( pi_size[0] > 0 && xiph_PackHeaders( &fmt.i_extra, &fmt.p_extra,
                                                        pi_size, pp_data, 2 ) )
                {
                    fmt.i_extra = 0;
                    fmt.p_extra = NULL;
                }
            }
            else if( cc->extradata_size > 0 )
            {
                fmt.p_extra = malloc( i_extra );
                if( fmt.p_extra )
                {
                    fmt.i_extra = i_extra;
                    memcpy( fmt.p_extra, p_extra, i_extra );
                }
            }
405
        }
gbazin's avatar
 
gbazin committed
406
        es = es_out_Add( p_demux->out, &fmt );
407
        es_format_Clean( &fmt );
gbazin's avatar
 
gbazin committed
408 409

        msg_Dbg( p_demux, "adding es: %s codec = %4.4s",
410
                 psz_type, (char*)&fcc );
gbazin's avatar
 
gbazin committed
411 412
        TAB_APPEND( p_sys->i_tk, p_sys->tk, es );
    }
hartman's avatar
hartman committed
413 414
    if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE )
        i_start_time = p_sys->ic->start_time * 1000000 / AV_TIME_BASE;
gbazin's avatar
 
gbazin committed
415 416 417 418

    msg_Dbg( p_demux, "AVFormat supported stream" );
    msg_Dbg( p_demux, "    - format = %s (%s)",
             p_sys->fmt->name, p_sys->fmt->long_name );
hartman's avatar
hartman committed
419
    msg_Dbg( p_demux, "    - start time = %"PRId64, i_start_time );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
420
    msg_Dbg( p_demux, "    - duration = %"PRId64,
421
             ( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) ?
gbazin's avatar
 
gbazin committed
422
             p_sys->ic->duration * 1000000 / AV_TIME_BASE : -1 );
gbazin's avatar
 
gbazin committed
423

ivoire's avatar
Typo  
ivoire committed
424
#ifdef HAVE_FFMPEG_CHAPTERS
425 426
    if( p_sys->ic->nb_chapters > 0 )
        p_sys->p_title = vlc_input_title_New();
hartman's avatar
hartman committed
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    for( i = 0; i < p_sys->ic->nb_chapters; i++ )
    {
        seekpoint_t *s = vlc_seekpoint_New();

        if( p_sys->ic->chapters[i]->title )
        {
            s->psz_name = strdup( p_sys->ic->chapters[i]->title );
            EnsureUTF8( s->psz_name );
            msg_Dbg( p_demux, "    - chapter %d: %s", i, s->psz_name );
        }
        s->i_time_offset = p_sys->ic->chapters[i]->start * 1000000 *
            p_sys->ic->chapters[i]->time_base.num /
            p_sys->ic->chapters[i]->time_base.den -
            (i_start_time != -1 ? i_start_time : 0 );
        TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s );
    }
#endif

gbazin's avatar
 
gbazin committed
445 446 447 448 449 450
    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
451
void CloseDemux( vlc_object_t *p_this )
gbazin's avatar
 
gbazin committed
452 453 454 455
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;

456
    FREENULL( p_sys->tk );
457

458
    if( p_sys->ic ) av_close_input_stream( p_sys->ic );
459

460 461 462 463
    for( int i = 0; i < p_sys->i_attachments; i++ )
        free( p_sys->attachments[i] );
    TAB_CLEAN( p_sys->i_attachments, p_sys->attachments);

hartman's avatar
hartman committed
464 465 466
    if( p_sys->p_title )
        vlc_input_title_Delete( p_sys->p_title );

467
    free( p_sys->io_buffer );
gbazin's avatar
 
gbazin committed
468 469 470 471 472 473 474 475 476 477 478
    free( p_sys );
}

/*****************************************************************************
 * Demux:
 *****************************************************************************/
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    AVPacket    pkt;
    block_t     *p_frame;
gbazin's avatar
 
gbazin committed
479
    int64_t     i_start_time;
gbazin's avatar
 
gbazin committed
480 481 482 483 484 485 486 487 488 489 490

    /* Read a frame */
    if( av_read_frame( p_sys->ic, &pkt ) )
    {
        return 0;
    }
    if( pkt.stream_index < 0 || pkt.stream_index >= p_sys->i_tk )
    {
        av_free_packet( &pkt );
        return 1;
    }
491 492
    const AVStream *p_stream = p_sys->ic->streams[pkt.stream_index];

gbazin's avatar
 
gbazin committed
493 494 495 496 497 498
    if( ( p_frame = block_New( p_demux, pkt.size ) ) == NULL )
    {
        return 0;
    }

    memcpy( p_frame->p_buffer, pkt.data, pkt.size );
gbazin's avatar
 
gbazin committed
499

500 501 502
    if( pkt.flags & PKT_FLAG_KEY )
        p_frame->i_flags |= BLOCK_FLAG_TYPE_I;

503
    i_start_time = ( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) ?
504
        ( p_sys->ic->start_time * 1000000 / AV_TIME_BASE )  : 0;
gbazin's avatar
 
gbazin committed
505

506
    p_frame->i_dts = ( pkt.dts == (int64_t)AV_NOPTS_VALUE ) ?
507
        VLC_TS_INVALID : (pkt.dts) * 1000000 *
508
        p_stream->time_base.num /
509
        p_stream->time_base.den - i_start_time + VLC_TS_0;
510
    p_frame->i_pts = ( pkt.pts == (int64_t)AV_NOPTS_VALUE ) ?
511
        VLC_TS_INVALID : (pkt.pts) * 1000000 *
512
        p_stream->time_base.num /
513
        p_stream->time_base.den - i_start_time + VLC_TS_0;
514 515
    if( pkt.duration > 0 )
        p_frame->i_length = pkt.duration * 1000000 *
516 517
            p_stream->time_base.num /
            p_stream->time_base.den - i_start_time;
gbazin's avatar
 
gbazin committed
518

519 520 521 522 523
    if( pkt.dts != AV_NOPTS_VALUE && pkt.dts == pkt.pts &&
        p_stream->codec->codec_type == CODEC_TYPE_VIDEO )
    {
        /* Add here notoriously bugged file formats/samples regarding PTS */
        if( !strcmp( p_sys->fmt->name, "flv" ) )
524
            p_frame->i_pts = VLC_TS_INVALID;
525
    }
526
#ifdef AVFORMAT_DEBUG
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
527
    msg_Dbg( p_demux, "tk[%d] dts=%"PRId64" pts=%"PRId64,
gbazin's avatar
 
gbazin committed
528
             pkt.stream_index, p_frame->i_dts, p_frame->i_pts );
529
#endif
gbazin's avatar
 
gbazin committed
530

531
    if( p_frame->i_dts > VLC_TS_INVALID  &&
gbazin's avatar
 
gbazin committed
532
        ( pkt.stream_index == p_sys->i_pcr_tk || p_sys->i_pcr_tk < 0 ) )
533
    {
gbazin's avatar
 
gbazin committed
534
        p_sys->i_pcr_tk = pkt.stream_index;
535
        p_sys->i_pcr = p_frame->i_dts;
gbazin's avatar
 
gbazin committed
536 537 538 539 540

        es_out_Control( p_demux->out, ES_OUT_SET_PCR, (int64_t)p_sys->i_pcr );
    }

    es_out_Send( p_demux->out, p_sys->tk[pkt.stream_index], p_frame );
hartman's avatar
hartman committed
541 542

    UpdateSeekPoint( p_demux, p_sys->i_pcr);
gbazin's avatar
 
gbazin committed
543 544 545 546
    av_free_packet( &pkt );
    return 1;
}

hartman's avatar
hartman committed
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
static void UpdateSeekPoint( demux_t *p_demux, int64_t i_time )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    int i;

    if( !p_sys->p_title )
        return;

    for( i = 0; i < p_sys->p_title->i_seekpoint; i++ )
    {
        if( i_time < p_sys->p_title->seekpoint[i]->i_time_offset )
            break;
    }
    i--;

    if( i != p_demux->info.i_seekpoint && i >= 0 )
    {
        p_demux->info.i_seekpoint = i;
        p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
    }
}

gbazin's avatar
 
gbazin committed
569 570 571 572 573 574 575 576 577 578 579 580
/*****************************************************************************
 * Control:
 *****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    double f, *pf;
    int64_t i64, *pi64;

    switch( i_query )
    {
        case DEMUX_GET_POSITION:
581
            pf = (double*) va_arg( args, double* ); *pf = 0.0;
gbazin's avatar
 
gbazin committed
582 583 584
            i64 = stream_Size( p_demux->s );
            if( i64 > 0 )
            {
585 586
                double current = stream_Tell( p_demux->s );
                *pf = current / (double)i64;
gbazin's avatar
 
gbazin committed
587
            }
588

589
            if( (p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE) && (p_sys->i_pcr > 0) )
gbazin's avatar
 
gbazin committed
590
            {
591
                *pf = (double)p_sys->i_pcr / (double)p_sys->ic->duration;
gbazin's avatar
 
gbazin committed
592
            }
593

gbazin's avatar
 
gbazin committed
594 595 596 597
            return VLC_SUCCESS;

        case DEMUX_SET_POSITION:
            f = (double) va_arg( args, double );
598
            if( p_sys->i_pcr > 0 )
gbazin's avatar
 
gbazin committed
599
            {
600
                i64 = p_sys->ic->duration * f;
601
                if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE )
gbazin's avatar
 
gbazin committed
602 603
                    i64 += p_sys->ic->start_time;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
604
                msg_Warn( p_demux, "DEMUX_SET_POSITION: %"PRId64, i64 );
gbazin's avatar
 
gbazin committed
605

606 607 608 609
                /* If we have a duration, we prefer to seek by time
                   but if we don't, or if the seek fails, try BYTE seeking */
                if( p_sys->ic->duration == (int64_t)AV_NOPTS_VALUE ||
                    (av_seek_frame( p_sys->ic, -1, i64, 0 ) < 0) )
gbazin's avatar
 
gbazin committed
610
                {
611
                    int64_t i_size = stream_Size( p_demux->s );
612
                    i64 = (i_size * f);
613

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
614
                    msg_Warn( p_demux, "DEMUX_SET_BYTE_POSITION: %"PRId64, i64 );
615
                    if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BYTE ) < 0 )
616
                        return VLC_EGENERIC;
gbazin's avatar
 
gbazin committed
617
                }
618 619 620 621
                else
                {
                    UpdateSeekPoint( p_demux, i64 );
                }
gbazin's avatar
 
gbazin committed
622
                p_sys->i_pcr = -1; /* Invalidate time display */
gbazin's avatar
 
gbazin committed
623 624 625
            }
            return VLC_SUCCESS;

626 627
        case DEMUX_GET_LENGTH:
            pi64 = (int64_t*)va_arg( args, int64_t * );
628
            if( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE )
629 630 631 632 633 634
            {
                *pi64 = p_sys->ic->duration;
            }
            else *pi64 = 0;
            return VLC_SUCCESS;

gbazin's avatar
 
gbazin committed
635 636 637 638 639 640 641
        case DEMUX_GET_TIME:
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = p_sys->i_pcr;
            return VLC_SUCCESS;

        case DEMUX_SET_TIME:
            i64 = (int64_t)va_arg( args, int64_t );
hartman's avatar
hartman committed
642
            i64 = i64 *AV_TIME_BASE / 1000000;
643
            if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE )
gbazin's avatar
 
gbazin committed
644 645
                i64 += p_sys->ic->start_time;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
646
            msg_Warn( p_demux, "DEMUX_SET_TIME: %"PRId64, i64 );
gbazin's avatar
 
gbazin committed
647

648
            if( av_seek_frame( p_sys->ic, -1, i64, 0 ) < 0 )
gbazin's avatar
 
gbazin committed
649 650 651 652
            {
                return VLC_EGENERIC;
            }
            p_sys->i_pcr = -1; /* Invalidate time display */
hartman's avatar
hartman committed
653
            UpdateSeekPoint( p_demux, i64 );
gbazin's avatar
 
gbazin committed
654 655
            return VLC_SUCCESS;

656 657 658 659 660 661 662 663
        case DEMUX_HAS_UNSUPPORTED_META:
        {
            bool *pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = true;
            return VLC_SUCCESS;
        }


664 665
        case DEMUX_GET_META:
        {
zorglub's avatar
zorglub committed
666
            vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
667 668 669 670 671 672 673 674 675

            if( !p_sys->ic->title[0] || !p_sys->ic->author[0] ||
                !p_sys->ic->copyright[0] || !p_sys->ic->comment[0] ||
                /*!p_sys->ic->album[0] ||*/ !p_sys->ic->genre[0] )
            {
                return VLC_EGENERIC;
            }

            if( p_sys->ic->title[0] )
zorglub's avatar
zorglub committed
676
                vlc_meta_SetTitle( p_meta, p_sys->ic->title );
677
            if( p_sys->ic->author[0] )
zorglub's avatar
zorglub committed
678
                vlc_meta_SetArtist( p_meta, p_sys->ic->author );
679
            if( p_sys->ic->copyright[0] )
zorglub's avatar
zorglub committed
680
                vlc_meta_SetCopyright( p_meta, p_sys->ic->copyright );
681
            if( p_sys->ic->comment[0] )
zorglub's avatar
zorglub committed
682
                vlc_meta_SetDescription( p_meta, p_sys->ic->comment );
683
            if( p_sys->ic->genre[0] )
zorglub's avatar
zorglub committed
684
                vlc_meta_SetGenre( p_meta, p_sys->ic->genre );
685 686 687
            return VLC_SUCCESS;
        }

688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
        case DEMUX_GET_ATTACHMENTS:
        {
            input_attachment_t ***ppp_attach =
                (input_attachment_t***)va_arg( args, input_attachment_t*** );
            int *pi_int = (int*)va_arg( args, int * );
            int i;

            if( p_sys->i_attachments <= 0 )
                return VLC_EGENERIC;

            *pi_int = p_sys->i_attachments;;
            *ppp_attach = malloc( sizeof(input_attachment_t**) * p_sys->i_attachments );
            for( i = 0; i < p_sys->i_attachments; i++ )
                (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] );
            return VLC_SUCCESS;
        }

hartman's avatar
hartman committed
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
        case DEMUX_GET_TITLE_INFO:
        {
            input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
            int *pi_int    = (int*)va_arg( args, int* );
            int *pi_title_offset = (int*)va_arg( args, int* );
            int *pi_seekpoint_offset = (int*)va_arg( args, int* );

            if( !p_sys->p_title )
                return VLC_EGENERIC;

            *pi_int = 1;
            *ppp_title = malloc( sizeof( input_title_t**) );
            (*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->p_title );
            *pi_title_offset = 0;
            *pi_seekpoint_offset = 0;
            return VLC_SUCCESS;
        }
        case DEMUX_SET_TITLE:
        {
            const int i_title = (int)va_arg( args, int );
            if( !p_sys->p_title || i_title != 0 )
                return VLC_EGENERIC;
            return VLC_SUCCESS;
        }
        case DEMUX_SET_SEEKPOINT:
        {
            const int i_seekpoint = (int)va_arg( args, int );
            if( !p_sys->p_title )
                return VLC_EGENERIC;

            i64 = p_sys->p_title->seekpoint[i_seekpoint]->i_time_offset *AV_TIME_BASE / 1000000;
            if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE )
                i64 += p_sys->ic->start_time;

            msg_Warn( p_demux, "DEMUX_SET_TIME: %"PRId64, i64 );

            if( av_seek_frame( p_sys->ic, -1, i64, 0 ) < 0 )
            {
                return VLC_EGENERIC;
            }
            p_sys->i_pcr = -1; /* Invalidate time display */
            UpdateSeekPoint( p_demux, i64 );
            return VLC_SUCCESS;
        }


gbazin's avatar
 
gbazin committed
751 752 753 754 755 756 757 758 759 760
        default:
            return VLC_EGENERIC;
    }
}

/*****************************************************************************
 * I/O wrappers for libavformat
 *****************************************************************************/
static int IORead( void *opaque, uint8_t *buf, int buf_size )
{
gbazin's avatar
 
gbazin committed
761 762
    URLContext *p_url = opaque;
    demux_t *p_demux = p_url->priv_data;
763
    if( buf_size < 0 ) return -1;
764 765
    int i_ret = stream_Read( p_demux->s, buf, buf_size );
    return i_ret ? i_ret : -1;
gbazin's avatar
 
gbazin committed
766 767
}

768
static int64_t IOSeek( void *opaque, int64_t offset, int whence )
gbazin's avatar
 
gbazin committed
769
{
gbazin's avatar
 
gbazin committed
770 771
    URLContext *p_url = opaque;
    demux_t *p_demux = p_url->priv_data;
ivoire's avatar
ivoire committed
772
    int64_t i_absolute;
773
    int64_t i_size = stream_Size( p_demux->s );
gbazin's avatar
 
gbazin committed
774

775
#ifdef AVFORMAT_DEBUG
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
776
    msg_Warn( p_demux, "IOSeek offset: %"PRId64", whence: %i", offset, whence );
777
#endif
gbazin's avatar
 
gbazin committed
778

gbazin's avatar
 
gbazin committed
779 780
    switch( whence )
    {
781 782 783 784
#ifdef AVSEEK_SIZE
        case AVSEEK_SIZE:
            return i_size;
#endif
gbazin's avatar
 
gbazin committed
785
        case SEEK_SET:
hartman's avatar
hartman committed
786
            i_absolute = (int64_t)offset;
gbazin's avatar
 
gbazin committed
787 788
            break;
        case SEEK_CUR:
hartman's avatar
hartman committed
789
            i_absolute = stream_Tell( p_demux->s ) + (int64_t)offset;
gbazin's avatar
 
gbazin committed
790 791
            break;
        case SEEK_END:
hartman's avatar
hartman committed
792
            i_absolute = i_size + (int64_t)offset;
gbazin's avatar
 
gbazin committed
793 794 795 796 797
            break;
        default:
            return -1;

    }
798

799
    if( i_absolute < 0 )
800 801 802 803
    {
        msg_Dbg( p_demux, "Trying to seek before the beginning" );
        return -1;
    }
804

hartman's avatar
hartman committed
805
    if( i_size > 0 && i_absolute >= i_size )
Rafaël Carré's avatar
Rafaël Carré committed
806
    {
807 808
        msg_Dbg( p_demux, "Trying to seek too far : EOF?" );
        return -1;
Rafaël Carré's avatar
Rafaël Carré committed
809
    }
gbazin's avatar
 
gbazin committed
810 811 812

    if( stream_Seek( p_demux->s, i_absolute ) )
    {
813
        msg_Warn( p_demux, "we were not allowed to seek, or EOF " );
gbazin's avatar
 
gbazin committed
814 815 816
        return -1;
    }

817
    return stream_Tell( p_demux->s );
gbazin's avatar
 
gbazin committed
818 819
}

820
#endif /* HAVE_LIBAVFORMAT_AVFORMAT_H */