]> git.sesse.net Git - vlc/blob - modules/codec/avcodec/vda.c
s/FFmpeg/libavcodec where applicable
[vlc] / modules / codec / avcodec / vda.c
1 /*****************************************************************************
2  * vda.c: VDA helpers for the libavcodec decoder
3  *****************************************************************************
4  * Copyright © 2012 VideoLAN
5  *
6  * Authors: Sebastien Zwickert <dilaroga@free.fr>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_vout.h>
29 #include <assert.h>
30
31 #include <libavcodec/avcodec.h>
32
33 #include "avcodec.h"
34 #include "va.h"
35 #include "copy.h"
36
37 #ifdef HAVE_AVCODEC_VDA
38
39 #include <libavcodec/vda.h>
40 #include <VideoDecodeAcceleration/VDADecoder.h>
41
42 typedef struct
43 {
44     vlc_va_t            va;
45     struct vda_context  hw_ctx;
46
47     uint8_t             *p_extradata;
48     int                 i_extradata;
49
50     vlc_fourcc_t        i_chroma;
51
52     copy_cache_t        image_cache;
53
54     vlc_object_t        *p_log;
55
56 } vlc_va_vda_t;
57
58 static vlc_va_vda_t *vlc_va_vda_Get( void *p_va )
59 {
60     return p_va;
61 }
62
63 /*****************************************************************************
64  * vda_Copy420YpCbCr8Planar: copy y420 CVPixelBuffer to picture_t
65  *****************************************************************************/
66 static void vda_Copy420YpCbCr8Planar( picture_t *p_pic,
67                                       CVPixelBufferRef buffer,
68                                       unsigned i_width,
69                                       unsigned i_height,
70                                       copy_cache_t *cache )
71 {
72     uint8_t *pp_plane[3];
73     size_t  pi_pitch[3];
74
75     CVPixelBufferLockBaseAddress( buffer, 0 );
76
77     for( int i = 0; i < 3; i++ )
78     {
79         pp_plane[i] = CVPixelBufferGetBaseAddressOfPlane( buffer, i );
80         pi_pitch[i] = CVPixelBufferGetBytesPerRowOfPlane( buffer, i );
81     }
82
83     CopyFromYv12( p_pic, pp_plane, pi_pitch,
84                   i_width, i_height, cache );
85
86     CVPixelBufferUnlockBaseAddress( buffer, 0 );
87 }
88
89 /*****************************************************************************
90  * vda_Copy422YpCbCr8: copy 2vuy CVPixelBuffer to picture_t
91  *****************************************************************************/
92 static void vda_Copy422YpCbCr8( picture_t *p_pic,
93                                 CVPixelBufferRef buffer )
94 {
95     int i_plane, i_line, i_dst_stride, i_src_stride;
96     uint8_t *p_dst, *p_src;
97
98     CVPixelBufferLockBaseAddress( buffer, 0 );
99
100     for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
101     {
102         p_dst = p_pic->p[i_plane].p_pixels;
103         p_src = CVPixelBufferGetBaseAddressOfPlane( buffer, i_plane );
104         i_dst_stride  = p_pic->p[i_plane].i_pitch;
105         i_src_stride  = CVPixelBufferGetBytesPerRowOfPlane( buffer, i_plane );
106
107         for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines ; i_line++ )
108         {
109             memcpy( p_dst, p_src, i_src_stride );
110
111             p_src += i_src_stride;
112             p_dst += i_dst_stride;
113         }
114     }
115
116     CVPixelBufferUnlockBaseAddress( buffer, 0 );
117 }
118
119 static int Setup( vlc_va_t *p_external, void **pp_hw_ctx, vlc_fourcc_t *pi_chroma,
120                   int i_width, int i_height )
121 {
122
123     vlc_va_vda_t *p_va = vlc_va_vda_Get( p_external );
124
125     if( p_va->hw_ctx.width == i_width
126         && p_va->hw_ctx.height == i_height
127         && p_va->hw_ctx.decoder )
128     {
129         *pp_hw_ctx = &p_va->hw_ctx;
130         *pi_chroma = p_va->i_chroma;
131         return VLC_SUCCESS;
132     }
133
134     if( p_va->hw_ctx.decoder )
135     {
136         ff_vda_destroy_decoder( &p_va->hw_ctx );
137         goto ok;
138     }
139
140     memset( &p_va->hw_ctx, 0, sizeof(p_va->hw_ctx) );
141     p_va->hw_ctx.width = i_width;
142     p_va->hw_ctx.height = i_height;
143     p_va->hw_ctx.format = 'avc1';
144     p_va->hw_ctx.use_sync_decoding = 1;
145
146     int i_pix_fmt = var_CreateGetInteger( p_va->p_log, "avcodec-vda-pix-fmt" );
147
148     switch( i_pix_fmt )
149     {
150         case 1 :
151             p_va->hw_ctx.cv_pix_fmt_type = kCVPixelFormatType_422YpCbCr8;
152             p_va->i_chroma = VLC_CODEC_UYVY;
153             break;
154         case 0 :
155         default :
156             p_va->hw_ctx.cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8Planar;
157             p_va->i_chroma = VLC_CODEC_I420;
158             CopyInitCache( &p_va->image_cache, i_width );
159     }
160
161 ok:
162     /* Setup the libavcodec hardware context */
163     *pp_hw_ctx = &p_va->hw_ctx;
164     *pi_chroma = p_va->i_chroma;
165
166     /* create the decoder */
167     int status = ff_vda_create_decoder( &p_va->hw_ctx,
168                                         p_va->p_extradata,
169                                         p_va->i_extradata );
170     if( status )
171     {
172         msg_Err( p_va->p_log, "Failed to create the decoder : %i", status );
173         return VLC_EGENERIC;
174     }
175
176     return VLC_SUCCESS;
177 }
178
179 static int Get( vlc_va_t *p_external, AVFrame *p_ff )
180 {
181     VLC_UNUSED( p_external );
182
183     /* */
184     for( int i = 0; i < 4; i++ )
185     {
186         p_ff->data[i] = NULL;
187         p_ff->linesize[i] = 0;
188
189         if( i == 0 || i == 3 )
190         p_ff->data[i] = 1; // dummy
191     }
192
193     return VLC_SUCCESS;
194 }
195
196 static int Extract( vlc_va_t *p_external, picture_t *p_picture, AVFrame *p_ff )
197 {
198     vlc_va_vda_t *p_va = vlc_va_vda_Get( p_external );
199     CVPixelBufferRef cv_buffer = ( CVPixelBufferRef )p_ff->data[3];
200
201     if( !cv_buffer )
202     {
203         msg_Dbg( p_va->p_log, "Frame buffer is empty.");
204         return VLC_EGENERIC;
205     }
206
207     if( p_va->hw_ctx.cv_pix_fmt_type == kCVPixelFormatType_420YpCbCr8Planar )
208     {
209         if( !p_va->image_cache.buffer )
210             return VLC_EGENERIC;
211
212         vda_Copy420YpCbCr8Planar( p_picture,
213                                   cv_buffer,
214                                   p_va->hw_ctx.width,
215                                   p_va->hw_ctx.height,
216                                   &p_va->image_cache );
217     }
218     else
219         vda_Copy422YpCbCr8( p_picture, cv_buffer );
220
221     return VLC_SUCCESS;
222 }
223
224 static void Release( vlc_va_t *p_external, AVFrame *p_ff )
225 {
226     VLC_UNUSED( p_external );
227     CVPixelBufferRef cv_buffer = ( CVPixelBufferRef )p_ff->data[3];
228
229     if ( cv_buffer )
230         CFRelease( cv_buffer );
231 }
232
233 static void Close( vlc_va_t *p_external )
234 {
235     vlc_va_vda_t *p_va = vlc_va_vda_Get( p_external );
236
237     ff_vda_destroy_decoder( &p_va->hw_ctx ) ;
238
239     if( p_va->hw_ctx.cv_pix_fmt_type == kCVPixelFormatType_420YpCbCr8Planar )
240         CopyCleanCache( &p_va->image_cache );
241
242     free( p_va );
243 }
244
245 vlc_va_t *vlc_va_NewVDA( vlc_object_t *p_log, int i_codec_id, void *p_extra, int i_extra )
246 {
247     if( i_codec_id != CODEC_ID_H264 )
248         return NULL;
249
250     if( !p_extra || i_extra < 7 )
251     {
252         msg_Warn( p_log, "VDA requires extradata." );
253         return NULL;
254     }
255
256     vlc_va_vda_t *p_va = calloc( 1, sizeof(*p_va) );
257     if( !p_va )
258         return NULL;
259
260     p_va->p_log = p_log;
261     p_va->p_extradata = p_extra;
262     p_va->i_extradata = i_extra;
263
264     p_va->va.setup = Setup;
265     p_va->va.get = Get;
266     p_va->va.release = Release;
267     p_va->va.extract = Extract;
268     p_va->va.close = Close;
269
270     return &p_va->va;
271 }
272
273 #else
274 vlc_va_t *vlc_va_NewVDA( vlc_object_t *p_log, int i_codec_id, void *p_extra, int i_extra )
275 {
276     VLC_UNUSED( p_log );
277     VLC_UNUSED( i_codec_id );
278     VLC_UNUSED( p_extra );
279     VLC_UNUSED( i_extra );
280     return NULL;
281 }
282 #endif