Coverage Report

Created: 2026-06-09 09:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/nsv.c
Line
Count
Source
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
168
vlc_module_begin ()
50
84
    set_description( N_("NullSoft demuxer" ) )
51
84
    set_capability( "demux", 10 )
52
84
    set_subcategory( SUBCAT_INPUT_DEMUX )
53
84
    set_callbacks( Open, Close )
54
84
    add_shortcut( "nsv" )
55
84
    add_file_extension("nsv")
56
84
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
423
{
94
423
    demux_t     *p_demux = (demux_t*)p_this;
95
423
    demux_sys_t *p_sys;
96
97
423
    const uint8_t *p_peek;
98
99
423
    if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
100
0
        return VLC_EGENERIC;
101
102
423
    if( memcmp( p_peek, "NSVf", 4 ) && memcmp( p_peek, "NSVs", 4 ) )
103
410
    {
104
       /* In case we had force this demuxer we try to resynch */
105
410
        if( !p_demux->obj.force || ReSynch( p_demux ) )
106
410
            return VLC_EGENERIC;
107
410
    }
108
109
13
    p_sys = malloc( sizeof( demux_sys_t ) );
110
13
    if( unlikely(p_sys == NULL) )
111
0
        return VLC_ENOMEM;
112
113
    /* Fill p_demux field */
114
13
    p_demux->p_sys = p_sys;
115
13
    p_demux->pf_demux = Demux;
116
13
    p_demux->pf_control = Control;
117
118
13
    es_format_Init( &p_sys->fmt_audio, AUDIO_ES, 0 );
119
13
    p_sys->p_audio = NULL;
120
121
13
    es_format_Init( &p_sys->fmt_video, VIDEO_ES, 0 );
122
13
    p_sys->p_video = NULL;
123
124
13
    es_format_Init( &p_sys->fmt_sub, SPU_ES, 0 );
125
13
    p_sys->p_sub = NULL;
126
127
13
    p_sys->i_pcr   = 0;
128
13
    p_sys->i_time  = 0;
129
13
    p_sys->i_pcr_inc = 0;
130
131
13
    p_sys->b_start_record = false;
132
13
    p_sys->record_dir_path = NULL;
133
134
13
    return VLC_SUCCESS;
135
13
}
136
137
/*****************************************************************************
138
 * Close
139
 *****************************************************************************/
140
static void Close( vlc_object_t *p_this )
141
13
{
142
13
    demux_t     *p_demux = (demux_t*)p_this;
143
13
    demux_sys_t *p_sys = p_demux->p_sys;
144
145
13
    free( p_sys->record_dir_path );
146
13
    free( p_sys );
147
13
}
148
149
150
/*****************************************************************************
151
 * Demux:
152
 *****************************************************************************/
153
static int Demux( demux_t *p_demux )
154
4.10k
{
155
4.10k
    demux_sys_t *p_sys = p_demux->p_sys;
156
157
4.10k
    uint8_t     header[5];
158
4.10k
    const uint8_t *p_peek;
159
160
4.10k
    int         i_size;
161
4.10k
    block_t     *p_frame;
162
163
4.10k
    for( ;; )
164
10.5k
    {
165
10.5k
        if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
166
5
            return VLC_DEMUXER_EOF;
167
168
10.5k
        if( !memcmp( p_peek, "NSVf", 4 ) )
169
1.19k
        {
170
1.19k
            if( ReadNSVf( p_demux ) )
171
1
                return VLC_DEMUXER_EGENERIC;
172
1.19k
        }
173
9.30k
        else if( !memcmp( p_peek, "NSVs", 4 ) )
174
4.08k
        {
175
4.08k
            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
4.08k
            if( ReadNSVs( p_demux ) )
184
0
                return VLC_DEMUXER_EGENERIC;
185
4.08k
            break;
186
4.08k
        }
187
5.21k
        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
5.21k
        else
198
5.21k
        {
199
5.21k
            msg_Err( p_demux, "invalid signature 0x%x (%4.4s)", GetDWLE( p_peek ), (const char*)p_peek );
200
5.21k
            if( ReSynch( p_demux ) )
201
7
                return VLC_DEMUXER_EGENERIC;
202
5.21k
        }
203
10.5k
    }
204
205
4.08k
    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
4.08k
    es_out_SetPCR( p_demux->out, VLC_TICK_0 + p_sys->i_pcr );
213
214
    /* Read video */
215
4.08k
    i_size = ( header[0] >> 4 ) | ( header[1] << 4 ) | ( header[2] << 12 );
216
4.08k
    if( i_size > 0 )
217
2.05k
    {
218
        /* extra data ? */
219
2.05k
        if( (header[0]&0x0f) != 0x0 )
220
1.30k
        {
221
1.30k
            uint8_t      aux[6];
222
1.30k
            int          i_aux;
223
1.30k
            vlc_fourcc_t fcc;
224
1.30k
            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
1.30k
            i_aux = GetWLE( aux );
230
1.30k
            fcc   = VLC_FOURCC( aux[2], aux[3], aux[4], aux[5] );
231
232
1.30k
            msg_Dbg( p_demux, "Belekas: %d - size=%d fcc=%4.4s",
233
1.30k
                     header[0]&0xf, i_aux, (char*)&fcc );
234
235
1.30k
            if( fcc == VLC_FOURCC( 'S', 'U', 'B', 'T' ) && i_aux > 2 )
236
800
            {
237
800
                if( p_sys->p_sub == NULL )
238
4
                {
239
4
                    p_sys->fmt_sub.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
240
4
                    p_sys->p_sub = es_out_Add( p_demux->out, &p_sys->fmt_sub );
241
4
                    if( p_sys->p_sub )
242
4
                        es_out_Control( p_demux->out, ES_OUT_SET_ES, p_sys->p_sub );
243
4
                }
244
800
                if( vlc_stream_Read( p_demux->s, NULL, 2 ) != 2 )
245
0
                    return VLC_DEMUXER_EOF;
246
247
800
                if( ( p_frame = vlc_stream_Block( p_demux->s, i_aux - 2 ) ) )
248
800
                {
249
800
                    uint8_t *p = p_frame->p_buffer;
250
251
46.6k
                    while( p < &p_frame->p_buffer[p_frame->i_buffer] && *p != 0 )
252
45.8k
                    {
253
45.8k
                        p++;
254
45.8k
                    }
255
800
                    if( p + 1 < &p_frame->p_buffer[p_frame->i_buffer] && *p == 0 )
256
799
                    {
257
799
                        p_frame->i_buffer -= p + 1 - p_frame->p_buffer;
258
799
                        p_frame->p_buffer = p + 1;
259
799
                    }
260
261
                    /* Skip the first part (it is the language name) */
262
800
                    p_frame->i_pts = VLC_TICK_0 + p_sys->i_pcr;
263
800
                    p_frame->i_dts = VLC_TICK_0 + p_sys->i_pcr + VLC_TICK_FROM_SEC(4);
264
265
800
                    if( p_sys->p_sub )
266
800
                        es_out_Send( p_demux->out, p_sys->p_sub, p_frame );
267
0
                    else
268
0
                        block_Release( p_frame );
269
800
                }
270
800
            }
271
505
            else
272
505
            {
273
                /* We skip this extra data */
274
505
                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
505
            }
280
1.30k
            i_size -= 6 + i_aux;
281
1.30k
        }
282
283
        /* msg_Dbg( p_demux, "frame video size=%d", i_size ); */
284
2.05k
        if( i_size > 0 && ( p_frame = vlc_stream_Block( p_demux->s, i_size ) ) )
285
1.25k
        {
286
1.25k
            p_frame->i_dts = VLC_TICK_0 + p_sys->i_pcr;
287
288
1.25k
            if( p_sys->p_video )
289
1.25k
                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
1.25k
        }
297
2.05k
    }
298
299
    /* Read audio */
300
4.08k
    i_size = header[3] | ( header[4] << 8 );
301
4.08k
    if( i_size > 0 )
302
1.35k
    {
303
        /* msg_Dbg( p_demux, "frame audio size=%d", i_size ); */
304
1.35k
        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
1.35k
        if( p_sys->p_audio == NULL )
316
658
        {
317
658
            p_sys->p_audio = es_out_Add( p_demux->out, &p_sys->fmt_audio );
318
658
        }
319
320
1.35k
        if( ( p_frame = vlc_stream_Block( p_demux->s, i_size ) ) )
321
1.35k
        {
322
1.35k
            p_frame->i_dts =
323
1.35k
            p_frame->i_pts = VLC_TICK_0 + p_sys->i_pcr;
324
325
1.35k
            if( p_sys->p_audio )
326
1.35k
                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
1.35k
        }
334
1.35k
    }
335
336
4.08k
    p_sys->i_pcr += p_sys->i_pcr_inc;
337
4.08k
    if( p_sys->i_time >= 0 )
338
4.08k
    {
339
4.08k
        p_sys->i_time += p_sys->i_pcr_inc;
340
4.08k
    }
341
342
4.08k
    return VLC_DEMUXER_SUCCESS;
343
4.08k
}
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
5.21k
{
453
5.21k
    for( ;; )
454
5.38k
    {
455
5.38k
        const uint8_t *p_peek;
456
5.38k
        int i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 1024 );
457
5.38k
        if( i_peek < 8 )
458
7
            break;
459
460
5.38k
        int i_skip = 0;
461
462
658k
        while( i_skip < i_peek - 4 )
463
658k
        {
464
658k
            if( !memcmp( p_peek, "NSVf", 4 )
465
657k
             || !memcmp( p_peek, "NSVs", 4 ) )
466
5.20k
            {
467
5.20k
                if( i_skip > 0 && vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip )
468
0
                    return VLC_EGENERIC;
469
5.20k
                return VLC_SUCCESS;
470
5.20k
            }
471
653k
            p_peek++;
472
653k
            i_skip++;
473
653k
        }
474
475
172
        if( vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip )
476
0
            break;
477
172
    }
478
7
    return VLC_EGENERIC;
479
5.21k
}
480
481
/*****************************************************************************
482
 * ReadNSVf:
483
 *****************************************************************************/
484
static int ReadNSVf( demux_t *p_demux )
485
1.19k
{
486
    /* demux_sys_t *p_sys = p_demux->p_sys; */
487
1.19k
    const uint8_t     *p;
488
489
1.19k
    msg_Dbg( p_demux, "new NSVf chunk" );
490
1.19k
    if( vlc_stream_Peek( p_demux->s, &p, 8 ) < 8 )
491
0
    {
492
0
        return VLC_EGENERIC;
493
0
    }
494
495
1.19k
    uint32_t i_header_size = GetDWLE( &p[4] );
496
1.19k
    msg_Dbg( p_demux, "    - size=%" PRIu32, i_header_size );
497
498
1.19k
    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
1.19k
    if ( vlc_stream_Read( p_demux->s, NULL, i_header_size ) != i_header_size )
505
1
         return VLC_EGENERIC;
506
1.19k
    return VLC_SUCCESS;
507
1.19k
}
508
/*****************************************************************************
509
 * ReadNSVs:
510
 *****************************************************************************/
511
static int ReadNSVs( demux_t *p_demux )
512
4.08k
{
513
4.08k
    demux_sys_t *p_sys = p_demux->p_sys;
514
4.08k
    uint8_t      header[19];
515
4.08k
    vlc_fourcc_t fcc;
516
517
4.08k
    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
4.08k
    switch( ( fcc = VLC_FOURCC( header[4], header[5], header[6], header[7] ) ) )
525
4.08k
    {
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
4.08k
        default:
547
4.08k
            msg_Err( p_demux, "unsupported video codec %4.4s", (char *)&fcc );
548
4.08k
            break;
549
4.08k
    }
550
4.08k
    if( fcc != VLC_FOURCC( 'N', 'O', 'N', 'E' ) && fcc != p_sys->fmt_video.i_codec  )
551
2.70k
    {
552
2.70k
        es_format_Init( &p_sys->fmt_video, VIDEO_ES, fcc );
553
2.70k
        p_sys->fmt_video.video.i_width = GetWLE( &header[12] );
554
2.70k
        p_sys->fmt_video.video.i_height = GetWLE( &header[14] );
555
2.70k
        p_sys->fmt_video.video.i_visible_width = p_sys->fmt_video.video.i_width;
556
2.70k
        p_sys->fmt_video.video.i_visible_height = p_sys->fmt_video.video.i_height;
557
2.70k
        if( p_sys->p_video )
558
2.69k
        {
559
2.69k
            es_out_Del( p_demux->out, p_sys->p_video );
560
2.69k
        }
561
2.70k
        p_sys->p_video = es_out_Add( p_demux->out, &p_sys->fmt_video );
562
563
2.70k
        msg_Dbg( p_demux, "    - video `%4.4s' %dx%d",
564
2.70k
                 (char*)&fcc,
565
2.70k
                 p_sys->fmt_video.video.i_width,
566
2.70k
                 p_sys->fmt_video.video.i_height );
567
2.70k
    }
568
569
    /* Audio */
570
4.08k
    switch( ( fcc = VLC_FOURCC( header[8], header[9], header[10], header[11] ) ) )
571
4.08k
    {
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
4.08k
        default:
588
4.08k
            msg_Err( p_demux, "unsupported audio codec %4.4s", (char *)&fcc );
589
4.08k
            break;
590
4.08k
    }
591
592
4.08k
    if( fcc != VLC_FOURCC( 'N', 'O', 'N', 'E' ) && fcc != p_sys->fmt_audio.i_codec )
593
1.75k
    {
594
1.75k
        msg_Dbg( p_demux, "    - audio `%4.4s'", (char*)&fcc );
595
596
1.75k
        if( p_sys->p_audio )
597
651
        {
598
651
            es_out_Del( p_demux->out, p_sys->p_audio );
599
651
            p_sys->p_audio = NULL;
600
651
        }
601
1.75k
        es_format_Init( &p_sys->fmt_audio, AUDIO_ES, fcc );
602
1.75k
    }
603
604
4.08k
    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
4.08k
    else if( header[16] != 0 )
629
2.01k
    {
630
        /* Integer frame rate */
631
2.01k
        p_sys->i_pcr_inc = vlc_tick_from_samples(1, header[16]);
632
2.01k
    }
633
2.07k
    else
634
2.07k
    {
635
2.07k
        msg_Dbg( p_demux, "invalid fps (0x00)" );
636
2.07k
        p_sys->i_pcr_inc = VLC_TICK_FROM_MS(40);
637
2.07k
    }
638
    //msg_Dbg( p_demux, "    - fps=%.3f", 1000000.0 / (double)p_sys->i_pcr_inc );
639
640
4.08k
    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
4.08k
    return VLC_SUCCESS;
647
4.08k
}