demux.c 31.7 KB
Newer Older
gbazin's avatar
 
gbazin committed
1
/*****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
2
 * demux.c: demuxer using libavformat
gbazin's avatar
 
gbazin committed
3
 *****************************************************************************
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
#include <libavformat/avformat.h>
gbazin's avatar
 
gbazin committed
42

43
#include "../../codec/avcodec/avcodec.h"
44
#include "../../codec/avcodec/chroma.h"
45
#include "avformat.h"
46
#include "../xiph.h"
47
#include "../vobsub.h"
48

49 50
//#define AVFORMAT_DEBUG 1

gbazin's avatar
 
gbazin committed
51
/* Version checking */
52
#if defined(HAVE_FFMPEG_AVFORMAT_H) || defined(HAVE_LIBAVFORMAT_AVFORMAT_H)
53

54
#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(50<<8)+0) )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
55
#   define HAVE_AVUTIL_CODEC_ATTACHMENT 1
56 57
#endif

gbazin's avatar
 
gbazin committed
58 59 60 61 62 63 64 65 66 67 68
/*****************************************************************************
 * 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
69 70
    URLContext     url;
    URLProtocol    prot;
gbazin's avatar
 
gbazin committed
71 72 73

    int             i_tk;
    es_out_id_t     **tk;
74 75
    int64_t         *tk_pcr;
    int64_t         i_pcr;
76

77 78
    unsigned    i_ssa_order;

79 80
    int                i_attachments;
    input_attachment_t **attachments;
hartman's avatar
hartman committed
81 82 83

    /* Only one title with seekpoints possible atm. */
    input_title_t *p_title;
gbazin's avatar
 
gbazin committed
84 85 86 87 88 89 90 91 92
};

/*****************************************************************************
 * 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 );
93
static int64_t IOSeek( void *opaque, int64_t offset, int whence );
gbazin's avatar
 
gbazin committed
94

95
static block_t *BuildSsaFrame( const AVPacket *p_pkt, unsigned i_order );
hartman's avatar
hartman committed
96
static void UpdateSeekPoint( demux_t *p_demux, int64_t i_time );
97
static void ResetTime( demux_t *p_demux, int64_t i_time );
hartman's avatar
hartman committed
98

gbazin's avatar
 
gbazin committed
99 100 101
/*****************************************************************************
 * Open
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
102
int OpenDemux( vlc_object_t *p_this )
gbazin's avatar
 
gbazin committed
103 104 105 106 107
{
    demux_t       *p_demux = (demux_t*)p_this;
    demux_sys_t   *p_sys;
    AVProbeData   pd;
    AVInputFormat *fmt;
hartman's avatar
hartman committed
108 109
    unsigned int  i;
    int64_t       i_start_time = -1;
110
    bool          b_can_seek;
111
    char         *psz_url;
gbazin's avatar
 
gbazin committed
112

113 114 115 116 117 118 119 120
    if( p_demux->psz_file )
        psz_url = strdup( p_demux->psz_file );
    else
    {
        if( asprintf( &psz_url, "%s://%s", p_demux->psz_access, p_demux->psz_location ) == -1)
            return VLC_ENOMEM;
    }
    msg_Dbg( p_demux, "trying url: %s", psz_url );
gbazin's avatar
 
gbazin committed
121
    /* Init Probe data */
122
    pd.filename = psz_url;
123
    if( ( pd.buf_size = stream_Peek( p_demux->s, &pd.buf, 2048 + 213 ) ) <= 0 )
gbazin's avatar
 
gbazin committed
124
    {
125
        free( psz_url );
gbazin's avatar
 
gbazin committed
126 127 128 129
        msg_Warn( p_demux, "cannot peek" );
        return VLC_EGENERIC;
    }

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

    /* Guess format */
    if( !( fmt = av_probe_input_format( &pd, 1 ) ) )
    {
        msg_Dbg( p_demux, "couldn't guess format" );
138
        free( psz_url );
gbazin's avatar
 
gbazin committed
139 140 141 142
        return VLC_EGENERIC;
    }

    /* Don't try to handle MPEG unless forced */
143
    if( !p_demux->b_force &&
gbazin's avatar
 
gbazin committed
144 145 146
        ( !strcmp( fmt->name, "mpeg" ) ||
          !strcmp( fmt->name, "vcd" ) ||
          !strcmp( fmt->name, "vob" ) ||
147 148 149 150
          !strcmp( fmt->name, "mpegts" ) ||
          /* libavformat's redirector won't work */
          !strcmp( fmt->name, "redir" ) ||
          !strcmp( fmt->name, "sdp" ) ) )
gbazin's avatar
 
gbazin committed
151
    {
152
        free( psz_url );
gbazin's avatar
 
gbazin committed
153 154 155
        return VLC_EGENERIC;
    }

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;

161 162 163 164 165
        if( !p_demux->psz_file )
        {
            free( psz_url );
            return VLC_EGENERIC;
        }
166

167
        i_len = strlen( p_demux->psz_file );
168 169 170 171 172
        if( i_len < 4 )
        {
            free( psz_url );
            return VLC_EGENERIC;
        }
173

174 175 176
        if( strcasecmp( &p_demux->psz_file[i_len - 4], ".str" ) &&
            strcasecmp( &p_demux->psz_file[i_len - 4], ".xai" ) &&
            strcasecmp( &p_demux->psz_file[i_len - 3], ".xa" ) )
177
        {
178
            free( psz_url );
179 180 181 182
            return VLC_EGENERIC;
        }
    }

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

gbazin's avatar
 
gbazin committed
185 186 187 188
    /* 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 ) );
189
    p_sys->ic = 0;
gbazin's avatar
 
gbazin committed
190 191 192
    p_sys->fmt = fmt;
    p_sys->i_tk = 0;
    p_sys->tk = NULL;
193
    p_sys->tk_pcr = NULL;
194
    p_sys->i_ssa_order = 0;
195
    TAB_INIT( p_sys->i_attachments, p_sys->attachments);
hartman's avatar
hartman committed
196
    p_sys->p_title = NULL;
gbazin's avatar
 
gbazin committed
197 198 199 200

    /* 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
201 202 203 204
    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;
205 206
    p_sys->url.prot->url_read =
                    (int (*) (URLContext *, unsigned char *, int))IORead;
gbazin's avatar
 
gbazin committed
207
    p_sys->url.prot->url_write = 0;
208
    p_sys->url.prot->url_seek =
209
                    (int64_t (*) (URLContext *, int64_t, int))IOSeek;
gbazin's avatar
 
gbazin committed
210 211
    p_sys->url.prot->url_close = 0;
    p_sys->url.prot->next = 0;
gbazin's avatar
 
gbazin committed
212
    init_put_byte( &p_sys->io, p_sys->io_buffer, p_sys->io_buffer_size,
gbazin's avatar
 
gbazin committed
213
                   0, &p_sys->url, IORead, NULL, IOSeek );
214 215 216 217 218

    stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_can_seek );
    if( !b_can_seek )
    {
       /* Tell avformat that input is stream, so it doesn't get stuck
219 220 221
       when trying av_find_stream_info() trying to seek all the wrong places
       init_put_byte defaults io.is_streamed=0, so thats why we set them after it
       */
222 223
       p_sys->url.is_streamed = 1;
       p_sys->io.is_streamed = 1;
224 225 226
#if defined(AVIO_SEEKABLE_NORMAL)
       p_sys->io.seekable = 0;
#endif
227
    }
228

gbazin's avatar
 
gbazin committed
229 230

    /* Open it */
231
    if( av_open_input_stream( &p_sys->ic, &p_sys->io, psz_url,
gbazin's avatar
 
gbazin committed
232 233 234
                              p_sys->fmt, NULL ) )
    {
        msg_Err( p_demux, "av_open_input_stream failed" );
235
        p_sys->ic = NULL;
236
        free( psz_url );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
237
        CloseDemux( p_this );
gbazin's avatar
 
gbazin committed
238 239
        return VLC_EGENERIC;
    }
240 241
    free( psz_url );
    psz_url = NULL;
gbazin's avatar
 
gbazin committed
242

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
243
    vlc_avcodec_lock(); /* avformat calls avcodec behind our back!!! */
244
    if( av_find_stream_info( p_sys->ic ) < 0 )
gbazin's avatar
 
gbazin committed
245
    {
246
        msg_Warn( p_demux, "av_find_stream_info failed" );
gbazin's avatar
 
gbazin committed
247
    }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
248
    vlc_avcodec_unlock();
gbazin's avatar
 
gbazin committed
249 250 251

    for( i = 0; i < p_sys->ic->nb_streams; i++ )
    {
Laurent Aimar's avatar
Laurent Aimar committed
252 253 254
        AVStream *s = p_sys->ic->streams[i];
        AVCodecContext *cc = s->codec;

gbazin's avatar
 
gbazin committed
255 256 257
        es_out_id_t  *es;
        es_format_t  fmt;
        vlc_fourcc_t fcc;
258
        const char *psz_type = "unknown";
gbazin's avatar
 
gbazin committed
259

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
260
        if( !GetVlcFourcc( cc->codec_id, NULL, &fcc, NULL ) )
gbazin's avatar
 
gbazin committed
261 262 263 264
            fcc = VLC_FOURCC( 'u', 'n', 'd', 'f' );

        switch( cc->codec_type )
        {
265
        case AVMEDIA_TYPE_AUDIO:
gbazin's avatar
 
gbazin committed
266
            es_format_Init( &fmt, AUDIO_ES, fcc );
267
            fmt.i_bitrate = cc->bit_rate;
gbazin's avatar
 
gbazin committed
268 269
            fmt.audio.i_channels = cc->channels;
            fmt.audio.i_rate = cc->sample_rate;
aballier's avatar
aballier committed
270
            fmt.audio.i_bitspersample = cc->bits_per_coded_sample;
gbazin's avatar
 
gbazin committed
271
            fmt.audio.i_blockalign = cc->block_align;
272
            psz_type = "audio";
gbazin's avatar
 
gbazin committed
273
            break;
274

275
        case AVMEDIA_TYPE_VIDEO:
gbazin's avatar
 
gbazin committed
276
            es_format_Init( &fmt, VIDEO_ES, fcc );
277 278 279 280 281 282 283 284 285 286 287 288

            /* 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;
            }
289
            /* We need this for the h264 packetizer */
290 291
            else if( cc->codec_id == CODEC_ID_H264 && ( p_sys->fmt == av_find_input_format("flv") ||
                p_sys->fmt == av_find_input_format("matroska") || p_sys->fmt == av_find_input_format("mp4") ) )
292
                fmt.i_original_fourcc = VLC_FOURCC( 'a', 'v', 'c', '1' );
293

gbazin's avatar
 
gbazin committed
294 295
            fmt.video.i_width = cc->width;
            fmt.video.i_height = cc->height;
gbazin's avatar
 
gbazin committed
296 297 298 299 300
            if( cc->palctrl )
            {
                fmt.video.p_palette = malloc( sizeof(video_palette_t) );
                *fmt.video.p_palette = *(video_palette_t *)cc->palctrl;
            }
301
            psz_type = "video";
302
            fmt.video.i_frame_rate = cc->time_base.den;
303
            fmt.video.i_frame_rate_base = cc->time_base.num * __MAX( cc->ticks_per_frame, 1 );
gbazin's avatar
 
gbazin committed
304
            break;
305

306
        case AVMEDIA_TYPE_SUBTITLE:
307
            es_format_Init( &fmt, SPU_ES, fcc );
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
            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 );
                }
            }

350
            psz_type = "subtitle";
351
            break;
352

gbazin's avatar
 
gbazin committed
353
        default:
354
            es_format_Init( &fmt, UNKNOWN_ES, 0 );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
355
#ifdef HAVE_AVUTIL_CODEC_ATTACHMENT
356
            if( cc->codec_type == AVMEDIA_TYPE_ATTACHMENT )
357 358
            {
                input_attachment_t *p_attachment;
359

360 361 362
                psz_type = "attachment";
                if( cc->codec_id == CODEC_ID_TTF )
                {
363 364 365 366 367 368 369 370 371
                    AVMetadataTag *filename = av_metadata_get( s->metadata, "filename", NULL, 0 );
                    if( filename && filename->value )
                    {
                        p_attachment = vlc_input_attachment_New(
                                filename->value, "application/x-truetype-font",
                                NULL, cc->extradata, (int)cc->extradata_size );
                        TAB_APPEND( p_sys->i_attachments, p_sys->attachments,
                                p_attachment );
                    }
372
                }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
373
                else msg_Warn( p_demux, "unsupported attachment type (%u) in avformat demux", cc->codec_id );
374
            }
375
            else
376
#endif
377 378 379
            {
                if( cc->codec_type == AVMEDIA_TYPE_DATA )
                    psz_type = "data";
380

381
                msg_Warn( p_demux, "unsupported track type (%u:%u) in avformat demux", cc->codec_type, cc->codec_id );
382
            }
hartman's avatar
hartman committed
383
            break;
gbazin's avatar
 
gbazin committed
384
        }
385 386 387 388 389

        AVMetadataTag *language = av_metadata_get( s->metadata, "language", NULL, 0 );
        if ( language && language->value )
            fmt.psz_language = strdup( language->value );

390 391
        if( s->disposition & AV_DISPOSITION_DEFAULT )
            fmt.i_priority = 1000;
392

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
393
#ifdef HAVE_AVUTIL_CODEC_ATTACHMENT
394
        if( cc->codec_type != AVMEDIA_TYPE_ATTACHMENT )
395
#endif
396
        if( cc->codec_type != AVMEDIA_TYPE_DATA )
397
        {
398
            const bool    b_ogg = !strcmp( p_sys->fmt->name, "ogg" );
399 400 401
            const uint8_t *p_extra = cc->extradata;
            unsigned      i_extra  = cc->extradata_size;

402
            if( cc->codec_id == CODEC_ID_THEORA && b_ogg )
403 404
            {
                unsigned pi_size[3];
Pierre Ynard's avatar
Pierre Ynard committed
405
                const void *pp_data[3];
406 407 408 409 410 411
                unsigned i_count;
                for( i_count = 0; i_count < 3; i_count++ )
                {
                    if( i_extra < 2 )
                        break;
                    pi_size[i_count] = GetWBE( p_extra );
Pierre Ynard's avatar
Pierre Ynard committed
412
                    pp_data[i_count] = &p_extra[2];
413 414 415 416 417 418 419 420 421 422 423 424 425
                    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;
                }
            }
426
            else if( cc->codec_id == CODEC_ID_SPEEX && b_ogg )
427
            {
Pierre Ynard's avatar
Pierre Ynard committed
428
                const uint8_t p_dummy_comment[] = {
429 430 431 432
                    0, 0, 0, 0,
                    0, 0, 0, 0,
                };
                unsigned pi_size[2];
Pierre Ynard's avatar
Pierre Ynard committed
433
                const void *pp_data[2];
434 435

                pi_size[0] = i_extra;
Pierre Ynard's avatar
Pierre Ynard committed
436
                pp_data[0] = p_extra;
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456

                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 );
                }
            }
457 458 459 460 461 462 463 464
            es = es_out_Add( p_demux->out, &fmt );
            if( s->disposition & AV_DISPOSITION_DEFAULT )
                es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, es );
            es_format_Clean( &fmt );

            msg_Dbg( p_demux, "adding es: %s codec = %4.4s",
                     psz_type, (char*)&fcc );
            TAB_APPEND( p_sys->i_tk, p_sys->tk, es );
465
        }
gbazin's avatar
 
gbazin committed
466
    }
467 468
    p_sys->tk_pcr = calloc( p_sys->i_tk, sizeof(*p_sys->tk_pcr) );

hartman's avatar
hartman committed
469 470
    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
471 472 473 474

    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
475
    msg_Dbg( p_demux, "    - start time = %"PRId64, i_start_time );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
476
    msg_Dbg( p_demux, "    - duration = %"PRId64,
477
             ( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) ?
gbazin's avatar
 
gbazin committed
478
             p_sys->ic->duration * 1000000 / AV_TIME_BASE : -1 );
gbazin's avatar
 
gbazin committed
479

480
    if( p_sys->ic->nb_chapters > 0 )
481
    {
482
        p_sys->p_title = vlc_input_title_New();
483 484 485
        p_sys->p_title->i_length = p_sys->ic->duration * 1000000 / AV_TIME_BASE;
    }

hartman's avatar
hartman committed
486 487 488 489
    for( i = 0; i < p_sys->ic->nb_chapters; i++ )
    {
        seekpoint_t *s = vlc_seekpoint_New();

490 491
        AVMetadataTag *title = av_metadata_get( p_sys->ic->metadata, "title", NULL, 0);
        if( title && title->value )
hartman's avatar
hartman committed
492
        {
493
            s->psz_name = strdup( title->value );
hartman's avatar
hartman committed
494 495 496 497 498 499 500 501 502 503
            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 );
    }

504
    ResetTime( p_demux, 0 );
gbazin's avatar
 
gbazin committed
505 506 507 508 509 510
    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
511
void CloseDemux( vlc_object_t *p_this )
gbazin's avatar
 
gbazin committed
512 513 514 515
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;

516
    FREENULL( p_sys->tk );
517
    free( p_sys->tk_pcr );
518

519
    if( p_sys->ic ) av_close_input_stream( p_sys->ic );
520

521 522 523 524
    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
525 526 527
    if( p_sys->p_title )
        vlc_input_title_Delete( p_sys->p_title );

528
    free( p_sys->io_buffer );
gbazin's avatar
 
gbazin committed
529 530 531 532 533 534 535 536 537 538 539
    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
540
    int64_t     i_start_time;
gbazin's avatar
 
gbazin committed
541 542 543 544 545 546 547 548 549 550 551

    /* 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;
    }
552
    const AVStream *p_stream = p_sys->ic->streams[pkt.stream_index];
553 554 555 556 557 558
    if( p_stream->time_base.den <= 0 )
    {
        msg_Warn( p_demux, "Invalid time base for the stream %d", pkt.stream_index );
        av_free_packet( &pkt );
        return 1;
    }
559
    if( p_stream->codec->codec_id == CODEC_ID_SSA )
gbazin's avatar
 
gbazin committed
560
    {
561 562
        p_frame = BuildSsaFrame( &pkt, p_sys->i_ssa_order++ );
        if( !p_frame )
563 564
        {
            av_free_packet( &pkt );
565
            return 1;
566
        }
567 568 569 570
    }
    else
    {
        if( ( p_frame = block_New( p_demux, pkt.size ) ) == NULL )
571 572
        {
            av_free_packet( &pkt );
573
            return 0;
574
        }
575
        memcpy( p_frame->p_buffer, pkt.data, pkt.size );
gbazin's avatar
 
gbazin committed
576
    }
gbazin's avatar
 
gbazin committed
577

578
    if( pkt.flags & AV_PKT_FLAG_KEY )
579 580
        p_frame->i_flags |= BLOCK_FLAG_TYPE_I;

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

584
    p_frame->i_dts = ( pkt.dts == (int64_t)AV_NOPTS_VALUE ) ?
585
        VLC_TS_INVALID : (pkt.dts) * 1000000 *
586
        p_stream->time_base.num /
587
        p_stream->time_base.den - i_start_time + VLC_TS_0;
588
    p_frame->i_pts = ( pkt.pts == (int64_t)AV_NOPTS_VALUE ) ?
589
        VLC_TS_INVALID : (pkt.pts) * 1000000 *
590
        p_stream->time_base.num /
591
        p_stream->time_base.den - i_start_time + VLC_TS_0;
592
    if( pkt.duration > 0 && p_frame->i_length <= 0 )
593
        p_frame->i_length = pkt.duration * 1000000 *
594
            p_stream->time_base.num /
595
            p_stream->time_base.den;
gbazin's avatar
 
gbazin committed
596

597
    if( pkt.dts != AV_NOPTS_VALUE && pkt.dts == pkt.pts &&
598
        p_stream->codec->codec_type == AVMEDIA_TYPE_VIDEO )
599 600 601
    {
        /* Add here notoriously bugged file formats/samples regarding PTS */
        if( !strcmp( p_sys->fmt->name, "flv" ) )
602
            p_frame->i_pts = VLC_TS_INVALID;
603
    }
604
#ifdef AVFORMAT_DEBUG
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
605
    msg_Dbg( p_demux, "tk[%d] dts=%"PRId64" pts=%"PRId64,
gbazin's avatar
 
gbazin committed
606
             pkt.stream_index, p_frame->i_dts, p_frame->i_pts );
607
#endif
608 609
    if( p_frame->i_dts > VLC_TS_INVALID )
        p_sys->tk_pcr[pkt.stream_index] = p_frame->i_dts;
gbazin's avatar
 
gbazin committed
610

611 612 613
    int64_t i_ts_max = INT64_MIN;
    for( int i = 0; i < p_sys->i_tk; i++ )
        i_ts_max = __MAX( i_ts_max, p_sys->tk_pcr[i] );
gbazin's avatar
 
gbazin committed
614

615 616 617 618 619 620 621 622 623 624 625
    int64_t i_ts_min = INT64_MAX;
    for( int i = 0; i < p_sys->i_tk; i++ )
    {
        if( p_sys->tk_pcr[i] > VLC_TS_INVALID && p_sys->tk_pcr[i] + 10 * CLOCK_FREQ >= i_ts_max )
            i_ts_min = __MIN( i_ts_min, p_sys->tk_pcr[i] );
    }
    if( i_ts_min >= p_sys->i_pcr )
    {
        p_sys->i_pcr = i_ts_min;
        es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
        UpdateSeekPoint( p_demux, p_sys->i_pcr );
gbazin's avatar
 
gbazin committed
626 627 628
    }

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

gbazin's avatar
 
gbazin committed
630 631 632 633
    av_free_packet( &pkt );
    return 1;
}

hartman's avatar
hartman committed
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
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;
    }
}

656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
static void ResetTime( demux_t *p_demux, int64_t i_time )
{
    demux_sys_t *p_sys = p_demux->p_sys;

    if( p_sys->ic->start_time == (int64_t)AV_NOPTS_VALUE || i_time < 0 )
        i_time = VLC_TS_INVALID;
    else if( i_time == 0 )
        i_time = 1;

    p_sys->i_pcr = i_time;
    for( int i = 0; i < p_sys->i_tk; i++ )
        p_sys->tk_pcr[i] = i_time;

    if( i_time > VLC_TS_INVALID )
    {
        es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_time );
        UpdateSeekPoint( p_demux, i_time );
    }
}

676 677 678 679 680 681
static block_t *BuildSsaFrame( const AVPacket *p_pkt, unsigned i_order )
{
    if( p_pkt->size <= 0 )
        return NULL;

    char buffer[256];
682
    const size_t i_buffer_size = __MIN( (int)sizeof(buffer) - 1, p_pkt->size );
683 684 685 686 687 688 689 690 691 692 693
    memcpy( buffer, p_pkt->data, i_buffer_size );
    buffer[i_buffer_size] = '\0';

    /* */
    int i_layer;
    int h0, m0, s0, c0;
    int h1, m1, s1, c1;
    int i_position = 0;
    if( sscanf( buffer, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,%n", &i_layer,
                &h0, &m0, &s0, &c0, &h1, &m1, &s1, &c1, &i_position ) < 9 )
        return NULL;
694
    if( i_position <= 0 || (unsigned)i_position >= i_buffer_size )
695 696 697 698 699 700 701 702
        return NULL;

    char *p;
    if( asprintf( &p, "%u,%d,%.*s", i_order, i_layer, p_pkt->size - i_position, p_pkt->data + i_position ) < 0 )
        return NULL;

    block_t *p_frame = block_heap_Alloc( p, p, strlen(p) + 1 );
    if( p_frame )
ivoire's avatar
ivoire committed
703
        p_frame->i_length = CLOCK_FREQ * ((h1-h0) * 3600 +
704 705 706 707 708 709
                                          (m1-m0) * 60 +
                                          (s1-s0) * 1) +
                            CLOCK_FREQ * (c1-c0) / 100;
    return p_frame;
}

gbazin's avatar
 
gbazin committed
710 711 712 713 714 715
/*****************************************************************************
 * Control:
 *****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
    demux_sys_t *p_sys = p_demux->p_sys;
716
    const int64_t i_start_time = p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ? p_sys->ic->start_time : 0;
gbazin's avatar
 
gbazin committed
717 718 719 720 721 722
    double f, *pf;
    int64_t i64, *pi64;

    switch( i_query )
    {
        case DEMUX_GET_POSITION:
723
            pf = (double*) va_arg( args, double* ); *pf = 0.0;
gbazin's avatar
 
gbazin committed
724 725 726
            i64 = stream_Size( p_demux->s );
            if( i64 > 0 )
            {
727 728
                double current = stream_Tell( p_demux->s );
                *pf = current / (double)i64;
gbazin's avatar
 
gbazin committed
729
            }
730

731
            if( (p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE) && (p_sys->i_pcr > 0) )
gbazin's avatar
 
gbazin committed
732
            {
733
                *pf = (double)p_sys->i_pcr / (double)p_sys->ic->duration;
gbazin's avatar
 
gbazin committed
734
            }
735

gbazin's avatar
 
gbazin committed
736 737 738 739
            return VLC_SUCCESS;

        case DEMUX_SET_POSITION:
            f = (double) va_arg( args, double );
740
            i64 = p_sys->ic->duration * f + i_start_time;
gbazin's avatar
 
gbazin committed
741

742
            msg_Warn( p_demux, "DEMUX_SET_POSITION: %"PRId64, i64 );
gbazin's avatar
 
gbazin committed
743

744 745 746 747 748 749 750
            /* 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, AVSEEK_FLAG_BACKWARD ) < 0) )
            {
                int64_t i_size = stream_Size( p_demux->s );
                i64 = (i_size * f);
751

752 753 754 755 756 757 758 759 760
                msg_Warn( p_demux, "DEMUX_SET_BYTE_POSITION: %"PRId64, i64 );
                if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BYTE ) < 0 )
                    return VLC_EGENERIC;

                ResetTime( p_demux, -1 );
            }
            else
            {
                ResetTime( p_demux, i64 - i_start_time );
gbazin's avatar
 
gbazin committed
761 762 763
            }
            return VLC_SUCCESS;

764 765
        case DEMUX_GET_LENGTH:
            pi64 = (int64_t*)va_arg( args, int64_t * );
766
            if( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE )
767 768 769
                *pi64 = p_sys->ic->duration * 1000000 / AV_TIME_BASE;
            else
                *pi64 = 0;
770 771
            return VLC_SUCCESS;

gbazin's avatar
 
gbazin committed
772 773 774 775 776 777
        case DEMUX_GET_TIME:
            pi64 = (int64_t*)va_arg( args, int64_t * );
            *pi64 = p_sys->i_pcr;
            return VLC_SUCCESS;

        case DEMUX_SET_TIME:
778
        {
gbazin's avatar
 
gbazin committed
779
            i64 = (int64_t)va_arg( args, int64_t );
780
            i64 = i64 *AV_TIME_BASE / 1000000 + i_start_time;
gbazin's avatar
 
gbazin committed
781

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

784
            if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BACKWARD ) < 0 )
gbazin's avatar
 
gbazin committed
785 786 787
            {
                return VLC_EGENERIC;
            }
788
            ResetTime( p_demux, i64 - i_start_time );
gbazin's avatar
 
gbazin committed
789
            return VLC_SUCCESS;
790
        }
gbazin's avatar
 
gbazin committed
791

792 793 794 795 796 797 798 799
        case DEMUX_HAS_UNSUPPORTED_META:
        {
            bool *pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = true;
            return VLC_SUCCESS;
        }


800 801
        case DEMUX_GET_META:
        {
zorglub's avatar
zorglub committed
802
            vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
803

804
            AVMetadataTag *title = av_metadata_get( p_sys->ic->metadata, "language", NULL, 0 );
805
            AVMetadataTag *artist = av_metadata_get( p_sys->ic->metadata, "artist", NULL, 0 );
806 807 808 809 810 811
            AVMetadataTag *copyright = av_metadata_get( p_sys->ic->metadata, "copyright", NULL, 0 );
            AVMetadataTag *comment = av_metadata_get( p_sys->ic->metadata, "comment", NULL, 0 );
            AVMetadataTag *genre = av_metadata_get( p_sys->ic->metadata, "genre", NULL, 0 );

            if( title && title->value )
                vlc_meta_SetTitle( p_meta, title->value );
812 813
            if( artist && artist->value )
                vlc_meta_SetArtist( p_meta, artist->value );
814 815 816 817 818 819
            if( copyright && copyright->value )
                vlc_meta_SetCopyright( p_meta, copyright->value );
            if( comment && comment->value )
                vlc_meta_SetDescription( p_meta, comment->value );
            if( genre && genre->value )
                vlc_meta_SetGenre( p_meta, genre->value );
820 821 822
            return VLC_SUCCESS;
        }

823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
        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
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
        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;

870 871
            i64 = p_sys->p_title->seekpoint[i_seekpoint]->i_time_offset *
                  AV_TIME_BASE / 1000000 + i_start_time;
hartman's avatar
hartman committed
872 873 874

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

875
            if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BACKWARD ) < 0 )
hartman's avatar
hartman committed
876 877 878
            {
                return VLC_EGENERIC;
            }
879
            ResetTime( p_demux, i64 - i_start_time );
hartman's avatar
hartman committed
880 881 882 883
            return VLC_SUCCESS;
        }


gbazin's avatar
 
gbazin committed
884 885 886 887 888 889 890 891 892 893
        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
894 895
    URLContext *p_url = opaque;
    demux_t *p_demux = p_url->priv_data;
896
    if( buf_size < 0 ) return -1;
897 898
    int i_ret = stream_Read( p_demux->s, buf, buf_size );
    return i_ret ? i_ret : -1;
gbazin's avatar
 
gbazin committed
899 900
}

901
static int64_t IOSeek( void *opaque, int64_t offset, int whence )
gbazin's avatar
 
gbazin committed
902
{
gbazin's avatar
 
gbazin committed
903 904
    URLContext *p_url = opaque;
    demux_t *p_demux = p_url->priv_data;
ivoire's avatar
ivoire committed
905
    int64_t i_absolute;
906
    int64_t i_size = stream_Size( p_demux->s );
gbazin's avatar
 
gbazin committed
907

908
#ifdef AVFORMAT_DEBUG
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
909
    msg_Warn( p_demux, "IOSeek offset: %"PRId64", whence: %i", offset, whence );
910
#endif
gbazin's avatar
 
gbazin committed
911