]> git.sesse.net Git - vlc/blob - modules/hw/vdpau/avcodec.c
av_vdpau_alloc_context replacement for FFmpeg
[vlc] / modules / hw / vdpau / avcodec.c
1 /*****************************************************************************
2  * avcodec.c: VDPAU decoder for libav
3  *****************************************************************************
4  * Copyright (C) 2012-2013 RĂ©mi Denis-Courmont
5  *
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.
10  *
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.
15  *
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  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <assert.h>
29
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>
37 #include <vlc_xlib.h>
38 #include "vlc_vdpau.h"
39 #include "../../codec/avcodec/va.h"
40 #include "../../codec/avcodec/avcommon_compat.h"
41
42 static int Open(vlc_va_t *, AVCodecContext *, const es_format_t *);
43 static void Close(vlc_va_t *);
44
45 vlc_module_begin()
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)
51     add_shortcut("vdpau")
52 vlc_module_end()
53
54 struct vlc_va_sys_t
55 {
56     AVVDPAUContext *context;
57     vdp_t *vdp;
58     VdpDevice device;
59     VdpDecoderProfile profile;
60     uint16_t width;
61     uint16_t height;
62 };
63
64 static int Lock(vlc_va_t *va, void **opaque, uint8_t **data)
65 {
66     vlc_va_sys_t *sys = va->sys;
67     VdpVideoSurface surface;
68     VdpStatus err;
69
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)
73     {
74         msg_Err(va, "%s creation failure: %s", "video surface",
75                 vdp_get_error_string(sys->vdp, err));
76         return VLC_EGENERIC;
77     }
78
79     vlc_vdp_video_field_t *field = vlc_vdp_video_create(sys->vdp, surface);
80     if (unlikely(field == NULL))
81         return VLC_ENOMEM;
82
83     *data = (void *)(uintptr_t)surface;
84     *opaque = field;
85     return VLC_SUCCESS;
86 }
87
88 static void Unlock(void *opaque, uint8_t *data)
89 {
90     vlc_vdp_video_field_t *field = opaque;
91
92     assert(field != NULL);
93     field->destroy(field);
94     (void) data;
95 }
96
97 static int Copy(vlc_va_t *va, picture_t *pic, void *opaque, uint8_t *data)
98 {
99     vlc_vdp_video_field_t *field = opaque;
100
101     assert(field != NULL);
102     field = vlc_vdp_video_copy(field);
103     if (unlikely(field == NULL))
104         return VLC_ENOMEM;
105
106     assert(pic->context == NULL);
107     pic->context = field;
108     (void) va; (void) data;
109     return VLC_SUCCESS;
110 }
111
112 static int Init(vlc_va_t *va, void **ctxp, vlc_fourcc_t *chromap,
113                 int width, int height)
114 {
115     vlc_va_sys_t *sys = va->sys;
116     VdpStatus err;
117
118     width = (width + 1) & ~1;
119     height = (height + 3) & ~3;
120     sys->width = width;
121     sys->height = height;
122
123     unsigned surfaces = 2;
124     switch (sys->profile)
125     {
126       case VDP_DECODER_PROFILE_H264_BASELINE:
127       case VDP_DECODER_PROFILE_H264_MAIN:
128       case VDP_DECODER_PROFILE_H264_HIGH:
129         surfaces = 16;
130         break;
131     }
132
133     err = vdp_decoder_create(sys->vdp, sys->device, sys->profile, width,
134                              height, surfaces, &sys->context->decoder);
135     if (err != VDP_STATUS_OK)
136     {
137         msg_Err(va, "%s creation failure: %s", "decoder",
138                 vdp_get_error_string(sys->vdp, err));
139         sys->context->decoder = VDP_INVALID_HANDLE;
140         return VLC_EGENERIC;
141     }
142
143     *ctxp = sys->context;
144     /* TODO: select better chromas when appropriate */
145     *chromap = VLC_CODEC_VDPAU_VIDEO_420;
146     return VLC_SUCCESS;
147 }
148
149 static void Deinit(vlc_va_t *va)
150 {
151     vlc_va_sys_t *sys = va->sys;
152
153     assert(sys->context->decoder != VDP_INVALID_HANDLE);
154     vdp_decoder_destroy(sys->vdp, sys->context->decoder);
155 }
156
157 static int Setup(vlc_va_t *va, void **ctxp, vlc_fourcc_t *chromap,
158                  int width, int height)
159 {
160     vlc_va_sys_t *sys = va->sys;
161
162     if (sys->context->decoder != VDP_INVALID_HANDLE)
163     {
164         if (sys->width == width && sys->height == height)
165             return VLC_SUCCESS;
166         Deinit(va);
167         sys->context->decoder = VDP_INVALID_HANDLE;
168     }
169
170     return Init(va, ctxp, chromap, width, height);
171 }
172
173 static int Open(vlc_va_t *va, AVCodecContext *ctx, const es_format_t *fmt)
174 {
175     VdpStatus err;
176     VdpDecoderProfile profile;
177     int level = fmt->i_level;
178
179     if (av_vdpau_get_profile(ctx, &profile))
180     {
181         msg_Err(va, "unsupported codec %d or profile %d", ctx->codec_id,
182                 fmt->i_profile);
183         return VLC_EGENERIC;
184     }
185
186     switch (ctx->codec_id)
187     {
188         case AV_CODEC_ID_MPEG1VIDEO:
189             level = VDP_DECODER_LEVEL_MPEG1_NA;
190             break;
191         case AV_CODEC_ID_MPEG2VIDEO:
192             level = VDP_DECODER_LEVEL_MPEG2_HL;
193             break;
194         case AV_CODEC_ID_H263:
195             level = VDP_DECODER_LEVEL_MPEG4_PART2_ASP_L5;
196             break;
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;
201          default:
202             break;
203     }
204
205     if (!vlc_xlib_init(VLC_OBJECT(va)))
206     {
207         msg_Err(va, "Xlib is required for VDPAU");
208         return VLC_EGENERIC;
209     }
210
211     vlc_va_sys_t *sys = malloc(sizeof (*sys));
212     if (unlikely(sys == NULL))
213        return VLC_ENOMEM;
214
215     sys->context = av_vdpau_alloc_context();
216     if (unlikely(sys->context == NULL))
217     {
218         free(sys);
219         return VLC_ENOMEM;
220     }
221
222     err = vdp_get_x11(NULL, -1, &sys->vdp, &sys->device);
223     if (err != VDP_STATUS_OK)
224     {
225         free(sys->context);
226         free(sys);
227         return VLC_EGENERIC;
228     }
229
230     void *func;
231     err = vdp_get_proc_address(sys->vdp, sys->device,
232                                VDP_FUNC_ID_DECODER_RENDER, &func);
233     if (err != VDP_STATUS_OK)
234         goto error;
235
236     sys->context->decoder = VDP_INVALID_HANDLE;
237     sys->context->render = func;
238     sys->profile = profile;
239
240     /* Check capabilities */
241     VdpBool support;
242     uint32_t l, mb, w, h;
243
244     if (vdp_video_surface_query_capabilities(sys->vdp, sys->device,
245               VDP_CHROMA_TYPE_420, &support, &w, &h) != VDP_STATUS_OK)
246         support = VDP_FALSE;
247     if (!support)
248     {
249         msg_Err(va, "video surface format not supported: %s", "YUV 4:2:0");
250         goto error;
251     }
252     msg_Dbg(va, "video surface limits: %"PRIu32"x%"PRIu32, w, h);
253     if (w < fmt->video.i_width || h < fmt->video.i_height)
254     {
255         msg_Err(va, "video surface above limits: %ux%u",
256                 fmt->video.i_width, fmt->video.i_height);
257         goto error;
258     }
259
260     if (vdp_decoder_query_capabilities(sys->vdp, sys->device, profile,
261                                    &support, &l, &mb, &w, &h) != VDP_STATUS_OK)
262         support = VDP_FALSE;
263     if (!support)
264     {
265         msg_Err(va, "decoder profile not supported: %u", profile);
266         goto error;
267     }
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)
271     {
272         msg_Err(va, "decoder profile above limits: level %d %ux%u",
273                 level, fmt->video.i_width, fmt->video.i_height);
274         goto error;
275     }
276
277     const char *infos;
278     if (vdp_get_information_string(sys->vdp, &infos) != VDP_STATUS_OK)
279         infos = "VDPAU";
280
281     va->sys = sys;
282     va->description = (char *)infos;
283     va->pix_fmt = AV_PIX_FMT_VDPAU;
284     va->setup = Setup;
285     va->get = Lock;
286     va->release = Unlock;
287     va->extract = Copy;
288     return VLC_SUCCESS;
289
290 error:
291     vdp_release_x11(sys->vdp);
292     av_free(sys->context);
293     free(sys);
294     return VLC_EGENERIC;
295 }
296
297 static void Close(vlc_va_t *va)
298 {
299     vlc_va_sys_t *sys = va->sys;
300
301     if (sys->context->decoder != VDP_INVALID_HANDLE)
302         Deinit(va);
303     vdp_release_x11(sys->vdp);
304     av_free(sys->context);
305     free(sys);
306 }