1 /*****************************************************************************
2 * rawvideo.c: Pseudo video decoder/packetizer for raw video data
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
35 /*****************************************************************************
36 * decoder_sys_t : raw video decoder descriptor
37 *****************************************************************************/
44 unsigned pitches
[PICTURE_PLANE_MAX
];
45 unsigned lines
[PICTURE_PLANE_MAX
];
53 /****************************************************************************
55 ****************************************************************************/
56 static int OpenDecoder ( vlc_object_t
* );
57 static int OpenPacketizer( vlc_object_t
* );
58 static void CloseCommon ( vlc_object_t
* );
60 /*****************************************************************************
62 *****************************************************************************/
64 set_description( N_("Pseudo raw video decoder") )
65 set_capability( "decoder", 50 )
66 set_category( CAT_INPUT
)
67 set_subcategory( SUBCAT_INPUT_VCODEC
)
68 set_callbacks( OpenDecoder
, CloseCommon
)
71 set_description( N_("Pseudo raw video packetizer") )
72 set_capability( "packetizer", 100 )
73 set_callbacks( OpenPacketizer
, CloseCommon
)
77 * Common initialization for decoder and packetizer
79 static int OpenCommon( decoder_t
*p_dec
)
81 const vlc_chroma_description_t
*dsc
=
82 vlc_fourcc_GetChromaDescription( p_dec
->fmt_in
.i_codec
);
83 if( dsc
== NULL
|| dsc
->plane_count
== 0 )
86 if( p_dec
->fmt_in
.video
.i_width
<= 0 || p_dec
->fmt_in
.video
.i_height
== 0 )
88 msg_Err( p_dec
, "invalid display size %dx%d",
89 p_dec
->fmt_in
.video
.i_width
, p_dec
->fmt_in
.video
.i_height
);
93 /* Allocate the memory needed to store the decoder's structure */
94 decoder_sys_t
*p_sys
= calloc(1, sizeof(*p_sys
));
95 if( unlikely(p_sys
== NULL
) )
98 if( !p_dec
->fmt_in
.video
.i_visible_width
)
99 p_dec
->fmt_in
.video
.i_visible_width
= p_dec
->fmt_in
.video
.i_width
;
100 if( !p_dec
->fmt_in
.video
.i_visible_height
)
101 p_dec
->fmt_in
.video
.i_visible_height
= p_dec
->fmt_in
.video
.i_height
;
103 es_format_Copy( &p_dec
->fmt_out
, &p_dec
->fmt_in
);
105 date_Init( &p_sys
->pts
, p_dec
->fmt_out
.video
.i_frame_rate
,
106 p_dec
->fmt_out
.video
.i_frame_rate_base
);
107 if( p_dec
->fmt_out
.video
.i_frame_rate
== 0 ||
108 p_dec
->fmt_out
.video
.i_frame_rate_base
== 0)
110 msg_Warn( p_dec
, "invalid frame rate %d/%d, using 25 fps instead",
111 p_dec
->fmt_out
.video
.i_frame_rate
,
112 p_dec
->fmt_out
.video
.i_frame_rate_base
);
113 date_Init( &p_sys
->pts
, 25, 1 );
116 for( unsigned i
= 0; i
< dsc
->plane_count
; i
++ )
118 unsigned pitch
= p_dec
->fmt_in
.video
.i_width
* dsc
->pixel_size
119 * dsc
->p
[i
].w
.num
/ dsc
->p
[i
].w
.den
;
120 unsigned lines
= p_dec
->fmt_in
.video
.i_height
121 * dsc
->p
[i
].h
.num
/ dsc
->p
[i
].h
.den
;
123 p_sys
->pitches
[i
] = pitch
;
124 p_sys
->lines
[i
] = lines
;
125 p_sys
->size
+= pitch
* lines
;
128 p_dec
->p_sys
= p_sys
;
132 /*****************************************************************************
134 *****************************************************************************/
135 static void Flush( decoder_t
*p_dec
)
137 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
139 date_Set( &p_sys
->pts
, VLC_TS_INVALID
);
142 /****************************************************************************
143 * DecodeBlock: the whole thing
144 ****************************************************************************
145 * This function must be fed with complete frames.
146 ****************************************************************************/
147 static block_t
*DecodeBlock( decoder_t
*p_dec
, block_t
*p_block
)
149 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
151 if( p_block
->i_flags
& (BLOCK_FLAG_CORRUPTED
|BLOCK_FLAG_DISCONTINUITY
) )
153 date_Set( &p_sys
->pts
, p_block
->i_dts
);
154 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
156 block_Release( p_block
);
161 if( p_block
->i_pts
<= VLC_TS_INVALID
&& p_block
->i_dts
<= VLC_TS_INVALID
&&
162 !date_Get( &p_sys
->pts
) )
164 /* We've just started the stream, wait for the first PTS. */
165 block_Release( p_block
);
169 /* Date management: If there is a pts avaliable, use that. */
170 if( p_block
->i_pts
> VLC_TS_INVALID
)
172 date_Set( &p_sys
->pts
, p_block
->i_pts
);
174 else if( p_block
->i_dts
> VLC_TS_INVALID
)
176 /* NB, davidf doesn't quite agree with this in general, it is ok
177 * for rawvideo since it is in order (ie pts=dts), however, it
178 * may not be ok for an out-of-order codec, so don't copy this
179 * without thinking */
180 date_Set( &p_sys
->pts
, p_block
->i_dts
);
183 if( p_block
->i_buffer
< p_sys
->size
)
185 msg_Warn( p_dec
, "invalid frame size (%zu < %zu)",
186 p_block
->i_buffer
, p_sys
->size
);
188 block_Release( p_block
);
195 /*****************************************************************************
197 *****************************************************************************/
198 static void FillPicture( decoder_t
*p_dec
, block_t
*p_block
, picture_t
*p_pic
)
200 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
201 const uint8_t *p_src
= p_block
->p_buffer
;
203 for( int i
= 0; i
< p_pic
->i_planes
; i
++ )
205 uint8_t *p_dst
= p_pic
->p
[i
].p_pixels
;
207 for( int x
= 0; x
< p_pic
->p
[i
].i_visible_lines
; x
++ )
209 memcpy( p_dst
, p_src
, p_pic
->p
[i
].i_visible_pitch
);
210 p_src
+= p_sys
->pitches
[i
];
211 p_dst
+= p_pic
->p
[i
].i_pitch
;
214 p_src
+= p_sys
->pitches
[i
]
215 * (p_sys
->lines
[i
] - p_pic
->p
[i
].i_visible_lines
);
219 /*****************************************************************************
220 * DecodeFrame: decodes a video frame.
221 *****************************************************************************/
222 static int DecodeFrame( decoder_t
*p_dec
, block_t
*p_block
)
224 if( p_block
== NULL
) /* No Drain */
225 return VLCDEC_SUCCESS
;
227 p_block
= DecodeBlock( p_dec
, p_block
);
228 if( p_block
== NULL
)
229 return VLCDEC_SUCCESS
;
231 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
233 /* Get a new picture */
234 picture_t
*p_pic
= NULL
;
235 if( !decoder_UpdateVideoFormat( p_dec
) )
236 p_pic
= decoder_NewPicture( p_dec
);
239 block_Release( p_block
);
240 return VLCDEC_SUCCESS
;
243 FillPicture( p_dec
, p_block
, p_pic
);
245 /* Date management: 1 frame per packet */
246 p_pic
->date
= date_Get( &p_dec
->p_sys
->pts
);
247 date_Increment( &p_sys
->pts
, 1 );
249 if( p_block
->i_flags
& BLOCK_FLAG_INTERLACED_MASK
)
251 p_pic
->b_progressive
= false;
252 p_pic
->i_nb_fields
= (p_block
->i_flags
& BLOCK_FLAG_SINGLE_FIELD
) ? 1 : 2;
253 if( p_block
->i_flags
& BLOCK_FLAG_TOP_FIELD_FIRST
)
254 p_pic
->b_top_field_first
= true;
256 p_pic
->b_top_field_first
= false;
259 p_pic
->b_progressive
= true;
261 block_Release( p_block
);
262 decoder_QueueVideo( p_dec
, p_pic
);
263 return VLCDEC_SUCCESS
;
266 static int OpenDecoder( vlc_object_t
*p_this
)
268 decoder_t
*p_dec
= (decoder_t
*)p_this
;
270 int ret
= OpenCommon( p_dec
);
271 if( ret
== VLC_SUCCESS
)
273 p_dec
->pf_decode
= DecodeFrame
;
274 p_dec
->pf_flush
= Flush
;
279 /*****************************************************************************
280 * SendFrame: send a video frame to the stream output.
281 *****************************************************************************/
282 static block_t
*SendFrame( decoder_t
*p_dec
, block_t
**pp_block
)
284 if( pp_block
== NULL
) /* No Drain */
287 block_t
*p_block
= *pp_block
;
288 if( p_block
== NULL
)
292 p_block
= DecodeBlock( p_dec
, p_block
);
293 if( p_block
== NULL
)
296 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
298 /* Date management: 1 frame per packet */
299 p_block
->i_dts
= p_block
->i_pts
= date_Get( &p_sys
->pts
);
300 date_Increment( &p_sys
->pts
, 1 );
304 static int OpenPacketizer( vlc_object_t
*p_this
)
306 decoder_t
*p_dec
= (decoder_t
*)p_this
;
308 int ret
= OpenCommon( p_dec
);
309 if( ret
== VLC_SUCCESS
)
310 p_dec
->pf_packetize
= SendFrame
;
315 * Common deinitialization
317 static void CloseCommon( vlc_object_t
*p_this
)
319 decoder_t
*p_dec
= (decoder_t
*)p_this
;
320 free( p_dec
->p_sys
);