]> git.sesse.net Git - vlc/blob - modules/demux/nsv.c
http access: Use EnsureUTF8() on the ICY strings. Avoids "illegal byte sequence"...
[vlc] / modules / demux / nsv.c
1 /*****************************************************************************
2  * nsv.c: NullSoft Video demuxer.
3  *****************************************************************************
4  * Copyright (C) 2004-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
35
36 /* TODO:
37  *  - implement NSVf parsing (to get meta data)
38  *  - implement missing Control (and in the right way)
39  *  - ...
40  */
41
42 /*****************************************************************************
43  * Module descriptor
44  *****************************************************************************/
45 static int  Open    ( vlc_object_t * );
46 static void Close  ( vlc_object_t * );
47
48 vlc_module_begin();
49     set_description( N_("NullSoft demuxer" ) );
50     set_capability( "demux", 10 );
51     set_category( CAT_INPUT );
52     set_subcategory( SUBCAT_INPUT_DEMUX );
53     set_callbacks( Open, Close );
54     add_shortcut( "nsv" );
55 vlc_module_end();
56
57 /*****************************************************************************
58  * Local prototypes
59  *****************************************************************************/
60
61 struct demux_sys_t
62 {
63     es_format_t  fmt_audio;
64     es_out_id_t *p_audio;
65
66     es_format_t  fmt_video;
67     es_out_id_t *p_video;
68
69     es_format_t  fmt_sub;
70     es_out_id_t  *p_sub;
71
72     int64_t     i_pcr;
73     int64_t     i_time;
74     int64_t     i_pcr_inc;
75 };
76
77 static int Demux  ( demux_t *p_demux );
78 static int Control( demux_t *p_demux, int i_query, va_list args );
79
80 static int ReSynch( demux_t *p_demux );
81
82 static int ReadNSVf( demux_t *p_demux );
83 static int ReadNSVs( demux_t *p_demux );
84
85 /*****************************************************************************
86  * Open
87  *****************************************************************************/
88 static int Open( vlc_object_t *p_this )
89 {
90     demux_t     *p_demux = (demux_t*)p_this;
91     demux_sys_t *p_sys;
92
93     const uint8_t *p_peek;
94
95     if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
96         return VLC_EGENERIC;
97
98     if( memcmp( p_peek, "NSVf", 4 ) && memcmp( p_peek, "NSVs", 4 ) )
99     {
100        /* In case we had force this demuxer we try to resynch */
101         if( !p_demux->b_force || ReSynch( p_demux ) )
102             return VLC_EGENERIC;
103     }
104
105     /* Fill p_demux field */
106     p_demux->pf_demux = Demux;
107     p_demux->pf_control = Control;
108     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
109
110     es_format_Init( &p_sys->fmt_audio, AUDIO_ES, 0 );
111     p_sys->p_audio = NULL;
112
113     es_format_Init( &p_sys->fmt_video, VIDEO_ES, 0 );
114     p_sys->p_video = NULL;
115
116     es_format_Init( &p_sys->fmt_sub, SPU_ES, 0 );
117     p_sys->p_sub = NULL;
118
119     p_sys->i_pcr   = 1;
120     p_sys->i_time  = 0;
121     p_sys->i_pcr_inc = 0;
122
123     return VLC_SUCCESS;
124 }
125
126 /*****************************************************************************
127  * Close
128  *****************************************************************************/
129 static void Close( vlc_object_t *p_this )
130 {
131     demux_t     *p_demux = (demux_t*)p_this;
132     demux_sys_t *p_sys = p_demux->p_sys;
133
134     free( p_sys );
135 }
136
137
138 /*****************************************************************************
139  * Demux:
140  *****************************************************************************/
141 static int Demux( demux_t *p_demux )
142 {
143     demux_sys_t *p_sys = p_demux->p_sys;
144
145     uint8_t     header[5];
146     const uint8_t *p_peek;
147
148     int         i_size;
149     block_t     *p_frame;
150
151     for( ;; )
152     {
153         if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
154         {
155             msg_Warn( p_demux, "cannot peek" );
156             return 0;
157         }
158
159         if( !memcmp( p_peek, "NSVf", 4 ) )
160         {
161             if( ReadNSVf( p_demux ) )
162             {
163                 return -1;
164             }
165         }
166         else if( !memcmp( p_peek, "NSVs", 4 ) )
167         {
168             if( ReadNSVs( p_demux ) )
169             {
170                 return -1;
171             }
172             break;
173         }
174         else if( GetWLE( p_peek ) == 0xbeef )
175         {
176             /* Next frame of the current NSVs chunk */
177             if( stream_Read( p_demux->s, NULL, 2 ) < 2 )
178             {
179                 msg_Warn( p_demux, "cannot read" );
180                 return 0;
181             }
182             break;
183         }
184         else
185         {
186             msg_Err( p_demux, "invalid signature 0x%x (%4.4s)", GetDWLE( p_peek ), (const char*)p_peek );
187             if( ReSynch( p_demux ) )
188             {
189                 return -1;
190             }
191         }
192     }
193
194     if( stream_Read( p_demux->s, header, 5 ) < 5 )
195     {
196         msg_Warn( p_demux, "cannot read" );
197         return 0;
198     }
199
200     /* Set PCR */
201     es_out_Control( p_demux->out, ES_OUT_SET_PCR, (int64_t)p_sys->i_pcr );
202
203     /* Read video */
204     i_size = ( header[0] >> 4 ) | ( header[1] << 4 ) | ( header[2] << 12 );
205     if( i_size > 0 )
206     {
207         /* extra data ? */
208         if( (header[0]&0x0f) != 0x0 )
209         {
210             uint8_t      aux[6];
211             int          i_aux;
212             vlc_fourcc_t fcc;
213             if( stream_Read( p_demux->s, aux, 6 ) < 6 )
214             {
215                 msg_Warn( p_demux, "cannot read" );
216                 return 0;
217             }
218             i_aux = GetWLE( aux );
219             fcc   = VLC_FOURCC( aux[2], aux[3], aux[4], aux[5] );
220
221             msg_Dbg( p_demux, "Belekas: %d - size=%d fcc=%4.4s",
222                      header[0]&0xf, i_aux, (char*)&fcc );
223
224             if( fcc == VLC_FOURCC( 'S', 'U', 'B', 'T' ) && i_aux > 2 )
225             {
226                 if( p_sys->p_sub == NULL )
227                 {
228                     p_sys->fmt_sub.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
229                     p_sys->p_sub = es_out_Add( p_demux->out, &p_sys->fmt_sub );
230                     es_out_Control( p_demux->out, ES_OUT_SET_ES, p_sys->p_sub );
231                 }
232                 stream_Read( p_demux->s, NULL, 2 );
233
234                 if( ( p_frame = stream_Block( p_demux->s, i_aux - 2 ) ) )
235                 {
236                     uint8_t *p = p_frame->p_buffer;
237
238                     while( p < &p_frame->p_buffer[p_frame->i_buffer] && *p != 0 )
239                     {
240                         p++;
241                     }
242                     if( *p == 0 && p + 1 < &p_frame->p_buffer[p_frame->i_buffer] )
243                     {
244                         p_frame->i_buffer -= p + 1 - p_frame->p_buffer;
245                         p_frame->p_buffer = p + 1;
246                     }
247
248                     /* Skip the first part (it is the language name) */
249                     p_frame->i_pts = p_sys->i_pcr;
250                     p_frame->i_dts = p_sys->i_pcr + 4000000;    /* 4s */
251
252                     es_out_Send( p_demux->out, p_sys->p_sub, p_frame );
253                 }
254             }
255             else
256             {
257                 /* We skip this extra data */
258                 if( stream_Read( p_demux->s, NULL, i_aux ) < i_aux )
259                 {
260                     msg_Warn( p_demux, "cannot read" );
261                     return 0;
262                 }
263             }
264             i_size -= 6 + i_aux;
265         }
266
267         /* msg_Dbg( p_demux, "frame video size=%d", i_size ); */
268         if( i_size > 0 && ( p_frame = stream_Block( p_demux->s, i_size ) ) )
269         {
270             p_frame->i_dts = p_sys->i_pcr;
271             es_out_Send( p_demux->out, p_sys->p_video, p_frame );
272         }
273     }
274
275     /* Read audio */
276     i_size = header[3] | ( header[4] << 8 );
277     if( i_size > 0 )
278     {
279         /* msg_Dbg( p_demux, "frame audio size=%d", i_size ); */
280         if( p_sys->fmt_audio.i_codec == VLC_FOURCC( 'a', 'r', 'a', 'w' ) )
281         {
282             uint8_t h[4];
283             stream_Read( p_demux->s, h, 4 );
284
285             p_sys->fmt_audio.audio.i_channels = h[1];
286             p_sys->fmt_audio.audio.i_rate = GetWLE( &h[2] );
287
288             i_size -= 4;
289         }
290         if( p_sys->p_audio == NULL )
291         {
292             p_sys->p_audio = es_out_Add( p_demux->out, &p_sys->fmt_audio );
293         }
294
295         if( ( p_frame = stream_Block( p_demux->s, i_size ) ) )
296         {
297             p_frame->i_dts =
298             p_frame->i_pts = p_sys->i_pcr;
299             es_out_Send( p_demux->out, p_sys->p_audio, p_frame );
300         }
301     }
302
303     p_sys->i_pcr += p_sys->i_pcr_inc;
304     if( p_sys->i_time >= 0 )
305     {
306         p_sys->i_time += p_sys->i_pcr_inc;
307     }
308
309     return 1;
310 }
311
312 /*****************************************************************************
313  * Control:
314  *****************************************************************************/
315 static int Control( demux_t *p_demux, int i_query, va_list args )
316 {
317     demux_sys_t *p_sys = p_demux->p_sys;
318     double f, *pf;
319     int64_t i64, *pi64;
320
321     switch( i_query )
322     {
323         case DEMUX_GET_POSITION:
324             pf = (double*) va_arg( args, double* );
325             i64 = stream_Size( p_demux->s );
326             if( i64 > 0 )
327             {
328                 *pf = (double)stream_Tell( p_demux->s ) / (double)i64;
329             }
330             else
331             {
332                 *pf = 0.0;
333             }
334             return VLC_SUCCESS;
335
336         case DEMUX_SET_POSITION:
337             f = (double) va_arg( args, double );
338             i64 = stream_Size( p_demux->s );
339
340             es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
341             if( stream_Seek( p_demux->s, (int64_t)(i64 * f) ) || ReSynch( p_demux ) )
342             {
343                 return VLC_EGENERIC;
344             }
345             p_sys->i_time = -1; /* Invalidate time display */
346             return VLC_SUCCESS;
347
348         case DEMUX_GET_TIME:
349             pi64 = (int64_t*)va_arg( args, int64_t * );
350             if( p_sys->i_time < 0 )
351             {
352                 *pi64 = 0;
353                 return VLC_EGENERIC;
354             }
355             *pi64 = p_sys->i_time;
356             return VLC_SUCCESS;
357
358 #if 0
359         case DEMUX_GET_LENGTH:
360             pi64 = (int64_t*)va_arg( args, int64_t * );
361             if( p_sys->i_mux_rate > 0 )
362             {
363                 *pi64 = (int64_t)1000000 * ( stream_Size( p_demux->s ) / 50 ) / p_sys->i_mux_rate;
364                 return VLC_SUCCESS;
365             }
366             *pi64 = 0;
367             return VLC_EGENERIC;
368
369 #endif
370         case DEMUX_GET_FPS:
371             pf = (double*)va_arg( args, double * );
372             *pf = (double)1000000.0 / (double)p_sys->i_pcr_inc;
373             return VLC_SUCCESS;
374
375         case DEMUX_SET_TIME:
376         default:
377             return VLC_EGENERIC;
378     }
379 }
380
381 /*****************************************************************************
382  * ReSynch:
383  *****************************************************************************/
384 static int ReSynch( demux_t *p_demux )
385 {
386     const uint8_t *p_peek;
387     int      i_skip;
388     int      i_peek;
389
390     while( vlc_object_alive (p_demux) )
391     {
392         if( ( i_peek = stream_Peek( p_demux->s, &p_peek, 1024 ) ) < 8 )
393         {
394             return VLC_EGENERIC;
395         }
396         i_skip = 0;
397
398         while( i_skip < i_peek - 4 )
399         {
400             if( !memcmp( p_peek, "NSVf", 4 )
401              || !memcmp( p_peek, "NSVs", 4 ) )
402             {
403                 if( i_skip > 0 )
404                 {
405                     stream_Read( p_demux->s, NULL, i_skip );
406                 }
407                 return VLC_SUCCESS;
408             }
409             p_peek++;
410             i_skip++;
411         }
412
413         stream_Read( p_demux->s, NULL, i_skip );
414     }
415     return VLC_EGENERIC;
416 }
417
418 /*****************************************************************************
419  * ReadNSVf:
420  *****************************************************************************/
421 static int ReadNSVf( demux_t *p_demux )
422 {
423     /* demux_sys_t *p_sys = p_demux->p_sys; */
424     const uint8_t     *p;
425     int         i_size;
426
427     msg_Dbg( p_demux, "new NSVf chunk" );
428     if( stream_Peek( p_demux->s, &p, 8 ) < 8 )
429     {
430         return VLC_EGENERIC;
431     }
432
433     i_size = GetDWLE( &p[4] );
434     msg_Dbg( p_demux, "    - size=%d", i_size );
435
436     return stream_Read( p_demux->s, NULL, i_size ) == i_size ? VLC_SUCCESS : VLC_EGENERIC;
437 }
438 /*****************************************************************************
439  * ReadNSVf:
440  *****************************************************************************/
441 static int ReadNSVs( demux_t *p_demux )
442 {
443     demux_sys_t *p_sys = p_demux->p_sys;
444     uint8_t      header[19];
445     vlc_fourcc_t fcc;
446
447     if( stream_Read( p_demux->s, header, 19 ) < 19 )
448     {
449         msg_Warn( p_demux, "cannot read" );
450         return VLC_EGENERIC;
451     }
452
453     /* Video */
454     switch( ( fcc = VLC_FOURCC( header[4], header[5], header[6], header[7] ) ) )
455     {
456         case VLC_FOURCC( 'V', 'P', '3', ' ' ):
457         case VLC_FOURCC( 'V', 'P', '3', '1' ):
458             fcc = VLC_FOURCC( 'V', 'P', '3', '1' );
459             break;
460         case VLC_FOURCC( 'V', 'P', '6', '0' ):
461         case VLC_FOURCC( 'V', 'P', '6', '1' ):
462         case VLC_FOURCC( 'V', 'P', '6', '2' ):
463         case VLC_FOURCC( 'H', '2', '6', '4' ):
464         case VLC_FOURCC( 'N', 'O', 'N', 'E' ):
465             break;
466         default:
467             msg_Warn( p_demux, "unknown codec %4.4s", (char *)&fcc );
468             break;
469     }
470     if( fcc != VLC_FOURCC( 'N', 'O', 'N', 'E' ) && fcc != p_sys->fmt_video.i_codec  )
471     {
472         es_format_Init( &p_sys->fmt_video, VIDEO_ES, fcc );
473         p_sys->fmt_video.video.i_width = GetWLE( &header[12] );
474         p_sys->fmt_video.video.i_height = GetWLE( &header[14] );
475         if( p_sys->p_video )
476         {
477             es_out_Del( p_demux->out, p_sys->p_video );
478         }
479         p_sys->p_video = es_out_Add( p_demux->out, &p_sys->fmt_video );
480
481         msg_Dbg( p_demux, "    - video `%4.4s' %dx%d",
482                  (char*)&fcc,
483                  p_sys->fmt_video.video.i_width,
484                  p_sys->fmt_video.video.i_height );
485     }
486
487     /* Audio */
488     switch( ( fcc = VLC_FOURCC( header[8], header[9], header[10], header[11] ) ) )
489     {
490         case VLC_FOURCC( 'M', 'P', '3', ' ' ):
491             fcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
492             break;
493         case VLC_FOURCC( 'P', 'C', 'M', ' ' ):
494             fcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
495             break;
496         case VLC_FOURCC( 'A', 'A', 'C', ' ' ):
497         case VLC_FOURCC( 'A', 'A', 'C', 'P' ):
498             fcc = VLC_FOURCC( 'm', 'p', '4', 'a' );
499             break;
500         case VLC_FOURCC( 'N', 'O', 'N', 'E' ):
501             break;
502         default:
503             msg_Warn( p_demux, "unknown codec %4.4s", (char *)&fcc );
504             break;
505     }
506
507     if( fcc != VLC_FOURCC( 'N', 'O', 'N', 'E' ) && fcc != p_sys->fmt_audio.i_codec )
508     {
509         msg_Dbg( p_demux, "    - audio `%4.4s'", (char*)&fcc );
510
511         if( p_sys->p_audio )
512         {
513             es_out_Del( p_demux->out, p_sys->p_audio );
514             p_sys->p_audio = NULL;
515         }
516         es_format_Init( &p_sys->fmt_audio, AUDIO_ES, fcc );
517     }
518
519     if( header[16]&0x80 )
520     {
521         /* Fractional frame rate */
522         switch( header[16]&0x03 )
523         {
524             case 0: /* 30 fps */
525                 p_sys->i_pcr_inc = 33333; /* 300000/9 */
526                 break;
527             case 1: /* 29.97 fps */
528                 p_sys->i_pcr_inc = 33367; /* 300300/9 */
529                 break;
530             case 2: /* 25 fps */
531                 p_sys->i_pcr_inc = 40000; /* 360000/9 */
532                 break;
533             case 3: /* 23.98 fps */
534                 p_sys->i_pcr_inc = 41700; /* 375300/9 */
535                 break;
536         }
537
538         if( header[16] < 0xc0 )
539             p_sys->i_pcr_inc = p_sys->i_pcr_inc * (((header[16] ^ 0x80) >> 2 ) +1 );
540         else
541             p_sys->i_pcr_inc = p_sys->i_pcr_inc / (((header[16] ^ 0xc0) >> 2 ) +1 );
542     }
543     else if( header[16] != 0 )
544     {
545         /* Integer frame rate */
546         p_sys->i_pcr_inc = 1000000 / header[16];
547     }
548     else
549     {
550         msg_Dbg( p_demux, "invalid fps (0x00)" );
551         p_sys->i_pcr_inc = 40000;
552     }
553     //msg_Dbg( p_demux, "    - fps=%.3f", 1000000.0 / (double)p_sys->i_pcr_inc );
554
555     return VLC_SUCCESS;
556 }
557