demux.c 29.8 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 "../../codec/avcodec/chroma.h"
50
#include "avformat.h"
51
#include "../xiph.h"
52
#include "../vobsub.h"
53

54
55
//#define AVFORMAT_DEBUG 1

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

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

gbazin's avatar
   
gbazin committed
63
64
65
66
67
68
69
70
71
72
73
/*****************************************************************************
 * 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
74
75
    URLContext     url;
    URLProtocol    prot;
gbazin's avatar
   
gbazin committed
76
77
78
79
80
81
82

    int             i_tk;
    es_out_id_t     **tk;

    int64_t     i_pcr;
    int64_t     i_pcr_inc;
    int         i_pcr_tk;
83

84
85
    unsigned    i_ssa_order;

86
87
    int                i_attachments;
    input_attachment_t **attachments;
hartman's avatar
hartman committed
88
89
90

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

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

102
static block_t *BuildSsaFrame( const AVPacket *p_pkt, unsigned i_order );
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;
116
    bool          b_can_seek;
117
    char         *psz_url;
gbazin's avatar
   
gbazin committed
118

119
120
121
122
123
124
125
126
    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
127
    /* Init Probe data */
128
    pd.filename = psz_url;
129
    if( ( pd.buf_size = stream_Peek( p_demux->s, &pd.buf, 2048 + 213 ) ) <= 0 )
gbazin's avatar
   
gbazin committed
130
    {
131
        free( psz_url );
gbazin's avatar
   
gbazin committed
132
133
134
135
        msg_Warn( p_demux, "cannot peek" );
        return VLC_EGENERIC;
    }

136
    vlc_avcodec_lock();
137
    av_register_all(); /* Can be called several times */
138
    vlc_avcodec_unlock();
gbazin's avatar
   
gbazin committed
139
140
141
142
143

    /* Guess format */
    if( !( fmt = av_probe_input_format( &pd, 1 ) ) )
    {
        msg_Dbg( p_demux, "couldn't guess format" );
144
        free( psz_url );
gbazin's avatar
   
gbazin committed
145
146
147
148
        return VLC_EGENERIC;
    }

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

162
163
164
165
166
    /* Don't trigger false alarms on bin files */
    if( !p_demux->b_force && !strcmp( fmt->name, "psxstr" ) )
    {
        int i_len;

167
168
169
170
171
        if( !p_demux->psz_file )
        {
            free( psz_url );
            return VLC_EGENERIC;
        }
172

173
        i_len = strlen( p_demux->psz_file );
174
175
176
177
178
        if( i_len < 4 )
        {
            free( psz_url );
            return VLC_EGENERIC;
        }
179

180
181
182
        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" ) )
183
        {
184
            free( psz_url );
185
186
187
188
            return VLC_EGENERIC;
        }
    }

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

gbazin's avatar
   
gbazin committed
191
192
193
194
    /* 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 ) );
195
    p_sys->ic = 0;
gbazin's avatar
   
gbazin committed
196
197
198
199
    p_sys->fmt = fmt;
    p_sys->i_tk = 0;
    p_sys->tk = NULL;
    p_sys->i_pcr_tk = -1;
200
    p_sys->i_pcr = -1;
201
    p_sys->i_ssa_order = 0;
202
    TAB_INIT( p_sys->i_attachments, p_sys->attachments);
hartman's avatar
hartman committed
203
    p_sys->p_title = NULL;
gbazin's avatar
   
gbazin committed
204
205
206
207

    /* 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
208
209
210
211
    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;
212
213
    p_sys->url.prot->url_read =
                    (int (*) (URLContext *, unsigned char *, int))IORead;
gbazin's avatar
   
gbazin committed
214
    p_sys->url.prot->url_write = 0;
215
    p_sys->url.prot->url_seek =
216
                    (int64_t (*) (URLContext *, int64_t, int))IOSeek;
gbazin's avatar
   
gbazin committed
217
218
    p_sys->url.prot->url_close = 0;
    p_sys->url.prot->next = 0;
gbazin's avatar
   
gbazin committed
219
    init_put_byte( &p_sys->io, p_sys->io_buffer, p_sys->io_buffer_size,
gbazin's avatar
   
gbazin committed
220
                   0, &p_sys->url, IORead, NULL, IOSeek );
221
222
223
224
225

    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
226
227
228
       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
       */
229
230
231
       p_sys->url.is_streamed = 1;
       p_sys->io.is_streamed = 1;
    }
232

gbazin's avatar
   
gbazin committed
233
234

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

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

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

gbazin's avatar
   
gbazin committed
258
259
260
        es_out_id_t  *es;
        es_format_t  fmt;
        vlc_fourcc_t fcc;
261
        const char *psz_type = "unknown";
gbazin's avatar
   
gbazin committed
262

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

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

gbazin's avatar
   
gbazin committed
278
279
        case CODEC_TYPE_VIDEO:
            es_format_Init( &fmt, VIDEO_ES, fcc );
280
281
282
283
284
285
286
287
288
289
290
291

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

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

309
310
        case CODEC_TYPE_SUBTITLE:
            es_format_Init( &fmt, SPU_ES, fcc );
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
350
351
352
            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 );
                }
            }

353
            psz_type = "subtitle";
354
            break;
355

gbazin's avatar
   
gbazin committed
356
        default:
357
            es_format_Init( &fmt, UNKNOWN_ES, 0 );
358
359
360
361
362
363
364
#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 )
                {
Laurent Aimar's avatar
Laurent Aimar committed
365
                    p_attachment = vlc_input_attachment_New( s->filename, "application/x-truetype-font", NULL,
366
367
368
369
370
371
372
373
                                             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

374
375
            if( cc->codec_type == CODEC_TYPE_DATA )
                psz_type = "data";
376

377
            msg_Warn( p_demux, "unsupported track type in ffmpeg demux" );
hartman's avatar
hartman committed
378
            break;
gbazin's avatar
   
gbazin committed
379
        }
Laurent Aimar's avatar
Laurent Aimar committed
380
        fmt.psz_language = strdup( s->language );
381
382
        if( s->disposition & AV_DISPOSITION_DEFAULT )
            fmt.i_priority = 1000;
383
384
385
386
387

#ifdef HAVE_FFMPEG_CODEC_ATTACHMENT
        if( cc->codec_type != CODEC_TYPE_ATTACHMENT )
#endif
        {
388
            const bool    b_ogg = !strcmp( p_sys->fmt->name, "ogg" );
389
390
391
            const uint8_t *p_extra = cc->extradata;
            unsigned      i_extra  = cc->extradata_size;

392
            if( cc->codec_id == CODEC_ID_THEORA && b_ogg )
393
394
            {
                unsigned pi_size[3];
Pierre Ynard's avatar
Pierre Ynard committed
395
                const void *pp_data[3];
396
397
398
399
400
401
                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
402
                    pp_data[i_count] = &p_extra[2];
403
404
405
406
407
408
409
410
411
412
413
414
415
                    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;
                }
            }
416
            else if( cc->codec_id == CODEC_ID_SPEEX && b_ogg )
417
            {
Pierre Ynard's avatar
Pierre Ynard committed
418
                const uint8_t p_dummy_comment[] = {
419
420
421
422
                    0, 0, 0, 0,
                    0, 0, 0, 0,
                };
                unsigned pi_size[2];
Pierre Ynard's avatar
Pierre Ynard committed
423
                const void *pp_data[2];
424
425

                pi_size[0] = i_extra;
Pierre Ynard's avatar
Pierre Ynard committed
426
                pp_data[0] = p_extra;
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446

                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 );
                }
            }
447
        }
gbazin's avatar
   
gbazin committed
448
        es = es_out_Add( p_demux->out, &fmt );
449
450
        if( s->disposition & AV_DISPOSITION_DEFAULT )
            es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, es );
451
        es_format_Clean( &fmt );
gbazin's avatar
   
gbazin committed
452
453

        msg_Dbg( p_demux, "adding es: %s codec = %4.4s",
454
                 psz_type, (char*)&fcc );
gbazin's avatar
   
gbazin committed
455
456
        TAB_APPEND( p_sys->i_tk, p_sys->tk, es );
    }
hartman's avatar
hartman committed
457
458
    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
459
460
461
462

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

468
469
    if( p_sys->ic->nb_chapters > 0 )
        p_sys->p_title = vlc_input_title_New();
hartman's avatar
hartman committed
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
    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 );
    }

gbazin's avatar
   
gbazin committed
487
488
489
490
491
492
    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close
 *****************************************************************************/
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
493
void CloseDemux( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
494
495
496
497
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;

498
    FREENULL( p_sys->tk );
499

500
    if( p_sys->ic ) av_close_input_stream( p_sys->ic );
501

502
503
504
505
    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
506
507
508
    if( p_sys->p_title )
        vlc_input_title_Delete( p_sys->p_title );

509
    free( p_sys->io_buffer );
gbazin's avatar
   
gbazin committed
510
511
512
513
514
515
516
517
518
519
520
    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
521
    int64_t     i_start_time;
gbazin's avatar
   
gbazin committed
522
523
524
525
526
527
528
529
530
531
532

    /* 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;
    }
533
    const AVStream *p_stream = p_sys->ic->streams[pkt.stream_index];
534
535
536
537
538
539
    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;
    }
540
    if( p_stream->codec->codec_id == CODEC_ID_SSA )
gbazin's avatar
   
gbazin committed
541
    {
542
543
        p_frame = BuildSsaFrame( &pkt, p_sys->i_ssa_order++ );
        if( !p_frame )
544
545
        {
            av_free_packet( &pkt );
546
            return 1;
547
        }
548
549
550
551
    }
    else
    {
        if( ( p_frame = block_New( p_demux, pkt.size ) ) == NULL )
552
553
        {
            av_free_packet( &pkt );
554
            return 0;
555
        }
556
        memcpy( p_frame->p_buffer, pkt.data, pkt.size );
gbazin's avatar
   
gbazin committed
557
    }
gbazin's avatar
   
gbazin committed
558

559
560
561
    if( pkt.flags & PKT_FLAG_KEY )
        p_frame->i_flags |= BLOCK_FLAG_TYPE_I;

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

565
    p_frame->i_dts = ( pkt.dts == (int64_t)AV_NOPTS_VALUE ) ?
566
        VLC_TS_INVALID : (pkt.dts) * 1000000 *
567
        p_stream->time_base.num /
568
        p_stream->time_base.den - i_start_time + VLC_TS_0;
569
    p_frame->i_pts = ( pkt.pts == (int64_t)AV_NOPTS_VALUE ) ?
570
        VLC_TS_INVALID : (pkt.pts) * 1000000 *
571
        p_stream->time_base.num /
572
        p_stream->time_base.den - i_start_time + VLC_TS_0;
573
    if( pkt.duration > 0 && p_frame->i_length <= 0 )
574
        p_frame->i_length = pkt.duration * 1000000 *
575
            p_stream->time_base.num /
576
            p_stream->time_base.den;
gbazin's avatar
   
gbazin committed
577

578
579
580
581
582
    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" ) )
583
            p_frame->i_pts = VLC_TS_INVALID;
584
    }
585
#ifdef AVFORMAT_DEBUG
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
586
    msg_Dbg( p_demux, "tk[%d] dts=%"PRId64" pts=%"PRId64,
gbazin's avatar
   
gbazin committed
587
             pkt.stream_index, p_frame->i_dts, p_frame->i_pts );
588
#endif
gbazin's avatar
   
gbazin committed
589

590
    if( p_frame->i_dts > VLC_TS_INVALID  &&
gbazin's avatar
   
gbazin committed
591
        ( pkt.stream_index == p_sys->i_pcr_tk || p_sys->i_pcr_tk < 0 ) )
592
    {
gbazin's avatar
   
gbazin committed
593
        p_sys->i_pcr_tk = pkt.stream_index;
594
        p_sys->i_pcr = p_frame->i_dts;
gbazin's avatar
   
gbazin committed
595
596
597
598
599

        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
600
601

    UpdateSeekPoint( p_demux, p_sys->i_pcr);
gbazin's avatar
   
gbazin committed
602
603
604
605
    av_free_packet( &pkt );
    return 1;
}

hartman's avatar
hartman committed
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
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;
    }
}

628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
static block_t *BuildSsaFrame( const AVPacket *p_pkt, unsigned i_order )
{
    if( p_pkt->size <= 0 )
        return NULL;

    char buffer[256];
    const size_t i_buffer_size = __MIN( sizeof(buffer) - 1, p_pkt->size );
    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;
    if( i_position <= 0 || i_position >= i_buffer_size )
        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
655
        p_frame->i_length = CLOCK_FREQ * ((h1-h0) * 3600 +
656
657
658
659
660
661
                                          (m1-m0) * 60 +
                                          (s1-s0) * 1) +
                            CLOCK_FREQ * (c1-c0) / 100;
    return p_frame;
}

gbazin's avatar
   
gbazin committed
662
663
664
665
666
667
668
669
670
671
672
673
/*****************************************************************************
 * 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:
674
            pf = (double*) va_arg( args, double* ); *pf = 0.0;
gbazin's avatar
   
gbazin committed
675
676
677
            i64 = stream_Size( p_demux->s );
            if( i64 > 0 )
            {
678
679
                double current = stream_Tell( p_demux->s );
                *pf = current / (double)i64;
gbazin's avatar
   
gbazin committed
680
            }
681

682
            if( (p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE) && (p_sys->i_pcr > 0) )
gbazin's avatar
   
gbazin committed
683
            {
684
                *pf = (double)p_sys->i_pcr / (double)p_sys->ic->duration;
gbazin's avatar
   
gbazin committed
685
            }
686

gbazin's avatar
   
gbazin committed
687
688
689
690
            return VLC_SUCCESS;

        case DEMUX_SET_POSITION:
            f = (double) va_arg( args, double );
691
            if( p_sys->i_pcr > 0 )
gbazin's avatar
   
gbazin committed
692
            {
693
                i64 = p_sys->ic->duration * f;
694
                if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE )
gbazin's avatar
   
gbazin committed
695
696
                    i64 += p_sys->ic->start_time;

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

699
700
701
702
                /* 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
703
                {
704
                    int64_t i_size = stream_Size( p_demux->s );
705
                    i64 = (i_size * f);
706

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
707
                    msg_Warn( p_demux, "DEMUX_SET_BYTE_POSITION: %"PRId64, i64 );
708
                    if( av_seek_frame( p_sys->ic, -1, i64, AVSEEK_FLAG_BYTE ) < 0 )
709
                        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
710
                }
711
712
713
714
                else
                {
                    UpdateSeekPoint( p_demux, i64 );
                }
gbazin's avatar
   
gbazin committed
715
                p_sys->i_pcr = -1; /* Invalidate time display */
gbazin's avatar
   
gbazin committed
716
717
718
            }
            return VLC_SUCCESS;

719
720
        case DEMUX_GET_LENGTH:
            pi64 = (int64_t*)va_arg( args, int64_t * );
721
            if( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE )
722
723
724
                *pi64 = p_sys->ic->duration * 1000000 / AV_TIME_BASE;
            else
                *pi64 = 0;
725
726
            return VLC_SUCCESS;

gbazin's avatar
   
gbazin committed
727
728
729
730
731
732
733
        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
734
            i64 = i64 *AV_TIME_BASE / 1000000;
735
            if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE )
gbazin's avatar
   
gbazin committed
736
737
                i64 += p_sys->ic->start_time;

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

740
            if( av_seek_frame( p_sys->ic, -1, i64, 0 ) < 0 )
gbazin's avatar
   
gbazin committed
741
742
743
744
            {
                return VLC_EGENERIC;
            }
            p_sys->i_pcr = -1; /* Invalidate time display */
hartman's avatar
hartman committed
745
            UpdateSeekPoint( p_demux, i64 );
gbazin's avatar
   
gbazin committed
746
747
            return VLC_SUCCESS;

748
749
750
751
752
753
754
755
        case DEMUX_HAS_UNSUPPORTED_META:
        {
            bool *pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = true;
            return VLC_SUCCESS;
        }


756
757
        case DEMUX_GET_META:
        {
zorglub's avatar
zorglub committed
758
            vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
759
760

            if( p_sys->ic->title[0] )
zorglub's avatar
zorglub committed
761
                vlc_meta_SetTitle( p_meta, p_sys->ic->title );
762
            if( p_sys->ic->author[0] )
zorglub's avatar
zorglub committed
763
                vlc_meta_SetArtist( p_meta, p_sys->ic->author );
764
            if( p_sys->ic->copyright[0] )
zorglub's avatar
zorglub committed
765
                vlc_meta_SetCopyright( p_meta, p_sys->ic->copyright );
766
            if( p_sys->ic->comment[0] )
zorglub's avatar
zorglub committed
767
                vlc_meta_SetDescription( p_meta, p_sys->ic->comment );
768
            if( p_sys->ic->genre[0] )
zorglub's avatar
zorglub committed
769
                vlc_meta_SetGenre( p_meta, p_sys->ic->genre );
770
771
772
            return VLC_SUCCESS;
        }

773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
        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
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
        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
836
837
838
839
840
841
842
843
844
845
        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
846
847
    URLContext *p_url = opaque;
    demux_t *p_demux = p_url->priv_data;
848
    if( buf_size < 0 ) return -1;
849
850
    int i_ret = stream_Read( p_demux->s, buf, buf_size );
    return i_ret ? i_ret : -1;
gbazin's avatar
   
gbazin committed
851
852
}

853
static int64_t IOSeek( void *opaque, int64_t offset, int whence )
gbazin's avatar
   
gbazin committed
854
{
gbazin's avatar
   
gbazin committed
855
856
    URLContext *p_url = opaque;
    demux_t *p_demux = p_url->priv_data;
ivoire's avatar
ivoire committed
857
    int64_t i_absolute;
858
    int64_t i_size = stream_Size( p_demux->s );
gbazin's avatar
   
gbazin committed
859

860
#ifdef AVFORMAT_DEBUG
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
861
    msg_Warn( p_demux, "IOSeek offset: %"PRId64", whence: %i", offset, whence );
862
#endif
gbazin's avatar
   
gbazin committed
863

gbazin's avatar
   
gbazin committed
864
865
    switch( whence )
    {
866
867
868
869
#ifdef AVSEEK_SIZE
        case AVSEEK_SIZE:
            return i_size;
#endif
gbazin's avatar
   
gbazin committed
870
        case SEEK_SET:
hartman's avatar
hartman committed
871
            i_absolute = (int64_t)offset;
gbazin's avatar
   
gbazin committed
872
873
            break;
        case SEEK_CUR:
hartman's avatar
hartman committed
874
            i_absolute = stream_Tell( p_demux->s ) + (int64_t)offset;
gbazin's avatar
   
gbazin committed
875
876
            break;
        case SEEK_END:
hartman's avatar
hartman committed
877
            i_absolute = i_size + (int64_t)offset;
gbazin's avatar
   
gbazin committed
878
879
880
881
882
            break;
        default:
            return -1;

    }
883

884
    if( i_absolute < 0 )
885
886
887
888
    {
        msg_Dbg( p_demux, "Trying to seek before the beginning" );
        return -1;
    }
889

hartman's avatar
hartman committed
890
    if( i_size > 0 && i_absolute >= i_size )
Rafaël Carré's avatar
Rafaël Carré committed
891
    {
892
893
        msg_Dbg( p_demux, "Trying to seek too far : EOF?" );
        return -1;
Rafaël Carré's avatar
Rafaël Carré committed
894
    }
gbazin's avatar
   
gbazin committed
895
896
897

    if( stream_Seek( p_demux->s, i_absolute ) )
    {
898
        msg_Warn( p_demux, "we were not allowed to seek, or EOF " );
gbazin's avatar
   
gbazin committed
899
900
901
        return -1;
    }

902
    return stream_Tell( p_demux->s );
gbazin's avatar
   
gbazin committed
903
904
}

905
#endif /* HAVE_LIBAVFORMAT_AVFORMAT_H */