]> git.sesse.net Git - vlc/blob - modules/demux/rawvid.c
Merge branch 'master' of git@git.videolan.org:vlc
[vlc] / 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( "demux", 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, 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                 true );
75     add_string( "rawvid-aspect-ratio", NULL, NULL,
76                 ASPECT_RATIO_TEXT, ASPECT_RATIO_LONGTEXT, 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     bool 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     bool b_valid = false;
138     bool b_y4m = 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 = true;
146             b_y4m = 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 = 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     if( !p_sys )
169         return VLC_ENOMEM;
170
171     p_sys->i_pcr = 1;
172
173     p_sys->b_y4m = b_y4m;
174     p_sys->f_fps = var_CreateGetFloat( p_demux, "rawvid-fps" );
175     i_width = var_CreateGetInteger( p_demux, "rawvid-width" );
176     i_height = var_CreateGetInteger( p_demux, "rawvid-height" );
177     psz_chroma = var_CreateGetString( p_demux, "rawvid-chroma" );
178     psz_aspect_ratio = var_CreateGetString( p_demux, "rawvid-aspect-ratio" );
179
180     if( b_y4m )
181     {
182         char *psz;
183         char *buf;
184         int a, b = 1;
185         psz = stream_ReadLine( p_demux->s );
186
187         /* TODO: handle interlacing */
188
189 #define READ_FRAC( key, num, den ) \
190         buf = strstr( psz+9, key );\
191         if( buf )\
192         {\
193             char *end = strchr( buf+1, ' ' );\
194             char *sep;\
195             if( end ) *end = '\0';\
196             sep = strchr( buf+1, ':' );\
197             if( sep )\
198             {\
199                 *sep = '\0';\
200                 den = atoi( sep+1 );\
201             }\
202             else\
203             {\
204                 den = 1;\
205             }\
206             num = atoi( buf+2 );\
207             if( sep ) *sep = ':';\
208             if( end ) *end = ' ';\
209         }
210         READ_FRAC( " W", i_width, a )
211         READ_FRAC( " H", i_height, a )
212         READ_FRAC( " F", a, b )
213         p_sys->f_fps = (double)a/(double)b;
214         READ_FRAC( " A", a, b )
215         if( b != 0 ) i_aspect = a * VOUT_ASPECT_FACTOR / b;
216
217         buf = strstr( psz+9, " C" );
218         if( buf )
219         {
220             char *end = strchr( buf+1, ' ' );
221             if( end ) *end = '\0';
222             buf+=2;
223             if( !strncmp( buf, "420jpeg", 7 ) )
224             {
225                 psz_chroma = strdup( "I420" );
226             }
227             else if( !strncmp( buf, "420paldv", 8 ) )
228             {
229                 psz_chroma = strdup( "I420" );
230             }
231             else if( !strncmp( buf, "420", 3 ) )
232             {
233                 psz_chroma = strdup( "I420" );
234             }
235             else if( !strncmp( buf, "422", 3 ) )
236             {
237                 psz_chroma = strdup( "I422" );
238             }
239             else if( !strncmp( buf, "444", 3 ) )
240             {
241                 psz_chroma = strdup( "I444" );
242             }
243             else if( !strncmp( buf, "mono", 4 ) )
244             {
245                 psz_chroma = strdup( "GREY" );
246             }
247             else
248             {
249                 msg_Warn( p_demux, "Unknown YUV4MPEG2 chroma type \"%s\"",
250                           buf );
251             }
252             if( end ) *end = ' ';
253         }
254
255         free( psz );
256     }
257
258     if( p_preset && *p_preset->psz_ext )
259     {
260         if( !i_width ) i_width = p_preset->i_width;
261         if( !i_height ) i_height = p_preset->i_height;
262         if( !p_sys->f_fps ) p_sys->f_fps = p_preset->f_fps;
263         if( !*psz_aspect_ratio )
264         {
265             free( psz_aspect_ratio );
266             psz_aspect_ratio = strdup( psz_aspect_ratio );
267         }
268         if( !*psz_chroma )
269         {
270             free( psz_chroma );
271             psz_chroma = strdup( psz_chroma );
272         }
273     }
274
275     if( i_width <= 0 || i_height <= 0 )
276     {
277         msg_Err( p_demux, "width and height must be strictly positive." );
278         free( psz_aspect_ratio );
279         free( psz_chroma );
280         free( p_sys );
281         return VLC_EGENERIC;
282     }
283
284     if( !i_aspect )
285     {
286         if( psz_aspect_ratio && *psz_aspect_ratio )
287         {
288             char *psz_parser = strchr( psz_aspect_ratio, ':' );
289             if( psz_parser )
290             {
291                 *psz_parser++ = '\0';
292                 i_aspect = atoi( psz_aspect_ratio ) * VOUT_ASPECT_FACTOR
293                            / atoi( psz_parser );
294             }
295             else
296             {
297                 i_aspect = atof( psz_aspect_ratio ) * VOUT_ASPECT_FACTOR;
298             }
299         }
300         else
301         {
302             i_aspect = i_width * VOUT_ASPECT_FACTOR / i_height;
303         }
304     }
305     free( psz_aspect_ratio );
306
307     if( psz_chroma && strlen( psz_chroma ) >= 4 )
308     {
309         memcpy( &i_chroma, psz_chroma, 4 );
310         msg_Dbg( p_demux, "Forcing chroma to 0x%.8x (%4.4s)", i_chroma,
311                  (char*)&i_chroma );
312     }
313     else
314     {
315         i_chroma = VLC_FOURCC('Y','V','1','2');
316         msg_Dbg( p_demux, "Using default chroma 0x%.8x (%4.4s)", i_chroma,
317                  (char*)&i_chroma );
318     }
319     free( psz_chroma );
320
321     es_format_Init( &p_sys->fmt_video, VIDEO_ES, i_chroma );
322     vout_InitFormat( &p_sys->fmt_video.video, i_chroma, i_width, i_height,
323                      i_aspect );
324     if( !p_sys->fmt_video.video.i_bits_per_pixel )
325     {
326         msg_Err( p_demux, "Unsupported chroma 0x%.8x (%4.4s)", i_chroma,
327                  (char*)&i_chroma );
328         free( p_sys );
329         return VLC_EGENERIC;
330     }
331     p_sys->frame_size = i_width * i_height
332                         * p_sys->fmt_video.video.i_bits_per_pixel / 8;
333     p_sys->p_es_video = es_out_Add( p_demux->out, &p_sys->fmt_video );
334
335     return VLC_SUCCESS;
336 }
337
338 /*****************************************************************************
339  * Close: frees unused data
340  *****************************************************************************/
341 static void Close( vlc_object_t *p_this )
342 {
343     demux_t     *p_demux = (demux_t*)p_this;
344     demux_sys_t *p_sys  = p_demux->p_sys;
345     free( p_sys );
346 }
347
348 /*****************************************************************************
349  * Demux: reads and demuxes data packets
350  *****************************************************************************
351  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
352  *****************************************************************************/
353 static int Demux( demux_t *p_demux )
354 {
355     demux_sys_t *p_sys  = p_demux->p_sys;
356     block_t     *p_block;
357
358     /* Call the pace control */
359     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
360
361     if( p_sys->b_y4m )
362     {
363         /* Skip the frame header */
364         unsigned char psz_buf[10];
365         psz_buf[9] = '\0';
366         stream_Read( p_demux->s, psz_buf, strlen( "FRAME" ) );
367         while( psz_buf[0] != 0x0a )
368         {
369             if( stream_Read( p_demux->s, psz_buf, 1 ) < 1 )
370                 return 0;
371         }
372     }
373
374     if( ( p_block = stream_Block( p_demux->s, p_sys->frame_size ) ) == NULL )
375     {
376         /* EOF */
377         return 0;
378     }
379
380     p_block->i_dts = p_block->i_pts = p_sys->i_pcr;
381     es_out_Send( p_demux->out, p_sys->p_es_video, p_block );
382
383     p_sys->i_pcr += ( I64C(1000000) / p_sys->f_fps );
384
385     return 1;
386 }
387
388 /*****************************************************************************
389  * Control:
390  *****************************************************************************/
391 static int Control( demux_t *p_demux, int i_query, va_list args )
392 {
393     demux_sys_t *p_sys  = p_demux->p_sys;
394
395     /* XXX: DEMUX_SET_TIME is precise here */
396     return demux_vaControlHelper( p_demux->s, 0, -1,
397                                    p_sys->frame_size * p_sys->f_fps * 8,
398                                    p_sys->frame_size, i_query, args );
399 }