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
23 extern pthread_mutex_t mlt_sdl_mutex;
25 static VdpGetProcAddress *vdp_get_proc_address;
26 static VdpGetErrorString *vdp_get_error_string;
27 static VdpGetApiVersion *vdp_get_api_version;
28 static VdpGetInformationString *vdp_get_information_string;
29 static VdpVideoSurfaceCreate *vdp_surface_create;
30 static VdpVideoSurfaceDestroy *vdp_surface_destroy;
31 static VdpVideoSurfaceGetBitsYCbCr *vdp_surface_get_bits;
32 static VdpDecoderCreate *vdp_decoder_create;
33 static VdpDecoderDestroy *vdp_decoder_destroy;
34 static VdpDecoderRender *vdp_decoder_render;
46 static void vdpau_decoder_close();
48 static int vdpau_init( producer_avformat this )
50 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_init\n" );
52 mlt_properties properties = MLT_PRODUCER_PROPERTIES( this->parent );
54 if ( !mlt_environment( "x11_display" ) || mlt_properties_get_int( properties, "novdpau" ) )
60 void *object = dlopen( "/usr/lib/libvdpau.so", flags );
64 VdpDeviceCreateX11 *create_device = dlsym( object, "vdp_device_create_x11" );
67 int screen = mlt_properties_get_int( properties, "x11_screen" );
69 Display *display = (Display*) strtol( mlt_environment( "x11_display" ), NULL, 16 );
71 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "X11 Display = %p\n", display );
72 if ( VDP_STATUS_OK == create_device( display, screen, &device, &vdp_get_proc_address ) )
74 // Allocate the global VDPAU context
75 g_vdpau = calloc( 1, sizeof( *g_vdpau ) );
78 g_vdpau->device = device;
79 g_vdpau->decoder = VDP_INVALID_HANDLE;
80 g_vdpau->producer = this;
81 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_ERROR_STRING, (void**) &vdp_get_error_string );
82 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_API_VERSION, (void**) &vdp_get_api_version );
83 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_INFORMATION_STRING, (void**) &vdp_get_information_string );
84 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, (void**) &vdp_surface_create );
85 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, (void**) &vdp_surface_destroy );
86 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, (void**) &vdp_surface_get_bits );
87 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_DECODER_CREATE, (void**) &vdp_decoder_create );
88 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_DECODER_DESTROY, (void**) &vdp_decoder_destroy );
89 vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_DECODER_RENDER, (void**) &vdp_decoder_render );
96 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to initialize device\n" );
104 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "VDPAU already initialized\n" );
107 if ( g_vdpau && g_vdpau->producer != this )
108 vdpau_decoder_close();
113 static enum PixelFormat vdpau_get_format( struct AVCodecContext *s, const enum PixelFormat *fmt )
115 return PIX_FMT_VDPAU_H264;
118 static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame )
121 producer_avformat this = codec_context->opaque;
122 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_get_buffer\n" );
124 if ( g_vdpau->producer == this && mlt_deque_count( this->vdpau->deque ) )
126 struct vdpau_render_state *render = mlt_deque_pop_front( this->vdpau->deque );
130 frame->data[0] = (uint8_t*) render;
131 frame->data[1] = (uint8_t*) render;
132 frame->data[2] = (uint8_t*) render;
133 frame->linesize[0] = 0;
134 frame->linesize[1] = 0;
135 frame->linesize[2] = 0;
136 frame->type = FF_BUFFER_TYPE_USER;
137 render->state = FF_VDPAU_STATE_USED_FOR_REFERENCE;
138 frame->reordered_opaque = codec_context->reordered_opaque;
139 if ( frame->reference )
141 frame->age = this->vdpau->ip_age[0];
142 this->vdpau->ip_age[0] = this->vdpau->ip_age[1] + 1;
143 this->vdpau->ip_age[1] = 1;
144 this->vdpau->b_age++;
148 frame->age = this->vdpau->b_age;
149 this->vdpau->ip_age[0] ++;
150 this->vdpau->ip_age[1] ++;
151 this->vdpau->b_age = 1;
156 mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU surface underrun\n" );
162 mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU surface underrun\n" );
169 static void vdpau_release_buffer( AVCodecContext *codec_context, AVFrame *frame )
171 producer_avformat this = codec_context->opaque;
172 struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0];
173 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_release_buffer (%x)\n", render->surface );
176 render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
177 for ( i = 0; i < 4; i++ )
178 frame->data[i] = NULL;
179 mlt_deque_push_back( this->vdpau->deque, render );
182 static void vdpau_draw_horiz( AVCodecContext *codec_context, const AVFrame *frame, int offset[4], int y, int type, int height )
184 producer_avformat this = codec_context->opaque;
185 struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0];
186 VdpVideoSurface surface = render->surface;
187 VdpStatus status = vdp_decoder_render( g_vdpau->decoder, surface, (void*) &render->info,
188 render->bitstream_buffers_used, render->bitstream_buffers );
190 if ( status != VDP_STATUS_OK )
192 this->vdpau->is_decoded = 0;
193 mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to decode (%s)\n",
194 vdp_get_error_string( status ) );
198 this->vdpau->is_decoded = 1;
202 static int vdpau_decoder_init( producer_avformat this )
204 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_decoder_init\n" );
207 this->video_codec->opaque = this;
208 this->video_codec->get_format = vdpau_get_format;
209 this->video_codec->get_buffer = vdpau_get_buffer;
210 this->video_codec->release_buffer = vdpau_release_buffer;
211 this->video_codec->draw_horiz_band = vdpau_draw_horiz;
212 this->video_codec->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
213 this->video_codec->pix_fmt = PIX_FMT_VDPAU_H264;
215 VdpDecoderProfile profile = VDP_DECODER_PROFILE_H264_HIGH;
216 uint32_t max_references = this->video_codec->refs;
217 pthread_mutex_lock( &mlt_sdl_mutex );
218 VdpStatus status = vdp_decoder_create( g_vdpau->device,
219 profile, this->video_codec->width, this->video_codec->height, max_references, &g_vdpau->decoder );
220 pthread_mutex_unlock( &mlt_sdl_mutex );
222 if ( status == VDP_STATUS_OK )
226 int i, n = FFMIN( this->video_codec->refs + 1, MAX_VDPAU_SURFACES );
228 this->vdpau = calloc( 1, sizeof( *this->vdpau ) );
229 this->vdpau->deque = mlt_deque_init();
230 for ( i = 0; i < n; i++ )
232 if ( VDP_STATUS_OK == vdp_surface_create( g_vdpau->device, VDP_CHROMA_TYPE_420,
233 this->video_codec->width, this->video_codec->height, &this->vdpau->render_states[i].surface ) )
235 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "successfully created VDPAU surface %x\n",
236 this->vdpau->render_states[i].surface );
237 mlt_deque_push_back( this->vdpau->deque, &this->vdpau->render_states[i] );
241 mlt_log_info( MLT_PRODUCER_SERVICE(this->parent), "failed to create VDPAU surface %dx%d\n",
242 this->video_codec->width, this->video_codec->height );
243 while ( mlt_deque_count( this->vdpau->deque ) )
245 struct vdpau_render_state *render = mlt_deque_pop_front( this->vdpau->deque );
246 vdp_surface_destroy( render->surface );
248 mlt_deque_close( this->vdpau->deque );
251 vdp_decoder_destroy( g_vdpau->decoder );
252 g_vdpau->decoder = VDP_INVALID_HANDLE;
257 this->vdpau->b_age = this->vdpau->ip_age[0] = this->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux
259 g_vdpau->producer = this;
264 g_vdpau->decoder = VDP_INVALID_HANDLE;
265 mlt_log_error( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to initialize decoder (%s)\n",
266 vdp_get_error_string( status ) );
272 static void vdpau_producer_close( producer_avformat this )
276 mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_producer_close\n" );
278 for ( i = 0; i < MAX_VDPAU_SURFACES; i++ )
280 if ( this->vdpau->render_states[i].surface != VDP_INVALID_HANDLE )
281 vdp_surface_destroy( this->vdpau->render_states[i].surface );
282 this->vdpau->render_states[i].surface = VDP_INVALID_HANDLE;
284 mlt_deque_close( this->vdpau->deque );
285 if ( this->vdpau->buffer )
286 mlt_pool_release( this->vdpau->buffer );
287 this->vdpau->buffer = NULL;
293 static void vdpau_decoder_close( )
295 mlt_log_debug( NULL, "vdpau_decoder_close (%x)\n", g_vdpau->decoder );
296 if ( g_vdpau && g_vdpau->decoder != VDP_INVALID_HANDLE )
298 vdp_decoder_destroy( g_vdpau->decoder );
299 g_vdpau->decoder = VDP_INVALID_HANDLE;
300 g_vdpau->producer = NULL;
305 static void vdpau_close( void *ignored )
307 mlt_log_debug( NULL, "vdpau_close\n" );
310 vdpau_decoder_close( );