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( "video 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 if( p_dec
->fmt_out
.video
.i_frame_rate
== 0 ||
106 p_dec
->fmt_out
.video
.i_frame_rate_base
== 0)
108 msg_Warn( p_dec
, "invalid frame rate %d/%d, using 25 fps instead",
109 p_dec
->fmt_out
.video
.i_frame_rate
,
110 p_dec
->fmt_out
.video
.i_frame_rate_base
);
111 date_Init( &p_sys
->pts
, 25, 1 );
114 date_Init( &p_sys
->pts
, p_dec
->fmt_out
.video
.i_frame_rate
,
115 p_dec
->fmt_out
.video
.i_frame_rate_base
);
117 for( unsigned i
= 0; i
< dsc
->plane_count
; i
++ )
119 unsigned pitch
= p_dec
->fmt_in
.video
.i_width
* dsc
->pixel_size
120 * dsc
->p
[i
].w
.num
/ dsc
->p
[i
].w
.den
;
121 unsigned lines
= p_dec
->fmt_in
.video
.i_height
122 * dsc
->p
[i
].h
.num
/ dsc
->p
[i
].h
.den
;
124 p_sys
->pitches
[i
] = pitch
;
125 p_sys
->lines
[i
] = lines
;
126 p_sys
->size
+= pitch
* lines
;
129 p_dec
->p_sys
= p_sys
;
133 /*****************************************************************************
135 *****************************************************************************/
136 static void Flush( decoder_t
*p_dec
)
138 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
140 date_Set( &p_sys
->pts
, VLC_TS_INVALID
);
143 /****************************************************************************
144 * DecodeBlock: the whole thing
145 ****************************************************************************
146 * This function must be fed with complete frames.
147 ****************************************************************************/
148 static block_t
*DecodeBlock( decoder_t
*p_dec
, block_t
*p_block
)
150 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
152 if( p_block
->i_flags
& (BLOCK_FLAG_CORRUPTED
|BLOCK_FLAG_DISCONTINUITY
) )
154 date_Set( &p_sys
->pts
, p_block
->i_dts
);
155 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
157 block_Release( p_block
);
162 if( p_block
->i_pts
<= VLC_TS_INVALID
&& p_block
->i_dts
<= VLC_TS_INVALID
&&
163 !date_Get( &p_sys
->pts
) )
165 /* We've just started the stream, wait for the first PTS. */
166 block_Release( p_block
);
170 /* Date management: If there is a pts avaliable, use that. */
171 if( p_block
->i_pts
> VLC_TS_INVALID
)
173 date_Set( &p_sys
->pts
, p_block
->i_pts
);
175 else if( p_block
->i_dts
> VLC_TS_INVALID
)
177 /* NB, davidf doesn't quite agree with this in general, it is ok
178 * for rawvideo since it is in order (ie pts=dts), however, it
179 * may not be ok for an out-of-order codec, so don't copy this
180 * without thinking */
181 date_Set( &p_sys
->pts
, p_block
->i_dts
);
184 if( p_block
->i_buffer
< p_sys
->size
)
186 msg_Warn( p_dec
, "invalid frame size (%zu < %zu)",
187 p_block
->i_buffer
, p_sys
->size
);
189 block_Release( p_block
);
196 /*****************************************************************************
198 *****************************************************************************/
199 static void FillPicture( decoder_t
*p_dec
, block_t
*p_block
, picture_t
*p_pic
)
201 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
202 const uint8_t *p_src
= p_block
->p_buffer
;
204 for( int i
= 0; i
< p_pic
->i_planes
; i
++ )
206 uint8_t *p_dst
= p_pic
->p
[i
].p_pixels
;
208 for( int x
= 0; x
< p_pic
->p
[i
].i_visible_lines
; x
++ )
210 memcpy( p_dst
, p_src
, p_pic
->p
[i
].i_visible_pitch
);
211 p_src
+= p_sys
->pitches
[i
];
212 p_dst
+= p_pic
->p
[i
].i_pitch
;
215 p_src
+= p_sys
->pitches
[i
]
216 * (p_sys
->lines
[i
] - p_pic
->p
[i
].i_visible_lines
);
220 /*****************************************************************************
221 * DecodeFrame: decodes a video frame.
222 *****************************************************************************/
223 static int DecodeFrame( decoder_t
*p_dec
, block_t
*p_block
)
225 if( p_block
== NULL
) /* No Drain */
226 return VLCDEC_SUCCESS
;
228 p_block
= DecodeBlock( p_dec
, p_block
);
229 if( p_block
== NULL
)
230 return VLCDEC_SUCCESS
;
232 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
234 /* Get a new picture */
235 picture_t
*p_pic
= NULL
;
236 if( !decoder_UpdateVideoFormat( p_dec
) )
237 p_pic
= decoder_NewPicture( p_dec
);
240 block_Release( p_block
);
241 return VLCDEC_SUCCESS
;
244 FillPicture( p_dec
, p_block
, p_pic
);
246 /* Date management: 1 frame per packet */
247 p_pic
->date
= date_Get( &p_dec
->p_sys
->pts
);
248 date_Increment( &p_sys
->pts
, 1 );
250 if( p_block
->i_flags
& BLOCK_FLAG_INTERLACED_MASK
)
252 p_pic
->b_progressive
= false;
253 p_pic
->i_nb_fields
= (p_block
->i_flags
& BLOCK_FLAG_SINGLE_FIELD
) ? 1 : 2;
254 if( p_block
->i_flags
& BLOCK_FLAG_TOP_FIELD_FIRST
)
255 p_pic
->b_top_field_first
= true;
257 p_pic
->b_top_field_first
= false;
260 p_pic
->b_progressive
= true;
262 block_Release( p_block
);
263 decoder_QueueVideo( p_dec
, p_pic
);
264 return VLCDEC_SUCCESS
;
267 static int OpenDecoder( vlc_object_t
*p_this
)
269 decoder_t
*p_dec
= (decoder_t
*)p_this
;
271 int ret
= OpenCommon( p_dec
);
272 if( ret
== VLC_SUCCESS
)
274 p_dec
->pf_decode
= DecodeFrame
;
275 p_dec
->pf_flush
= Flush
;
280 /*****************************************************************************
281 * SendFrame: send a video frame to the stream output.
282 *****************************************************************************/
283 static block_t
*SendFrame( decoder_t
*p_dec
, block_t
**pp_block
)
285 if( pp_block
== NULL
) /* No Drain */
288 block_t
*p_block
= *pp_block
;
289 if( p_block
== NULL
)
293 p_block
= DecodeBlock( p_dec
, p_block
);
294 if( p_block
== NULL
)
297 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
299 /* Date management: 1 frame per packet */
300 p_block
->i_dts
= p_block
->i_pts
= date_Get( &p_sys
->pts
);
301 date_Increment( &p_sys
->pts
, 1 );
305 static int OpenPacketizer( vlc_object_t
*p_this
)
307 decoder_t
*p_dec
= (decoder_t
*)p_this
;
309 int ret
= OpenCommon( p_dec
);
310 if( ret
== VLC_SUCCESS
)
311 p_dec
->pf_packetize
= SendFrame
;
316 * Common deinitialization
318 static void CloseCommon( vlc_object_t
*p_this
)
320 decoder_t
*p_dec
= (decoder_t
*)p_this
;
321 free( p_dec
->p_sys
);