PageRenderTime 62ms CodeModel.GetById 34ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/libavcodec/vdpau.c

http://github.com/FFmpeg/FFmpeg
C | 472 lines | 374 code | 67 blank | 31 comment | 86 complexity | 334869f5f6c2df3ad218a05b2a3aa57b MD5 | raw file
  1/*
  2 * Video Decode and Presentation API for UNIX (VDPAU) is used for
  3 * HW decode acceleration for MPEG-1/2, MPEG-4 ASP, H.264 and VC-1.
  4 *
  5 * Copyright (c) 2008 NVIDIA
  6 *
  7 * This file is part of FFmpeg.
  8 *
  9 * FFmpeg is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation; either
 12 * version 2.1 of the License, or (at your option) any later version.
 13 *
 14 * FFmpeg is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 *
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with FFmpeg; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 22 */
 23
 24#include <limits.h>
 25
 26#include "avcodec.h"
 27#include "decode.h"
 28#include "internal.h"
 29#include "h264dec.h"
 30#include "vc1.h"
 31#include "vdpau.h"
 32#include "vdpau_internal.h"
 33
 34// XXX: at the time of adding this ifdefery, av_assert* wasn't use outside.
 35// When dropping it, make sure other av_assert* were not added since then.
 36
 37/**
 38 * @addtogroup VDPAU_Decoding
 39 *
 40 * @{
 41 */
 42
 43static int vdpau_error(VdpStatus status)
 44{
 45    switch (status) {
 46    case VDP_STATUS_OK:
 47        return 0;
 48    case VDP_STATUS_NO_IMPLEMENTATION:
 49        return AVERROR(ENOSYS);
 50    case VDP_STATUS_DISPLAY_PREEMPTED:
 51        return AVERROR(EIO);
 52    case VDP_STATUS_INVALID_HANDLE:
 53        return AVERROR(EBADF);
 54    case VDP_STATUS_INVALID_POINTER:
 55        return AVERROR(EFAULT);
 56    case VDP_STATUS_RESOURCES:
 57        return AVERROR(ENOBUFS);
 58    case VDP_STATUS_HANDLE_DEVICE_MISMATCH:
 59        return AVERROR(EXDEV);
 60    case VDP_STATUS_ERROR:
 61        return AVERROR(EIO);
 62    default:
 63        return AVERROR(EINVAL);
 64    }
 65}
 66
 67AVVDPAUContext *av_alloc_vdpaucontext(void)
 68{
 69    return av_vdpau_alloc_context();
 70}
 71
 72MAKE_ACCESSORS(AVVDPAUContext, vdpau_hwaccel, AVVDPAU_Render2, render2)
 73
 74int av_vdpau_get_surface_parameters(AVCodecContext *avctx,
 75                                    VdpChromaType *type,
 76                                    uint32_t *width, uint32_t *height)
 77{
 78    VdpChromaType t;
 79    uint32_t w = avctx->coded_width;
 80    uint32_t h = avctx->coded_height;
 81
 82    /* See <vdpau/vdpau.h> for per-type alignment constraints. */
 83    switch (avctx->sw_pix_fmt) {
 84    case AV_PIX_FMT_YUV420P:
 85    case AV_PIX_FMT_YUVJ420P:
 86        t = VDP_CHROMA_TYPE_420;
 87        w = (w + 1) & ~1;
 88        h = (h + 3) & ~3;
 89        break;
 90    case AV_PIX_FMT_YUV422P:
 91    case AV_PIX_FMT_YUVJ422P:
 92        t = VDP_CHROMA_TYPE_422;
 93        w = (w + 1) & ~1;
 94        h = (h + 1) & ~1;
 95        break;
 96    case AV_PIX_FMT_YUV444P:
 97    case AV_PIX_FMT_YUVJ444P:
 98        t = VDP_CHROMA_TYPE_444;
 99        h = (h + 1) & ~1;
100        break;
101    default:
102        return AVERROR(ENOSYS);
103    }
104
105    if (type)
106        *type = t;
107    if (width)
108        *width = w;
109    if (height)
110        *height = h;
111    return 0;
112}
113
114int ff_vdpau_common_frame_params(AVCodecContext *avctx,
115                                 AVBufferRef *hw_frames_ctx)
116{
117    AVHWFramesContext *hw_frames = (AVHWFramesContext*)hw_frames_ctx->data;
118    VdpChromaType type;
119    uint32_t width;
120    uint32_t height;
121
122    if (av_vdpau_get_surface_parameters(avctx, &type, &width, &height))
123        return AVERROR(EINVAL);
124
125    hw_frames->format    = AV_PIX_FMT_VDPAU;
126    hw_frames->sw_format = avctx->sw_pix_fmt;
127    hw_frames->width     = width;
128    hw_frames->height    = height;
129
130    return 0;
131}
132
133int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
134                         int level)
135{
136    VDPAUHWContext *hwctx = avctx->hwaccel_context;
137    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
138    VdpVideoSurfaceQueryCapabilities *surface_query_caps;
139    VdpDecoderQueryCapabilities *decoder_query_caps;
140    VdpDecoderCreate *create;
141    VdpGetInformationString *info;
142    const char *info_string;
143    void *func;
144    VdpStatus status;
145    VdpBool supported;
146    uint32_t max_level, max_mb, max_width, max_height;
147    VdpChromaType type;
148    uint32_t width;
149    uint32_t height;
150    int ret;
151
152    vdctx->width            = UINT32_MAX;
153    vdctx->height           = UINT32_MAX;
154
155    if (av_vdpau_get_surface_parameters(avctx, &type, &width, &height))
156        return AVERROR(ENOSYS);
157
158    if (hwctx) {
159        hwctx->reset            = 0;
160
161        if (hwctx->context.decoder != VDP_INVALID_HANDLE) {
162            vdctx->decoder = hwctx->context.decoder;
163            vdctx->render  = hwctx->context.render;
164            vdctx->device  = VDP_INVALID_HANDLE;
165            return 0; /* Decoder created by user */
166        }
167
168        vdctx->device           = hwctx->device;
169        vdctx->get_proc_address = hwctx->get_proc_address;
170
171        if (hwctx->flags & AV_HWACCEL_FLAG_IGNORE_LEVEL)
172            level = 0;
173
174        if (!(hwctx->flags & AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH) &&
175            type != VDP_CHROMA_TYPE_420)
176            return AVERROR(ENOSYS);
177    } else {
178        AVHWFramesContext *frames_ctx;
179        AVVDPAUDeviceContext *dev_ctx;
180
181        ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VDPAU);
182        if (ret < 0)
183            return ret;
184
185        frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
186        dev_ctx = frames_ctx->device_ctx->hwctx;
187
188        vdctx->device           = dev_ctx->device;
189        vdctx->get_proc_address = dev_ctx->get_proc_address;
190
191        if (avctx->hwaccel_flags & AV_HWACCEL_FLAG_IGNORE_LEVEL)
192            level = 0;
193    }
194
195    if (level < 0)
196        return AVERROR(ENOTSUP);
197
198    status = vdctx->get_proc_address(vdctx->device,
199                                     VDP_FUNC_ID_GET_INFORMATION_STRING,
200                                     &func);
201    if (status != VDP_STATUS_OK)
202        return vdpau_error(status);
203    else
204        info = func;
205
206    status = info(&info_string);
207    if (status != VDP_STATUS_OK)
208        return vdpau_error(status);
209    if (avctx->codec_id == AV_CODEC_ID_HEVC && strncmp(info_string, "NVIDIA ", 7) == 0 &&
210        !(avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH)) {
211        int driver_version = 0;
212        sscanf(info_string, "NVIDIA VDPAU Driver Shared Library  %d", &driver_version);
213        if (driver_version < 410) {
214            av_log(avctx, AV_LOG_VERBOSE, "HEVC with NVIDIA VDPAU drivers is buggy, skipping.\n");
215            return AVERROR(ENOTSUP);
216        }
217    }
218
219    status = vdctx->get_proc_address(vdctx->device,
220                                     VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES,
221                                     &func);
222    if (status != VDP_STATUS_OK)
223        return vdpau_error(status);
224    else
225        surface_query_caps = func;
226
227    status = surface_query_caps(vdctx->device, type, &supported,
228                                &max_width, &max_height);
229    if (status != VDP_STATUS_OK)
230        return vdpau_error(status);
231    if (supported != VDP_TRUE ||
232        max_width < width || max_height < height)
233        return AVERROR(ENOTSUP);
234
235    status = vdctx->get_proc_address(vdctx->device,
236                                     VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES,
237                                     &func);
238    if (status != VDP_STATUS_OK)
239        return vdpau_error(status);
240    else
241        decoder_query_caps = func;
242
243    status = decoder_query_caps(vdctx->device, profile, &supported, &max_level,
244                                &max_mb, &max_width, &max_height);
245#ifdef VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE
246    if ((status != VDP_STATUS_OK || supported != VDP_TRUE) && profile == VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE) {
247        profile = VDP_DECODER_PROFILE_H264_MAIN;
248        status = decoder_query_caps(vdctx->device, profile, &supported,
249                                    &max_level, &max_mb,
250                                    &max_width, &max_height);
251    }
252#endif
253    if (status != VDP_STATUS_OK)
254        return vdpau_error(status);
255
256    if (supported != VDP_TRUE || max_level < level ||
257        max_width < width || max_height < height)
258        return AVERROR(ENOTSUP);
259
260    status = vdctx->get_proc_address(vdctx->device, VDP_FUNC_ID_DECODER_CREATE,
261                                     &func);
262    if (status != VDP_STATUS_OK)
263        return vdpau_error(status);
264    else
265        create = func;
266
267    status = vdctx->get_proc_address(vdctx->device, VDP_FUNC_ID_DECODER_RENDER,
268                                     &func);
269    if (status != VDP_STATUS_OK)
270        return vdpau_error(status);
271    else
272        vdctx->render = func;
273
274    status = create(vdctx->device, profile, width, height, avctx->refs,
275                    &vdctx->decoder);
276    if (status == VDP_STATUS_OK) {
277        vdctx->width  = avctx->coded_width;
278        vdctx->height = avctx->coded_height;
279    }
280
281    return vdpau_error(status);
282}
283
284int ff_vdpau_common_uninit(AVCodecContext *avctx)
285{
286    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
287    VdpDecoderDestroy *destroy;
288    void *func;
289    VdpStatus status;
290
291    if (vdctx->device == VDP_INVALID_HANDLE)
292        return 0; /* Decoder created and destroyed by user */
293    if (vdctx->width == UINT32_MAX && vdctx->height == UINT32_MAX)
294        return 0;
295
296    status = vdctx->get_proc_address(vdctx->device,
297                                     VDP_FUNC_ID_DECODER_DESTROY, &func);
298    if (status != VDP_STATUS_OK)
299        return vdpau_error(status);
300    else
301        destroy = func;
302
303    status = destroy(vdctx->decoder);
304    return vdpau_error(status);
305}
306
307static int ff_vdpau_common_reinit(AVCodecContext *avctx)
308{
309    VDPAUHWContext *hwctx = avctx->hwaccel_context;
310    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
311
312    if (vdctx->device == VDP_INVALID_HANDLE)
313        return 0; /* Decoder created by user */
314    if (avctx->coded_width == vdctx->width &&
315        avctx->coded_height == vdctx->height && (!hwctx || !hwctx->reset))
316        return 0;
317
318    avctx->hwaccel->uninit(avctx);
319    return avctx->hwaccel->init(avctx);
320}
321
322int ff_vdpau_common_start_frame(struct vdpau_picture_context *pic_ctx,
323                                av_unused const uint8_t *buffer,
324                                av_unused uint32_t size)
325{
326    pic_ctx->bitstream_buffers_allocated = 0;
327    pic_ctx->bitstream_buffers_used      = 0;
328    pic_ctx->bitstream_buffers           = NULL;
329    return 0;
330}
331
332int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
333                              struct vdpau_picture_context *pic_ctx)
334{
335    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
336    AVVDPAUContext *hwctx = avctx->hwaccel_context;
337    VdpVideoSurface surf = ff_vdpau_get_surface_id(frame);
338    VdpStatus status;
339    int val;
340
341    val = ff_vdpau_common_reinit(avctx);
342    if (val < 0)
343        return val;
344
345    if (hwctx && !hwctx->render && hwctx->render2) {
346        status = hwctx->render2(avctx, frame, (void *)&pic_ctx->info,
347                                pic_ctx->bitstream_buffers_used, pic_ctx->bitstream_buffers);
348    } else
349    status = vdctx->render(vdctx->decoder, surf, &pic_ctx->info,
350                           pic_ctx->bitstream_buffers_used,
351                           pic_ctx->bitstream_buffers);
352
353    av_freep(&pic_ctx->bitstream_buffers);
354
355    return vdpau_error(status);
356}
357
358#if CONFIG_MPEG1_VDPAU_HWACCEL || \
359    CONFIG_MPEG2_VDPAU_HWACCEL || CONFIG_MPEG4_VDPAU_HWACCEL || \
360    CONFIG_VC1_VDPAU_HWACCEL   || CONFIG_WMV3_VDPAU_HWACCEL
361int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx)
362{
363    MpegEncContext *s = avctx->priv_data;
364    Picture *pic = s->current_picture_ptr;
365    struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private;
366    int val;
367
368    val = ff_vdpau_common_end_frame(avctx, pic->f, pic_ctx);
369    if (val < 0)
370        return val;
371
372    ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
373    return 0;
374}
375#endif
376
377int ff_vdpau_add_buffer(struct vdpau_picture_context *pic_ctx,
378                        const uint8_t *buf, uint32_t size)
379{
380    VdpBitstreamBuffer *buffers = pic_ctx->bitstream_buffers;
381
382    buffers = av_fast_realloc(buffers, &pic_ctx->bitstream_buffers_allocated,
383                              (pic_ctx->bitstream_buffers_used + 1) * sizeof(*buffers));
384    if (!buffers)
385        return AVERROR(ENOMEM);
386
387    pic_ctx->bitstream_buffers = buffers;
388    buffers += pic_ctx->bitstream_buffers_used++;
389
390    buffers->struct_version  = VDP_BITSTREAM_BUFFER_VERSION;
391    buffers->bitstream       = buf;
392    buffers->bitstream_bytes = size;
393    return 0;
394}
395
396#if FF_API_VDPAU_PROFILE
397int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile)
398{
399#define PROFILE(prof)                      \
400do {                                       \
401    *profile = VDP_DECODER_PROFILE_##prof; \
402    return 0;                              \
403} while (0)
404
405    switch (avctx->codec_id) {
406    case AV_CODEC_ID_MPEG1VIDEO:               PROFILE(MPEG1);
407    case AV_CODEC_ID_MPEG2VIDEO:
408        switch (avctx->profile) {
409        case FF_PROFILE_MPEG2_MAIN:            PROFILE(MPEG2_MAIN);
410        case FF_PROFILE_MPEG2_SIMPLE:          PROFILE(MPEG2_SIMPLE);
411        default:                               return AVERROR(EINVAL);
412        }
413    case AV_CODEC_ID_H263:                     PROFILE(MPEG4_PART2_ASP);
414    case AV_CODEC_ID_MPEG4:
415        switch (avctx->profile) {
416        case FF_PROFILE_MPEG4_SIMPLE:          PROFILE(MPEG4_PART2_SP);
417        case FF_PROFILE_MPEG4_ADVANCED_SIMPLE: PROFILE(MPEG4_PART2_ASP);
418        default:                               return AVERROR(EINVAL);
419        }
420    case AV_CODEC_ID_H264:
421        switch (avctx->profile & ~FF_PROFILE_H264_INTRA) {
422        case FF_PROFILE_H264_BASELINE:         PROFILE(H264_BASELINE);
423        case FF_PROFILE_H264_CONSTRAINED_BASELINE:
424        case FF_PROFILE_H264_MAIN:             PROFILE(H264_MAIN);
425        case FF_PROFILE_H264_HIGH:             PROFILE(H264_HIGH);
426#ifdef VDP_DECODER_PROFILE_H264_EXTENDED
427        case FF_PROFILE_H264_EXTENDED:         PROFILE(H264_EXTENDED);
428#endif
429        default:                               return AVERROR(EINVAL);
430        }
431    case AV_CODEC_ID_WMV3:
432    case AV_CODEC_ID_VC1:
433        switch (avctx->profile) {
434        case FF_PROFILE_VC1_SIMPLE:            PROFILE(VC1_SIMPLE);
435        case FF_PROFILE_VC1_MAIN:              PROFILE(VC1_MAIN);
436        case FF_PROFILE_VC1_ADVANCED:          PROFILE(VC1_ADVANCED);
437        default:                               return AVERROR(EINVAL);
438        }
439    }
440    return AVERROR(EINVAL);
441#undef PROFILE
442}
443#endif /* FF_API_VDPAU_PROFILE */
444
445AVVDPAUContext *av_vdpau_alloc_context(void)
446{
447    return av_mallocz(sizeof(VDPAUHWContext));
448}
449
450int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device,
451                          VdpGetProcAddress *get_proc, unsigned flags)
452{
453    VDPAUHWContext *hwctx;
454
455    if (flags & ~(AV_HWACCEL_FLAG_IGNORE_LEVEL|AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH))
456        return AVERROR(EINVAL);
457
458    if (av_reallocp(&avctx->hwaccel_context, sizeof(*hwctx)))
459        return AVERROR(ENOMEM);
460
461    hwctx = avctx->hwaccel_context;
462
463    memset(hwctx, 0, sizeof(*hwctx));
464    hwctx->context.decoder  = VDP_INVALID_HANDLE;
465    hwctx->device           = device;
466    hwctx->get_proc_address = get_proc;
467    hwctx->flags            = flags;
468    hwctx->reset            = 1;
469    return 0;
470}
471
472/* @}*/