]> git.sesse.net Git - vlc/blob - modules/codec/rawvideo.c
Rawvideo: we can have a 0 visible_*, since we copy from width|height
[vlc] / modules / codec / rawvideo.c
1 /*****************************************************************************
2  * rawvideo.c: Pseudo video decoder/packetizer for raw video data
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VLC authors and VideoLAN
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 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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
34
35 /*****************************************************************************
36  * decoder_sys_t : raw video decoder descriptor
37  *****************************************************************************/
38 struct decoder_sys_t
39 {
40     /* Module mode */
41     bool b_packetizer;
42
43     /*
44      * Input properties
45      */
46     bool b_invert;
47
48     size_t size;
49     unsigned pitches[PICTURE_PLANE_MAX];
50     unsigned lines[PICTURE_PLANE_MAX];
51
52     /*
53      * Common properties
54      */
55     date_t pts;
56 };
57
58 /****************************************************************************
59  * Local prototypes
60  ****************************************************************************/
61 static int  OpenDecoder   ( vlc_object_t * );
62 static int  OpenPacketizer( vlc_object_t * );
63 static void CloseDecoder  ( vlc_object_t * );
64
65 static void *DecodeBlock  ( decoder_t *, block_t ** );
66
67 static picture_t *DecodeFrame( decoder_t *, block_t * );
68 static block_t   *SendFrame  ( decoder_t *, block_t * );
69
70 /*****************************************************************************
71  * Module descriptor
72  *****************************************************************************/
73 vlc_module_begin ()
74     set_description( N_("Pseudo raw video decoder") )
75     set_capability( "decoder", 50 )
76     set_category( CAT_INPUT )
77     set_subcategory( SUBCAT_INPUT_VCODEC )
78     set_callbacks( OpenDecoder, CloseDecoder )
79
80     add_submodule ()
81     set_description( N_("Pseudo raw video packetizer") )
82     set_capability( "packetizer", 100 )
83     set_callbacks( OpenPacketizer, CloseDecoder )
84 vlc_module_end ()
85
86 /*****************************************************************************
87  * OpenDecoder: probe the decoder and return score
88  *****************************************************************************/
89 static int OpenDecoder( vlc_object_t *p_this )
90 {
91     decoder_t *p_dec = (decoder_t*)p_this;
92
93     const vlc_chroma_description_t *dsc =
94         vlc_fourcc_GetChromaDescription( p_dec->fmt_in.i_codec );
95     if( dsc == NULL || dsc->plane_count == 0 )
96         return VLC_EGENERIC;
97
98     if( p_dec->fmt_in.video.i_visible_width < 0
99      || p_dec->fmt_in.video.i_visible_height < 0 )
100     {
101         msg_Err( p_dec, "invalid display size %dx%d",
102                  p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height );
103         return VLC_EGENERIC;
104     }
105
106     /* Allocate the memory needed to store the decoder's structure */
107     decoder_sys_t *p_sys = calloc(1, sizeof(*p_sys));
108     if( unlikely(p_sys == NULL) )
109         return VLC_ENOMEM;
110
111     if( (int)p_dec->fmt_in.video.i_height < 0 )
112     {
113         /* Frames are coded from bottom to top */
114         p_dec->fmt_in.video.i_height =
115             (unsigned int)(-(int)p_dec->fmt_in.video.i_height);
116         p_sys->b_invert = true;
117     }
118     if( !p_dec->fmt_in.video.i_visible_width )
119         p_dec->fmt_in.video.i_visible_width = p_dec->fmt_in.video.i_width;
120     if( !p_dec->fmt_in.video.i_visible_height )
121         p_dec->fmt_in.video.i_visible_height = p_dec->fmt_in.video.i_height;
122
123     es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
124
125     date_Init( &p_sys->pts, p_dec->fmt_out.video.i_frame_rate,
126                p_dec->fmt_out.video.i_frame_rate_base );
127     if( p_dec->fmt_out.video.i_frame_rate == 0 ||
128         p_dec->fmt_out.video.i_frame_rate_base == 0)
129     {
130         msg_Warn( p_dec, "invalid frame rate %d/%d, using 25 fps instead",
131                   p_dec->fmt_out.video.i_frame_rate,
132                   p_dec->fmt_out.video.i_frame_rate_base);
133         date_Init( &p_sys->pts, 25, 1 );
134     }
135
136     for( unsigned i = 0; i < dsc->plane_count; i++ )
137     {
138         unsigned pitch = p_dec->fmt_in.video.i_width * dsc->pixel_size
139                          * dsc->p[i].w.num / dsc->p[i].w.den;
140         unsigned lines = p_dec->fmt_in.video.i_height
141                          * dsc->p[i].h.num / dsc->p[i].h.den;
142
143         p_sys->pitches[i] = pitch;
144         p_sys->lines[i] = lines;
145         p_sys->size += pitch * lines;
146     }
147
148     /* Set callbacks */
149     p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
150         DecodeBlock;
151     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
152         DecodeBlock;
153     p_dec->p_sys           = p_sys;
154
155     return VLC_SUCCESS;
156 }
157
158 static int OpenPacketizer( vlc_object_t *p_this )
159 {
160     decoder_t *p_dec = (decoder_t*)p_this;
161
162     int i_ret = OpenDecoder( p_this );
163
164     if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = true;
165
166     return i_ret;
167 }
168
169 /****************************************************************************
170  * DecodeBlock: the whole thing
171  ****************************************************************************
172  * This function must be fed with complete frames.
173  ****************************************************************************/
174 static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
175 {
176     decoder_sys_t *p_sys = p_dec->p_sys;
177     block_t *p_block;
178     void *p_buf;
179
180     if( !pp_block || !*pp_block ) return NULL;
181
182     p_block = *pp_block;
183
184
185     if( p_block->i_pts <= VLC_TS_INVALID && p_block->i_dts <= VLC_TS_INVALID &&
186         !date_Get( &p_sys->pts ) )
187     {
188         /* We've just started the stream, wait for the first PTS. */
189         block_Release( p_block );
190         return NULL;
191     }
192
193     /* Date management: If there is a pts avaliable, use that. */
194     if( p_block->i_pts > VLC_TS_INVALID )
195     {
196         date_Set( &p_sys->pts, p_block->i_pts );
197     }
198     else if( p_block->i_dts > VLC_TS_INVALID )
199     {
200         /* NB, davidf doesn't quite agree with this in general, it is ok
201          * for rawvideo since it is in order (ie pts=dts), however, it
202          * may not be ok for an out-of-order codec, so don't copy this
203          * without thinking */
204         date_Set( &p_sys->pts, p_block->i_dts );
205     }
206
207     if( p_block->i_buffer < p_sys->size )
208     {
209         msg_Warn( p_dec, "invalid frame size (%zu < %zu)",
210                   p_block->i_buffer, p_sys->size );
211
212         block_Release( p_block );
213         return NULL;
214     }
215
216     if( p_sys->b_packetizer )
217     {
218         p_buf = SendFrame( p_dec, p_block );
219     }
220     else
221     {
222         p_buf = DecodeFrame( p_dec, p_block );
223     }
224
225     /* Date management: 1 frame per packet */
226     date_Increment( &p_sys->pts, 1 );
227     *pp_block = NULL;
228
229     return p_buf;
230 }
231
232 /*****************************************************************************
233  * FillPicture:
234  *****************************************************************************/
235 static void FillPicture( decoder_t *p_dec, block_t *p_block, picture_t *p_pic )
236 {
237     decoder_sys_t *p_sys = p_dec->p_sys;
238     const uint8_t *p_src = p_block->p_buffer;
239
240     if( p_sys->b_invert )
241         for( int i = 0; i < p_pic->i_planes; i++ )
242         {
243             uint8_t *p_dst = p_pic->p[i].p_pixels
244                          + (p_pic->p[i].i_pitch * p_pic->p[i].i_visible_lines);
245
246             for( int x = 0; x < p_pic->p[i].i_visible_lines; x++ )
247             {
248                 p_dst -= p_pic->p[i].i_pitch;
249                 memcpy( p_dst, p_src, p_pic->p[i].i_visible_pitch );
250                 p_src += p_sys->pitches[i];
251             }
252
253             p_src += p_sys->pitches[i]
254                    * (p_sys->lines[i] - p_pic->p[i].i_visible_lines);
255         }
256     else
257         for( int i = 0; i < p_pic->i_planes; i++ )
258         {
259             uint8_t *p_dst = p_pic->p[i].p_pixels;
260
261             for( int x = 0; x < p_pic->p[i].i_visible_lines; x++ )
262             {
263                 memcpy( p_dst, p_src, p_pic->p[i].i_visible_pitch );
264                 p_src += p_sys->pitches[i];
265                 p_dst += p_pic->p[i].i_pitch;
266             }
267
268             p_src += p_sys->pitches[i]
269                    * (p_sys->lines[i] - p_pic->p[i].i_visible_lines);
270         }
271 }
272
273 /*****************************************************************************
274  * DecodeFrame: decodes a video frame.
275  *****************************************************************************/
276 static picture_t *DecodeFrame( decoder_t *p_dec, block_t *p_block )
277 {
278     decoder_sys_t *p_sys = p_dec->p_sys;
279     picture_t *p_pic;
280
281     /* Get a new picture */
282     p_pic = decoder_NewPicture( p_dec );
283     if( !p_pic )
284     {
285         block_Release( p_block );
286         return NULL;
287     }
288
289     FillPicture( p_dec, p_block, p_pic );
290
291     p_pic->date = date_Get( &p_sys->pts );
292     if( p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK )
293     {
294         p_pic->b_progressive = false;
295         p_pic->i_nb_fields = 2;
296         if( p_block->i_flags & BLOCK_FLAG_TOP_FIELD_FIRST )
297             p_pic->b_top_field_first = true;
298         else
299             p_pic->b_top_field_first = false;
300     }
301     else
302         p_pic->b_progressive = true;
303
304     block_Release( p_block );
305     return p_pic;
306 }
307
308 /*****************************************************************************
309  * SendFrame: send a video frame to the stream output.
310  *****************************************************************************/
311 static block_t *SendFrame( decoder_t *p_dec, block_t *p_block )
312 {
313     decoder_sys_t *p_sys = p_dec->p_sys;
314
315     p_block->i_dts = p_block->i_pts = date_Get( &p_sys->pts );
316
317     if( p_sys->b_invert )
318     {
319         block_t *out = block_Alloc( p_block->i_buffer );
320         if( likely(out != NULL) )
321         {
322             block_CopyProperties( out, p_block );
323
324             const uint8_t *p_src = p_block->p_buffer;
325             uint8_t *p_pixels = out->p_buffer;
326
327             for( unsigned i = 0; i < PICTURE_PLANE_MAX; i++ )
328             {
329                 unsigned pitch = p_sys->pitches[i];
330                 unsigned lines = p_sys->lines[i];
331                 uint8_t *p_dst = p_pixels + (pitch * lines);
332
333                 for( unsigned x = 0; x < lines; x++ )
334                 {
335                     p_dst -= p_sys->pitches[i];
336                     memcpy( p_dst, p_src, p_sys->pitches[i] );
337                     p_src += p_sys->pitches[i];
338                 }
339             }
340         }
341         block_Release( p_block );
342     }
343
344     return p_block;
345 }
346
347 /*****************************************************************************
348  * CloseDecoder: decoder destruction
349  *****************************************************************************/
350 static void CloseDecoder( vlc_object_t *p_this )
351 {
352     decoder_t *p_dec = (decoder_t*)p_this;
353     free( p_dec->p_sys );
354 }