2 * producer_avformat/vdpau.c -- VDPAU functions for the avformat producer
3 * Copyright (C) 2009 Ushodaya Enterprises Limited
4 * Author: Dan Dennedy <dan@dennedy.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <libavcodec/vdpau.h>
25 extern pthread_mutex_t mlt_sdl_mutex;
27 static VdpDeviceCreateX11 *vdpau_device_create_x11;
28 static VdpDeviceDestroy *vdp_device_destroy;
29 static VdpGetProcAddress *vdp_get_proc_address;
30 static VdpGetErrorString *vdp_get_error_string;
31 static VdpGetApiVersion *vdp_get_api_version;
32 static VdpGetInformationString *vdp_get_information_string;
33 static VdpVideoSurfaceCreate *vdp_surface_create;
34 static VdpVideoSurfaceDestroy *vdp_surface_destroy;
35 static VdpVideoSurfaceGetBitsYCbCr *vdp_surface_get_bits;
36 static VdpDecoderCreate *vdp_decoder_create;
37 static VdpDecoderDestroy *vdp_decoder_destroy;
38 static VdpDecoderRender *vdp_decoder_render;
40 // TODO: Shouldn't these be protected by a mutex?
41 static int vdpau_init_done = 0;
42 static int vdpau_supported = 1;
47 static void vdpau_fini( producer_avformat self )
51 mlt_log_debug( NULL, "vdpau_fini (%x)\n", self->vdpau->device );
52 if ( self->vdpau->decoder != VDP_INVALID_HANDLE )
53 vdp_decoder_destroy( self->vdpau->decoder );
54 if ( self->vdpau->device != VDP_INVALID_HANDLE )
55 vdp_device_destroy( self->vdpau->device );
60 static int vdpau_init( producer_avformat self )
62 if ( !vdpau_supported )
64 mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_init\n" );
66 mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent );
67 Display *display = XOpenDisplay( NULL );
69 if ( !display || mlt_properties_get_int( properties, "novdpau" )
70 || ( getenv( "MLT_NO_VDPAU" ) && strcmp( getenv( "MLT_NO_VDPAU" ), "1" ) == 0 ) )
74 if ( !vdpau_init_done )
77 object = dlopen( "/usr/lib/libvdpau.so", flags );
80 object = dlopen( "/usr/lib64/libvdpau.so", flags );
82 object = dlopen( "/usr/lib/x86_64-linux-gnu/libvdpau.so.1", flags );
85 object = dlopen( "/usr/lib/i386-linux-gnu/libvdpau.so.1", flags );
88 object = dlopen( "/usr/local/lib/libvdpau.so", flags );
90 vdpau_device_create_x11 = dlsym( object, "vdp_device_create_x11" );
93 mlt_log( MLT_PRODUCER_SERVICE(self->parent), MLT_LOG_WARNING, "%s: failed to dlopen libvdpau.so\n (%s)\n", __FUNCTION__, dlerror() );
100 if ( vdpau_device_create_x11 )
102 int screen = mlt_properties_get_int( properties, "x11_screen" );
104 self->vdpau = calloc( 1, sizeof( *self->vdpau ) );
105 self->vdpau->device = VDP_INVALID_HANDLE;
106 self->vdpau->decoder = VDP_INVALID_HANDLE;
108 mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "X11 Display = %p\n", display );
109 if ( VDP_STATUS_OK == vdpau_device_create_x11( display, screen, &self->vdpau->device, &vdp_get_proc_address ) )
111 if ( !vdpau_init_done ) {
112 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_ERROR_STRING, (void**) &vdp_get_error_string );
113 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_API_VERSION, (void**) &vdp_get_api_version );
114 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_INFORMATION_STRING, (void**) &vdp_get_information_string );
115 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, (void**) &vdp_surface_create );
116 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, (void**) &vdp_surface_destroy );
117 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, (void**) &vdp_surface_get_bits );
118 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_CREATE, (void**) &vdp_decoder_create );
119 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_DESTROY, (void**) &vdp_decoder_destroy );
120 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_RENDER, (void**) &vdp_decoder_render );
121 vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DEVICE_DESTROY, (void**) &vdp_device_destroy );
130 mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize device\n" );
141 static enum PixelFormat vdpau_get_format( struct AVCodecContext *s, const enum PixelFormat *fmt )
143 return PIX_FMT_VDPAU_H264;
146 static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame )
149 producer_avformat self = codec_context->opaque;
150 mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_get_buffer\n" );
152 if ( self->vdpau && mlt_deque_count( self->vdpau->deque ) )
154 struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque );
158 frame->data[0] = (uint8_t*) render;
159 frame->data[1] = (uint8_t*) render;
160 frame->data[2] = (uint8_t*) render;
161 frame->linesize[0] = 0;
162 frame->linesize[1] = 0;
163 frame->linesize[2] = 0;
164 frame->type = FF_BUFFER_TYPE_USER;
165 render->state = FF_VDPAU_STATE_USED_FOR_REFERENCE;
166 frame->reordered_opaque = codec_context->reordered_opaque;
167 if ( frame->reference )
169 self->vdpau->ip_age[0] = self->vdpau->ip_age[1] + 1;
170 self->vdpau->ip_age[1] = 1;
171 self->vdpau->b_age++;
175 self->vdpau->ip_age[0] ++;
176 self->vdpau->ip_age[1] ++;
177 self->vdpau->b_age = 1;
182 mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" );
188 mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" );
195 static void vdpau_release_buffer( AVCodecContext *codec_context, AVFrame *frame )
197 producer_avformat self = codec_context->opaque;
200 struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0];
201 mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_release_buffer (%x)\n", render->surface );
204 render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
205 for ( i = 0; i < 4; i++ )
206 frame->data[i] = NULL;
207 mlt_deque_push_back( self->vdpau->deque, render );
211 static void vdpau_draw_horiz( AVCodecContext *codec_context, const AVFrame *frame, int offset[4], int y, int type, int height )
213 producer_avformat self = codec_context->opaque;
216 struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0];
217 VdpVideoSurface surface = render->surface;
218 VdpStatus status = vdp_decoder_render( self->vdpau->decoder, surface, (void*) &render->info,
219 render->bitstream_buffers_used, render->bitstream_buffers );
221 if ( status != VDP_STATUS_OK )
223 self->vdpau->is_decoded = 0;
224 mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to decode (%s)\n",
225 vdp_get_error_string( status ) );
229 self->vdpau->is_decoded = 1;
234 static int vdpau_decoder_init( producer_avformat self )
236 mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_decoder_init\n" );
239 self->video_codec->opaque = self;
240 self->video_codec->get_format = vdpau_get_format;
241 self->video_codec->get_buffer = vdpau_get_buffer;
242 self->video_codec->release_buffer = vdpau_release_buffer;
243 self->video_codec->draw_horiz_band = vdpau_draw_horiz;
244 self->video_codec->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
245 self->video_codec->pix_fmt = PIX_FMT_VDPAU_H264;
247 VdpDecoderProfile profile = VDP_DECODER_PROFILE_H264_HIGH;
248 uint32_t max_references = self->video_codec->refs;
249 pthread_mutex_lock( &mlt_sdl_mutex );
250 VdpStatus status = vdp_decoder_create( self->vdpau->device,
251 profile, self->video_codec->width, self->video_codec->height, max_references, &self->vdpau->decoder );
252 pthread_mutex_unlock( &mlt_sdl_mutex );
254 if ( status == VDP_STATUS_OK )
256 int i, n = FFMIN( self->video_codec->refs + 2, MAX_VDPAU_SURFACES );
258 self->vdpau->deque = mlt_deque_init();
259 for ( i = 0; i < n; i++ )
261 if ( VDP_STATUS_OK == vdp_surface_create( self->vdpau->device, VDP_CHROMA_TYPE_420,
262 self->video_codec->width, self->video_codec->height, &self->vdpau->render_states[i].surface ) )
264 mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "successfully created VDPAU surface %x\n",
265 self->vdpau->render_states[i].surface );
266 mlt_deque_push_back( self->vdpau->deque, &self->vdpau->render_states[i] );
270 mlt_log_info( MLT_PRODUCER_SERVICE(self->parent), "failed to create VDPAU surface %dx%d\n",
271 self->video_codec->width, self->video_codec->height );
272 while ( mlt_deque_count( self->vdpau->deque ) )
274 struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque );
275 vdp_surface_destroy( render->surface );
277 mlt_deque_close( self->vdpau->deque );
283 self->vdpau->b_age = self->vdpau->ip_age[0] = self->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux
288 self->vdpau->decoder = VDP_INVALID_HANDLE;
289 mlt_log_error( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize decoder (%s)\n",
290 vdp_get_error_string( status ) );
296 static void vdpau_producer_close( producer_avformat self )
300 mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_producer_close\n" );
302 for ( i = 0; i < MAX_VDPAU_SURFACES; i++ )
304 if ( self->vdpau->render_states[i].surface != VDP_INVALID_HANDLE )
305 vdp_surface_destroy( self->vdpau->render_states[i].surface );
306 self->vdpau->render_states[i].surface = VDP_INVALID_HANDLE;
309 mlt_deque_close( self->vdpau->deque );
310 if ( self->vdpau->buffer )
311 mlt_pool_release( self->vdpau->buffer );
312 self->vdpau->buffer = NULL;