vdpau.c 12.4 KB
Newer Older
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 Libav.
8
 *
9
 * Libav is free software; you can redistribute it and/or
10 11 12 13
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
14
 * Libav is distributed in the hope that it will be useful,
15 16 17 18 19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with Libav; if not, write to the Free Software
21 22 23 24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <limits.h>
25

26
#include "avcodec.h"
27
#include "internal.h"
28
#include "h264.h"
29
#include "vc1.h"
30
#include "vdpau.h"
31 32 33
#include "vdpau_internal.h"

/**
34
 * @addtogroup VDPAU_Decoding
35 36 37 38
 *
 * @{
 */

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
static int vdpau_error(VdpStatus status)
{
    switch (status) {
    case VDP_STATUS_OK:
        return 0;
    case VDP_STATUS_NO_IMPLEMENTATION:
        return AVERROR(ENOSYS);
    case VDP_STATUS_DISPLAY_PREEMPTED:
        return AVERROR(EIO);
    case VDP_STATUS_INVALID_HANDLE:
        return AVERROR(EBADF);
    case VDP_STATUS_INVALID_POINTER:
        return AVERROR(EFAULT);
    case VDP_STATUS_RESOURCES:
        return AVERROR(ENOBUFS);
    case VDP_STATUS_HANDLE_DEVICE_MISMATCH:
        return AVERROR(EXDEV);
    case VDP_STATUS_ERROR:
        return AVERROR(EIO);
    default:
        return AVERROR(EINVAL);
    }
}

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
int av_vdpau_get_surface_parameters(AVCodecContext *avctx,
                                    VdpChromaType *type,
                                    uint32_t *width, uint32_t *height)
{
    VdpChromaType t;
    uint32_t w = avctx->coded_width;
    uint32_t h = avctx->coded_height;

    /* See <vdpau/vdpau.h> for per-type alignment constraints. */
    switch (avctx->sw_pix_fmt) {
    case AV_PIX_FMT_YUV420P:
    case AV_PIX_FMT_YUVJ420P:
        t = VDP_CHROMA_TYPE_420;
        w = (w + 1) & ~1;
        h = (h + 3) & ~3;
        break;
    case AV_PIX_FMT_YUV422P:
    case AV_PIX_FMT_YUVJ422P:
        t = VDP_CHROMA_TYPE_422;
        w = (w + 1) & ~1;
        h = (h + 1) & ~1;
        break;
    case AV_PIX_FMT_YUV444P:
    case AV_PIX_FMT_YUVJ444P:
        t = VDP_CHROMA_TYPE_444;
        h = (h + 1) & ~1;
        break;
    default:
        return AVERROR(ENOSYS);
    }

    if (type)
        *type = t;
    if (width)
        *width = w;
    if (height)
        *height = h;
    return 0;
}

103 104 105 106 107
int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
                         int level)
{
    VDPAUHWContext *hwctx = avctx->hwaccel_context;
    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
108 109
    VdpVideoSurfaceQueryCapabilities *surface_query_caps;
    VdpDecoderQueryCapabilities *decoder_query_caps;
110 111 112
    VdpDecoderCreate *create;
    void *func;
    VdpStatus status;
113 114
    VdpBool supported;
    uint32_t max_level, max_mb, max_width, max_height;
115 116 117
    VdpChromaType type;
    uint32_t width;
    uint32_t height;
118

119 120
    vdctx->width            = UINT32_MAX;
    vdctx->height           = UINT32_MAX;
121
    hwctx->reset            = 0;
122

123 124 125 126 127 128 129 130 131 132
    if (hwctx->context.decoder != VDP_INVALID_HANDLE) {
        vdctx->decoder = hwctx->context.decoder;
        vdctx->render  = hwctx->context.render;
        vdctx->device  = VDP_INVALID_HANDLE;
        return 0; /* Decoder created by user */
    }

    vdctx->device           = hwctx->device;
    vdctx->get_proc_address = hwctx->get_proc_address;

133 134 135
    if (hwctx->flags & AV_HWACCEL_FLAG_IGNORE_LEVEL)
        level = 0;
    else if (level < 0)
136 137
        return AVERROR(ENOTSUP);

138 139 140
    if (av_vdpau_get_surface_parameters(avctx, &type, &width, &height))
        return AVERROR(ENOSYS);

141 142 143 144
    if (!(hwctx->flags & AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH) &&
        type != VDP_CHROMA_TYPE_420)
        return AVERROR(ENOSYS);

145 146 147 148 149 150 151 152
    status = vdctx->get_proc_address(vdctx->device,
                                     VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES,
                                     &func);
    if (status != VDP_STATUS_OK)
        return vdpau_error(status);
    else
        surface_query_caps = func;

153
    status = surface_query_caps(vdctx->device, type, &supported,
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
                                &max_width, &max_height);
    if (status != VDP_STATUS_OK)
        return vdpau_error(status);
    if (supported != VDP_TRUE ||
        max_width < width || max_height < height)
        return AVERROR(ENOTSUP);

    status = vdctx->get_proc_address(vdctx->device,
                                     VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES,
                                     &func);
    if (status != VDP_STATUS_OK)
        return vdpau_error(status);
    else
        decoder_query_caps = func;

    status = decoder_query_caps(vdctx->device, profile, &supported, &max_level,
                                &max_mb, &max_width, &max_height);
171
#ifdef VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE
172
    if ((status != VDP_STATUS_OK || supported != VDP_TRUE) && profile == VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE) {
173 174 175 176 177 178
        profile = VDP_DECODER_PROFILE_H264_MAIN;
        status = decoder_query_caps(vdctx->device, profile, &supported,
                                    &max_level, &max_mb,
                                    &max_width, &max_height);
    }
#endif
179 180 181 182 183 184 185
    if (status != VDP_STATUS_OK)
        return vdpau_error(status);

    if (supported != VDP_TRUE || max_level < level ||
        max_width < width || max_height < height)
        return AVERROR(ENOTSUP);

186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    status = vdctx->get_proc_address(vdctx->device, VDP_FUNC_ID_DECODER_CREATE,
                                     &func);
    if (status != VDP_STATUS_OK)
        return vdpau_error(status);
    else
        create = func;

    status = vdctx->get_proc_address(vdctx->device, VDP_FUNC_ID_DECODER_RENDER,
                                     &func);
    if (status != VDP_STATUS_OK)
        return vdpau_error(status);
    else
        vdctx->render = func;

    status = create(vdctx->device, profile, width, height, avctx->refs,
                    &vdctx->decoder);
202 203 204 205 206
    if (status == VDP_STATUS_OK) {
        vdctx->width  = avctx->coded_width;
        vdctx->height = avctx->coded_height;
    }

207 208 209 210 211 212 213 214 215 216 217 218
    return vdpau_error(status);
}

int ff_vdpau_common_uninit(AVCodecContext *avctx)
{
    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
    VdpDecoderDestroy *destroy;
    void *func;
    VdpStatus status;

    if (vdctx->device == VDP_INVALID_HANDLE)
        return 0; /* Decoder created and destroyed by user */
219 220
    if (vdctx->width == UINT32_MAX && vdctx->height == UINT32_MAX)
        return 0;
221 222 223 224 225 226 227 228 229 230 231 232

    status = vdctx->get_proc_address(vdctx->device,
                                     VDP_FUNC_ID_DECODER_DESTROY, &func);
    if (status != VDP_STATUS_OK)
        return vdpau_error(status);
    else
        destroy = func;

    status = destroy(vdctx->decoder);
    return vdpau_error(status);
}

233 234
static int ff_vdpau_common_reinit(AVCodecContext *avctx)
{
235
    VDPAUHWContext *hwctx = avctx->hwaccel_context;
236 237 238 239 240
    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;

    if (vdctx->device == VDP_INVALID_HANDLE)
        return 0; /* Decoder created by user */
    if (avctx->coded_width == vdctx->width &&
241
        avctx->coded_height == vdctx->height && !hwctx->reset)
242 243 244 245 246 247
        return 0;

    avctx->hwaccel->uninit(avctx);
    return avctx->hwaccel->init(avctx);
}

248
int ff_vdpau_common_start_frame(struct vdpau_picture_context *pic_ctx,
249 250 251
                                av_unused const uint8_t *buffer,
                                av_unused uint32_t size)
{
252 253 254
    pic_ctx->bitstream_buffers_allocated = 0;
    pic_ctx->bitstream_buffers_used      = 0;
    pic_ctx->bitstream_buffers           = NULL;
255 256 257
    return 0;
}

258 259 260
int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
                              struct vdpau_picture_context *pic_ctx)
{
261
    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
262 263
    VdpVideoSurface surf = ff_vdpau_get_surface_id(frame);
    VdpStatus status;
264 265 266 267 268
    int val;

    val = ff_vdpau_common_reinit(avctx);
    if (val < 0)
        return val;
269

270
    status = vdctx->render(vdctx->decoder, surf, (void *)&pic_ctx->info,
271 272 273 274 275 276 277
                           pic_ctx->bitstream_buffers_used,
                           pic_ctx->bitstream_buffers);

    av_freep(&pic_ctx->bitstream_buffers);
    return vdpau_error(status);
}

278
#if CONFIG_MPEG1_VDPAU_HWACCEL || \
279 280
    CONFIG_MPEG2_VDPAU_HWACCEL || CONFIG_MPEG4_VDPAU_HWACCEL || \
    CONFIG_VC1_VDPAU_HWACCEL   || CONFIG_WMV3_VDPAU_HWACCEL
281
int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx)
282
{
283
    MpegEncContext *s = avctx->priv_data;
284 285
    Picture *pic = s->current_picture_ptr;
    struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private;
286
    int val;
287

288 289 290
    val = ff_vdpau_common_end_frame(avctx, pic->f, pic_ctx);
    if (val < 0)
        return val;
291

292
    ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
293 294
    return 0;
}
295
#endif
296

297 298
int ff_vdpau_add_buffer(struct vdpau_picture_context *pic_ctx,
                        const uint8_t *buf, uint32_t size)
299
{
300
    VdpBitstreamBuffer *buffers = pic_ctx->bitstream_buffers;
301

302 303
    buffers = av_fast_realloc(buffers, &pic_ctx->bitstream_buffers_allocated,
                              (pic_ctx->bitstream_buffers_used + 1) * sizeof(*buffers));
304 305 306
    if (!buffers)
        return AVERROR(ENOMEM);

307 308
    pic_ctx->bitstream_buffers = buffers;
    buffers += pic_ctx->bitstream_buffers_used++;
309 310 311 312 313 314 315

    buffers->struct_version  = VDP_BITSTREAM_BUFFER_VERSION;
    buffers->bitstream       = buf;
    buffers->bitstream_bytes = size;
    return 0;
}

316
#if FF_API_VDPAU_PROFILE
317 318
int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile)
{
319 320 321 322
#define PROFILE(prof)                      \
do {                                       \
    *profile = VDP_DECODER_PROFILE_##prof; \
    return 0;                              \
323 324 325
} while (0)

    switch (avctx->codec_id) {
326
    case AV_CODEC_ID_MPEG1VIDEO:               PROFILE(MPEG1);
327 328
    case AV_CODEC_ID_MPEG2VIDEO:
        switch (avctx->profile) {
329 330
        case FF_PROFILE_MPEG2_MAIN:            PROFILE(MPEG2_MAIN);
        case FF_PROFILE_MPEG2_SIMPLE:          PROFILE(MPEG2_SIMPLE);
331 332
        default:                               return AVERROR(EINVAL);
        }
333
    case AV_CODEC_ID_H263:                     PROFILE(MPEG4_PART2_ASP);
334 335
    case AV_CODEC_ID_MPEG4:
        switch (avctx->profile) {
336 337
        case FF_PROFILE_MPEG4_SIMPLE:          PROFILE(MPEG4_PART2_SP);
        case FF_PROFILE_MPEG4_ADVANCED_SIMPLE: PROFILE(MPEG4_PART2_ASP);
338 339 340
        default:                               return AVERROR(EINVAL);
        }
    case AV_CODEC_ID_H264:
341
        switch (avctx->profile & ~FF_PROFILE_H264_INTRA) {
342
        case FF_PROFILE_H264_BASELINE:         PROFILE(H264_BASELINE);
343
        case FF_PROFILE_H264_CONSTRAINED_BASELINE:
344 345
        case FF_PROFILE_H264_MAIN:             PROFILE(H264_MAIN);
        case FF_PROFILE_H264_HIGH:             PROFILE(H264_HIGH);
346 347 348
#ifdef VDP_DECODER_PROFILE_H264_EXTENDED
        case FF_PROFILE_H264_EXTENDED:         PROFILE(H264_EXTENDED);
#endif
349 350 351 352 353
        default:                               return AVERROR(EINVAL);
        }
    case AV_CODEC_ID_WMV3:
    case AV_CODEC_ID_VC1:
        switch (avctx->profile) {
354 355 356
        case FF_PROFILE_VC1_SIMPLE:            PROFILE(VC1_SIMPLE);
        case FF_PROFILE_VC1_MAIN:              PROFILE(VC1_MAIN);
        case FF_PROFILE_VC1_ADVANCED:          PROFILE(VC1_ADVANCED);
357 358 359 360
        default:                               return AVERROR(EINVAL);
        }
    }
    return AVERROR(EINVAL);
361
#undef PROFILE
362
}
363
#endif /* FF_API_VDPAU_PROFILE */
364

365 366 367 368 369
AVVDPAUContext *av_vdpau_alloc_context(void)
{
    return av_mallocz(sizeof(AVVDPAUContext));
}

370 371 372 373 374
int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device,
                          VdpGetProcAddress *get_proc, unsigned flags)
{
    VDPAUHWContext *hwctx;

375
    if (flags & ~(AV_HWACCEL_FLAG_IGNORE_LEVEL|AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH))
376 377
        return AVERROR(EINVAL);

378 379 380 381 382 383 384 385 386
    if (av_reallocp(&avctx->hwaccel_context, sizeof(*hwctx)))
        return AVERROR(ENOMEM);

    hwctx = avctx->hwaccel_context;

    memset(hwctx, 0, sizeof(*hwctx));
    hwctx->context.decoder  = VDP_INVALID_HANDLE;
    hwctx->device           = device;
    hwctx->get_proc_address = get_proc;
387
    hwctx->flags            = flags;
388 389 390 391
    hwctx->reset            = 1;
    return 0;
}

392
/* @}*/