diff options
Diffstat (limited to 'video/decode/vdpau_old.c')
-rw-r--r-- | video/decode/vdpau_old.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/video/decode/vdpau_old.c b/video/decode/vdpau_old.c new file mode 100644 index 0000000000..e9c88b69ea --- /dev/null +++ b/video/decode/vdpau_old.c @@ -0,0 +1,267 @@ +/* + * VDPAU video output driver + * + * Copyright (C) 2008 NVIDIA + * Copyright (C) 2009 Uoti Urpala + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stddef.h> +#include <assert.h> + +#include <libavcodec/vdpau.h> +#include <libavutil/common.h> + +#include "lavc.h" +#include "video/fmt-conversion.h" +#include "video/vdpau.h" +#include "video/decode/dec_video.h" + +struct priv { + struct mp_vdpau_ctx *mpvdp; + struct vdp_functions *vdp; + VdpDevice vdp_device; + uint64_t preemption_counter; + + int image_format; + int vid_width; + int vid_height; + + VdpDecoder decoder; + int decoder_max_refs; +}; + +static void mark_uninitialized(struct lavc_ctx *ctx) +{ + struct priv *p = ctx->hwdec_priv; + + p->vdp_device = VDP_INVALID_HANDLE; + p->decoder = VDP_INVALID_HANDLE; +} + +static int handle_preemption(struct lavc_ctx *ctx) +{ + struct priv *p = ctx->hwdec_priv; + + if (!mp_vdpau_status_ok(p->mpvdp)) + return -1; + + // Mark objects as destroyed if preemption+reinit occured + if (p->preemption_counter < p->mpvdp->preemption_counter) { + p->preemption_counter = p->mpvdp->preemption_counter; + mark_uninitialized(ctx); + } + + p->vdp_device = p->mpvdp->vdp_device; + p->vdp = p->mpvdp->vdp; + + return 0; +} + +static bool create_vdp_decoder(struct lavc_ctx *ctx, int max_refs) +{ + struct priv *p = ctx->hwdec_priv; + struct vdp_functions *vdp = p->mpvdp->vdp; + VdpStatus vdp_st; + VdpDecoderProfile vdp_decoder_profile; + + if (handle_preemption(ctx) < 0) + return false; + + if (p->decoder != VDP_INVALID_HANDLE) + vdp->decoder_destroy(p->decoder); + + switch (p->image_format) { + case IMGFMT_VDPAU_MPEG1: + vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1; + break; + case IMGFMT_VDPAU_MPEG2: + vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN; + break; + case IMGFMT_VDPAU_H264: + vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH; + mp_msg(MSGT_VO, MSGL_V, "[vdpau] Creating H264 hardware decoder " + "for %d reference frames.\n", max_refs); + break; + case IMGFMT_VDPAU_WMV3: + vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN; + break; + case IMGFMT_VDPAU_VC1: + vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED; + break; + case IMGFMT_VDPAU_MPEG4: + vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; + break; + default: + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Unknown image format!\n"); + goto fail; + } + vdp_st = vdp->decoder_create(p->vdp_device, vdp_decoder_profile, + p->vid_width, p->vid_height, max_refs, + &p->decoder); + CHECK_ST_WARNING("Failed creating VDPAU decoder"); + if (vdp_st != VDP_STATUS_OK) + goto fail; + p->decoder_max_refs = max_refs; + return true; + +fail: + p->decoder = VDP_INVALID_HANDLE; + p->decoder_max_refs = 0; + return false; +} + +static void draw_slice_hwdec(struct AVCodecContext *s, + const AVFrame *src, int offset[4], + int y, int type, int height) +{ + sh_video_t *sh = s->opaque; + struct lavc_ctx *ctx = sh->context; + struct priv *p = ctx->hwdec_priv; + struct vdp_functions *vdp = p->vdp; + VdpStatus vdp_st; + + if (handle_preemption(ctx) < 0) + return; + + struct vdpau_render_state *rndr = (void *)src->data[0]; + + int max_refs = p->image_format == IMGFMT_VDPAU_H264 ? + rndr->info.h264.num_ref_frames : 2; + if ((p->decoder == VDP_INVALID_HANDLE || p->decoder_max_refs < max_refs) + && !create_vdp_decoder(ctx, max_refs)) + return; + + vdp_st = vdp->decoder_render(p->decoder, rndr->surface, + (void *)&rndr->info, + rndr->bitstream_buffers_used, + rndr->bitstream_buffers); + CHECK_ST_WARNING("Failed VDPAU decoder rendering"); +} + +static void release_surface(void *ptr) +{ + struct vdpau_render_state *state = ptr; + // Free bitstream buffers allocated by libavcodec + av_freep(&state->bitstream_buffers); + talloc_free(state); +} + +static struct mp_image *allocate_image(struct lavc_ctx *ctx, AVFrame *frame) +{ + struct priv *p = ctx->hwdec_priv; + int imgfmt = pixfmt2imgfmt(frame->format); + + if (!IMGFMT_IS_VDPAU(imgfmt)) + return NULL; + + // frame->width/height lie. Using them breaks with non-mod 16 video. + int w = ctx->avctx->width; + int h = ctx->avctx->height; + + if (w != p->vid_width || h != p->vid_height || imgfmt != p->image_format) { + p->vid_width = w; + p->vid_height = h; + p->image_format = imgfmt; + if (!create_vdp_decoder(ctx, 2)) + return NULL; + } + + VdpChromaType chroma; + mp_vdpau_get_format(p->image_format, &chroma, NULL); + + struct mp_image *img = + mp_vdpau_get_video_surface(p->mpvdp, imgfmt, chroma, w, h); + + if (!img) + return NULL; + + // Create chained reference for vdpau_render_state. This will track the + // lifetime of the actual reference too. + // This is quite roundabout, but at least it allows us to share the + // surface allocator in vo_vdpau.c with the new vdpau code. + + struct vdpau_render_state *state = talloc_ptrtype(NULL, state); + memset(state, 0, sizeof(*state)); + state->surface = (VdpVideoSurface)(intptr_t)img->planes[3]; + + talloc_steal(state, img); + + struct mp_image *new = mp_image_new_custom_ref(img, state, release_surface); + new->planes[0] = (void *)state; + return new; +} + +static void uninit(struct lavc_ctx *ctx) +{ + struct priv *p = ctx->hwdec_priv; + + if (!p) + return; + + if (p->decoder != VDP_INVALID_HANDLE) + p->vdp->decoder_destroy(p->decoder); + + talloc_free(p); + ctx->hwdec_priv = NULL; +} + +static int init(struct lavc_ctx *ctx) +{ + if (!ctx->hwdec_info || !ctx->hwdec_info->vdpau_ctx) + return -1; + + struct priv *p = talloc_ptrtype(NULL, p); + *p = (struct priv) { + .mpvdp = ctx->hwdec_info->vdpau_ctx, + }; + ctx->hwdec_priv = p; + + p->preemption_counter = p->mpvdp->preemption_counter; + mark_uninitialized(ctx); + + if (handle_preemption(ctx) < 0) + return -1; + + AVCodecContext *avctx = ctx->avctx; + + avctx->draw_horiz_band = draw_slice_hwdec; + avctx->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; + + return 0; +} + +static void fix_image(struct lavc_ctx *ctx, struct mp_image *img) +{ + // Make it follow the convention of the "new" vdpau decoder + struct vdpau_render_state *rndr = (void *)img->planes[0]; + img->planes[0] = (void *)"dummy"; // must be non-NULL, otherwise arbitrary + img->planes[3] = (void *)(intptr_t)rndr->surface; +} + +const struct vd_lavc_hwdec_functions mp_vd_lavc_vdpau_old = { + .image_formats = (const int[]) { + IMGFMT_VDPAU_MPEG1, IMGFMT_VDPAU_MPEG2, IMGFMT_VDPAU_H264, + IMGFMT_VDPAU_WMV3, IMGFMT_VDPAU_VC1, IMGFMT_VDPAU_MPEG4, + 0 + }, + .init = init, + .uninit = uninit, + .allocate_image = allocate_image, + .fix_image = fix_image, +}; |