1 /*****************************************************************************
2 * vda.c: VDA helpers for the libavcodec decoder
3 *****************************************************************************
4 * Copyright © 2012 VideoLAN
6 * Authors: Sebastien Zwickert <dilaroga@free.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
29 #include <vlc_common.h>
31 #include <vlc_plugin.h>
33 #include <libavcodec/avcodec.h>
39 #include <libavcodec/vda.h>
40 #include <VideoDecodeAcceleration/VDADecoder.h>
42 static int Open( vlc_va_t *, int, const es_format_t * );
43 static void Close( vlc_va_t * );
45 static const int nvda_pix_fmt_list[] = { 0, 1 };
46 static const char *const nvda_pix_fmt_list_text[] =
47 { N_("420YpCbCr8Planar"), N_("422YpCbCr8") };
50 set_description( N_("Video Decode Acceleration Framework (VDA)") )
51 set_capability( "hw decoder", 50 )
52 set_category( CAT_INPUT )
53 set_subcategory( SUBCAT_INPUT_VCODEC )
54 set_callbacks( Open, Close )
55 add_integer ( "avcodec-vda-pix-fmt", 0, VDA_PIX_FMT_TEXT,
56 VDA_PIX_FMT_LONGTEXT, false)
57 change_integer_list( nvda_pix_fmt_list, nvda_pix_fmt_list_text )
62 struct vda_context hw_ctx;
67 vlc_fourcc_t i_chroma;
69 copy_cache_t image_cache;
75 typedef struct vlc_va_sys_t vlc_va_vda_t;
77 static vlc_va_vda_t *vlc_va_vda_Get( vlc_va_t *p_va )
82 /*****************************************************************************
83 * vda_Copy420YpCbCr8Planar: copy y420 CVPixelBuffer to picture_t
84 *****************************************************************************/
85 static void vda_Copy420YpCbCr8Planar( picture_t *p_pic,
86 CVPixelBufferRef buffer,
94 CVPixelBufferLockBaseAddress( buffer, 0 );
96 for( int i = 0; i < 3; i++ )
98 pp_plane[i] = CVPixelBufferGetBaseAddressOfPlane( buffer, i );
99 pi_pitch[i] = CVPixelBufferGetBytesPerRowOfPlane( buffer, i );
102 CopyFromYv12( p_pic, pp_plane, pi_pitch,
103 i_width, i_height, cache );
105 CVPixelBufferUnlockBaseAddress( buffer, 0 );
106 CVPixelBufferRelease( buffer );
109 /*****************************************************************************
110 * vda_Copy422YpCbCr8: copy 2vuy CVPixelBuffer to picture_t
111 *****************************************************************************/
112 static void vda_Copy422YpCbCr8( picture_t *p_pic,
113 CVPixelBufferRef buffer )
115 int i_plane, i_line, i_dst_stride, i_src_stride;
116 uint8_t *p_dst, *p_src;
118 CVPixelBufferLockBaseAddress( buffer, 0 );
120 for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
122 p_dst = p_pic->p[i_plane].p_pixels;
123 p_src = CVPixelBufferGetBaseAddressOfPlane( buffer, i_plane );
124 i_dst_stride = p_pic->p[i_plane].i_pitch;
125 i_src_stride = CVPixelBufferGetBytesPerRowOfPlane( buffer, i_plane );
127 for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines ; i_line++ )
129 memcpy( p_dst, p_src, i_src_stride );
131 p_src += i_src_stride;
132 p_dst += i_dst_stride;
136 CVPixelBufferUnlockBaseAddress( buffer, 0 );
137 CVPixelBufferRelease( buffer );
140 static int Setup( vlc_va_t *p_external, void **pp_hw_ctx, vlc_fourcc_t *pi_chroma,
141 int i_width, int i_height )
144 vlc_va_vda_t *p_va = vlc_va_vda_Get( p_external );
146 if( p_va->hw_ctx.width == i_width
147 && p_va->hw_ctx.height == i_height
148 && p_va->hw_ctx.decoder )
150 *pp_hw_ctx = &p_va->hw_ctx;
151 *pi_chroma = p_va->i_chroma;
155 if( p_va->hw_ctx.decoder )
157 ff_vda_destroy_decoder( &p_va->hw_ctx );
161 memset( &p_va->hw_ctx, 0, sizeof(p_va->hw_ctx) );
162 p_va->hw_ctx.width = i_width;
163 p_va->hw_ctx.height = i_height;
164 p_va->hw_ctx.format = 'avc1';
166 int i_pix_fmt = var_CreateGetInteger( p_va->p_log, "avcodec-vda-pix-fmt" );
171 p_va->hw_ctx.cv_pix_fmt_type = kCVPixelFormatType_422YpCbCr8;
172 p_va->i_chroma = VLC_CODEC_UYVY;
173 msg_Dbg(p_va->p_log, "using pixel format 422YpCbCr8");
177 p_va->hw_ctx.cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8Planar;
178 p_va->i_chroma = VLC_CODEC_I420;
179 CopyInitCache( &p_va->image_cache, i_width );
180 msg_Dbg(p_va->p_log, "using pixel format 420YpCbCr8Planar");
184 /* Setup the libavcodec hardware context */
185 *pp_hw_ctx = &p_va->hw_ctx;
186 *pi_chroma = p_va->i_chroma;
188 /* create the decoder */
189 int status = ff_vda_create_decoder( &p_va->hw_ctx,
194 msg_Err( p_va->p_log, "Failed to create decoder: %i", status );
198 msg_Dbg( p_va->p_log, "VDA decoder created");
203 static int Get( vlc_va_t *p_external, AVFrame *p_ff )
205 VLC_UNUSED( p_external );
208 for( int i = 0; i < 4; i++ )
210 p_ff->data[i] = NULL;
211 p_ff->linesize[i] = 0;
213 if( i == 0 || i == 3 )
214 p_ff->data[i] = (uint8_t *)1; // dummy
220 static int Extract( vlc_va_t *p_external, picture_t *p_picture, AVFrame *p_ff )
222 vlc_va_vda_t *p_va = vlc_va_vda_Get( p_external );
223 CVPixelBufferRef cv_buffer = ( CVPixelBufferRef )p_ff->data[3];
227 msg_Dbg( p_va->p_log, "Frame buffer is empty.");
231 if( p_va->hw_ctx.cv_pix_fmt_type == kCVPixelFormatType_420YpCbCr8Planar )
233 if( !p_va->image_cache.buffer )
236 vda_Copy420YpCbCr8Planar( p_picture,
240 &p_va->image_cache );
243 vda_Copy422YpCbCr8( p_picture, cv_buffer );
248 static void Release( vlc_va_t *p_external, AVFrame *p_ff )
250 VLC_UNUSED( p_external );
251 CVPixelBufferRef cv_buffer = ( CVPixelBufferRef )p_ff->data[3];
254 CFRelease( cv_buffer );
257 static void Close( vlc_va_t *p_external )
259 vlc_va_vda_t *p_va = vlc_va_vda_Get( p_external );
261 msg_Dbg(p_va->p_log, "destroying VDA decoder");
263 ff_vda_destroy_decoder( &p_va->hw_ctx ) ;
265 if( p_va->hw_ctx.cv_pix_fmt_type == kCVPixelFormatType_420YpCbCr8Planar )
266 CopyCleanCache( &p_va->image_cache );
271 static int Open( vlc_va_t *external, int i_codec_id, const es_format_t *fmt )
273 msg_Dbg( external, "opening VDA module" );
274 if( i_codec_id != AV_CODEC_ID_H264 )
276 msg_Warn( external, "input codec isn't H264, canceling VDA decoding" );
280 if( fmt->p_extra == NULL || fmt->i_extra < 7 )
282 msg_Warn( external, "VDA requires extradata." );
286 vlc_va_vda_t *p_va = calloc( 1, sizeof(*p_va) );
290 p_va->p_log = VLC_OBJECT(external);
291 p_va->p_extradata = fmt->p_extra;
292 p_va->i_extradata = fmt->i_extra;
294 external->sys = p_va;
295 external->description = (char *)"VDA";
296 external->pix_fmt = PIX_FMT_VDA_VLD;
297 external->setup = Setup;
299 external->release = Release;
300 external->extract = Extract;