Coverage Report

Created: 2023-06-07 06:30

/src/vlc/modules/demux/nsv.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * nsv.c: NullSoft Video demuxer.
3
 *****************************************************************************
4
 * Copyright (C) 2004-2007 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 <limits.h>
32
33
#include <vlc_common.h>
34
#include <vlc_plugin.h>
35
#include <vlc_demux.h>
36
37
/* TODO:
38
 *  - implement NSVf parsing (to get meta data)
39
 *  - implement missing Control (and in the right way)
40
 *  - ...
41
 */
42
43
/*****************************************************************************
44
 * Module descriptor
45
 *****************************************************************************/
46
static int  Open    ( vlc_object_t * );
47
static void Close  ( vlc_object_t * );
48
49
4
vlc_module_begin ()
50
2
    set_description( N_("NullSoft demuxer" ) )
51
2
    set_capability( "demux", 10 )
52
2
    set_subcategory( SUBCAT_INPUT_DEMUX )
53
2
    set_callbacks( Open, Close )
54
2
    add_shortcut( "nsv" )
55
2
    add_file_extension("nsv")
56
2
vlc_module_end ()
57
58
/*****************************************************************************
59
 * Local prototypes
60
 *****************************************************************************/
61
62
typedef struct
63
{
64
    es_format_t  fmt_audio;
65
    es_out_id_t *p_audio;
66
67
    es_format_t  fmt_video;
68
    es_out_id_t *p_video;
69
70
    es_format_t  fmt_sub;
71
    es_out_id_t  *p_sub;
72
73
    vlc_tick_t  i_pcr;
74
    vlc_tick_t  i_time;
75
    vlc_tick_t  i_pcr_inc;
76
77
    bool b_start_record;
78
    char *record_dir_path;
79
} demux_sys_t;
80
81
static int Demux  ( demux_t *p_demux );
82
static int Control( demux_t *p_demux, int i_query, va_list args );
83
84
static int ReSynch( demux_t *p_demux );
85
86
static int ReadNSVf( demux_t *p_demux );
87
static int ReadNSVs( demux_t *p_demux );
88
89
/*****************************************************************************
90
 * Open
91
 *****************************************************************************/
92
static int Open( vlc_object_t *p_this )
93
39
{
94
39
    demux_t     *p_demux = (demux_t*)p_this;
95
39
    demux_sys_t *p_sys;
96
97
39
    const uint8_t *p_peek;
98
99
39
    if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
100
0
        return VLC_EGENERIC;
101
102
39
    if( memcmp( p_peek, "NSVf", 4 ) && memcmp( p_peek, "NSVs", 4 ) )
103
39
    {
104
       /* In case we had force this demuxer we try to resynch */
105
39
        if( !p_demux->obj.force || ReSynch( p_demux ) )
106
39
            return VLC_EGENERIC;
107
39
    }
108
109
0
    p_sys = malloc( sizeof( demux_sys_t ) );
110
0
    if( unlikely(p_sys == NULL) )
111
0
        return VLC_ENOMEM;
112
113
    /* Fill p_demux field */
114
0
    p_demux->p_sys = p_sys;
115
0
    p_demux->pf_demux = Demux;
116
0
    p_demux->pf_control = Control;
117
118
0
    es_format_Init( &p_sys->fmt_audio, AUDIO_ES, 0 );
119
0
    p_sys->p_audio = NULL;
120
121
0
    es_format_Init( &p_sys->fmt_video, VIDEO_ES, 0 );
122
0
    p_sys->p_video = NULL;
123
124
0
    es_format_Init( &p_sys->fmt_sub, SPU_ES, 0 );
125
0
    p_sys->p_sub = NULL;
126
127
0
    p_sys->i_pcr   = 0;
128
0
    p_sys->i_time  = 0;
129
0
    p_sys->i_pcr_inc = 0;
130
131
0
    p_sys->b_start_record = false;
132
0
    p_sys->record_dir_path = NULL;
133
134
0
    return VLC_SUCCESS;
135
0
}
136
137
/*****************************************************************************
138
 * Close
139
 *****************************************************************************/
140
static void Close( vlc_object_t *p_this )
141
0
{
142
0
    demux_t     *p_demux = (demux_t*)p_this;
143
0
    demux_sys_t *p_sys = p_demux->p_sys;
144
145
0
    free( p_sys->record_dir_path );
146
0
    free( p_sys );
147
0
}
148
149
150
/*****************************************************************************
151
 * Demux:
152
 *****************************************************************************/
153
static int Demux( demux_t *p_demux )
154
0
{
155
0
    demux_sys_t *p_sys = p_demux->p_sys;
156
157
0
    uint8_t     header[5];
158
0
    const uint8_t *p_peek;
159
160
0
    int         i_size;
161
0
    block_t     *p_frame;
162
163
0
    for( ;; )
164
0
    {
165
0
        if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
166
0
            return VLC_DEMUXER_EOF;
167
168
0
        if( !memcmp( p_peek, "NSVf", 4 ) )
169
0
        {
170
0
            if( ReadNSVf( p_demux ) )
171
0
                return VLC_DEMUXER_EGENERIC;
172
0
        }
173
0
        else if( !memcmp( p_peek, "NSVs", 4 ) )
174
0
        {
175
0
            if( p_sys->b_start_record )
176
0
            {
177
                /* Enable recording once synchronized */
178
0
                vlc_stream_Control( p_demux->s, STREAM_SET_RECORD_STATE, true,
179
0
                                    p_sys->record_dir_path, "nsv" );
180
0
                p_sys->b_start_record = false;
181
0
            }
182
183
0
            if( ReadNSVs( p_demux ) )
184
0
                return VLC_DEMUXER_EGENERIC;
185
0
            break;
186
0
        }
187
0
        else if( GetWLE( p_peek ) == 0xbeef )
188
0
        {
189
            /* Next frame of the current NSVs chunk */
190
0
            if( vlc_stream_Read( p_demux->s, NULL, 2 ) != 2 )
191
0
            {
192
0
                msg_Warn( p_demux, "cannot read" );
193
0
                return VLC_DEMUXER_EOF;
194
0
            }
195
0
            break;
196
0
        }
197
0
        else
198
0
        {
199
0
            msg_Err( p_demux, "invalid signature 0x%x (%4.4s)", GetDWLE( p_peek ), (const char*)p_peek );
200
0
            if( ReSynch( p_demux ) )
201
0
                return VLC_DEMUXER_EGENERIC;
202
0
        }
203
0
    }
204
205
0
    if( vlc_stream_Read( p_demux->s, header, 5 ) < 5 )
206
0
    {
207
0
        msg_Warn( p_demux, "cannot read" );
208
0
        return VLC_DEMUXER_EOF;
209
0
    }
210
211
    /* Set PCR */
212
0
    es_out_SetPCR( p_demux->out, VLC_TICK_0 + p_sys->i_pcr );
213
214
    /* Read video */
215
0
    i_size = ( header[0] >> 4 ) | ( header[1] << 4 ) | ( header[2] << 12 );
216
0
    if( i_size > 0 )
217
0
    {
218
        /* extra data ? */
219
0
        if( (header[0]&0x0f) != 0x0 )
220
0
        {
221
0
            uint8_t      aux[6];
222
0
            int          i_aux;
223
0
            vlc_fourcc_t fcc;
224
0
            if( vlc_stream_Read( p_demux->s, aux, 6 ) < 6 )
225
0
            {
226
0
                msg_Warn( p_demux, "cannot read" );
227
0
                return VLC_DEMUXER_EOF;
228
0
            }
229
0
            i_aux = GetWLE( aux );
230
0
            fcc   = VLC_FOURCC( aux[2], aux[3], aux[4], aux[5] );
231
232
0
            msg_Dbg( p_demux, "Belekas: %d - size=%d fcc=%4.4s",
233
0
                     header[0]&0xf, i_aux, (char*)&fcc );
234
235
0
            if( fcc == VLC_FOURCC( 'S', 'U', 'B', 'T' ) && i_aux > 2 )
236
0
            {
237
0
                if( p_sys->p_sub == NULL )
238
0
                {
239
0
                    p_sys->fmt_sub.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
240
0
                    p_sys->p_sub = es_out_Add( p_demux->out, &p_sys->fmt_sub );
241
0
                    if( p_sys->p_sub )
242
0
                        es_out_Control( p_demux->out, ES_OUT_SET_ES, p_sys->p_sub );
243
0
                }
244
0
                if( vlc_stream_Read( p_demux->s, NULL, 2 ) != 2 )
245
0
                    return VLC_DEMUXER_EOF;
246
247
0
                if( ( p_frame = vlc_stream_Block( p_demux->s, i_aux - 2 ) ) )
248
0
                {
249
0
                    uint8_t *p = p_frame->p_buffer;
250
251
0
                    while( p < &p_frame->p_buffer[p_frame->i_buffer] && *p != 0 )
252
0
                    {
253
0
                        p++;
254
0
                    }
255
0
                    if( *p == 0 && p + 1 < &p_frame->p_buffer[p_frame->i_buffer] )
256
0
                    {
257
0
                        p_frame->i_buffer -= p + 1 - p_frame->p_buffer;
258
0
                        p_frame->p_buffer = p + 1;
259
0
                    }
260
261
                    /* Skip the first part (it is the language name) */
262
0
                    p_frame->i_pts = VLC_TICK_0 + p_sys->i_pcr;
263
0
                    p_frame->i_dts = VLC_TICK_0 + p_sys->i_pcr + VLC_TICK_FROM_SEC(4);
264
265
0
                    if( p_sys->p_sub )
266
0
                        es_out_Send( p_demux->out, p_sys->p_sub, p_frame );
267
0
                    else
268
0
                        block_Release( p_frame );
269
0
                }
270
0
            }
271
0
            else
272
0
            {
273
                /* We skip this extra data */
274
0
                if( vlc_stream_Read( p_demux->s, NULL, i_aux ) != i_aux )
275
0
                {
276
0
                    msg_Warn( p_demux, "cannot read" );
277
0
                    return VLC_DEMUXER_EOF;
278
0
                }
279
0
            }
280
0
            i_size -= 6 + i_aux;
281
0
        }
282
283
        /* msg_Dbg( p_demux, "frame video size=%d", i_size ); */
284
0
        if( i_size > 0 && ( p_frame = vlc_stream_Block( p_demux->s, i_size ) ) )
285
0
        {
286
0
            p_frame->i_dts = VLC_TICK_0 + p_sys->i_pcr;
287
288
0
            if( p_sys->p_video )
289
0
                es_out_Send( p_demux->out, p_sys->p_video, p_frame );
290
0
            else
291
0
            {
292
0
                block_Release( p_frame );
293
0
                msg_Dbg( p_demux, "ignoring unsupported video frame (size=%d)",
294
0
                         i_size );
295
0
            }
296
0
        }
297
0
    }
298
299
    /* Read audio */
300
0
    i_size = header[3] | ( header[4] << 8 );
301
0
    if( i_size > 0 )
302
0
    {
303
        /* msg_Dbg( p_demux, "frame audio size=%d", i_size ); */
304
0
        if( p_sys->fmt_audio.i_codec == VLC_FOURCC( 'a', 'r', 'a', 'w' ) )
305
0
        {
306
0
            uint8_t h[4];
307
0
            if( vlc_stream_Read( p_demux->s, h, 4 ) < 4 )
308
0
                return VLC_DEMUXER_EOF;
309
310
0
            p_sys->fmt_audio.audio.i_channels = h[1];
311
0
            p_sys->fmt_audio.audio.i_rate = GetWLE( &h[2] );
312
313
0
            i_size -= 4;
314
0
        }
315
0
        if( p_sys->p_audio == NULL )
316
0
        {
317
0
            p_sys->p_audio = es_out_Add( p_demux->out, &p_sys->fmt_audio );
318
0
        }
319
320
0
        if( ( p_frame = vlc_stream_Block( p_demux->s, i_size ) ) )
321
0
        {
322
0
            p_frame->i_dts =
323
0
            p_frame->i_pts = VLC_TICK_0 + p_sys->i_pcr;
324
325
0
            if( p_sys->p_audio )
326
0
                es_out_Send( p_demux->out, p_sys->p_audio, p_frame );
327
0
            else
328
0
            {
329
0
                block_Release( p_frame );
330
0
                msg_Dbg( p_demux, "ignoring unsupported audio frame (size=%d)",
331
0
                         i_size );
332
0
            }
333
0
        }
334
0
    }
335
336
0
    p_sys->i_pcr += p_sys->i_pcr_inc;
337
0
    if( p_sys->i_time >= 0 )
338
0
    {
339
0
        p_sys->i_time += p_sys->i_pcr_inc;
340
0
    }
341
342
0
    return VLC_DEMUXER_SUCCESS;
343
0
}
344
345
/*****************************************************************************
346
 * Control:
347
 *****************************************************************************/
348
static int Control( demux_t *p_demux, int i_query, va_list args )
349
0
{
350
0
    demux_sys_t *p_sys = p_demux->p_sys;
351
0
    double f, *pf;
352
0
    bool b_bool, *pb_bool;
353
0
    int64_t i64;
354
355
0
    switch( i_query )
356
0
    {
357
0
        case DEMUX_CAN_SEEK:
358
0
            return vlc_stream_vaControl( p_demux->s, i_query, args );
359
360
0
        case DEMUX_GET_POSITION:
361
0
            pf = va_arg( args, double * );
362
0
            i64 = stream_Size( p_demux->s );
363
0
            if( i64 > 0 )
364
0
            {
365
0
                double current = vlc_stream_Tell( p_demux->s );
366
0
                *pf = current / (double)i64;
367
0
            }
368
0
            else
369
0
            {
370
0
                *pf = 0.0;
371
0
            }
372
0
            return VLC_SUCCESS;
373
374
0
        case DEMUX_SET_POSITION:
375
0
            f = va_arg( args, double );
376
0
            i64 = stream_Size( p_demux->s );
377
378
0
            if( vlc_stream_Seek( p_demux->s, (int64_t)(i64 * f) ) || ReSynch( p_demux ) )
379
0
                return VLC_EGENERIC;
380
381
0
            p_sys->i_time = -1; /* Invalidate time display */
382
0
            return VLC_SUCCESS;
383
384
0
        case DEMUX_GET_TIME:
385
0
            if( p_sys->i_time < 0 )
386
0
            {
387
0
                *va_arg( args, vlc_tick_t * ) = 0;
388
0
                return VLC_EGENERIC;
389
0
            }
390
0
            *va_arg( args, vlc_tick_t * ) = p_sys->i_time;
391
0
            return VLC_SUCCESS;
392
393
#if 0
394
        case DEMUX_GET_LENGTH:
395
            if( p_sys->i_mux_rate > 0 )
396
            {
397
                *va_arg( args, vlc_tick_t * ) = vlc_tick_from_samples( stream_Size( p_demux->s ) / 50, p_sys->i_mux_rate);
398
                return VLC_SUCCESS;
399
            }
400
            *va_arg( args, vlc_tick_t * ) = 0;
401
            return VLC_EGENERIC;
402
403
#endif
404
0
        case DEMUX_GET_FPS:
405
0
            pf = va_arg( args, double * );
406
0
            *pf = (double)CLOCK_FREQ / (double)p_sys->i_pcr_inc;
407
0
            return VLC_SUCCESS;
408
409
0
        case DEMUX_CAN_RECORD:
410
0
            pb_bool = va_arg( args, bool * );
411
0
            *pb_bool = true;
412
0
            return VLC_SUCCESS;
413
414
0
        case DEMUX_SET_RECORD_STATE:
415
0
        {
416
0
            b_bool = (bool)va_arg( args, int );
417
0
            const char *dir_path = va_arg( args, const char * );
418
419
0
            free( p_sys->record_dir_path );
420
0
            p_sys->record_dir_path = NULL;
421
422
0
            if( !b_bool )
423
0
                vlc_stream_Control( p_demux->s, STREAM_SET_RECORD_STATE, false );
424
0
            else if( dir_path != NULL )
425
0
            {
426
0
                p_sys->record_dir_path = strdup(dir_path);
427
0
                if( p_sys->record_dir_path == NULL )
428
0
                    return VLC_ENOMEM;
429
0
            }
430
0
            p_sys->b_start_record = b_bool;
431
0
            return VLC_SUCCESS;
432
0
        }
433
434
0
        case DEMUX_SET_TIME:
435
0
            return VLC_EGENERIC;
436
437
0
        case DEMUX_CAN_PAUSE:
438
0
        case DEMUX_SET_PAUSE_STATE:
439
0
        case DEMUX_CAN_CONTROL_PACE:
440
0
        case DEMUX_GET_PTS_DELAY:
441
0
            return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args );
442
443
0
        default:
444
0
            return VLC_EGENERIC;
445
0
    }
446
0
}
447
448
/*****************************************************************************
449
 * ReSynch:
450
 *****************************************************************************/
451
static int ReSynch( demux_t *p_demux )
452
0
{
453
0
    for( ;; )
454
0
    {
455
0
        const uint8_t *p_peek;
456
0
        int i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 1024 );
457
0
        if( i_peek < 8 )
458
0
            break;
459
460
0
        int i_skip = 0;
461
462
0
        while( i_skip < i_peek - 4 )
463
0
        {
464
0
            if( !memcmp( p_peek, "NSVf", 4 )
465
0
             || !memcmp( p_peek, "NSVs", 4 ) )
466
0
            {
467
0
                if( i_skip > 0 && vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip )
468
0
                    return VLC_EGENERIC;
469
0
                return VLC_SUCCESS;
470
0
            }
471
0
            p_peek++;
472
0
            i_skip++;
473
0
        }
474
475
0
        if( vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip )
476
0
            break;
477
0
    }
478
0
    return VLC_EGENERIC;
479
0
}
480
481
/*****************************************************************************
482
 * ReadNSVf:
483
 *****************************************************************************/
484
static int ReadNSVf( demux_t *p_demux )
485
0
{
486
    /* demux_sys_t *p_sys = p_demux->p_sys; */
487
0
    const uint8_t     *p;
488
489
0
    msg_Dbg( p_demux, "new NSVf chunk" );
490
0
    if( vlc_stream_Peek( p_demux->s, &p, 8 ) < 8 )
491
0
    {
492
0
        return VLC_EGENERIC;
493
0
    }
494
495
0
    uint32_t i_header_size = GetDWLE( &p[4] );
496
0
    msg_Dbg( p_demux, "    - size=%" PRIu32, i_header_size );
497
498
0
    if( i_header_size == 0 || i_header_size == UINT32_MAX )
499
0
        return VLC_EGENERIC;
500
#if (UINT32_MAX > SSIZE_MAX)
501
    if( i_header_size > SSIZE_MAX )
502
        return VLC_EGENERIC;
503
#endif
504
0
    if ( vlc_stream_Read( p_demux->s, NULL, i_header_size ) != i_header_size )
505
0
         return VLC_EGENERIC;
506
0
    return VLC_SUCCESS;
507
0
}
508
/*****************************************************************************
509
 * ReadNSVs:
510
 *****************************************************************************/
511
static int ReadNSVs( demux_t *p_demux )
512
0
{
513
0
    demux_sys_t *p_sys = p_demux->p_sys;
514
0
    uint8_t      header[19];
515
0
    vlc_fourcc_t fcc;
516
517
0
    if( vlc_stream_Read( p_demux->s, header, 19 ) < 19 )
518
0
    {
519
0
        msg_Warn( p_demux, "cannot read" );
520
0
        return VLC_EGENERIC;
521
0
    }
522
523
    /* Video */
524
0
    switch( ( fcc = VLC_FOURCC( header[4], header[5], header[6], header[7] ) ) )
525
0
    {
526
0
        case VLC_FOURCC( 'V', 'P', '3', ' ' ):
527
0
        case VLC_FOURCC( 'V', 'P', '3', '0' ):
528
0
            fcc = VLC_FOURCC( 'V', 'P', '3', '0' );
529
0
            break;
530
531
0
        case VLC_FOURCC( 'V', 'P', '3', '1' ):
532
0
            fcc = VLC_FOURCC( 'V', 'P', '3', '1' );
533
0
            break;
534
535
0
        case VLC_FOURCC( 'V', 'P', '5', ' ' ):
536
0
        case VLC_FOURCC( 'V', 'P', '5', '0' ):
537
0
            fcc = VLC_FOURCC( 'V', 'P', '5', '0' );
538
0
            break;
539
0
        case VLC_FOURCC( 'V', 'P', '6', '0' ):
540
0
        case VLC_FOURCC( 'V', 'P', '6', '1' ):
541
0
        case VLC_FOURCC( 'V', 'P', '6', '2' ):
542
0
        case VLC_FOURCC( 'V', 'P', '8', '0' ):
543
0
        case VLC_FOURCC( 'H', '2', '6', '4' ):
544
0
        case VLC_FOURCC( 'N', 'O', 'N', 'E' ):
545
0
            break;
546
0
        default:
547
0
            msg_Err( p_demux, "unsupported video codec %4.4s", (char *)&fcc );
548
0
            break;
549
0
    }
550
0
    if( fcc != VLC_FOURCC( 'N', 'O', 'N', 'E' ) && fcc != p_sys->fmt_video.i_codec  )
551
0
    {
552
0
        es_format_Init( &p_sys->fmt_video, VIDEO_ES, fcc );
553
0
        p_sys->fmt_video.video.i_width = GetWLE( &header[12] );
554
0
        p_sys->fmt_video.video.i_height = GetWLE( &header[14] );
555
0
        p_sys->fmt_video.video.i_visible_width = p_sys->fmt_video.video.i_width;
556
0
        p_sys->fmt_video.video.i_visible_height = p_sys->fmt_video.video.i_height;
557
0
        if( p_sys->p_video )
558
0
        {
559
0
            es_out_Del( p_demux->out, p_sys->p_video );
560
0
        }
561
0
        p_sys->p_video = es_out_Add( p_demux->out, &p_sys->fmt_video );
562
563
0
        msg_Dbg( p_demux, "    - video `%4.4s' %dx%d",
564
0
                 (char*)&fcc,
565
0
                 p_sys->fmt_video.video.i_width,
566
0
                 p_sys->fmt_video.video.i_height );
567
0
    }
568
569
    /* Audio */
570
0
    switch( ( fcc = VLC_FOURCC( header[8], header[9], header[10], header[11] ) ) )
571
0
    {
572
0
        case VLC_FOURCC( 'M', 'P', '3', ' ' ):
573
0
            fcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
574
0
            break;
575
0
        case VLC_FOURCC( 'P', 'C', 'M', ' ' ):
576
0
            fcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
577
0
            break;
578
0
        case VLC_FOURCC( 'A', 'A', 'C', ' ' ):
579
0
        case VLC_FOURCC( 'A', 'A', 'C', 'P' ):
580
0
            fcc = VLC_FOURCC( 'm', 'p', '4', 'a' );
581
0
            break;
582
0
        case VLC_FOURCC( 'S', 'P', 'X', ' ' ):
583
0
            fcc = VLC_FOURCC( 's', 'p', 'x', ' ' );
584
0
            break;
585
0
        case VLC_FOURCC( 'N', 'O', 'N', 'E' ):
586
0
            break;
587
0
        default:
588
0
            msg_Err( p_demux, "unsupported audio codec %4.4s", (char *)&fcc );
589
0
            break;
590
0
    }
591
592
0
    if( fcc != VLC_FOURCC( 'N', 'O', 'N', 'E' ) && fcc != p_sys->fmt_audio.i_codec )
593
0
    {
594
0
        msg_Dbg( p_demux, "    - audio `%4.4s'", (char*)&fcc );
595
596
0
        if( p_sys->p_audio )
597
0
        {
598
0
            es_out_Del( p_demux->out, p_sys->p_audio );
599
0
            p_sys->p_audio = NULL;
600
0
        }
601
0
        es_format_Init( &p_sys->fmt_audio, AUDIO_ES, fcc );
602
0
    }
603
604
0
    if( header[16]&0x80 )
605
0
    {
606
        /* Fractional frame rate */
607
0
        switch( header[16]&0x03 )
608
0
        {
609
0
            case 0: /* 30 fps */
610
0
                p_sys->i_pcr_inc = 33333; /* 300000/9 */
611
0
                break;
612
0
            case 1: /* 29.97 fps */
613
0
                p_sys->i_pcr_inc = 33367; /* 300300/9 */
614
0
                break;
615
0
            case 2: /* 25 fps */
616
0
                p_sys->i_pcr_inc = 40000; /* 360000/9 */
617
0
                break;
618
0
            case 3: /* 23.98 fps */
619
0
                p_sys->i_pcr_inc = 41700; /* 375300/9 */
620
0
                break;
621
0
        }
622
623
0
        if( header[16] < 0xc0 )
624
0
            p_sys->i_pcr_inc = p_sys->i_pcr_inc * (((header[16] ^ 0x80) >> 2 ) +1 );
625
0
        else
626
0
            p_sys->i_pcr_inc = p_sys->i_pcr_inc / (((header[16] ^ 0xc0) >> 2 ) +1 );
627
0
    }
628
0
    else if( header[16] != 0 )
629
0
    {
630
        /* Integer frame rate */
631
0
        p_sys->i_pcr_inc = vlc_tick_from_samples(1, header[16]);
632
0
    }
633
0
    else
634
0
    {
635
0
        msg_Dbg( p_demux, "invalid fps (0x00)" );
636
0
        p_sys->i_pcr_inc = VLC_TICK_FROM_MS(40);
637
0
    }
638
    //msg_Dbg( p_demux, "    - fps=%.3f", 1000000.0 / (double)p_sys->i_pcr_inc );
639
640
0
    if( p_sys->p_audio == NULL && p_sys->p_video == NULL )
641
0
    {
642
0
        msg_Err( p_demux, "unable to play neither audio nor video, aborting." );
643
0
        return VLC_EGENERIC;
644
0
    }
645
646
0
    return VLC_SUCCESS;
647
0
}
648