Coverage Report

Created: 2025-10-10 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/asf/asf.c
Line
Count
Source
1
/*****************************************************************************
2
 * asf.c : ASF demux module
3
 *****************************************************************************
4
 * Copyright © 2002-2004, 2006-2008, 2010 VLC authors and VideoLAN
5
 *
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
/*****************************************************************************
24
 * Preamble
25
 *****************************************************************************/
26
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
#include <vlc_common.h>
32
#include <vlc_arrays.h>
33
#include <vlc_plugin.h>
34
#include <vlc_demux.h>
35
#include <vlc_dialog.h>
36
37
#include <vlc_meta.h>                  /* vlc_meta_Set*, vlc_meta_New */
38
#include <vlc_access.h>                /* GET_PRIVATE_ID_STATE */
39
#include <vlc_codecs.h>                /* VLC_BITMAPINFOHEADER, WAVEFORMATEX */
40
#include <vlc_vout.h>
41
42
#include <limits.h>
43
#include <stdckdint.h>
44
45
#include "asfpacket.h"
46
#include "libasf.h"
47
#include "assert.h"
48
49
/* TODO
50
 *  - add support for the newly added object: language, bitrate,
51
 *                                            extended stream properties.
52
 */
53
54
/*****************************************************************************
55
 * Module descriptor
56
 *****************************************************************************/
57
static int  Open  ( vlc_object_t * );
58
static void Close ( vlc_object_t * );
59
60
108
vlc_module_begin ()
61
54
    set_subcategory( SUBCAT_INPUT_DEMUX )
62
54
    set_description( N_("ASF/WMV demuxer") )
63
54
    set_capability( "demux", 200 )
64
108
    set_callbacks( Open, Close )
65
54
    add_shortcut( "asf", "wmv" )
66
54
    add_file_extension("asf")
67
54
    add_file_extension("wma")
68
54
    add_file_extension("wmv")
69
54
vlc_module_end ()
70
71
72
/*****************************************************************************
73
 * Local prototypes
74
 *****************************************************************************/
75
static int Demux  ( demux_t * );
76
static int Control( demux_t *, int i_query, va_list args );
77
78
39.3G
#define MAX_ASF_TRACKS (ASF_MAX_STREAMNUMBER + 1)
79
#define ASF_PREROLL_FROM_CURRENT -1
80
81
/* callbacks for packet parser */
82
static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
83
                               vlc_tick_t i_time );
84
static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, vlc_tick_t i_time);
85
static bool Block_Dequeue( demux_t *p_demux, vlc_tick_t i_nexttime );
86
static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys,
87
                                               uint8_t i_stream_number );
88
static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe );
89
static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame );
90
static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
91
                          uint8_t i_ratio_x, uint8_t i_ratio_y );
92
93
typedef struct
94
{
95
    int i_cat;
96
97
    es_out_id_t     *p_es;
98
    es_format_t     *p_fmt; /* format backup for video changes */
99
    bool             b_selected;
100
101
    vlc_tick_t       i_time; /* track time*/
102
103
    asf_track_info_t info;
104
105
    struct
106
    {
107
        block_t     *p_first;
108
        block_t    **pp_last;
109
    } queue;
110
111
} asf_track_t;
112
113
typedef struct
114
{
115
    vlc_tick_t          i_time;     /* s */
116
    vlc_tick_t          i_sendtime;
117
    vlc_tick_t          i_length;   /* length of file */
118
    uint64_t            i_bitrate;  /* global file bitrate */
119
    bool                b_eos;      /* end of current stream */
120
    bool                b_eof;      /* end of current media */
121
122
    asf_object_root_t            *p_root;
123
    asf_object_file_properties_t *p_fp;
124
125
    unsigned int        i_track;
126
    asf_track_t         *track[MAX_ASF_TRACKS]; /* track number is stored on 7 bits */
127
128
    uint64_t            i_data_begin;
129
    uint64_t            i_data_end;
130
131
    bool                b_index;
132
    bool                b_canfastseek;
133
    bool                b_pcr_sent;
134
    uint8_t             i_seek_track;
135
    uint8_t             i_access_selected_track[ES_CATEGORY_COUNT]; /* mms, depends on access algorithm */
136
    unsigned int        i_wait_keyframe;
137
138
    vlc_tick_t          i_preroll_start;
139
140
    asf_packet_sys_t    packet_sys;
141
142
    vlc_meta_t          *meta;
143
} demux_sys_t;
144
145
static int      DemuxInit( demux_t * );
146
static void     DemuxEnd( demux_t * );
147
148
static void     FlushQueue( asf_track_t * );
149
static void     FlushQueues( demux_t *p_demux );
150
151
/*****************************************************************************
152
 * Open: check file and initializes ASF structures
153
 *****************************************************************************/
154
static int Open( vlc_object_t * p_this )
155
8.36k
{
156
8.36k
    demux_t     *p_demux = (demux_t *)p_this;
157
8.36k
    demux_sys_t *p_sys;
158
8.36k
    vlc_guid_t      guid;
159
8.36k
    const uint8_t     *p_peek;
160
161
    /* A little test to see if it could be a asf stream */
162
8.36k
    if( vlc_stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) return VLC_EGENERIC;
163
164
8.35k
    ASF_GetGUID( &guid, p_peek );
165
8.35k
    if( !guidcmp( &guid, &asf_object_header_guid ) ) return VLC_EGENERIC;
166
167
    /* Set p_demux fields */
168
7.34k
    p_demux->pf_demux = Demux;
169
7.34k
    p_demux->pf_control = Control;
170
7.34k
    p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
171
172
    /* Load the headers */
173
7.34k
    if( DemuxInit( p_demux ) )
174
4.62k
    {
175
4.62k
        free( p_sys );
176
4.62k
        return VLC_EGENERIC;
177
4.62k
    }
178
179
2.72k
    p_sys->packet_sys.priv = p_demux;
180
2.72k
    p_sys->packet_sys.s = p_demux->s;
181
2.72k
    p_sys->packet_sys.logger = p_demux->obj.logger;
182
2.72k
    p_sys->packet_sys.b_deduplicate = false;
183
2.72k
    p_sys->packet_sys.b_can_hold_multiple_packets = false;
184
2.72k
    p_sys->packet_sys.pf_doskip = Packet_DoSkip;
185
2.72k
    p_sys->packet_sys.pf_send = Packet_Enqueue;
186
2.72k
    p_sys->packet_sys.pf_gettrackinfo = Packet_GetTrackInfo;
187
2.72k
    p_sys->packet_sys.pf_updatetime = Packet_UpdateTime;
188
2.72k
    p_sys->packet_sys.pf_updatesendtime = Packet_SetSendTime;
189
2.72k
    p_sys->packet_sys.pf_setaspectratio = Packet_SetAR;
190
191
2.72k
    return VLC_SUCCESS;
192
7.34k
}
193
194
/*****************************************************************************
195
 * Demux: read packet and send them to decoders
196
 *****************************************************************************/
197
699M
#define CHUNK VLC_TICK_FROM_MS(100)
198
static int Demux( demux_t *p_demux )
199
152M
{
200
152M
    demux_sys_t *p_sys = p_demux->p_sys;
201
202
915M
    for( int i=0; i<ES_CATEGORY_COUNT; i++ )
203
762M
    {
204
762M
        if ( p_sys->i_access_selected_track[i] > 0 )
205
0
        {
206
0
            es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE,
207
0
                            p_sys->track[p_sys->i_access_selected_track[i]]->p_es, true );
208
0
            p_sys->i_access_selected_track[i] = 0;
209
0
        }
210
762M
    }
211
212
    /* Get selected tracks, especially for computing PCR */
213
19.6G
    for( int i=0; i<MAX_ASF_TRACKS; i++ )
214
19.5G
    {
215
19.5G
        asf_track_t *tk = p_sys->track[i];
216
19.5G
        if ( !tk ) continue;
217
160M
        if ( tk->p_es )
218
156M
            es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, & tk->b_selected );
219
4.08M
        else
220
4.08M
            tk->b_selected = false;
221
160M
    }
222
223
153M
    while( !p_sys->b_eos && ( p_sys->i_sendtime - p_sys->i_time - CHUNK < 0 ||
224
98.4M
                            ( p_sys->i_sendtime - p_sys->i_time - CHUNK ) <
225
98.4M
                                                     p_sys->p_fp->i_preroll ) )
226
1.28M
    {
227
        /* Read and demux a packet */
228
1.28M
        if( DemuxASFPacket( &p_sys->packet_sys,
229
1.28M
                             p_sys->p_fp->i_min_data_packet_size,
230
1.28M
                             p_sys->p_fp->i_max_data_packet_size,
231
1.28M
                             p_sys->i_data_begin, p_sys->i_data_end ) <= 0 )
232
3.03k
        {
233
3.03k
            p_sys->b_eos = true;
234
            /* Check if we have concatenated files */
235
3.03k
            const uint8_t *p_peek;
236
3.03k
            if( vlc_stream_Peek( p_demux->s, &p_peek, 16 ) == 16 )
237
2.23k
            {
238
2.23k
                vlc_guid_t guid;
239
240
2.23k
                ASF_GetGUID( &guid, p_peek );
241
2.23k
                p_sys->b_eof = !guidcmp( &guid, &asf_object_header_guid );
242
2.23k
                if( !p_sys->b_eof )
243
2.23k
                    msg_Warn( p_demux, "found a new ASF header" );
244
2.23k
            }
245
805
            else
246
805
            {
247
805
                p_sys->b_eof = true;
248
103k
                for ( int i=0; i<MAX_ASF_TRACKS; i++ )
249
103k
                {
250
103k
                    asf_track_t *tk = p_sys->track[i];
251
103k
                    if ( tk && tk->info.p_frame )
252
319
                        Packet_Enqueue( &p_sys->packet_sys, i, &tk->info.p_frame );
253
103k
                }
254
805
            }
255
3.03k
        }
256
257
1.28M
        if ( p_sys->i_time == VLC_TICK_INVALID )
258
1.27M
            p_sys->i_time = p_sys->i_sendtime;
259
1.28M
    }
260
261
152M
    if( p_sys->b_eos || ( p_sys->i_sendtime - p_sys->i_time - CHUNK >= 0 &&
262
98.4M
                        ( p_sys->i_sendtime - p_sys->i_time - CHUNK ) >=
263
98.4M
                                                     p_sys->p_fp->i_preroll ) )
264
152M
    {
265
152M
        bool b_data = Block_Dequeue( p_demux, p_sys->i_time + CHUNK );
266
267
152M
        if( p_sys->i_time != VLC_TICK_INVALID )
268
152M
        {
269
152M
            p_sys->i_time += CHUNK;
270
152M
            p_sys->b_pcr_sent = true;
271
152M
            es_out_SetPCR( p_demux->out, p_sys->i_time );
272
#ifdef ASF_DEBUG
273
            msg_Dbg( p_demux, "Demux Loop Setting PCR to %"PRId64, p_sys->i_time );
274
#endif
275
152M
        }
276
277
152M
        if ( !b_data && p_sys->b_eos )
278
3.03k
        {
279
3.03k
            if( p_sys->i_time != VLC_TICK_INVALID )
280
922
                es_out_SetPCR( p_demux->out, p_sys->i_time );
281
282
            /* We end this stream */
283
3.03k
            if( !p_sys->b_eof )
284
366
            {
285
366
                DemuxEnd( p_demux );
286
287
                /* And we prepare to read the next one */
288
366
                if( DemuxInit( p_demux ) )
289
54
                {
290
54
                    msg_Err( p_demux, "failed to load the new header" );
291
54
                    return VLC_DEMUXER_EOF;
292
54
                }
293
312
                es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
294
312
            }
295
2.67k
            else
296
2.67k
                return VLC_DEMUXER_EOF;
297
3.03k
        }
298
152M
    }
299
300
152M
    return 1;
301
152M
}
302
303
/*****************************************************************************
304
 * Close: frees unused data
305
 *****************************************************************************/
306
static void Close( vlc_object_t * p_this )
307
2.72k
{
308
2.72k
    demux_t     *p_demux = (demux_t *)p_this;
309
310
2.72k
    DemuxEnd( p_demux );
311
312
2.72k
    free( p_demux->p_sys );
313
2.72k
}
314
315
/*****************************************************************************
316
 * WaitKeyframe: computes the number of frames to wait for a keyframe
317
 *****************************************************************************/
318
static void WaitKeyframe( demux_t *p_demux )
319
0
{
320
0
    demux_sys_t *p_sys = p_demux->p_sys;
321
0
    if ( ! p_sys->i_seek_track )
322
0
    {
323
0
        for ( int i=0; i<MAX_ASF_TRACKS; i++ )
324
0
        {
325
0
            asf_track_t *tk = p_sys->track[i];
326
0
            if ( tk && tk->info.p_sp && tk->i_cat == VIDEO_ES && tk->b_selected )
327
0
            {
328
0
                p_sys->i_seek_track = tk->info.p_sp->i_stream_number;
329
0
                break;
330
0
            }
331
0
        }
332
0
    }
333
334
0
    if ( p_sys->i_seek_track )
335
0
    {
336
        /* Skip forward at least 1 min */
337
0
        asf_track_t *tk = p_sys->track[p_sys->i_seek_track];
338
0
        if ( tk->info.p_esp && tk->info.p_esp->i_average_time_per_frame )
339
0
        {
340
            /* 1 min if fastseek, otherwise 5 sec */
341
            /* That's a guess for bandwidth */
342
0
            msftime_t i_maxwaittime = MSFTIME_FROM_SEC( p_sys->b_canfastseek ? 60 : 5);
343
0
            uint64_t frames = i_maxwaittime / tk->info.p_esp->i_average_time_per_frame;
344
0
            p_sys->i_wait_keyframe = __MIN( frames, UINT_MAX );
345
0
        }
346
0
        else
347
0
        {
348
0
            p_sys->i_wait_keyframe = ( p_sys->b_canfastseek ) ? 25 * 30 : 25 * 5;
349
0
        }
350
0
    }
351
0
    else
352
0
    {
353
0
        p_sys->i_wait_keyframe = 0;
354
0
    }
355
356
0
}
357
358
/*****************************************************************************
359
 * SeekIndex: goto to i_date or i_percent
360
 *****************************************************************************/
361
static int SeekPercent( demux_t *p_demux, int i_query, va_list args )
362
0
{
363
0
    demux_sys_t *p_sys = p_demux->p_sys;
364
365
0
    WaitKeyframe( p_demux );
366
367
0
    msg_Dbg( p_demux, "seek with percent: waiting %i frames", p_sys->i_wait_keyframe );
368
0
    return demux_vaControlHelper( p_demux->s, __MIN( INT64_MAX, p_sys->i_data_begin ),
369
0
                                   __MIN( INT64_MAX, p_sys->i_data_end ),
370
0
                                   __MIN( INT64_MAX, p_sys->i_bitrate ),
371
0
                                   __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ),
372
0
                                   i_query, args );
373
0
}
374
375
static int SeekIndex( demux_t *p_demux, vlc_tick_t i_date, float f_pos )
376
0
{
377
0
    demux_sys_t *p_sys = p_demux->p_sys;
378
0
    asf_object_index_t *p_index;
379
380
0
    msg_Dbg( p_demux, "seek with index: %i seconds, position %f",
381
0
             i_date >= 0 ? (int)SEC_FROM_VLC_TICK(i_date) : -1, f_pos );
382
383
0
    if( i_date < 0 )
384
0
        i_date = p_sys->i_length * f_pos;
385
386
0
    p_sys->i_preroll_start = i_date - p_sys->p_fp->i_preroll;
387
0
    if ( p_sys->i_preroll_start < 0 ) p_sys->i_preroll_start = 0;
388
389
0
    p_index = ASF_FindObject( p_sys->p_root, &asf_object_simple_index_guid, 0 );
390
391
0
    uint64_t i_entry = MSFTIME_FROM_VLC_TICK(p_sys->i_preroll_start) / p_index->i_index_entry_time_interval;
392
0
    if( i_entry >= p_index->i_index_entry_count )
393
0
    {
394
0
        msg_Warn( p_demux, "Incomplete index" );
395
0
        return VLC_EGENERIC;
396
0
    }
397
398
0
    WaitKeyframe( p_demux );
399
400
0
    uint64_t i_offset = (uint64_t)p_index->index_entry[i_entry].i_packet_number *
401
0
                        p_sys->p_fp->i_min_data_packet_size;
402
403
0
    if ( vlc_stream_Seek( p_demux->s, i_offset + p_sys->i_data_begin ) == VLC_SUCCESS )
404
0
    {
405
0
        es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, VLC_TICK_0 + i_date );
406
0
        return VLC_SUCCESS;
407
0
    }
408
0
    else return VLC_EGENERIC;
409
0
}
410
411
static void SeekPrepare( demux_t *p_demux )
412
0
{
413
0
    demux_sys_t *p_sys = p_demux->p_sys;
414
415
0
    p_sys->b_eof = false;
416
0
    p_sys->b_eos = false;
417
0
    p_sys->b_pcr_sent = false;
418
0
    p_sys->i_time = VLC_TICK_INVALID;
419
0
    p_sys->i_sendtime = VLC_TICK_INVALID;
420
0
    p_sys->i_preroll_start = ASFPACKET_PREROLL_FROM_CURRENT;
421
422
0
    for( int i = 0; i < MAX_ASF_TRACKS ; i++ )
423
0
    {
424
0
        asf_track_t *tk = p_sys->track[i];
425
0
        if( tk )
426
0
        {
427
0
            FlushQueue( tk );
428
0
            tk->i_time = VLC_TICK_INVALID;
429
0
        }
430
0
    }
431
432
0
    es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
433
0
}
434
435
/*****************************************************************************
436
 * Control:
437
 *****************************************************************************/
438
static int Control( demux_t *p_demux, int i_query, va_list args )
439
0
{
440
0
    demux_sys_t *p_sys = p_demux->p_sys;
441
0
    vlc_meta_t  *p_meta;
442
0
    vlc_tick_t  i64;
443
0
    int         i;
444
0
    double      f, *pf;
445
446
0
    switch( i_query )
447
0
    {
448
0
    case DEMUX_GET_LENGTH:
449
0
        *va_arg( args, vlc_tick_t * ) = p_sys->i_length;
450
0
        return VLC_SUCCESS;
451
452
0
    case DEMUX_GET_TIME:
453
0
        if( p_sys->i_time == VLC_TICK_INVALID ) return VLC_EGENERIC;
454
0
        *va_arg( args, vlc_tick_t * ) = p_sys->i_time;
455
0
        return VLC_SUCCESS;
456
457
0
    case DEMUX_SET_TIME:
458
0
        if ( !p_sys->p_fp ||
459
0
             ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) )
460
0
            return VLC_EGENERIC;
461
462
0
        SeekPrepare( p_demux );
463
464
0
        if( p_sys->b_index && p_sys->i_length != 0 )
465
0
        {
466
0
            va_list acpy;
467
0
            va_copy( acpy, args );
468
0
            i64 = va_arg( acpy, vlc_tick_t );
469
0
            va_end( acpy );
470
471
0
            if( !SeekIndex( p_demux, i64, -1 ) )
472
0
                return VLC_SUCCESS;
473
0
        }
474
0
        return SeekPercent( p_demux, i_query, args );
475
476
0
    case DEMUX_SET_ES:
477
0
    {
478
0
        i = va_arg( args, int );
479
0
        int i_ret;
480
0
        if ( i >= 0 )
481
0
        {
482
0
            msg_Dbg( p_demux, "Requesting access to enable stream %d", i );
483
0
            i_ret = vlc_stream_Control( p_demux->s,
484
0
                                        STREAM_SET_PRIVATE_ID_STATE, i, true );
485
0
        }
486
0
        else
487
0
        {  /* i contains -1 * es_category */
488
0
            msg_Dbg( p_demux, "Requesting access to disable stream %d", i );
489
0
            i_ret = vlc_stream_Control( p_demux->s,
490
0
                                        STREAM_SET_PRIVATE_ID_STATE, i,
491
0
                                        false );
492
0
        }
493
494
0
        if ( i_ret == VLC_SUCCESS )
495
0
        {
496
0
            asf_track_t *tk;
497
0
            if( i >= 0 )
498
0
            {
499
0
                tk = p_sys->track[i];
500
0
            }
501
0
            else
502
0
            {
503
0
                for( int j = 0; j < MAX_ASF_TRACKS ; j++ )
504
0
                {
505
0
                    tk = p_sys->track[j];
506
0
                    if( !tk || !tk->p_fmt || tk->i_cat != -1 * i )
507
0
                        continue;
508
0
                    FlushQueue( tk );
509
0
                    tk->i_time = VLC_TICK_INVALID;
510
0
                }
511
0
            }
512
513
0
            p_sys->i_seek_track = 0;
514
0
            if ( ( tk && tk->i_cat == VIDEO_ES ) || i == -1 * VIDEO_ES )
515
0
                WaitKeyframe( p_demux );
516
0
        }
517
0
        return i_ret;
518
0
    }
519
520
0
    case DEMUX_SET_ES_LIST:
521
0
        return VLC_EGENERIC; /* TODO */
522
523
0
    case DEMUX_GET_POSITION:
524
0
        if( p_sys->i_time == VLC_TICK_INVALID ) return VLC_EGENERIC;
525
0
        if( p_sys->i_length != 0 )
526
0
        {
527
0
            pf = va_arg( args, double * );
528
0
            *pf = p_sys->i_time / (double)p_sys->i_length;
529
0
            return VLC_SUCCESS;
530
0
        }
531
0
        return demux_vaControlHelper( p_demux->s,
532
0
                                       __MIN( INT64_MAX, p_sys->i_data_begin ),
533
0
                                       __MIN( INT64_MAX, p_sys->i_data_end ),
534
0
                                       __MIN( INT64_MAX, p_sys->i_bitrate ),
535
0
                                       __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ),
536
0
                                       i_query, args );
537
538
0
    case DEMUX_SET_POSITION:
539
0
        if ( !p_sys->p_fp ||
540
0
             ( !( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) && !p_sys->b_index ) )
541
0
            return VLC_EGENERIC;
542
543
0
        SeekPrepare( p_demux );
544
545
0
        if( p_sys->b_index && p_sys->i_length != 0 )
546
0
        {
547
0
            va_list acpy;
548
0
            va_copy( acpy, args );
549
0
            f = va_arg( acpy, double );
550
0
            va_end( acpy );
551
552
0
            if( !SeekIndex( p_demux, -1, f ) )
553
0
                return VLC_SUCCESS;
554
0
        }
555
0
        return SeekPercent( p_demux, i_query, args );
556
557
0
    case DEMUX_GET_META:
558
0
        p_meta = va_arg( args, vlc_meta_t * );
559
0
        vlc_meta_Merge( p_meta, p_sys->meta );
560
0
        return VLC_SUCCESS;
561
562
0
    case DEMUX_CAN_SEEK:
563
0
        if ( !p_sys->p_fp ||
564
0
             ( !( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) && !p_sys->b_index ) )
565
0
        {
566
0
            bool *pb_bool = va_arg( args, bool * );
567
0
            *pb_bool = false;
568
0
            return VLC_SUCCESS;
569
0
        }
570
        /* fall through */
571
0
    default:
572
0
        return demux_vaControlHelper( p_demux->s,
573
0
                                      __MIN( INT64_MAX, p_sys->i_data_begin ),
574
0
                                      __MIN( INT64_MAX, p_sys->i_data_end),
575
0
                                      __MIN( INT64_MAX, p_sys->i_bitrate ),
576
0
                    ( p_sys->p_fp ) ? __MIN( INT_MAX, p_sys->p_fp->i_min_data_packet_size ) : 1,
577
0
                    i_query, args );
578
0
    }
579
0
}
580
581
/*****************************************************************************
582
 *
583
 *****************************************************************************/
584
static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
585
                          uint8_t i_ratio_x, uint8_t i_ratio_y )
586
0
{
587
0
    demux_t *p_demux = p_packetsys->priv;
588
0
    demux_sys_t *p_sys = p_demux->p_sys;
589
0
    asf_track_t *tk = p_sys->track[i_stream_number];
590
591
0
    if ( !tk->p_fmt || (tk->p_fmt->video.i_sar_num == i_ratio_x && tk->p_fmt->video.i_sar_den == i_ratio_y ) )
592
0
        return;
593
594
0
    tk->p_fmt->video.i_sar_num = i_ratio_x;
595
0
    tk->p_fmt->video.i_sar_den = i_ratio_y;
596
0
    if( tk->p_es )
597
0
        es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT, tk->p_es, tk->p_fmt );
598
0
}
599
600
static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, vlc_tick_t i_time )
601
14.4k
{
602
14.4k
    demux_t *p_demux = p_packetsys->priv;
603
14.4k
    demux_sys_t *p_sys = p_demux->p_sys;
604
605
14.4k
    p_sys->i_sendtime = VLC_TICK_0 + i_time;
606
14.4k
}
607
608
static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number,
609
                               vlc_tick_t i_time )
610
5.11k
{
611
5.11k
    demux_t *p_demux = p_packetsys->priv;
612
5.11k
    demux_sys_t *p_sys = p_demux->p_sys;
613
5.11k
    asf_track_t *tk = p_sys->track[i_stream_number];
614
615
5.11k
    if ( tk )
616
5.11k
        tk->i_time = VLC_TICK_0 + i_time;
617
5.11k
}
618
619
static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys,
620
                                               uint8_t i_stream_number )
621
43.1k
{
622
43.1k
    demux_t *p_demux = p_packetsys->priv;
623
43.1k
    demux_sys_t *p_sys = p_demux->p_sys;
624
43.1k
    asf_track_t *tk = p_sys->track[i_stream_number];
625
626
43.1k
    if (!tk)
627
27.4k
        return NULL;
628
15.7k
    else
629
15.7k
        return & tk->info;
630
43.1k
}
631
632
static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe )
633
15.3k
{
634
15.3k
    demux_t *p_demux = p_packetsys->priv;
635
15.3k
    demux_sys_t *p_sys = p_demux->p_sys;
636
15.3k
    const asf_track_t *tk = p_sys->track[i_stream_number];
637
638
15.3k
    if( tk == NULL )
639
0
    {
640
0
        msg_Warn( p_demux, "undeclared stream[Id 0x%x]", i_stream_number );
641
0
        return true;
642
0
    }
643
644
15.3k
    if( p_sys->i_wait_keyframe )
645
0
    {
646
0
        if ( i_stream_number == p_sys->i_seek_track )
647
0
        {
648
0
            if ( !b_packet_keyframe )
649
0
            {
650
0
                p_sys->i_wait_keyframe--;
651
0
                return true;
652
0
            }
653
0
            else
654
0
                p_sys->i_wait_keyframe = 0;
655
0
        }
656
0
        else
657
0
            return true;
658
0
    }
659
660
15.3k
    if( !tk->p_es )
661
890
        return true;
662
663
14.4k
    return false;
664
15.3k
}
665
666
static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame )
667
78.2k
{
668
78.2k
    demux_t *p_demux = p_packetsys->priv;
669
78.2k
    demux_sys_t *p_sys = p_demux->p_sys;
670
78.2k
    asf_track_t *tk = p_sys->track[i_stream_number];
671
78.2k
    if ( !tk )
672
0
        return;
673
674
78.2k
    block_t *p_gather = block_ChainGather( *pp_frame );
675
78.2k
    if( p_gather )
676
78.2k
    {
677
78.2k
        block_ChainLastAppend( & tk->queue.pp_last, p_gather );
678
#ifdef ASF_DEBUG
679
        msg_Dbg( p_demux, "    enqueue packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_gather->i_dts, p_gather->i_pts, p_sys->i_time );
680
#endif
681
78.2k
    }
682
683
78.2k
    *pp_frame = NULL;
684
78.2k
}
685
686
static bool Block_Dequeue( demux_t *p_demux, vlc_tick_t i_nexttime )
687
152M
{
688
152M
    demux_sys_t *p_sys = p_demux->p_sys;
689
152M
    bool b_tracks_have_data = false;
690
19.6G
    for( int i = 0; i < MAX_ASF_TRACKS; i++ )
691
19.5G
    {
692
19.5G
        asf_track_t *tk = p_sys->track[i];
693
19.5G
        if (!tk)
694
19.3G
            continue;
695
160M
        b_tracks_have_data |= (tk->queue.p_first != NULL);
696
160M
        while( tk->queue.p_first && tk->queue.p_first->i_dts <= i_nexttime )
697
78.2k
        {
698
78.2k
            block_t *p_block = tk->queue.p_first;
699
78.2k
            tk->queue.p_first = p_block->p_next;
700
78.2k
            if( tk->queue.p_first == NULL )
701
996
                tk->queue.pp_last = &tk->queue.p_first;
702
77.2k
            else
703
77.2k
                p_block->p_next = NULL;
704
705
78.2k
            if( !p_sys->b_pcr_sent && p_sys->i_time != VLC_TICK_INVALID )
706
764
            {
707
764
                p_sys->b_pcr_sent = true;
708
764
                es_out_SetPCR( p_demux->out, p_sys->i_time );
709
#ifdef ASF_DEBUG
710
                msg_Dbg( p_demux, "    dequeue setting PCR to %"PRId64, p_sys->i_time );
711
#endif
712
764
            }
713
714
#ifdef ASF_DEBUG
715
            msg_Dbg( p_demux, "    sending packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_block->i_dts, p_block->i_pts, p_sys->i_time );
716
#endif
717
78.2k
            es_out_Send( p_demux->out, tk->p_es, p_block );
718
78.2k
        }
719
160M
    }
720
152M
    return b_tracks_have_data;
721
152M
}
722
723
/*****************************************************************************
724
 *
725
 *****************************************************************************/
726
typedef struct asf_es_priorities_t
727
{
728
    uint16_t *pi_stream_numbers;
729
    uint16_t i_count;
730
} asf_es_priorities_t;
731
732
/* Fills up our exclusion list */
733
static void ASF_fillup_es_priorities_ex( demux_sys_t *p_sys, void *p_hdr,
734
                                         asf_es_priorities_t *p_prios )
735
1.62k
{
736
    /* Find stream exclusions */
737
1.62k
    asf_object_advanced_mutual_exclusion_t *p_mutex =
738
1.62k
            ASF_FindObject( p_hdr, &asf_object_advanced_mutual_exclusion, 0 );
739
1.62k
    if (! p_mutex ) return;
740
741
0
    p_prios->pi_stream_numbers = vlc_alloc( p_sys->i_track, sizeof(*p_prios->pi_stream_numbers) );
742
0
    if ( !p_prios->pi_stream_numbers ) return;
743
744
0
    if ( p_mutex->i_stream_number_count )
745
0
    {
746
        /* Just set highest prio on highest in the group */
747
0
        for ( uint16_t i = 1; i < p_mutex->i_stream_number_count; i++ )
748
0
        {
749
0
            if ( p_prios->i_count > p_sys->i_track || i > p_sys->i_track ) break;
750
0
            p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_mutex->pi_stream_number[ i ];
751
0
        }
752
0
    }
753
0
}
754
755
/* Fills up our bitrate exclusion list */
756
static void ASF_fillup_es_bitrate_priorities_ex( demux_sys_t *p_sys, void *p_hdr,
757
                                                 asf_es_priorities_t *p_prios )
758
1.62k
{
759
    /* Find bitrate exclusions */
760
1.62k
    asf_object_bitrate_mutual_exclusion_t *p_bitrate_mutex =
761
1.62k
            ASF_FindObject( p_hdr, &asf_object_bitrate_mutual_exclusion_guid, 0 );
762
1.62k
    if (! p_bitrate_mutex ) return;
763
764
0
    p_prios->pi_stream_numbers = vlc_alloc( p_sys->i_track, sizeof(*p_prios->pi_stream_numbers) );
765
0
    if ( !p_prios->pi_stream_numbers ) return;
766
767
0
    if ( p_bitrate_mutex->i_stream_number_count )
768
0
    {
769
        /* Just remove < highest */
770
0
        for ( uint16_t i = 1; i < p_bitrate_mutex->i_stream_number_count; i++ )
771
0
        {
772
0
            if ( p_prios->i_count > p_sys->i_track || i > p_sys->i_track ) break;
773
0
            p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_bitrate_mutex->pi_stream_numbers[ i ];
774
0
        }
775
0
    }
776
777
0
}
778
779
8.01k
#define GET_CHECKED( target, getter, maxtarget, temp ) \
780
8.01k
{\
781
8.01k
    temp i_temp = getter;\
782
8.01k
    if ( i_temp > maxtarget ) {\
783
20
        msg_Warn( p_demux, "rejecting stream %u : " #target " overflow", i_stream );\
784
20
        es_format_Clean( &fmt );\
785
20
        goto error;\
786
7.99k
    } else {\
787
7.99k
        target = i_temp;\
788
7.99k
    }\
789
8.01k
}
790
791
static int DemuxInit( demux_t *p_demux )
792
7.71k
{
793
7.71k
    demux_sys_t *p_sys = p_demux->p_sys;
794
7.71k
    asf_es_priorities_t fmt_priorities_ex = { NULL, 0 };
795
7.71k
    asf_es_priorities_t fmt_priorities_bitrate_ex = { NULL, 0 };
796
797
    /* init context */
798
7.71k
    p_sys->i_time   = VLC_TICK_INVALID;
799
7.71k
    p_sys->i_sendtime    = VLC_TICK_INVALID;
800
7.71k
    p_sys->i_length = 0;
801
7.71k
    p_sys->b_eos = false;
802
7.71k
    p_sys->b_eof = false;
803
7.71k
    p_sys->i_bitrate = 0;
804
7.71k
    p_sys->p_root   = NULL;
805
7.71k
    p_sys->p_fp     = NULL;
806
7.71k
    p_sys->b_index  = 0;
807
7.71k
    p_sys->i_track  = 0;
808
7.71k
    p_sys->i_seek_track = 0;
809
7.71k
    p_sys->b_pcr_sent = false;
810
7.71k
    p_sys->i_wait_keyframe = 0;
811
995k
    for( int i = 0; i < MAX_ASF_TRACKS; i++ )
812
987k
    {
813
987k
        p_sys->track[i] = NULL;
814
987k
    }
815
7.71k
    p_sys->i_data_begin = 0;
816
7.71k
    p_sys->i_data_end   = 0;
817
7.71k
    p_sys->i_preroll_start = 0;
818
7.71k
    p_sys->meta         = NULL;
819
820
    /* Now load all object ( except raw data ) */
821
7.71k
    vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK,
822
7.71k
                        &p_sys->b_canfastseek );
823
7.71k
    if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, p_sys->b_canfastseek)) )
824
4.38k
    {
825
4.38k
        msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" );
826
4.38k
        return VLC_EGENERIC;
827
4.38k
    }
828
3.32k
    p_sys->p_fp = p_sys->p_root->p_fp;
829
830
3.32k
    if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size )
831
74
    {
832
74
        msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" );
833
74
        goto error;
834
74
    }
835
836
3.25k
    if ( ASF_FindObject( p_sys->p_root->p_hdr,
837
3.25k
                         &asf_object_content_encryption_guid, 0 ) != NULL
838
3.25k
         || ASF_FindObject( p_sys->p_root->p_hdr,
839
3.25k
                            &asf_object_extended_content_encryption_guid, 0 ) != NULL
840
3.25k
         || ASF_FindObject( p_sys->p_root->p_hdr,
841
3.25k
                         &asf_object_advanced_content_encryption_guid, 0 ) != NULL )
842
0
    {
843
0
        vlc_dialog_display_error( p_demux, _("Could not demux ASF stream"), "%s",
844
0
            ("DRM protected streams are not supported.") );
845
0
        goto error;
846
0
    }
847
848
3.25k
    p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr,
849
3.25k
                                      &asf_object_stream_properties_guid );
850
3.25k
    if( p_sys->i_track == 0 )
851
197
    {
852
197
        msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" );
853
197
        goto error;
854
197
    }
855
3.05k
    msg_Dbg( p_demux, "found %u streams", p_sys->i_track );
856
857
    /* check if index is available */
858
3.05k
    asf_object_index_t *p_index = ASF_FindObject( p_sys->p_root,
859
3.05k
                                                  &asf_object_simple_index_guid, 0 );
860
3.05k
    const bool b_index = p_index && p_index->i_index_entry_count;
861
862
    /* Find the extended header if any */
863
3.05k
    asf_object_t *p_hdr_ext = ASF_FindObject( p_sys->p_root->p_hdr,
864
3.05k
                                              &asf_object_header_extension_guid, 0 );
865
866
3.05k
    asf_object_language_list_t *p_languages = NULL;
867
868
3.05k
    if( p_hdr_ext )
869
1.62k
    {
870
1.62k
        p_languages = ASF_FindObject( p_hdr_ext, &asf_object_language_list, 0 );
871
872
1.62k
        ASF_fillup_es_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_ex );
873
1.62k
        ASF_fillup_es_bitrate_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_bitrate_ex );
874
1.62k
    }
875
876
3.05k
    const bool b_mms = !strncasecmp( p_demux->psz_url, "mms:", 4 );
877
3.05k
    bool b_dvrms = false;
878
879
3.05k
    if( b_mms )
880
0
    {
881
0
        es_out_Control( p_demux->out, ES_OUT_SET_ES_CAT_POLICY,
882
0
                        VIDEO_ES, ES_OUT_ES_POLICY_EXCLUSIVE );
883
0
    }
884
885
6.47k
    for( unsigned i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
886
3.43k
    {
887
3.43k
        asf_track_t    *tk;
888
3.43k
        asf_object_stream_properties_t *p_sp;
889
3.43k
        asf_object_extended_stream_properties_t *p_esp;
890
3.43k
        bool b_access_selected;
891
892
3.43k
        p_sp = ASF_FindObject( p_sys->p_root->p_hdr,
893
3.43k
                               &asf_object_stream_properties_guid,
894
3.43k
                               i_stream );
895
3.43k
        p_esp = NULL;
896
897
        /* Ignore duplicated streams numbers */
898
3.43k
        if (p_sys->track[p_sp->i_stream_number])
899
7
            continue;
900
901
3.42k
        tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) );
902
3.42k
        if (!tk)
903
0
            goto error;
904
3.42k
        memset( tk, 0, sizeof( asf_track_t ) );
905
906
3.42k
        ASFPacketTrackInit( &tk->info );
907
3.42k
        tk->i_time = VLC_TICK_INVALID;
908
3.42k
        tk->info.p_sp = p_sp;
909
3.42k
        tk->p_es = NULL;
910
3.42k
        tk->queue.p_first = NULL;
911
3.42k
        tk->queue.pp_last = &tk->queue.p_first;
912
3.42k
        tk->info.i_pkt = 0;
913
3.42k
        tk->info.i_pktcount = 0;
914
915
3.42k
        if ( !b_mms )
916
3.42k
        {
917
            /* Check (not mms) if this track is selected (ie will receive data) */
918
3.42k
            if( !vlc_stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE,
919
3.42k
                                     (int) p_sp->i_stream_number,
920
3.42k
                                     &b_access_selected ) &&
921
0
                !b_access_selected )
922
0
            {
923
0
                tk->i_cat = UNKNOWN_ES;
924
0
                msg_Dbg( p_demux, "ignoring not selected stream(ID:%u) (by access)",
925
0
                         p_sp->i_stream_number );
926
0
                continue;
927
0
            }
928
3.42k
        }
929
930
        /* Find the associated extended_stream_properties if any */
931
3.42k
        if( p_hdr_ext )
932
1.97k
        {
933
1.97k
            int i_ext_stream = ASF_CountObject( p_hdr_ext,
934
1.97k
                                                &asf_object_extended_stream_properties_guid );
935
2.24k
            for( int i = 0; i < i_ext_stream; i++ )
936
685
            {
937
685
                asf_object_t *p_tmp =
938
685
                    ASF_FindObject( p_hdr_ext,
939
685
                                    &asf_object_extended_stream_properties_guid, i );
940
685
                if( p_tmp->ext_stream.i_stream_number == p_sp->i_stream_number )
941
417
                {
942
417
                    p_esp = &p_tmp->ext_stream;
943
417
                    tk->info.p_esp = p_esp;
944
417
                    break;
945
417
                }
946
685
            }
947
1.97k
        }
948
949
        /* Check for DVR-MS */
950
3.42k
        if( p_esp )
951
1.95k
            for( uint16_t i=0; i<p_esp->i_payload_extension_system_count && !b_dvrms; i++ )
952
1.53k
                b_dvrms = guidcmp( &p_esp->p_ext[i].i_extension_id, &asf_dvr_sampleextension_timing_rep_data_guid );
953
954
3.42k
        es_format_t fmt;
955
956
3.42k
        if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_audio ) &&
957
2.19k
            p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 )
958
2.12k
        {
959
2.12k
            uint8_t *p_data = p_sp->p_type_specific_data;
960
2.12k
            int i_format;
961
962
2.12k
            es_format_Init( &fmt, AUDIO_ES, 0 );
963
2.12k
            i_format = GetWLE( &p_data[0] );
964
2.12k
            wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
965
966
2.12k
            GET_CHECKED( fmt.audio.i_channels,      GetWLE( &p_data[2] ),
967
2.12k
                                                        255, uint16_t );
968
2.10k
            GET_CHECKED( fmt.audio.i_rate,          GetDWLE( &p_data[4] ),
969
2.10k
                                                        UINT_MAX, uint32_t );
970
2.10k
            GET_CHECKED( fmt.i_bitrate,             GetDWLE( &p_data[8] ) * 8,
971
2.10k
                                                        UINT_MAX, uint32_t );
972
2.10k
            fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
973
2.10k
            fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
974
975
2.10k
            if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
976
477
                i_format != WAVE_FORMAT_MPEGLAYER3 &&
977
472
                i_format != WAVE_FORMAT_MPEG )
978
471
            {
979
471
                GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ),
980
471
                                     p_sp->i_type_specific_data_length -
981
471
                                     sizeof( WAVEFORMATEX ) ),
982
471
                             INT_MAX, uint32_t );
983
471
                fmt.p_extra = malloc( fmt.i_extra );
984
471
                memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )],
985
471
                        fmt.i_extra );
986
471
            }
987
2.10k
            msg_Dbg( p_demux, "added new audio stream (codec:%4.4s(0x%x),ID:%d)",
988
2.10k
                (char*)&fmt.i_codec, GetWLE( p_data ), p_sp->i_stream_number );
989
2.10k
        }
990
1.30k
        else if( guidcmp( &p_sp->i_stream_type,
991
1.30k
                              &asf_object_stream_type_video ) &&
992
397
                 p_sp->i_type_specific_data_length >= 11 +
993
397
                 sizeof( VLC_BITMAPINFOHEADER ) )
994
361
        {
995
361
            uint8_t      *p_data = &p_sp->p_type_specific_data[11];
996
997
361
            es_format_Init( &fmt, VIDEO_ES,
998
361
                            VLC_FOURCC( p_data[16], p_data[17],
999
361
                                        p_data[18], p_data[19] ) );
1000
1001
361
            GET_CHECKED( fmt.video.i_width,      GetDWLE( p_data + 4 ),
1002
361
                                                     UINT_MAX, uint32_t );
1003
361
            GET_CHECKED( fmt.video.i_height,     GetDWLE( p_data + 8 ),
1004
361
                                                     UINT_MAX, uint32_t );
1005
361
            fmt.video.i_visible_width = fmt.video.i_width;
1006
361
            fmt.video.i_visible_height = fmt.video.i_height;
1007
1008
361
            if( p_esp && p_esp->i_average_time_per_frame > 0 )
1009
156
            {
1010
156
                fmt.video.i_frame_rate = 10000000;
1011
156
                GET_CHECKED( fmt.video.i_frame_rate_base,
1012
156
                             p_esp->i_average_time_per_frame,
1013
156
                             UINT_MAX, uint64_t );
1014
148
            }
1015
1016
353
            if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') )
1017
0
            {
1018
                /* DVR-MS special ASF */
1019
0
                fmt.i_codec = VLC_CODEC_MPGV;
1020
0
            }
1021
1022
353
            if( p_sp->i_type_specific_data_length > 11 +
1023
353
                sizeof( VLC_BITMAPINFOHEADER ) )
1024
330
            {
1025
330
                GET_CHECKED( fmt.i_extra, __MIN( GetDWLE( p_data ),
1026
330
                                     p_sp->i_type_specific_data_length - 11 -
1027
330
                                     sizeof( VLC_BITMAPINFOHEADER ) ),
1028
330
                             UINT_MAX, uint32_t );
1029
330
                fmt.p_extra = malloc( fmt.i_extra );
1030
330
                memcpy( fmt.p_extra, &p_data[sizeof( VLC_BITMAPINFOHEADER )],
1031
330
                        fmt.i_extra );
1032
330
            }
1033
1034
            /* Look for an aspect ratio */
1035
353
            if( p_sys->p_root->p_metadata )
1036
239
            {
1037
239
                asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata;
1038
239
                unsigned int i_aspect_x = 0, i_aspect_y = 0;
1039
239
                uint32_t i;
1040
1.49k
                for( i = 0; i < p_meta->i_record_entries_count; i++ )
1041
1.25k
                {
1042
1.25k
                    if( !p_meta->record[i].psz_name )
1043
28
                        continue;
1044
1.22k
                    if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) )
1045
0
                    {
1046
0
                        if( (!i_aspect_x && !p_meta->record[i].i_stream) ||
1047
0
                            p_meta->record[i].i_stream ==
1048
0
                            p_sp->i_stream_number )
1049
0
                            GET_CHECKED( i_aspect_x, p_meta->record[i].i_val,
1050
0
                                         UINT_MAX, uint64_t );
1051
0
                    }
1052
1.22k
                    if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) )
1053
0
                    {
1054
0
                        if( (!i_aspect_y && !p_meta->record[i].i_stream) ||
1055
0
                            p_meta->record[i].i_stream ==
1056
0
                            p_sp->i_stream_number )
1057
0
                            GET_CHECKED( i_aspect_y, p_meta->record[i].i_val,
1058
0
                                         UINT_MAX, uint64_t );
1059
0
                    }
1060
1.22k
                }
1061
1062
239
                if( i_aspect_x && i_aspect_y )
1063
0
                {
1064
0
                    fmt.video.i_sar_num = i_aspect_x;
1065
0
                    fmt.video.i_sar_den = i_aspect_y;
1066
0
                }
1067
239
            }
1068
1069
            /* If there is a video track then use the index for seeking */
1070
353
            p_sys->b_index = b_index;
1071
1072
353
            msg_Dbg( p_demux, "added new video stream(codec:%4.4s,ID:%d)",
1073
353
                     (char*)&fmt.i_codec, p_sp->i_stream_number );
1074
353
        }
1075
944
        else if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_binary ) &&
1076
0
            p_sp->i_type_specific_data_length >= 64 )
1077
0
        {
1078
0
            vlc_guid_t i_major_media_type;
1079
0
            ASF_GetGUID( &i_major_media_type, p_sp->p_type_specific_data );
1080
0
            msg_Dbg( p_demux, "stream(ID:%d) major type " GUID_FMT, p_sp->i_stream_number,
1081
0
                     GUID_PRINT(i_major_media_type) );
1082
1083
0
            vlc_guid_t i_media_subtype;
1084
0
            ASF_GetGUID( &i_media_subtype, &p_sp->p_type_specific_data[16] );
1085
0
            msg_Dbg( p_demux, "stream(ID:%d) subtype " GUID_FMT, p_sp->i_stream_number,
1086
0
                     GUID_PRINT(i_media_subtype) );
1087
1088
            //uint32_t i_fixed_size_samples = GetDWBE( &p_sp->p_type_specific_data[32] );
1089
            //uint32_t i_temporal_compression = GetDWBE( &p_sp->p_type_specific_data[36] );
1090
            //uint32_t i_sample_size = GetDWBE( &p_sp->p_type_specific_data[40] );
1091
1092
0
            vlc_guid_t i_format_type;
1093
0
            ASF_GetGUID( &i_format_type, &p_sp->p_type_specific_data[44] );
1094
0
            msg_Dbg( p_demux, "stream(ID:%d) format type " GUID_FMT, p_sp->i_stream_number,
1095
0
                     GUID_PRINT(i_format_type) );
1096
1097
            //uint32_t i_format_data_size = GetDWBE( &p_sp->p_type_specific_data[60] );
1098
0
            uint8_t *p_data = p_sp->p_type_specific_data + 64;
1099
0
            unsigned int i_data = p_sp->i_type_specific_data_length - 64;
1100
1101
0
            msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length );
1102
0
            if( guidcmp( &i_major_media_type, &asf_object_extended_stream_type_audio ) &&
1103
0
                i_data >= sizeof( WAVEFORMATEX ) - 2)
1104
0
            {
1105
0
                uint16_t i_format;
1106
0
                es_format_Init( &fmt, AUDIO_ES, 0 );
1107
1108
0
                i_format = GetWLE( &p_data[0] );
1109
0
                if( i_format == 0 )
1110
0
                    fmt.i_codec = VLC_CODEC_A52;
1111
0
                else
1112
0
                    wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL );
1113
1114
0
                GET_CHECKED( fmt.audio.i_channels,      GetWLE( &p_data[2] ),
1115
0
                                                            255, uint16_t );
1116
0
                GET_CHECKED( fmt.audio.i_rate,          GetDWLE( &p_data[4] ),
1117
0
                                                            UINT_MAX, uint32_t );
1118
0
                GET_CHECKED( fmt.i_bitrate,             GetDWLE( &p_data[8] ) * 8,
1119
0
                                                            UINT_MAX, uint32_t );
1120
0
                fmt.audio.i_blockalign      = GetWLE(  &p_data[12] );
1121
0
                fmt.audio.i_bitspersample   = GetWLE(  &p_data[14] );
1122
1123
0
                if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) &&
1124
0
                    i_format != WAVE_FORMAT_MPEGLAYER3 &&
1125
0
                    i_format != WAVE_FORMAT_MPEG && i_data >= 19 )
1126
0
                {
1127
0
                    GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ),
1128
0
                                         p_sp->i_type_specific_data_length -
1129
0
                                         sizeof( WAVEFORMATEX ) - 64),
1130
0
                                 INT_MAX, uint32_t );
1131
0
                    fmt.p_extra = malloc( fmt.i_extra );
1132
0
                    if ( fmt.p_extra )
1133
0
                        memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )], fmt.i_extra );
1134
0
                    else
1135
0
                        fmt.i_extra = 0;
1136
0
                }
1137
1138
0
                msg_Dbg( p_demux, "added new audio stream (codec:%4.4s(0x%x),ID:%d)",
1139
0
                    (char*)&fmt.i_codec, i_format, p_sp->i_stream_number );
1140
0
            }
1141
0
            else
1142
0
            {
1143
0
                es_format_Init( &fmt, UNKNOWN_ES, 0 );
1144
0
            }
1145
0
        }
1146
944
        else
1147
944
        {
1148
944
            es_format_Init( &fmt, UNKNOWN_ES, 0 );
1149
944
        }
1150
1151
3.40k
        if( b_dvrms )
1152
0
        {
1153
0
            fmt.i_original_fourcc = VLC_FOURCC( 'D','V','R',' ');
1154
0
            fmt.b_packetized = false;
1155
0
        }
1156
1157
3.40k
        if( fmt.i_codec == VLC_CODEC_MP4A )
1158
201
            fmt.b_packetized = false;
1159
1160
3.40k
        tk->i_cat = tk->info.i_cat = fmt.i_cat;
1161
3.40k
        if( fmt.i_cat != UNKNOWN_ES )
1162
2.46k
        {
1163
2.46k
            if( p_esp && p_languages &&
1164
239
                p_esp->i_language_index < p_languages->i_language &&
1165
233
                p_languages->ppsz_language[p_esp->i_language_index] )
1166
230
            {
1167
230
                fmt.psz_language = strdup( p_languages->ppsz_language[p_esp->i_language_index] );
1168
230
                char *p;
1169
230
                if( fmt.psz_language && (p = strchr( fmt.psz_language, '-' )) )
1170
226
                    *p = '\0';
1171
230
            }
1172
1173
            /* Set our priority so we won't get multiple videos */
1174
2.46k
            int i_priority = ES_PRIORITY_SELECTABLE_MIN;
1175
2.46k
            for( uint16_t i = 0; i < fmt_priorities_ex.i_count; i++ )
1176
0
            {
1177
0
                if ( fmt_priorities_ex.pi_stream_numbers[i] == p_sp->i_stream_number )
1178
0
                {
1179
0
                    i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
1180
0
                    break;
1181
0
                }
1182
0
            }
1183
2.46k
            for( uint16_t i = 0; i < fmt_priorities_bitrate_ex.i_count; i++ )
1184
0
            {
1185
0
                if ( fmt_priorities_bitrate_ex.pi_stream_numbers[i] == p_sp->i_stream_number )
1186
0
                {
1187
0
                    i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
1188
0
                    break;
1189
0
                }
1190
0
            }
1191
2.46k
            fmt.i_priority = i_priority;
1192
1193
2.46k
            if ( i_stream <= INT_MAX )
1194
2.46k
                fmt.i_id = i_stream;
1195
0
            else
1196
2.46k
                msg_Warn( p_demux, "Can't set fmt.i_id to match stream id %u", i_stream );
1197
1198
2.46k
            if ( fmt.i_cat == VIDEO_ES )
1199
353
            {
1200
                /* Backup our video format */
1201
353
                tk->p_fmt = malloc( sizeof( es_format_t ) );
1202
353
                if ( tk->p_fmt )
1203
353
                    es_format_Copy( tk->p_fmt, &fmt );
1204
353
            }
1205
1206
2.46k
            fmt.i_id = tk->info.p_sp->i_stream_number;
1207
1208
2.46k
            tk->p_es = es_out_Add( p_demux->out, &fmt );
1209
1210
2.46k
            if( !vlc_stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE,
1211
2.46k
                                     (int) p_sp->i_stream_number,
1212
2.46k
                                     &b_access_selected ) &&
1213
0
                b_access_selected )
1214
0
            {
1215
0
                p_sys->i_access_selected_track[fmt.i_cat] = p_sp->i_stream_number;
1216
0
            }
1217
1218
2.46k
        }
1219
944
        else
1220
944
        {
1221
944
            msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)",
1222
944
                     p_sp->i_stream_number );
1223
944
        }
1224
1225
3.40k
        es_format_Clean( &fmt );
1226
3.40k
    }
1227
1228
3.03k
    p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50;
1229
3.03k
    if( p_sys->p_root->p_data->i_object_size > 50 ) /* see libasf ASF_OBJECT_DATA <= 50 handling */
1230
2.88k
    { /* local file */
1231
2.88k
        p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos +
1232
2.88k
                                    p_sys->p_root->p_data->i_object_size;
1233
2.88k
        p_sys->i_data_end = __MIN( (uint64_t)stream_Size( p_demux->s ), p_sys->i_data_end );
1234
2.88k
    }
1235
156
    else
1236
156
    { /* live/broacast */
1237
156
        p_sys->i_data_end = 0;
1238
156
    }
1239
1240
    /* go to first packet */
1241
3.03k
    if( vlc_stream_Seek( p_demux->s, p_sys->i_data_begin ) != VLC_SUCCESS )
1242
0
        goto error;
1243
1244
    /* try to calculate movie time */
1245
3.03k
    if( p_sys->p_fp->i_data_packets_count > 0 )
1246
2.98k
    {
1247
2.98k
        uint64_t i_count;
1248
2.98k
        uint64_t i_size = stream_Size( p_demux->s );
1249
1250
2.98k
        if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
1251
72
        {
1252
72
            i_size = p_sys->i_data_end;
1253
72
        }
1254
1255
        /* real number of packets */
1256
2.98k
        i_count = ( i_size - p_sys->i_data_begin ) /
1257
2.98k
                  p_sys->p_fp->i_min_data_packet_size;
1258
1259
        /* calculate the time duration in micro-s */
1260
2.98k
        if ( ckd_mul(&p_sys->i_length, VLC_TICK_FROM_MSFTIME(p_sys->p_fp->i_play_duration), i_count) )
1261
106
            p_sys->i_length = 0;
1262
2.98k
        p_sys->i_length = p_sys->i_length /
1263
2.98k
                   (vlc_tick_t)p_sys->p_fp->i_data_packets_count;
1264
2.98k
        if( p_sys->i_length <= p_sys->p_fp->i_preroll )
1265
2.62k
            p_sys->i_length = 0;
1266
360
        else
1267
360
        {
1268
360
            p_sys->i_length  -= p_sys->p_fp->i_preroll;
1269
360
            p_sys->i_bitrate = 8 * i_size * CLOCK_FREQ / p_sys->i_length;
1270
360
        }
1271
2.98k
    }
1272
1273
    /* Create meta information */
1274
3.03k
    p_sys->meta = vlc_meta_New();
1275
1276
3.03k
    asf_object_content_description_t *p_cd;
1277
3.03k
    if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr,
1278
3.03k
                                 &asf_object_content_description_guid, 0 ) ) )
1279
620
    {
1280
620
        if( p_cd->psz_title && *p_cd->psz_title )
1281
561
        {
1282
561
            vlc_meta_SetTitle( p_sys->meta, p_cd->psz_title );
1283
561
        }
1284
620
        if( p_cd->psz_artist && *p_cd->psz_artist )
1285
552
        {
1286
552
             vlc_meta_SetArtist( p_sys->meta, p_cd->psz_artist );
1287
552
        }
1288
620
        if( p_cd->psz_copyright && *p_cd->psz_copyright )
1289
538
        {
1290
538
            vlc_meta_SetCopyright( p_sys->meta, p_cd->psz_copyright );
1291
538
        }
1292
620
        if( p_cd->psz_description && *p_cd->psz_description )
1293
63
        {
1294
63
            vlc_meta_SetDescription( p_sys->meta, p_cd->psz_description );
1295
63
        }
1296
620
        if( p_cd->psz_rating && *p_cd->psz_rating )
1297
5
        {
1298
5
            vlc_meta_SetRating( p_sys->meta, p_cd->psz_rating );
1299
5
        }
1300
620
    }
1301
3.03k
    asf_object_extended_content_description_t *p_ecd;
1302
3.03k
    if( ( p_ecd = ASF_FindObject( p_sys->p_root->p_hdr,
1303
3.03k
                                 &asf_object_extended_content_description, 0 ) ) )
1304
626
    {
1305
4.54k
        for( int i = 0; i < p_ecd->i_count; i++ )
1306
3.92k
        {
1307
1308
3.92k
#define set_meta( name, vlc_type ) \
1309
31.3k
            if( p_ecd->ppsz_name[i] && !strncmp( p_ecd->ppsz_name[i], name, strlen(name) ) ) \
1310
31.3k
                vlc_meta_Set( p_sys->meta, vlc_type, p_ecd->ppsz_value[i] );
1311
1312
3.92k
            set_meta( "WM/AlbumTitle",   vlc_meta_Album )
1313
3.92k
            else set_meta( "WM/TrackNumber",  vlc_meta_TrackNumber )
1314
3.92k
            else set_meta( "WM/Year",         vlc_meta_Date )
1315
3.92k
            else set_meta( "WM/Genre",        vlc_meta_Genre )
1316
3.92k
            else set_meta( "WM/Genre",        vlc_meta_Genre )
1317
3.92k
            else set_meta( "WM/AlbumArtist",  vlc_meta_AlbumArtist )
1318
3.92k
            else set_meta( "WM/Publisher",    vlc_meta_Publisher )
1319
3.92k
            else set_meta( "WM/PartOfSet",    vlc_meta_DiscNumber )
1320
3.92k
            else if( p_ecd->ppsz_value[i] != NULL && p_ecd->ppsz_name[i] &&
1321
3.16k
                    *p_ecd->ppsz_value[i] != '\0' && /* no empty value */
1322
2.03k
                    *p_ecd->ppsz_value[i] != '{'  && /* no guid value */
1323
2.03k
                    *p_ecd->ppsz_name[i] != '{' )    /* no guid name */
1324
2.02k
                    vlc_meta_SetExtra( p_sys->meta, p_ecd->ppsz_name[i], p_ecd->ppsz_value[i] );
1325
            /* TODO map WM/Composer, WM/Provider, WM/PartOfSet, PeakValue, AverageLevel  */
1326
3.92k
#undef set_meta
1327
3.92k
        }
1328
626
    }
1329
1330
    /// \todo Fix Child meta for ASF tracks
1331
#if 0
1332
    for( i_stream = 0, i = 0; i < MAX_ASF_TRACKS; i++ )
1333
    {
1334
        asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr,
1335
                                                        &asf_object_codec_list_guid, 0 );
1336
1337
        if( p_sys->track[i] )
1338
        {
1339
            vlc_meta_t *tk = vlc_meta_New();
1340
            TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk );
1341
1342
            if( p_cl && i_stream < p_cl->i_codec_entries_count )
1343
            {
1344
                if( p_cl->codec[i_stream].psz_name &&
1345
                    *p_cl->codec[i_stream].psz_name )
1346
                {
1347
                    vlc_meta_Add( tk, VLC_META_CODEC_NAME,
1348
                                  p_cl->codec[i_stream].psz_name );
1349
                }
1350
                if( p_cl->codec[i_stream].psz_description &&
1351
                    *p_cl->codec[i_stream].psz_description )
1352
                {
1353
                    vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION,
1354
                                  p_cl->codec[i_stream].psz_description );
1355
                }
1356
            }
1357
            i_stream++;
1358
        }
1359
    }
1360
#endif
1361
3.03k
    free( fmt_priorities_ex.pi_stream_numbers );
1362
3.03k
    free( fmt_priorities_bitrate_ex.pi_stream_numbers );
1363
1364
3.03k
    p_sys->packet_sys.pi_preroll = &p_sys->p_fp->i_preroll;
1365
3.03k
    p_sys->packet_sys.pi_preroll_start = &p_sys->i_preroll_start;
1366
3.03k
    p_sys->packet_sys.b_can_hold_multiple_packets = false;
1367
1368
3.03k
    return VLC_SUCCESS;
1369
1370
291
error:
1371
291
    free( fmt_priorities_ex.pi_stream_numbers );
1372
291
    free( fmt_priorities_bitrate_ex.pi_stream_numbers );
1373
291
    DemuxEnd( p_demux );
1374
291
    return VLC_EGENERIC;
1375
3.03k
}
1376
1377
/*****************************************************************************
1378
 * FlushQueues: flushes tail packets and send queues
1379
 *****************************************************************************/
1380
static void FlushQueue( asf_track_t *tk )
1381
3.42k
{
1382
3.42k
    ASFPacketTrackReset( &tk->info );
1383
3.42k
    if( tk->queue.p_first )
1384
0
    {
1385
0
        block_ChainRelease( tk->queue.p_first );
1386
0
        tk->queue.p_first = NULL;
1387
0
        tk->queue.pp_last = &tk->queue.p_first;
1388
0
    }
1389
3.42k
}
1390
1391
static void FlushQueues( demux_t *p_demux )
1392
3.38k
{
1393
3.38k
    demux_sys_t *p_sys = p_demux->p_sys;
1394
436k
    for ( unsigned int i = 0; i < MAX_ASF_TRACKS; i++ )
1395
433k
    {
1396
433k
        asf_track_t *tk = p_sys->track[i];
1397
433k
        if( !tk )
1398
429k
            continue;
1399
3.42k
        FlushQueue( tk );
1400
3.42k
    }
1401
3.38k
}
1402
1403
/*****************************************************************************
1404
 *
1405
 *****************************************************************************/
1406
static void DemuxEnd( demux_t *p_demux )
1407
3.38k
{
1408
3.38k
    demux_sys_t *p_sys = p_demux->p_sys;
1409
1410
3.38k
    if( p_sys->p_root )
1411
3.32k
    {
1412
3.32k
        ASF_FreeObjectRoot( p_demux->s, p_sys->p_root );
1413
3.32k
        p_sys->p_root = NULL;
1414
3.32k
        p_sys->p_fp = NULL;
1415
3.32k
    }
1416
3.38k
    if( p_sys->meta )
1417
3.03k
    {
1418
3.03k
        vlc_meta_Delete( p_sys->meta );
1419
3.03k
        p_sys->meta = NULL;
1420
3.03k
    }
1421
1422
3.38k
    FlushQueues( p_demux );
1423
1424
436k
    for( int i = 0; i < MAX_ASF_TRACKS; i++ )
1425
433k
    {
1426
433k
        asf_track_t *tk = p_sys->track[i];
1427
1428
433k
        if( tk )
1429
3.42k
        {
1430
3.42k
            if( tk->p_es )
1431
2.46k
            {
1432
2.46k
                es_out_Del( p_demux->out, tk->p_es );
1433
2.46k
            }
1434
3.42k
            if ( tk->p_fmt )
1435
353
            {
1436
353
                es_format_Clean( tk->p_fmt );
1437
353
                free( tk->p_fmt );
1438
353
            }
1439
3.42k
            free( tk );
1440
3.42k
        }
1441
433k
        p_sys->track[i] = 0;
1442
433k
    }
1443
3.38k
}