Fix issues with the VLC rawvid demux and bump it's priority.
[vlc.git] / modules / demux / rawvid.c
1 /*****************************************************************************
2  * rawvid.c : raw video input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *          Antoine Cellerier <dionoea at videolan d.t org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc/vlc.h>
34 #include <vlc_demux.h>
35 #include <vlc_vout.h>                                     /* vout_InitFormat */
36
37 /*****************************************************************************
38  * Module descriptor
39  *****************************************************************************/
40 static int  Open ( vlc_object_t * );
41 static void Close( vlc_object_t * );
42
43 #define FPS_TEXT N_("Frames per Second")
44 #define FPS_LONGTEXT N_("This is the desired frame rate when " \
45     "playing raw video streams.")
46
47 #define WIDTH_TEXT N_("Width")
48 #define WIDTH_LONGTEXT N_("This specifies the width in pixels of the raw " \
49     "video stream.")
50
51 #define HEIGHT_TEXT N_("Height")
52 #define HEIGHT_LONGTEXT N_("This specifies the height in pixels of the raw " \
53     "video stream.")
54
55 #define CHROMA_TEXT N_("Force chroma (Use carefully)")
56 #define CHROMA_LONGTEXT N_("Force chroma. This is a four character string.")
57
58 #define ASPECT_RATIO_TEXT N_("Aspect ratio")
59 #define ASPECT_RATIO_LONGTEXT N_( \
60     "Aspect ratio (4:3, 16:9). Default is square pixels." )
61
62 vlc_module_begin();
63     set_shortname( "Raw Video" );
64     set_description( _("Raw video demuxer") );
65     set_capability( "demux2", 10 );
66     set_category( CAT_INPUT );
67     set_subcategory( SUBCAT_INPUT_DEMUX );
68     set_callbacks( Open, Close );
69     add_shortcut( "rawvideo" );
70     add_float( "rawvid-fps", 0, 0, FPS_TEXT, FPS_LONGTEXT, VLC_FALSE );
71     add_integer( "rawvid-width", 0, 0, WIDTH_TEXT, WIDTH_LONGTEXT, 0 );
72     add_integer( "rawvid-height", 0, 0, HEIGHT_TEXT, HEIGHT_LONGTEXT, 0 );
73     add_string( "rawvid-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
74                 VLC_TRUE );
75     add_string( "rawvid-aspect-ratio", NULL, NULL,
76                 ASPECT_RATIO_TEXT, ASPECT_RATIO_LONGTEXT, VLC_TRUE );
77 vlc_module_end();
78
79 /*****************************************************************************
80  * Definitions of structures used by this plugin
81  *****************************************************************************/
82 struct demux_sys_t
83 {
84     int    frame_size;
85     float  f_fps;
86
87     es_out_id_t *p_es_video;
88     es_format_t  fmt_video;
89
90     mtime_t i_pcr;
91
92     vlc_bool_t b_y4m;
93 };
94
95 /*****************************************************************************
96  * Local prototypes
97  *****************************************************************************/
98 static int Demux( demux_t * );
99 static int Control( demux_t *, int i_query, va_list args );
100
101 struct preset_t
102 {
103     const char *psz_ext;
104     int i_width;
105     int i_height;
106     double f_fps;
107     const char *psz_aspect_ratio;
108     const char *psz_chroma;
109 };
110
111 static struct preset_t p_presets[] =
112 {
113     { "sqcif", 128, 96, 29.97, "4:3", "YV12" },
114     { "qcif", 176, 144, 29.97, "4:3", "YV12" },
115     { "cif", 352, 288, 29.97, "4:3", "YV12" },
116     { "4cif", 704, 576, 29.97, "4:3", "YV12" },
117     { "16cif", 1408, 1152, 29.97, "4:3", "YV12" },
118     { "yuv", 176, 144, 25, "4:3", "YV12" },
119     { "", 0, 0, 0., "", "" }
120 };
121
122 /*****************************************************************************
123  * Open: initializes raw DV demux structures
124  *****************************************************************************/
125 static int Open( vlc_object_t * p_this )
126 {
127     demux_t     *p_demux = (demux_t*)p_this;
128     demux_sys_t *p_sys;
129     int i_width, i_height;
130     char *psz_ext;
131     char *psz_chroma;
132     uint32_t i_chroma;
133     char *psz_aspect_ratio;
134     unsigned int i_aspect = 0;
135     struct preset_t *p_preset = NULL;
136     const uint8_t *p_peek;
137     vlc_bool_t b_valid = VLC_FALSE;
138     vlc_bool_t b_y4m = VLC_FALSE;
139
140     if( stream_Peek( p_demux->s, &p_peek, 9 ) == 9 )
141     {
142         /* http://wiki.multimedia.cx/index.php?title=YUV4MPEG2 */
143         if( !strncmp( (char *)p_peek, "YUV4MPEG2", 9 ) )
144         {
145             b_valid = VLC_TRUE;
146             b_y4m = VLC_TRUE;
147         }
148     }
149
150     psz_ext = strrchr( p_demux->psz_path, '.' );
151     if( psz_ext )
152     {
153         psz_ext++;
154         for( p_preset = p_presets; *p_preset->psz_ext; p_preset++ )
155             if( !strcasecmp( psz_ext, p_preset->psz_ext ) )
156             {
157                 b_valid = VLC_TRUE;
158                 break;
159             }
160     }
161     if( !b_valid && !p_demux->b_force )
162         return VLC_EGENERIC;
163
164     /* Set p_input field */
165     p_demux->pf_demux   = Demux;
166     p_demux->pf_control = Control;
167     p_demux->p_sys      = p_sys = malloc( sizeof( demux_sys_t ) );
168     p_sys->i_pcr = 1;
169
170     p_sys->b_y4m = b_y4m;
171     p_sys->f_fps = var_CreateGetFloat( p_demux, "rawvid-fps" );
172     i_width = var_CreateGetInteger( p_demux, "rawvid-width" );
173     i_height = var_CreateGetInteger( p_demux, "rawvid-height" );
174     psz_chroma = var_CreateGetString( p_demux, "rawvid-chroma" );
175     psz_aspect_ratio = var_CreateGetString( p_demux, "rawvid-aspect-ratio" );
176
177     if( b_y4m )
178     {
179         char *psz;
180         char *buf;
181         int a, b;
182         psz = stream_ReadLine( p_demux->s );
183
184         /* TODO: handle interlacing */
185
186 #define READ_FRAC( key, num, den ) \
187         buf = strstr( psz+9, key );\
188         if( buf )\
189         {\
190             char *end = strchr( buf+1, ' ' );\
191             char *sep;\
192             if( end ) *end = '\0';\
193             sep = strchr( buf+1, ':' );\
194             if( sep )\
195             {\
196                 *sep = '\0';\
197                 den = atoi( sep+1 );\
198             }\
199             else\
200             {\
201                 den = 1;\
202             }\
203             num = atoi( buf+2 );\
204             if( sep ) *sep = ':';\
205             if( end ) *end = ' ';\
206         }
207         READ_FRAC( " W", i_width, a )
208         READ_FRAC( " H", i_height, a )
209         READ_FRAC( " F", a, b )
210         p_sys->f_fps = (double)a/(double)b;
211         READ_FRAC( " A", a, b )
212         if( b != 0 ) i_aspect = a * VOUT_ASPECT_FACTOR / b;
213
214         buf = strstr( psz+9, " C" );
215         if( buf )
216         {
217             char *end = strchr( buf+1, ' ' );
218             if( end ) *end = '\0';
219             buf+=2;
220             if( !strncmp( buf, "420jpeg", 7 ) )
221             {
222                 psz_chroma = strdup( "I420" );
223             }
224             else if( !strncmp( buf, "420paldv", 8 ) )
225             {
226                 psz_chroma = strdup( "I420" );
227             }
228             else if( !strncmp( buf, "420", 3 ) )
229             {
230                 psz_chroma = strdup( "I420" );
231             }
232             else if( !strncmp( buf, "422", 3 ) )
233             {
234                 psz_chroma = strdup( "I422" );
235             }
236             else if( !strncmp( buf, "444", 3 ) )
237             {
238                 psz_chroma = strdup( "I444" );
239             }
240             else if( !strncmp( buf, "mono", 3 ) )
241             {
242                 psz_chroma = strdup( "GREY" );
243             }
244             else
245             {
246                 msg_Warn( p_demux, "Unknown YUV4MPEG2 chroma type \"%s\"",
247                           buf );
248             }
249             if( end ) *end = ' ';
250         }
251
252         free( psz );
253     }
254
255     if( p_preset && *p_preset->psz_ext )
256     {
257         if( !i_width ) i_width = p_preset->i_width;
258         if( !i_height ) i_height = p_preset->i_height;
259         if( !p_sys->f_fps ) p_sys->f_fps = p_preset->f_fps;
260         if( !*psz_aspect_ratio )
261         {
262             free( psz_aspect_ratio );
263             psz_aspect_ratio = strdup( psz_aspect_ratio );
264         }
265         if( !*psz_chroma )
266         {
267             free( psz_chroma );
268             psz_chroma = strdup( psz_chroma );
269         }
270     }
271
272     if( i_width <= 0 || i_height <= 0 )
273     {
274         msg_Err( p_demux, "width and height must be strictly positive." );
275         free( psz_aspect_ratio );
276         free( psz_chroma );
277         free( p_sys );
278         return VLC_EGENERIC;
279     }
280
281     if( !i_aspect )
282     {
283         if( psz_aspect_ratio && *psz_aspect_ratio )
284         {
285             char *psz_parser = strchr( psz_aspect_ratio, ':' );
286             if( psz_parser )
287             {
288                 *psz_parser++ = '\0';
289                 i_aspect = atoi( psz_aspect_ratio ) * VOUT_ASPECT_FACTOR
290                            / atoi( psz_parser );
291             }
292             else
293             {
294                 i_aspect = atof( psz_aspect_ratio ) * VOUT_ASPECT_FACTOR;
295             }
296         }
297         else
298         {
299             i_aspect = i_width * VOUT_ASPECT_FACTOR / i_height;
300         }
301     }
302     free( psz_aspect_ratio );
303
304     if( psz_chroma && strlen( psz_chroma ) >= 4 )
305     {
306         memcpy( &i_chroma, psz_chroma, 4 );
307         msg_Dbg( p_demux, "Forcing chroma to 0x%.8x (%4.4s)", i_chroma,
308                  (char*)&i_chroma );
309     }
310     else
311     {
312         i_chroma = VLC_FOURCC('Y','V','1','2');
313         msg_Dbg( p_demux, "Using default chroma 0x%.8x (%4.4s)", i_chroma,
314                  (char*)&i_chroma );
315     }
316     free( psz_chroma );
317
318     es_format_Init( &p_sys->fmt_video, VIDEO_ES, i_chroma );
319     vout_InitFormat( &p_sys->fmt_video.video, i_chroma, i_width, i_height,
320                      i_aspect );
321     if( !p_sys->fmt_video.video.i_bits_per_pixel )
322     {
323         msg_Err( p_demux, "Unsupported chroma 0x%.8x (%4.4s)", i_chroma,
324                  (char*)&i_chroma );
325         free( p_sys );
326         return VLC_EGENERIC;
327     }
328     p_sys->frame_size = i_width * i_height
329                         * p_sys->fmt_video.video.i_bits_per_pixel / 8;
330     p_sys->p_es_video = es_out_Add( p_demux->out, &p_sys->fmt_video );
331
332     return VLC_SUCCESS;
333 }
334
335 /*****************************************************************************
336  * Close: frees unused data
337  *****************************************************************************/
338 static void Close( vlc_object_t *p_this )
339 {
340     demux_t     *p_demux = (demux_t*)p_this;
341     demux_sys_t *p_sys  = p_demux->p_sys;
342     free( p_sys );
343 }
344
345 /*****************************************************************************
346  * Demux: reads and demuxes data packets
347  *****************************************************************************
348  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
349  *****************************************************************************/
350 static int Demux( demux_t *p_demux )
351 {
352     demux_sys_t *p_sys  = p_demux->p_sys;
353     block_t     *p_block;
354
355     /* Call the pace control */
356     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
357
358     if( p_sys->b_y4m )
359     {
360         /* Skip the frame header */
361         unsigned char psz_buf[10];
362         psz_buf[9] = '\0';
363         stream_Read( p_demux->s, psz_buf, strlen( "FRAME" ) );
364         while( psz_buf[0] != 0x0a )
365         {
366             if( stream_Read( p_demux->s, psz_buf, 1 ) < 1 )
367                 return 0;
368         }
369     }
370
371     if( ( p_block = stream_Block( p_demux->s, p_sys->frame_size ) ) == NULL )
372     {
373         /* EOF */
374         return 0;
375     }
376
377     p_block->i_dts = p_block->i_pts = p_sys->i_pcr;
378     es_out_Send( p_demux->out, p_sys->p_es_video, p_block );
379
380     p_sys->i_pcr += ( I64C(1000000) / p_sys->f_fps );
381
382     return 1;
383 }
384
385 /*****************************************************************************
386  * Control:
387  *****************************************************************************/
388 static int Control( demux_t *p_demux, int i_query, va_list args )
389 {
390     demux_sys_t *p_sys  = p_demux->p_sys;
391
392     /* XXX: DEMUX_SET_TIME is precise here */
393     return demux2_vaControlHelper( p_demux->s, 0, -1,
394                                    p_sys->frame_size * p_sys->f_fps * 8,
395                                    p_sys->frame_size, i_query, args );
396 }