/src/vlc/modules/demux/rawvid.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * rawvid.c : raw video input module for vlc |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2007 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Gildas Bazin <gbazin@videolan.org> |
7 | | * Antoine Cellerier <dionoea at videolan d.t org> |
8 | | * |
9 | | * This program is free software; you can redistribute it and/or modify it |
10 | | * under the terms of the GNU Lesser General Public License as published by |
11 | | * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with this program; if not, write to the Free Software Foundation, |
21 | | * 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 | | /***************************************************************************** |
37 | | * Module descriptor |
38 | | *****************************************************************************/ |
39 | | static int Open ( vlc_object_t * ); |
40 | | static void Close( vlc_object_t * ); |
41 | | |
42 | | #define FPS_TEXT N_("Frames per Second") |
43 | | #define FPS_LONGTEXT N_("This is the desired frame rate when " \ |
44 | | "playing raw video streams. In the form 30000/1001 or 29.97") |
45 | | |
46 | | #define WIDTH_TEXT N_("Width") |
47 | | #define WIDTH_LONGTEXT N_("This specifies the width in pixels of the raw " \ |
48 | | "video stream.") |
49 | | |
50 | | #define HEIGHT_TEXT N_("Height") |
51 | | #define HEIGHT_LONGTEXT N_("This specifies the height in pixels of the raw " \ |
52 | | "video stream.") |
53 | | |
54 | | #define CHROMA_TEXT N_("Force chroma (Use carefully)") |
55 | | #define CHROMA_LONGTEXT N_("Force chroma. This is a four character string.") |
56 | | |
57 | | #define ASPECT_RATIO_TEXT N_("Aspect ratio") |
58 | | #define ASPECT_RATIO_LONGTEXT N_( \ |
59 | | "Aspect ratio (4:3, 16:9). Default assumes square pixels." ) |
60 | | |
61 | 108 | vlc_module_begin () |
62 | 54 | set_shortname( "Raw Video" ) |
63 | 54 | set_description( N_("Raw video demuxer") ) |
64 | 54 | set_capability( "demux", 10 ) |
65 | 54 | set_subcategory( SUBCAT_INPUT_DEMUX ) |
66 | 54 | set_callbacks( Open, Close ) |
67 | 54 | add_shortcut( "rawvideo" ) |
68 | 54 | add_string( "rawvid-fps", NULL, FPS_TEXT, FPS_LONGTEXT ) |
69 | 54 | add_integer( "rawvid-width", 0, WIDTH_TEXT, WIDTH_LONGTEXT ) |
70 | 54 | add_integer( "rawvid-height", 0, HEIGHT_TEXT, HEIGHT_LONGTEXT ) |
71 | 54 | add_string( "rawvid-chroma", NULL, CHROMA_TEXT, CHROMA_LONGTEXT ) |
72 | 54 | add_string( "rawvid-aspect-ratio", NULL, |
73 | 54 | ASPECT_RATIO_TEXT, ASPECT_RATIO_LONGTEXT ) |
74 | 54 | vlc_module_end () |
75 | | |
76 | | /***************************************************************************** |
77 | | * Definitions of structures used by this plugin |
78 | | *****************************************************************************/ |
79 | | typedef struct |
80 | | { |
81 | | int frame_size; |
82 | | |
83 | | es_out_id_t *p_es_video; |
84 | | es_format_t fmt_video; |
85 | | |
86 | | date_t pcr; |
87 | | |
88 | | bool b_y4m; |
89 | | } demux_sys_t; |
90 | | |
91 | | /***************************************************************************** |
92 | | * Local prototypes |
93 | | *****************************************************************************/ |
94 | | static int Demux( demux_t * ); |
95 | | static int Control( demux_t *, int i_query, va_list args ); |
96 | | |
97 | | struct preset_t |
98 | | { |
99 | | const char *psz_ext; |
100 | | int i_width; |
101 | | int i_height; |
102 | | unsigned u_fps_num; |
103 | | unsigned u_fps_den; |
104 | | unsigned u_ar_num; |
105 | | unsigned u_ar_den; |
106 | | vlc_fourcc_t i_chroma; |
107 | | }; |
108 | | |
109 | | static const struct preset_t p_presets[] = |
110 | | { |
111 | | { "sqcif", 128, 96, 30000, 1001, 4,3, VLC_CODEC_YV12 }, |
112 | | { "qcif", 176, 144, 30000, 1001, 4,3, VLC_CODEC_YV12 }, |
113 | | { "cif", 352, 288, 30000, 1001, 4,3, VLC_CODEC_YV12 }, |
114 | | { "4cif", 704, 576, 30000, 1001, 4,3, VLC_CODEC_YV12 }, |
115 | | { "16cif", 1408, 1152, 30000, 1001, 4,3, VLC_CODEC_YV12 }, |
116 | | { "yuv", 176, 144, 25, 1, 4,3, VLC_CODEC_YV12 }, |
117 | | { NULL, 0, 0, 0, 0, 0,0, 0 } |
118 | | }; |
119 | | |
120 | | /***************************************************************************** |
121 | | * Open: initializes raw DV demux structures |
122 | | *****************************************************************************/ |
123 | | static int Open( vlc_object_t * p_this ) |
124 | 403 | { |
125 | 403 | demux_t *p_demux = (demux_t*)p_this; |
126 | 403 | demux_sys_t *p_sys; |
127 | 403 | int i_width=-1, i_height=-1; |
128 | 403 | unsigned u_fps_num, u_fps_den; |
129 | 403 | vlc_fourcc_t i_chroma = 0; |
130 | 403 | unsigned int i_sar_num; |
131 | 403 | unsigned int i_sar_den; |
132 | 403 | const struct preset_t *p_preset = NULL; |
133 | 403 | const uint8_t *p_peek; |
134 | 403 | bool b_y4m = false; |
135 | | |
136 | 403 | if( vlc_stream_Peek( p_demux->s, &p_peek, 9 ) == 9 ) |
137 | 403 | { |
138 | | /* http://wiki.multimedia.cx/index.php?title=YUV4MPEG2 */ |
139 | 403 | if( !strncmp( (char *)p_peek, "YUV4MPEG2", 9 ) ) |
140 | 0 | { |
141 | 0 | b_y4m = true; |
142 | 0 | goto valid; |
143 | 0 | } |
144 | 403 | } |
145 | | |
146 | 403 | if( !p_demux->obj.force ) |
147 | 403 | { |
148 | | /* guess preset based on file extension */ |
149 | 403 | if( !p_demux->psz_filepath ) |
150 | 403 | return VLC_EGENERIC; |
151 | | |
152 | 0 | const char *psz_ext = strrchr( p_demux->psz_filepath, '.' ); |
153 | 0 | if( !psz_ext ) |
154 | 0 | return VLC_EGENERIC; |
155 | 0 | psz_ext++; |
156 | |
|
157 | 0 | for( unsigned i = 0; p_presets[i].psz_ext ; i++ ) |
158 | 0 | { |
159 | 0 | if( !strcasecmp( psz_ext, p_presets[i].psz_ext ) ) |
160 | 0 | { |
161 | 0 | p_preset = &p_presets[i]; |
162 | 0 | goto valid; |
163 | 0 | } |
164 | 0 | } |
165 | 0 | return VLC_EGENERIC; |
166 | 0 | } |
167 | 0 | valid: |
168 | 0 | p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); |
169 | 0 | if( !p_sys ) |
170 | 0 | return VLC_ENOMEM; |
171 | | |
172 | 0 | p_sys->b_y4m = b_y4m; |
173 | | |
174 | | /* guess the parameters based on the preset */ |
175 | 0 | if( p_preset ) |
176 | 0 | { |
177 | 0 | i_width = p_preset->i_width; |
178 | 0 | i_height = p_preset->i_height; |
179 | 0 | u_fps_num = p_preset->u_fps_num; |
180 | 0 | u_fps_den = p_preset->u_fps_den; |
181 | 0 | i_sar_num = p_preset->u_ar_num * p_preset->i_height; |
182 | 0 | i_sar_den = p_preset->u_ar_den * p_preset->i_width; |
183 | 0 | i_chroma = p_preset->i_chroma; |
184 | 0 | } |
185 | | |
186 | | /* override presets if yuv4mpeg2 */ |
187 | 0 | if( b_y4m ) |
188 | 0 | { |
189 | | /* The string should start with "YUV4MPEG2" */ |
190 | 0 | char *psz = vlc_stream_ReadLine( p_demux->s ); |
191 | 0 | char *psz_buf; |
192 | 0 | int a = 1; |
193 | 0 | int b = 1; |
194 | |
|
195 | 0 | if( unlikely(psz == NULL) ) |
196 | 0 | goto error; |
197 | | |
198 | | /* NB, it is not possible to handle interlaced here, since the |
199 | | * interlaced picture flags are in picture_t not block_t */ |
200 | | |
201 | 0 | #define READ_FRAC( key, num, den ) do { \ |
202 | 0 | psz_buf = strstr( psz+9, key );\ |
203 | 0 | if( psz_buf )\ |
204 | 0 | {\ |
205 | 0 | char *end = strchr( psz_buf+1, ' ' );\ |
206 | 0 | char *sep;\ |
207 | 0 | if( end ) *end = '\0';\ |
208 | 0 | sep = strchr( psz_buf+1, ':' );\ |
209 | 0 | if( sep )\ |
210 | 0 | {\ |
211 | 0 | *sep = '\0';\ |
212 | 0 | den = atoi( sep+1 );\ |
213 | 0 | }\ |
214 | 0 | else\ |
215 | 0 | {\ |
216 | 0 | den = 1;\ |
217 | 0 | }\ |
218 | 0 | num = atoi( psz_buf+2 );\ |
219 | 0 | if( sep ) *sep = ':';\ |
220 | 0 | if( end ) *end = ' ';\ |
221 | 0 | } } while(0) |
222 | 0 | READ_FRAC( " W", i_width, a ); |
223 | 0 | READ_FRAC( " H", i_height, a ); |
224 | 0 | READ_FRAC( " F", u_fps_num, u_fps_den ); |
225 | 0 | READ_FRAC( " A", a, b ); |
226 | 0 | #undef READ_FRAC |
227 | 0 | if( b != 0 ) |
228 | 0 | { |
229 | 0 | i_sar_num = a; |
230 | 0 | i_sar_den = b; |
231 | 0 | } |
232 | |
|
233 | 0 | psz_buf = strstr( psz+9, " C" ); |
234 | 0 | if( psz_buf ) |
235 | 0 | { |
236 | 0 | static const struct { const char *psz_name; vlc_fourcc_t i_fcc; } formats[] = |
237 | 0 | { |
238 | 0 | { "420jpeg", VLC_CODEC_I420 }, |
239 | 0 | { "420paldv", VLC_CODEC_I420 }, |
240 | 0 | { "420", VLC_CODEC_I420 }, |
241 | 0 | { "422", VLC_CODEC_I422 }, |
242 | 0 | { "444", VLC_CODEC_I444 }, |
243 | 0 | { "mono", VLC_CODEC_GREY }, |
244 | 0 | { NULL, 0 } |
245 | 0 | }; |
246 | 0 | bool b_found = false; |
247 | 0 | char *psz_end = strchr( psz_buf+1, ' ' ); |
248 | 0 | if( psz_end ) |
249 | 0 | *psz_end = '\0'; |
250 | 0 | psz_buf += 2; |
251 | |
|
252 | 0 | for( int i = 0; formats[i].psz_name != NULL; i++ ) |
253 | 0 | { |
254 | 0 | if( !strncmp( psz_buf, formats[i].psz_name, strlen(formats[i].psz_name) ) ) |
255 | 0 | { |
256 | 0 | i_chroma = formats[i].i_fcc; |
257 | 0 | b_found = true; |
258 | 0 | break; |
259 | 0 | } |
260 | 0 | } |
261 | 0 | if( !b_found ) |
262 | 0 | msg_Warn( p_demux, "Unknown YUV4MPEG2 chroma type \"%s\"", psz_buf ); |
263 | 0 | if( psz_end ) |
264 | 0 | *psz_end = ' '; |
265 | 0 | } |
266 | |
|
267 | 0 | free( psz ); |
268 | 0 | } |
269 | | |
270 | | /* allow the user to override anything guessed from the input */ |
271 | 0 | int i_tmp; |
272 | 0 | i_tmp = var_CreateGetInteger( p_demux, "rawvid-width" ); |
273 | 0 | if( i_tmp ) i_width = i_tmp; |
274 | |
|
275 | 0 | i_tmp = var_CreateGetInteger( p_demux, "rawvid-height" ); |
276 | 0 | if( i_tmp ) i_height = i_tmp; |
277 | |
|
278 | 0 | char *psz_tmp; |
279 | 0 | psz_tmp = var_CreateGetNonEmptyString( p_demux, "rawvid-chroma" ); |
280 | 0 | if( psz_tmp ) |
281 | 0 | { |
282 | 0 | if( strlen( psz_tmp ) != 4 ) |
283 | 0 | { |
284 | 0 | msg_Err( p_demux, "Invalid fourcc format/chroma specification %s" |
285 | 0 | " expecting four characters eg, UYVY", psz_tmp ); |
286 | 0 | free( psz_tmp ); |
287 | 0 | goto error; |
288 | 0 | } |
289 | 0 | memcpy( &i_chroma, psz_tmp, 4 ); |
290 | 0 | msg_Dbg( p_demux, "Forcing chroma to 0x%.8x (%4.4s)", i_chroma, (char*)&i_chroma ); |
291 | 0 | free( psz_tmp ); |
292 | 0 | } |
293 | | |
294 | 0 | if( var_InheritURational( p_demux, &u_fps_num, &u_fps_den, "rawvid-fps" ) ) |
295 | 0 | { |
296 | 0 | u_fps_num = 0; |
297 | 0 | u_fps_den = 1; |
298 | 0 | } |
299 | |
|
300 | 0 | if( var_InheritURational( p_demux, &i_sar_num, &i_sar_den, |
301 | 0 | "rawvid-aspect-ratio" ) ) |
302 | 0 | i_sar_num = i_sar_den = 1; |
303 | | |
304 | | /* moan about anything wrong */ |
305 | 0 | if( i_width <= 0 || i_height <= 0 ) |
306 | 0 | { |
307 | 0 | msg_Err( p_demux, "width and height must be strictly positive." ); |
308 | 0 | goto error; |
309 | 0 | } |
310 | | |
311 | 0 | if( !u_fps_num || !u_fps_den ) |
312 | 0 | { |
313 | 0 | msg_Err( p_demux, "invalid or no framerate specified." ); |
314 | 0 | goto error; |
315 | 0 | } |
316 | | |
317 | 0 | if( i_chroma == 0 ) |
318 | 0 | { |
319 | 0 | msg_Err( p_demux, "invalid or no chroma specified." ); |
320 | 0 | goto error; |
321 | 0 | } |
322 | | |
323 | | /* fixup anything missing with sensible assumptions */ |
324 | 0 | if( i_sar_num <= 0 || i_sar_den <= 0 ) |
325 | 0 | { |
326 | | /* assume 1:1 sar */ |
327 | 0 | i_sar_num = 1; |
328 | 0 | i_sar_den = 1; |
329 | 0 | } |
330 | |
|
331 | 0 | es_format_Init( &p_sys->fmt_video, VIDEO_ES, i_chroma ); |
332 | 0 | video_format_Setup( &p_sys->fmt_video.video, i_chroma, |
333 | 0 | i_width, i_height, i_width, i_height, |
334 | 0 | i_sar_num, i_sar_den ); |
335 | |
|
336 | 0 | vlc_ureduce( &p_sys->fmt_video.video.i_frame_rate, |
337 | 0 | &p_sys->fmt_video.video.i_frame_rate_base, |
338 | 0 | u_fps_num, u_fps_den, 0); |
339 | 0 | date_Init( &p_sys->pcr, p_sys->fmt_video.video.i_frame_rate, |
340 | 0 | p_sys->fmt_video.video.i_frame_rate_base ); |
341 | 0 | date_Set( &p_sys->pcr, VLC_TICK_0 ); |
342 | |
|
343 | 0 | const vlc_chroma_description_t *dsc = |
344 | 0 | vlc_fourcc_GetChromaDescription(p_sys->fmt_video.video.i_chroma); |
345 | 0 | if (unlikely(dsc == NULL)) |
346 | 0 | goto error; |
347 | 0 | if (dsc->plane_count == 0) |
348 | 0 | { |
349 | 0 | msg_Err( p_demux, "Unsupported chroma 0x%.8x (%4.4s)", i_chroma, |
350 | 0 | (char*)&i_chroma ); |
351 | 0 | goto error; |
352 | 0 | } |
353 | 0 | p_sys->frame_size = 0; |
354 | 0 | for (unsigned i=0; i<dsc->plane_count; i++) |
355 | 0 | { |
356 | 0 | unsigned pitch = ((i_width + (dsc->p[i].w.den - 1)) / dsc->p[i].w.den) |
357 | 0 | * dsc->p[i].w.num * dsc->pixel_size; |
358 | 0 | unsigned lines = ((i_height + (dsc->p[i].h.den - 1)) / dsc->p[i].h.den) |
359 | 0 | * dsc->p[i].h.num; |
360 | 0 | p_sys->frame_size += pitch * lines; |
361 | 0 | } |
362 | 0 | p_sys->p_es_video = es_out_Add( p_demux->out, &p_sys->fmt_video ); |
363 | |
|
364 | 0 | p_demux->pf_demux = Demux; |
365 | 0 | p_demux->pf_control = Control; |
366 | 0 | return VLC_SUCCESS; |
367 | | |
368 | 0 | error: |
369 | 0 | free( p_sys ); |
370 | 0 | return VLC_EGENERIC; |
371 | 0 | } |
372 | | |
373 | | /***************************************************************************** |
374 | | * Close: frees unused data |
375 | | *****************************************************************************/ |
376 | | static void Close( vlc_object_t *p_this ) |
377 | 0 | { |
378 | 0 | demux_t *p_demux = (demux_t*)p_this; |
379 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
380 | 0 | free( p_sys ); |
381 | 0 | } |
382 | | |
383 | | /***************************************************************************** |
384 | | * Demux: reads and demuxes data packets |
385 | | ***************************************************************************** |
386 | | * Returns -1 in case of error, 0 in case of EOF, 1 otherwise |
387 | | *****************************************************************************/ |
388 | | static int Demux( demux_t *p_demux ) |
389 | 0 | { |
390 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
391 | 0 | block_t *p_block; |
392 | 0 | vlc_tick_t i_pcr = date_Get( &p_sys->pcr ); |
393 | | |
394 | | /* Call the pace control */ |
395 | 0 | es_out_SetPCR( p_demux->out, i_pcr ); |
396 | |
|
397 | 0 | if( p_sys->b_y4m ) |
398 | 0 | { |
399 | | /* Skip the frame header */ |
400 | | /* Skip "FRAME" */ |
401 | 0 | if( vlc_stream_Read( p_demux->s, NULL, 5 ) != 5 ) |
402 | 0 | return VLC_DEMUXER_EOF; |
403 | | /* Find \n */ |
404 | 0 | for( ;; ) |
405 | 0 | { |
406 | 0 | uint8_t b; |
407 | 0 | if( vlc_stream_Read( p_demux->s, &b, 1 ) < 1 ) |
408 | 0 | return VLC_DEMUXER_EOF; |
409 | 0 | if( b == 0x0a ) |
410 | 0 | break; |
411 | 0 | } |
412 | 0 | } |
413 | | |
414 | 0 | p_block = vlc_stream_Block( p_demux->s, p_sys->frame_size ); |
415 | 0 | if( p_block == NULL ) |
416 | 0 | return VLC_DEMUXER_EOF; |
417 | | |
418 | 0 | p_block->i_dts = p_block->i_pts = i_pcr; |
419 | 0 | es_out_Send( p_demux->out, p_sys->p_es_video, p_block ); |
420 | |
|
421 | 0 | date_Increment( &p_sys->pcr, 1 ); |
422 | |
|
423 | 0 | return VLC_DEMUXER_SUCCESS; |
424 | 0 | } |
425 | | |
426 | | /***************************************************************************** |
427 | | * Control: |
428 | | *****************************************************************************/ |
429 | | static int Control( demux_t *p_demux, int i_query, va_list args ) |
430 | 0 | { |
431 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
432 | | |
433 | | /* (2**31)-1 is insufficient to store 1080p50 4:4:4. */ |
434 | 0 | const int64_t i_bps = 8LL * p_sys->frame_size * p_sys->pcr.i_divider_num / |
435 | 0 | p_sys->pcr.i_divider_den; |
436 | | |
437 | | /* XXX: DEMUX_SET_TIME is precise here */ |
438 | 0 | return demux_vaControlHelper( p_demux->s, 0, -1, i_bps, |
439 | 0 | p_sys->frame_size, i_query, args ); |
440 | 0 | } |
441 | | |