1 /*****************************************************************************
2 * decoder_helpers.c: Functions for the management of decoders
3 *****************************************************************************
4 * Copyright (C) 1999-2019 VLC authors and VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 * Gildas Bazin <gbazin@videolan.org>
8 * Laurent Aimar <fenrir@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
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 Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_codec.h>
31 #include <vlc_atomic.h>
33 #include <vlc_modules.h>
34 #include <vlc_picture.h>
37 void decoder_Init( decoder_t
*p_dec
, const es_format_t
*restrict p_fmt
)
39 p_dec
->i_extra_picture_buffers
= 0;
40 p_dec
->b_frame_drop_allowed
= false;
42 p_dec
->pf_decode
= NULL
;
43 p_dec
->pf_get_cc
= NULL
;
44 p_dec
->pf_packetize
= NULL
;
45 p_dec
->pf_flush
= NULL
;
46 p_dec
->p_module
= NULL
;
48 es_format_Copy( &p_dec
->fmt_in
, p_fmt
);
49 es_format_Init( &p_dec
->fmt_out
, p_fmt
->i_cat
, 0 );
52 void decoder_Clean( decoder_t
*p_dec
)
54 if ( p_dec
->p_module
!= NULL
)
56 module_unneed(p_dec
, p_dec
->p_module
);
57 p_dec
->p_module
= NULL
;
60 es_format_Clean( &p_dec
->fmt_in
);
61 es_format_Clean( &p_dec
->fmt_out
);
63 if ( p_dec
->p_description
)
65 vlc_meta_Delete(p_dec
->p_description
);
66 p_dec
->p_description
= NULL
;
70 void decoder_Destroy( decoder_t
*p_dec
)
74 decoder_Clean( p_dec
);
75 vlc_object_delete(p_dec
);
79 int decoder_UpdateVideoFormat( decoder_t
*dec
)
81 return decoder_UpdateVideoOutput( dec
, NULL
);
84 int decoder_UpdateVideoOutput( decoder_t
*dec
, vlc_video_context
*vctx_out
)
86 vlc_assert( dec
->fmt_in
.i_cat
== VIDEO_ES
&& dec
->cbs
!= NULL
);
87 if ( unlikely(dec
->fmt_in
.i_cat
!= VIDEO_ES
|| dec
->cbs
== NULL
) )
91 dec
->fmt_out
.video
.i_chroma
= dec
->fmt_out
.i_codec
;
93 if( dec
->fmt_out
.video
.i_visible_height
== 1088 &&
94 var_CreateGetBool( dec
, "hdtv-fix" ) )
96 dec
->fmt_out
.video
.i_visible_height
= 1080;
97 if( !(dec
->fmt_out
.video
.i_sar_num
% 136))
99 dec
->fmt_out
.video
.i_sar_num
*= 135;
100 dec
->fmt_out
.video
.i_sar_den
*= 136;
102 msg_Warn( dec
, "Fixing broken HDTV stream (display_height=1088)");
105 if( !dec
->fmt_out
.video
.i_sar_num
|| !dec
->fmt_out
.video
.i_sar_den
)
107 dec
->fmt_out
.video
.i_sar_num
= 1;
108 dec
->fmt_out
.video
.i_sar_den
= 1;
111 vlc_ureduce( &dec
->fmt_out
.video
.i_sar_num
, &dec
->fmt_out
.video
.i_sar_den
,
112 dec
->fmt_out
.video
.i_sar_num
, dec
->fmt_out
.video
.i_sar_den
, 50000 );
114 if( vlc_fourcc_IsYUV( dec
->fmt_out
.video
.i_chroma
) )
116 const vlc_chroma_description_t
*dsc
= vlc_fourcc_GetChromaDescription( dec
->fmt_out
.video
.i_chroma
);
117 for( unsigned int i
= 0; dsc
&& i
< dsc
->plane_count
; i
++ )
119 while( dec
->fmt_out
.video
.i_width
% dsc
->p
[i
].w
.den
)
120 dec
->fmt_out
.video
.i_width
++;
121 while( dec
->fmt_out
.video
.i_height
% dsc
->p
[i
].h
.den
)
122 dec
->fmt_out
.video
.i_height
++;
126 if( !dec
->fmt_out
.video
.i_visible_width
||
127 !dec
->fmt_out
.video
.i_visible_height
)
129 if( dec
->fmt_in
.video
.i_visible_width
&&
130 dec
->fmt_in
.video
.i_visible_height
)
132 dec
->fmt_out
.video
.i_visible_width
= dec
->fmt_in
.video
.i_visible_width
;
133 dec
->fmt_out
.video
.i_visible_height
= dec
->fmt_in
.video
.i_visible_height
;
134 dec
->fmt_out
.video
.i_x_offset
= dec
->fmt_in
.video
.i_x_offset
;
135 dec
->fmt_out
.video
.i_y_offset
= dec
->fmt_in
.video
.i_y_offset
;
139 dec
->fmt_out
.video
.i_visible_width
= dec
->fmt_out
.video
.i_width
;
140 dec
->fmt_out
.video
.i_visible_height
= dec
->fmt_out
.video
.i_height
;
141 dec
->fmt_out
.video
.i_x_offset
= 0;
142 dec
->fmt_out
.video
.i_y_offset
= 0;
146 video_format_AdjustColorSpace( &dec
->fmt_out
.video
);
148 if (dec
->cbs
->video
.format_update
== NULL
)
151 return dec
->cbs
->video
.format_update( dec
, vctx_out
);
154 picture_t
*decoder_NewPicture( decoder_t
*dec
)
156 vlc_assert( dec
->fmt_in
.i_cat
== VIDEO_ES
&& dec
->cbs
!= NULL
);
157 if (dec
->cbs
->video
.buffer_new
== NULL
)
158 return picture_NewFromFormat( &dec
->fmt_out
.video
);
159 return dec
->cbs
->video
.buffer_new( dec
);
162 void decoder_AbortPictures(decoder_t
*dec
, bool abort
)
164 vlc_assert(dec
->fmt_in
.i_cat
== VIDEO_ES
&& dec
->cbs
);
165 if (dec
->cbs
->video
.abort_pictures
)
166 dec
->cbs
->video
.abort_pictures(dec
, abort
);
169 struct vlc_decoder_device_priv
171 struct vlc_decoder_device device
;
175 static int decoder_device_Open(void *func
, bool forced
, va_list ap
)
178 vlc_decoder_device_Open open
= func
;
179 vlc_decoder_device
*device
= va_arg(ap
, vlc_decoder_device
*);
180 vout_window_t
*window
= va_arg(ap
, vout_window_t
*);
181 return open(device
, window
);
185 vlc_decoder_device_Create(vlc_object_t
*o
, vout_window_t
*window
)
187 struct vlc_decoder_device_priv
*priv
=
188 vlc_object_create(o
, sizeof (*priv
));
191 char *name
= var_InheritString(o
, "dec-dev");
192 module_t
*module
= vlc_module_load(&priv
->device
, "decoder device", name
,
193 true, decoder_device_Open
, &priv
->device
,
198 vlc_objres_clear(VLC_OBJECT(&priv
->device
));
199 vlc_object_delete(&priv
->device
);
202 assert(priv
->device
.ops
!= NULL
);
203 vlc_atomic_rc_init(&priv
->rc
);
204 return &priv
->device
;
208 vlc_decoder_device_Hold(vlc_decoder_device
*device
)
210 struct vlc_decoder_device_priv
*priv
=
211 container_of(device
, struct vlc_decoder_device_priv
, device
);
212 vlc_atomic_rc_inc(&priv
->rc
);
217 vlc_decoder_device_Release(vlc_decoder_device
*device
)
219 struct vlc_decoder_device_priv
*priv
=
220 container_of(device
, struct vlc_decoder_device_priv
, device
);
221 if (vlc_atomic_rc_dec(&priv
->rc
))
223 if (device
->ops
->close
!= NULL
)
224 device
->ops
->close(device
);
225 vlc_objres_clear(VLC_OBJECT(device
));
226 vlc_object_delete(device
);
232 struct vlc_video_context
235 vlc_decoder_device
*device
;
236 const struct vlc_video_context_operations
*ops
;
237 enum vlc_video_context_type private_type
;
242 vlc_video_context
* vlc_video_context_Create(vlc_decoder_device
*device
,
243 enum vlc_video_context_type private_type
,
245 const struct vlc_video_context_operations
*ops
)
247 assert(private_type
!= VLC_VIDEO_CONTEXT_NONE
); // use a NULL video context for that
248 vlc_video_context
*vctx
= malloc(sizeof(*vctx
) + private_size
);
249 if (unlikely(vctx
== NULL
))
251 vlc_atomic_rc_init( &vctx
->rc
);
252 vctx
->private_type
= private_type
;
253 vctx
->private_size
= private_size
;
254 vctx
->device
= device
;
256 vlc_decoder_device_Hold( vctx
->device
);
261 void *vlc_video_context_GetPrivate(vlc_video_context
*vctx
, enum vlc_video_context_type type
)
263 if (vctx
&& vctx
->private_type
== type
)
264 return &vctx
->private;
268 enum vlc_video_context_type
vlc_video_context_GetType(const vlc_video_context
*vctx
)
270 return vctx
->private_type
;
273 vlc_video_context
*vlc_video_context_Hold(vlc_video_context
*vctx
)
275 vlc_atomic_rc_inc( &vctx
->rc
);
279 void vlc_video_context_Release(vlc_video_context
*vctx
)
281 if ( vlc_atomic_rc_dec( &vctx
->rc
) )
284 vlc_decoder_device_Release( vctx
->device
);
285 if ( vctx
->ops
&& vctx
->ops
->destroy
)
286 vctx
->ops
->destroy( vlc_video_context_GetPrivate(vctx
, vctx
->private_type
) );
291 vlc_decoder_device
* vlc_video_context_HoldDevice(vlc_video_context
*vctx
)
295 return vlc_decoder_device_Hold( vctx
->device
);
300 vlc_decoder_device
*vlc_encoder_GetDecoderDevice( encoder_t
*enc
)
302 vlc_assert( enc
->fmt_in
.i_cat
== VIDEO_ES
&& enc
->cbs
!= NULL
);
303 if ( unlikely(enc
->fmt_in
.i_cat
!= VIDEO_ES
|| enc
->cbs
== NULL
) )
306 return enc
->cbs
->video
.get_device( enc
);