7eabc399088c39c03b3ba5d1b19c54ccd9acd6e9
[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", 3 );
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 = strchr( psz+9, key );\
188         if( buf )\
189         {\
190             char *end = strchr( buf, ' ' );\
191             char *sep;\
192             if( end ) *end = '\0';\
193             sep = strchr( buf, ':' );\
194             if( sep )\
195             {\
196                 *sep = '\0';\
197                 den = atoi( sep+1 );\
198             }\
199             else\
200             {\
201                 den = 1;\
202             }\
203             num = atoi( buf+1 );\
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 = strchr( psz+9, 'C' );
215         if( buf )
216         {
217             char *end = strchr( buf, ' ' );
218             if( end ) *end = '\0';
219             buf++;
220             if( !strncmp( buf, "C420jpeg", 8 ) )
221             {
222                 psz_chroma = strdup( "I420" );
223             }
224             else if( !strncmp( buf, "C420paldv", 9 ) )
225             {
226                 psz_chroma = strdup( "I420" );
227             }
228             else if( !strncmp( buf, "C420", 4 ) )
229             {
230                 psz_chroma = strdup( "I420" );
231             }
232             else if( !strncmp( buf, "C422", 4 ) )
233             {
234                 psz_chroma = strdup( "I422" );
235             }
236             else if( !strncmp( buf, "C444", 4 ) )
237             {
238                 psz_chroma = strdup( "I444" );
239             }
240             else
241             {
242                 msg_Warn( p_demux, "Unknown YUV4MPEG2 chroma type \"%s\"",
243                           buf );
244             }
245             if( end ) *end = ' ';
246         }
247
248         free( psz );
249     }
250
251     if( p_preset && *p_preset->psz_ext )
252     {
253         if( !i_width ) i_width = p_preset->i_width;
254         if( !i_height ) i_height = p_preset->i_height;
255         if( !p_sys->f_fps ) p_sys->f_fps = p_preset->f_fps;
256         if( !*psz_aspect_ratio )
257         {
258             free( psz_aspect_ratio );
259             psz_aspect_ratio = strdup( psz_aspect_ratio );
260         }
261         if( !*psz_chroma )
262         {
263             free( psz_chroma );
264             psz_chroma = strdup( psz_chroma );
265         }
266     }
267
268     if( i_width <= 0 || i_height <= 0 )
269     {
270         msg_Err( p_demux, "width and height must be strictly positive." );
271         free( psz_aspect_ratio );
272         free( psz_chroma );
273         free( p_sys );
274         return VLC_EGENERIC;
275     }
276
277     if( !i_aspect )
278     {
279         if( psz_aspect_ratio && *psz_aspect_ratio )
280         {
281             char *psz_parser = strchr( psz_aspect_ratio, ':' );
282             if( psz_parser )
283             {
284                 *psz_parser++ = '\0';
285                 i_aspect = atoi( psz_aspect_ratio ) * VOUT_ASPECT_FACTOR
286                            / atoi( psz_parser );
287             }
288             else
289             {
290                 i_aspect = atof( psz_aspect_ratio ) * VOUT_ASPECT_FACTOR;
291             }
292         }
293         else
294         {
295             i_aspect = i_width * VOUT_ASPECT_FACTOR / i_height;
296         }
297     }
298     free( psz_aspect_ratio );
299
300     if( psz_chroma && strlen( psz_chroma ) >= 4 )
301     {
302         memcpy( &i_chroma, psz_chroma, 4 );
303         msg_Dbg( p_demux, "Forcing chroma to 0x%.8x (%4.4s)", i_chroma,
304                  (char*)&i_chroma );
305     }
306     else
307     {
308         i_chroma = VLC_FOURCC('Y','V','1','2');
309         msg_Dbg( p_demux, "Using default chroma 0x%.8x (%4.4s)", i_chroma,
310                  (char*)&i_chroma );
311     }
312     free( psz_chroma );
313
314     es_format_Init( &p_sys->fmt_video, VIDEO_ES, i_chroma );
315     vout_InitFormat( &p_sys->fmt_video.video, i_chroma, i_width, i_height,
316                      i_aspect );
317     if( !p_sys->fmt_video.video.i_bits_per_pixel )
318     {
319         msg_Err( p_demux, "Unsupported chroma 0x%.8x (%4.4s)", i_chroma,
320                  (char*)&i_chroma );
321         free( p_sys );
322         return VLC_EGENERIC;
323     }
324     p_sys->frame_size = i_width * i_height
325                         * p_sys->fmt_video.video.i_bits_per_pixel / 8;
326     p_sys->p_es_video = es_out_Add( p_demux->out, &p_sys->fmt_video );
327
328     return VLC_SUCCESS;
329 }
330
331 /*****************************************************************************
332  * Close: frees unused data
333  *****************************************************************************/
334 static void Close( vlc_object_t *p_this )
335 {
336     demux_t     *p_demux = (demux_t*)p_this;
337     demux_sys_t *p_sys  = p_demux->p_sys;
338     free( p_sys );
339 }
340
341 /*****************************************************************************
342  * Demux: reads and demuxes data packets
343  *****************************************************************************
344  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
345  *****************************************************************************/
346 static int Demux( demux_t *p_demux )
347 {
348     demux_sys_t *p_sys  = p_demux->p_sys;
349     block_t     *p_block;
350
351     /* Call the pace control */
352     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
353
354     if( p_sys->b_y4m )
355     {
356         /* Skip the frame header */
357         unsigned char psz_buf[10];
358         psz_buf[9] = '\0';
359         stream_Read( p_demux->s, psz_buf, strlen( "FRAME" ) );
360         while( psz_buf[0] != 0x0a )
361         {
362             if( stream_Read( p_demux->s, psz_buf, 1 ) < 1 )
363                 return 0;
364         }
365     }
366
367     if( ( p_block = stream_Block( p_demux->s, p_sys->frame_size ) ) == NULL )
368     {
369         /* EOF */
370         return 0;
371     }
372
373     p_block->i_dts = p_block->i_pts = p_sys->i_pcr;
374     es_out_Send( p_demux->out, p_sys->p_es_video, p_block );
375
376     p_sys->i_pcr += ( I64C(1000000) / p_sys->f_fps );
377
378     return 1;
379 }
380
381 /*****************************************************************************
382  * Control:
383  *****************************************************************************/
384 static int Control( demux_t *p_demux, int i_query, va_list args )
385 {
386     demux_sys_t *p_sys  = p_demux->p_sys;
387
388     /* XXX: DEMUX_SET_TIME is precise here */
389     return demux2_vaControlHelper( p_demux->s, 0, -1,
390                                    p_sys->frame_size * p_sys->f_fps * 8,
391                                    p_sys->frame_size, i_query, args );
392 }