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