1 /*****************************************************************************
2 * avcodec.c: VDPAU decoder for libav
3 *****************************************************************************
4 * Copyright (C) 2012-2013 RĂ©mi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
30 #include <libavutil/mem.h>
31 #include <libavcodec/avcodec.h>
32 #include <libavcodec/vdpau.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_fourcc.h>
36 #include <vlc_picture.h>
38 #include "vlc_vdpau.h"
39 #include "../../codec/avcodec/va.h"
40 #include "../../codec/avcodec/avcommon_compat.h"
42 static int Open(vlc_va_t *, AVCodecContext *, const es_format_t *);
43 static void Close(vlc_va_t *);
46 set_description(N_("VDPAU hardware-accelerated decoder"))
47 set_capability("hw decoder", 100)
48 set_category(CAT_INPUT)
49 set_subcategory(SUBCAT_INPUT_VCODEC)
50 set_callbacks(Open, Close)
56 AVVDPAUContext *context;
59 VdpDecoderProfile profile;
64 static int Lock(vlc_va_t *va, void **opaque, uint8_t **data)
66 vlc_va_sys_t *sys = va->sys;
67 VdpVideoSurface surface;
70 err = vdp_video_surface_create(sys->vdp, sys->device, VDP_CHROMA_TYPE_420,
71 sys->width, sys->height, &surface);
72 if (err != VDP_STATUS_OK)
74 msg_Err(va, "%s creation failure: %s", "video surface",
75 vdp_get_error_string(sys->vdp, err));
79 vlc_vdp_video_field_t *field = vlc_vdp_video_create(sys->vdp, surface);
80 if (unlikely(field == NULL))
83 *data = (void *)(uintptr_t)surface;
88 static void Unlock(void *opaque, uint8_t *data)
90 vlc_vdp_video_field_t *field = opaque;
92 assert(field != NULL);
93 field->destroy(field);
97 static int Copy(vlc_va_t *va, picture_t *pic, void *opaque, uint8_t *data)
99 vlc_vdp_video_field_t *field = opaque;
101 assert(field != NULL);
102 field = vlc_vdp_video_copy(field);
103 if (unlikely(field == NULL))
106 assert(pic->context == NULL);
107 pic->context = field;
108 (void) va; (void) data;
112 static int Init(vlc_va_t *va, void **ctxp, vlc_fourcc_t *chromap,
113 int width, int height)
115 vlc_va_sys_t *sys = va->sys;
118 width = (width + 1) & ~1;
119 height = (height + 3) & ~3;
121 sys->height = height;
123 unsigned surfaces = 2;
124 switch (sys->profile)
126 case VDP_DECODER_PROFILE_H264_BASELINE:
127 case VDP_DECODER_PROFILE_H264_MAIN:
128 case VDP_DECODER_PROFILE_H264_HIGH:
133 err = vdp_decoder_create(sys->vdp, sys->device, sys->profile, width,
134 height, surfaces, &sys->context->decoder);
135 if (err != VDP_STATUS_OK)
137 msg_Err(va, "%s creation failure: %s", "decoder",
138 vdp_get_error_string(sys->vdp, err));
139 sys->context->decoder = VDP_INVALID_HANDLE;
143 *ctxp = sys->context;
144 /* TODO: select better chromas when appropriate */
145 *chromap = VLC_CODEC_VDPAU_VIDEO_420;
149 static void Deinit(vlc_va_t *va)
151 vlc_va_sys_t *sys = va->sys;
153 assert(sys->context->decoder != VDP_INVALID_HANDLE);
154 vdp_decoder_destroy(sys->vdp, sys->context->decoder);
157 static int Setup(vlc_va_t *va, void **ctxp, vlc_fourcc_t *chromap,
158 int width, int height)
160 vlc_va_sys_t *sys = va->sys;
162 if (sys->context->decoder != VDP_INVALID_HANDLE)
164 if (sys->width == width && sys->height == height)
167 sys->context->decoder = VDP_INVALID_HANDLE;
170 return Init(va, ctxp, chromap, width, height);
173 static int Open(vlc_va_t *va, AVCodecContext *ctx, const es_format_t *fmt)
176 VdpDecoderProfile profile;
177 int level = fmt->i_level;
179 if (av_vdpau_get_profile(ctx, &profile))
181 msg_Err(va, "unsupported codec %d or profile %d", ctx->codec_id,
186 switch (ctx->codec_id)
188 case AV_CODEC_ID_MPEG1VIDEO:
189 level = VDP_DECODER_LEVEL_MPEG1_NA;
191 case AV_CODEC_ID_MPEG2VIDEO:
192 level = VDP_DECODER_LEVEL_MPEG2_HL;
194 case AV_CODEC_ID_H263:
195 level = VDP_DECODER_LEVEL_MPEG4_PART2_ASP_L5;
197 case AV_CODEC_ID_H264:
198 if ((fmt->i_profile & FF_PROFILE_H264_INTRA)
199 && (fmt->i_level == 11))
200 level = VDP_DECODER_LEVEL_H264_1b;
205 if (!vlc_xlib_init(VLC_OBJECT(va)))
207 msg_Err(va, "Xlib is required for VDPAU");
211 vlc_va_sys_t *sys = malloc(sizeof (*sys));
212 if (unlikely(sys == NULL))
215 sys->context = av_vdpau_alloc_context();
216 if (unlikely(sys->context == NULL))
222 err = vdp_get_x11(NULL, -1, &sys->vdp, &sys->device);
223 if (err != VDP_STATUS_OK)
231 err = vdp_get_proc_address(sys->vdp, sys->device,
232 VDP_FUNC_ID_DECODER_RENDER, &func);
233 if (err != VDP_STATUS_OK)
236 sys->context->decoder = VDP_INVALID_HANDLE;
237 sys->context->render = func;
238 sys->profile = profile;
240 /* Check capabilities */
242 uint32_t l, mb, w, h;
244 if (vdp_video_surface_query_capabilities(sys->vdp, sys->device,
245 VDP_CHROMA_TYPE_420, &support, &w, &h) != VDP_STATUS_OK)
249 msg_Err(va, "video surface format not supported: %s", "YUV 4:2:0");
252 msg_Dbg(va, "video surface limits: %"PRIu32"x%"PRIu32, w, h);
253 if (w < fmt->video.i_width || h < fmt->video.i_height)
255 msg_Err(va, "video surface above limits: %ux%u",
256 fmt->video.i_width, fmt->video.i_height);
260 if (vdp_decoder_query_capabilities(sys->vdp, sys->device, profile,
261 &support, &l, &mb, &w, &h) != VDP_STATUS_OK)
265 msg_Err(va, "decoder profile not supported: %u", profile);
268 msg_Dbg(va, "decoder profile limits: level %"PRIu32" mb %"PRIu32" "
269 "%"PRIu32"x%"PRIu32, l, mb, w, h);
270 if ((int)l < level || w < fmt->video.i_width || h < fmt->video.i_height)
272 msg_Err(va, "decoder profile above limits: level %d %ux%u",
273 level, fmt->video.i_width, fmt->video.i_height);
278 if (vdp_get_information_string(sys->vdp, &infos) != VDP_STATUS_OK)
282 va->description = (char *)infos;
283 va->pix_fmt = AV_PIX_FMT_VDPAU;
286 va->release = Unlock;
291 vdp_release_x11(sys->vdp);
292 av_free(sys->context);
297 static void Close(vlc_va_t *va)
299 vlc_va_sys_t *sys = va->sys;
301 if (sys->context->decoder != VDP_INVALID_HANDLE)
303 vdp_release_x11(sys->vdp);
304 av_free(sys->context);