[RFC] Split out hwaccel code

Roberto Togni <[email protected]>
Newsgroups gmane.comp.video.mplayer.devel
Message-ID <[email protected]>
Hi,
 this is a proposed patch to split the hwaccel code out of vd_ffmpeg,
and put it into its own driver (vd_ffhw, but better names are welcome).


The main purpose of this is to be able to change vd_ffmpeg code without
the risk of breaking hwaccel (difficult to test if you don't have the
hardware); at the same time it allows to work on hwaccel in a small and
clean decoder, without all the special cases needed for the many
formats supported by vd_ffmpeg.

This also permit to use hwaccel by passing only "-vfm ffhw -vo vdpau"
on the commandline, without specifying the codec (now you have to use
"-vo vdpau -vc xxxvdpau"). If you add -vfm ffhw and the codec is not
supported by hwaccel, MPlayer will fall back to vd_ffmpeg.
The current syntax with -vc is also supported, so backward
compatibility is guaranteed.


The code is tested only with h264 and vaapi over vdpau; xvmc and other
vdpau formats are untested.


Hopefully this should accelerate the addition of more hwaccel formats
(eg. vaapi), and ease the work on buffer management in vd_ffmpeg (today
dr1 mostly fails).


Please comment.

Ciao,
 Roberto

_______________________________________________
MPlayer-dev-eng mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
vd_ffhw.c (text/x-c++src, 20.6 KB)
/*
 * 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 <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <assert.h>
#include <time.h>

#include "config.h"
#include "mp_msg.h"
#include "help_mp.h"
#include "av_opts.h"
#include "av_helpers.h"

#include "libavutil/common.h"
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
#include "fmt-conversion.h"

#include "vd_internal.h"

#if CONFIG_VDPAU
#include "libavcodec/vdpau.h"
#include "vdpau_frame_data.h"
#endif
#include "libavutil/pixdesc.h"

static const vd_info_t info = {
    "FFmpeg's libavcodec hardware codec family",
    "ffhw",
    "A'rpi",
    "A'rpi, Michael, Alex",
    "native codecs"
};

LIBVD_EXTERN(ffhw)

#include "libavcodec/avcodec.h"

#if CONFIG_XVMC
#include "libavcodec/xvmc.h"
#endif

typedef struct {
    AVCodecContext *avctx;
    AVFrame *pic;
    AVFrame *refcount_frame;
    enum AVPixelFormat pix_fmt;
    int do_slices;
    int vo_initialized;
    int best_csp;
    AVRational last_sample_aspect_ratio;
    int use_vdpau;
} vd_ffmpeg_ctx;

#include "m_option.h"

static int get_buffer_hw(AVCodecContext *avctx, AVFrame *frame, int flags);
static void release_buffer_hw(void *opaque, uint8_t *data);
static void draw_slice(struct AVCodecContext *s, const AVFrame *src, int offset[4],
                       int y, int type, int height);

static enum AVPixelFormat get_format(struct AVCodecContext *avctx,
                                     const enum AVPixelFormat *pix_fmt);

static int lavc_param_workaround_bugs= FF_BUG_AUTODETECT;
static int lavc_param_debug=0;
static char *lavc_avopt = NULL;

static const mp_image_t mpi_no_picture =
{
	.type = MP_IMGTYPE_INCOMPLETE
};

const m_option_t lavc_hwdecode_opts_conf[]={
    {"bug"           , &lavc_param_workaround_bugs      , CONF_TYPE_INT     , CONF_RANGE, -1, 999999, NULL},
    {"debug"         , &lavc_param_debug                , CONF_TYPE_INT     , CONF_RANGE, 0, 9999999, NULL},
    {"o"             , &lavc_avopt                      , CONF_TYPE_STRING  , 0, 0, 0, NULL},
    {NULL, NULL, 0, 0, 0, 0, NULL}
};

// to set/get/query special features/parameters
static int control(sh_video_t *sh, int cmd, void *arg, ...){
    vd_ffmpeg_ctx *ctx = sh->context;
    AVCodecContext *avctx = ctx->avctx;
    switch(cmd){
    case VDCTRL_QUERY_FORMAT:
    {
        int format =(*((int *)arg));
        if(format == ctx->best_csp) return CONTROL_TRUE;//supported
        // possible conversions:
        switch(format){
#if CONFIG_XVMC
        case IMGFMT_XVMC_IDCT_MPEG2:
        case IMGFMT_XVMC_MOCO_MPEG2:
            if(avctx->pix_fmt == AV_PIX_FMT_XVMC_MPEG2_IDCT) return CONTROL_TRUE;
#endif
        }
        return CONTROL_FALSE;
    }
    case VDCTRL_RESYNC_STREAM:
        avcodec_flush_buffers(avctx);
        return CONTROL_TRUE;
    case VDCTRL_QUERY_UNSEEN_FRAMES:
        // "has_b_frames" contains the (e.g. reorder) delay as specified
        // in the standard. "delay" contains the libavcodec-specific delay
        // e.g. due to frame multithreading
        return avctx->has_b_frames + avctx->delay + 10;
    }
    return CONTROL_UNKNOWN;
}

#if CONFIG_VDPAU
static int vdpau_render_wrapper(AVCodecContext *s, AVFrame *f,
    const VdpPictureInfo *info, uint32_t count, const VdpBitstreamBuffer *buffers)
{
    mp_image_t *mpi = f->opaque;
    sh_video_t *sh = s->opaque;
    struct vdpau_frame_data data;
    uint8_t *planes[4] = {(void *)&data};
    data.surface = (VdpVideoSurface)mpi->priv;
    data.info = info;
    data.bitstream_buffers_used = count;
    data.bitstream_buffers = buffers;
    mpcodecs_draw_slice(sh, planes, NULL, sh->disp_w, sh->disp_h, 0, 0);
    return 0;
}
#endif

static int pixfmt2imgfmt2(enum AVPixelFormat fmt, enum AVCodecID cid)
{
    if (fmt == AV_PIX_FMT_VDPAU)
        switch (cid) {
        case AV_CODEC_ID_H264:       return IMGFMT_VDPAU_H264;
        case AV_CODEC_ID_MPEG1VIDEO: return IMGFMT_VDPAU_MPEG1;
        case AV_CODEC_ID_MPEG2VIDEO: return IMGFMT_VDPAU_MPEG2;
        case AV_CODEC_ID_MPEG4:      return IMGFMT_VDPAU_MPEG4;
        case AV_CODEC_ID_WMV3:       return IMGFMT_VDPAU_WMV3;
        case AV_CODEC_ID_VC1:        return IMGFMT_VDPAU_VC1;
        case AV_CODEC_ID_HEVC:       return IMGFMT_VDPAU_HEVC;
        }
    return pixfmt2imgfmt(fmt);
}


static void set_format_params(struct AVCodecContext *avctx,
                              enum AVPixelFormat fmt)
{
    sh_video_t *sh     = avctx->opaque;
    vd_ffmpeg_ctx *ctx = sh->context;
    int imgfmt;
    if (fmt == AV_PIX_FMT_NONE)
        return;
    ctx->use_vdpau = fmt == AV_PIX_FMT_VDPAU;
    imgfmt = pixfmt2imgfmt2(fmt, avctx->codec_id);
#if CONFIG_VDPAU
    if (!ctx->use_vdpau) {
        av_freep(&avctx->hwaccel_context);
    } else {
        AVVDPAUContext *vdpc = avctx->hwaccel_context;
        if (!vdpc)
            avctx->hwaccel_context = vdpc = av_alloc_vdpaucontext();
        vdpc->render2 = vdpau_render_wrapper;
    }
#endif
        avctx->get_buffer2 = get_buffer_hw;
        mp_msg(MSGT_DECVIDEO, MSGL_V, IMGFMT_IS_XVMC(imgfmt) ?
               MSGTR_MPCODECS_XVMCAcceleratedMPEG2 :
               "[VD_FFMPEG] VDPAU accelerated decoding\n");
        if (ctx->use_vdpau) {
            avctx->draw_horiz_band = NULL;
            avctx->slice_flags = 0;
            ctx->do_slices = 0;
        } else {
            avctx->draw_horiz_band = draw_slice;
            avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
            ctx->do_slices = 1;
        }
}

// init driver
static int init(sh_video_t *sh){
    AVCodecContext *avctx;
    vd_ffmpeg_ctx *ctx;
    AVCodec *lavc_codec;
    AVDictionary *opts = NULL;

    init_avcodec();

    ctx = sh->context = calloc(1, sizeof(*ctx));
    if (!ctx)
        return 0;

    lavc_codec = avcodec_find_decoder_by_name(codec_idx2str(sh->codec->dll_idx));
    if(!lavc_codec){
        mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_MissingLAVCcodec, codec_idx2str(sh->codec->dll_idx));
        uninit(sh);
        return 0;
    }

    ctx->pic = av_frame_alloc();
    ctx->avctx = avcodec_alloc_context3(lavc_codec);
    avctx = ctx->avctx;
    avctx->opaque = sh;
    avctx->codec_id = lavc_codec->id;

    avctx->get_format = get_format;

    avctx->coded_width = sh->disp_w;
    avctx->coded_height= sh->disp_h;
    avctx->workaround_bugs= lavc_param_workaround_bugs;
    avctx->codec_tag= sh->format;
    avctx->debug= lavc_param_debug;
    if (lavc_param_debug)
        av_log_set_level(AV_LOG_DEBUG);
    av_opt_set_int(avctx, "skip_alpha", 1, 0);

    if(lavc_avopt){
        if (parse_avopts(avctx, lavc_avopt) < 0 &&
            (!lavc_codec->priv_class ||
             parse_avopts(avctx->priv_data, lavc_avopt) < 0)) {
            mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Your options /%s/ look like gibberish to me pal\n", lavc_avopt);
            uninit(sh);
            return 0;
        }
    }

    mp_dbg(MSGT_DECVIDEO, MSGL_DBG2, "libavcodec.size: %d x %d\n", avctx->width, avctx->height);

    if (sh->bih && sh->bih->biSize > sizeof(*sh->bih)) {
        avctx->extradata_size = sh->bih->biSize-sizeof(*sh->bih);
        avctx->extradata = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
        memcpy(avctx->extradata, sh->bih+1, avctx->extradata_size);
    }

    if(sh->bih)
        avctx->bits_per_coded_sample= sh->bih->biBitCount;

    avctx->thread_count = 1;
    avctx->refcounted_frames = 1;

    /* open it */
    if (avcodec_open2(avctx, lavc_codec, &opts) < 0) {
        mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_CantOpenCodec);
        uninit(sh);
        return 0;
    }
    av_dict_free(&opts);
    // this is necessary in case get_format was never called and init_vo is
    // too late e.g. for H.264 VDPAU
    set_format_params(avctx, avctx->pix_fmt);
    mp_msg(MSGT_DECVIDEO, MSGL_V, "INFO: libavcodec init OK!\n");
    return 1; //mpcodecs_config_vo(sh, sh->disp_w, sh->disp_h, IMGFMT_YV12);
}

// uninit driver
static void uninit(sh_video_t *sh){
    vd_ffmpeg_ctx *ctx = sh->context;
    AVCodecContext *avctx = ctx->avctx;

    if (ctx->refcount_frame) {
        av_frame_unref(ctx->refcount_frame);
        ctx->refcount_frame = NULL;
    }

    if (avctx) {
        if (avctx->codec && avcodec_close(avctx) < 0)
            mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_CantCloseCodec);

        av_freep(&avctx->extradata);
        av_freep(&avctx->hwaccel_context);
        av_freep(&avctx->slice_offset);
    }

    avcodec_free_context(&avctx);
    av_frame_free(&ctx->pic);
    free(ctx);
}

static void draw_slice(struct AVCodecContext *s,
                        const AVFrame *src, int offset[4],
                        int y, int type, int height){
    mp_image_t *mpi = src->opaque;
    sh_video_t *sh = s->opaque;
    vd_ffmpeg_ctx *ctx = sh->context;
    uint8_t *source[MP_MAX_PLANES]= {src->data[0] + offset[0], src->data[1] + offset[1], src->data[2] + offset[2]};
    int strides[MP_MAX_PLANES] = {src->linesize[0], src->linesize[1], src->linesize[2]};
    if (!src->data[0]) {
        mp_msg(MSGT_DECVIDEO, MSGL_FATAL, "BUG in FFmpeg, draw_slice called with NULL pointer!\n");
        return;
    }
    if (mpi && ctx->use_vdpau) {
        mp_msg(MSGT_DECVIDEO, MSGL_FATAL, "BUG in FFmpeg, draw_slice called for VDPAU!\n");
        return;
    }
/*    if (height < 0)
    {
        int i;
        height = -height;
        y -= height;
        for (i = 0; i < MP_MAX_PLANES; i++)
        {
            strides[i] = -strides[i];
            source[i] -= strides[i];
        }
    }*/
    if (y < sh->disp_h) {
        height = FFMIN(height, sh->disp_h-y);
        mpcodecs_draw_slice (sh, source, strides, sh->disp_w, height, 0, y);
    }
}

// ignore_aspect is used to not bother with aspect changes during get_buffer.
// The aspect can be wrong when get_buffer is called before decoding and it
// should simply not be necessary.
// In particular this stops spurious get_buffer aspect values from causing
// a container value to be overwritten.
static void update_configuration(sh_video_t *sh, enum AVPixelFormat pix_fmt, int ignore_aspect) {
    vd_ffmpeg_ctx *ctx = sh->context;
    AVCodecContext *avctx = ctx->avctx;
    int aspect_change = av_cmp_q(avctx->sample_aspect_ratio, ctx->last_sample_aspect_ratio);
    if (!avctx->sample_aspect_ratio.den) {
        mp_msg(MSGT_DECVIDEO, MSGL_WARN, "FFmpeg bug: Invalid aspect\n");
        avctx->sample_aspect_ratio.den = 1;
    }
     // it is possible another vo buffers to be used after vo config()
     // lavc reset its buffers on width/heigh change but not on aspect change!!!
    if ((!ignore_aspect && aspect_change) ||
        pix_fmt != ctx->pix_fmt ||
        !ctx->vo_initialized)
    {
        float aspect= av_q2d(avctx->sample_aspect_ratio) * avctx->width / avctx->height;
        ctx->vo_initialized = 0;
        // this is a special-case HACK for MPEG-1/2 VDPAU that uses neither get_format nor
        // sets the value correctly in avcodec_open.
        set_format_params(avctx, pix_fmt);

        if (!ignore_aspect) {
            mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] aspect_ratio: %f\n", aspect);

            // Do not overwrite sh->original_aspect on the first call,
            // if a container aspect is available (which is preferred then).
            // But set it even if the sample aspect did not change, since a
            // resolution change can cause an aspect change even if the
            // _sample_ aspect is unchanged.
            if (sh->original_aspect == 0 || (aspect_change && ctx->last_sample_aspect_ratio.den))
                sh->original_aspect = aspect;
            ctx->last_sample_aspect_ratio = avctx->sample_aspect_ratio;
        }
        ctx->pix_fmt = pix_fmt;
        ctx->best_csp = pixfmt2imgfmt2(pix_fmt, avctx->codec_id);
    }
}

static int is_in_format_list(sh_video_t *sh, int imgfmt)
{
    int i;
    for (i = 0; i < CODECS_MAX_OUTFMT; i++)
        if (sh->codec->outfmt[i] == imgfmt)
            return 1;
    return 0;
}

static int init_vo(sh_video_t *sh, enum AVPixelFormat pix_fmt, int ignore_aspect)
{
    vd_ffmpeg_ctx *ctx = sh->context;
    const AVCodecContext *avctx = ctx->avctx;
    int width, height;
    int imgfmt = pixfmt2imgfmt2(pix_fmt, avctx->codec_id);

    // avoid initialization for formats not on the supported
    // list in the codecs.conf entry.
    if (!is_in_format_list(sh, imgfmt)) {
        if (imgfmt)
            mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Unexpected decoder output format %s\n",
                   vo_format_name(imgfmt));
        return -1;
    }

    width = avctx->width;
    height = avctx->height;

    // HACK!
    // if sh->ImageDesc is non-NULL, it means we decode QuickTime(tm) video.
    // use dimensions from BIH to avoid black borders at the right and bottom.
    if (sh->bih && sh->ImageDesc) {
        width = sh->bih->biWidth;
        height = sh->bih->biHeight;
    }
    if (width != sh->disp_w  || height != sh->disp_h)
        ctx->vo_initialized = 0;

    update_configuration(sh, pix_fmt, ignore_aspect);
    if (!ctx->vo_initialized)
    {
        sh->disp_w = width;
        sh->disp_h = height;
        if (!mpcodecs_config_vo(sh, sh->disp_w, sh->disp_h, ctx->best_csp))
            return -1;
        ctx->vo_initialized = 1;
    }
    return 0;
}

static int get_buffer_hw(AVCodecContext *avctx, AVFrame *pic, int isreference){
    sh_video_t *sh = avctx->opaque;
    vd_ffmpeg_ctx *ctx = sh->context;
    mp_image_t *mpi=NULL;
    int flags= MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE | MP_IMGFLAG_PREFER_ALIGNED_STRIDE;
    int type= MP_IMGTYPE_NUMBERED;
    int width = FFMAX(avctx->width,  -(-avctx->coded_width  >> avctx->lowres));
    int height= FFMAX(avctx->height, -(-avctx->coded_height >> avctx->lowres));

    avcodec_align_dimensions(avctx, &width, &height);
//printf("get_buffer %d %d %d\n", pic->reference, ctx->ip_count, ctx->b_count);

        if(!(isreference & AV_GET_BUFFER_FLAG_REF)){
            flags|=(avctx->skip_idct<=AVDISCARD_DEFAULT && avctx->skip_frame<=AVDISCARD_DEFAULT && ctx->do_slices) ?
                     MP_IMGFLAG_DRAW_CALLBACK:0;
        }else{
            flags|= MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE
                      | (ctx->do_slices ? MP_IMGFLAG_DRAW_CALLBACK : 0);
        }

    if(init_vo(sh, avctx->pix_fmt, 1) < 0){
        return -1;
    }

    mpi= mpcodecs_get_image(sh, type, flags, width, height);
    if (!mpi) return -1;

#if CONFIG_VDPAU
    if (ctx->use_vdpau) {
        VdpVideoSurface surface = (VdpVideoSurface)mpi->priv;
        avctx->draw_horiz_band= NULL;
        mpi->planes[3] = surface;
    }
#endif
#if CONFIG_XVMC
    if(IMGFMT_IS_XVMC(mpi->imgfmt)) {
        struct xvmc_pix_fmt *render = mpi->priv; //same as data[2]
        if(!(mpi->flags & MP_IMGFLAG_DIRECT)) {
            mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_MPCODECS_OnlyBuffersAllocatedByVoXvmcAllowed);
            assert(0);
            return -1;//!!fixme check error conditions in ffmpeg
        }
        if(mp_msg_test(MSGT_DECVIDEO, MSGL_DBG5))
            mp_msg(MSGT_DECVIDEO, MSGL_DBG5, "vd_ffmpeg::get_buffer (xvmc render=%p)\n", render);
        assert(render != 0);
        assert(render->xvmc_id == AV_XVMC_ID);
        avctx->draw_horiz_band= draw_slice;
    }
#endif

    pic->data[0]= mpi->planes[0];
    pic->data[1]= mpi->planes[1];
    pic->data[2]= mpi->planes[2];
    pic->data[3]= mpi->planes[3];

    /* Note, some (many) codecs in libavcodec must have stride1==stride2 && no changes between frames
     * lavc will check that and die with an error message, if its not true
     */
    pic->linesize[0]= mpi->stride[0];
    pic->linesize[1]= mpi->stride[1];
    pic->linesize[2]= mpi->stride[2];
    pic->linesize[3]= mpi->stride[3];

    pic->width  = avctx->width;
    pic->height = avctx->height;
    pic->format = avctx->pix_fmt;

    pic->opaque = mpi;
//printf("%X\n", (int)mpi->planes[0]);

    pic->buf[0] = av_buffer_create(pic->data[0], pic->height * pic->linesize[0],
                                release_buffer_hw, pic->opaque, 0);
    if (!pic->buf[0]) {
        av_frame_unref(pic);
        release_buffer_hw(mpi, NULL);
        return AVERROR(ENOMEM);
    }

    return 0;
}

static void release_buffer_hw(void *opaque, uint8_t *data){
    mp_image_t *mpi= opaque;

    if (mpi) {
//printf("release buffer %d %d %d\n", mpi ? mpi->flags&MP_IMGFLAG_PRESERVE : -99, ctx->ip_count, ctx->b_count);

        // release mpi (in case MPI_IMGTYPE_NUMBERED is used, e.g. for VDPAU)
        mpi->usage_count--;
        if (mpi->usage_count < 0) {
            mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Bad mp_image usage count, please report!\n");
            mpi->usage_count = 0;
        }
    }

//printf("R%X %X\n", pic->linesize[0], pic->data[0]);
}

// decode a frame
static mp_image_t *decode(sh_video_t *sh, void *data, int len, int flags){
    int got_picture=0;
    int ret;
    vd_ffmpeg_ctx *ctx = sh->context;
    AVFrame *pic= ctx->pic;
    AVCodecContext *avctx = ctx->avctx;
    mp_image_t *mpi=NULL;
    AVPacket pkt;

    if (ctx->refcount_frame) {
        av_frame_unref(ctx->refcount_frame);
        ctx->refcount_frame = NULL;
    }
    if(data && len<=0) return NULL; // skipped frame

    if (flags&3) {
        avctx->skip_frame = AVDISCARD_NONREF;
    }
    if (data)
    mp_msg(MSGT_DECVIDEO, MSGL_DBG2, "vd_ffmpeg data: %04x, %04x, %04x, %04x\n",
           ((int *)data)[0], ((int *)data)[1], ((int *)data)[2], ((int *)data)[3]);
    av_init_packet(&pkt);
    pkt.data = data;
    pkt.size = len;
    // Necessary to decode e.g. CorePNG and ZeroCodec correctly
    pkt.flags = (sh->ds->flags & 1) ? AV_PKT_FLAG_KEY : 0;
//    av_packet_split_side_data(&pkt);

    ret = avcodec_decode_video2(avctx, pic, &got_picture, &pkt);
    ctx->refcount_frame = pic;
    pkt.data = NULL;
    pkt.size = 0;
//    av_packet_free_side_data(&pkt);

    if(ret<0) mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Error while decoding frame!\n");
//printf("repeat: %d\n", pic->repeat_pict);

    if(!got_picture) {
        if (avctx->codec->id == AV_CODEC_ID_H264)// &&
//	    skip_frame <= AVDISCARD_DEFAULT)
	    return &mpi_no_picture; // H.264 first field only
	else
	    return NULL;    // skipped image
    }

    if(init_vo(sh, avctx->pix_fmt, 0) < 0) return NULL;

    if(pic->opaque){
        mpi=pic->opaque;
    }

    if(!mpi){        // temporary!
        mp_msg(MSGT_DECVIDEO, MSGL_WARN, MSGTR_MPCODECS_CouldntAllocateImageForCodec);
        return NULL;
    }

    if (mpi->w != avctx->width || mpi->h != avctx->height ||
        pic->width < mpi->w || pic->height < mpi->h) {
        mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Dropping frame with size not matching configured size (%ix%i vs %ix%i vs %ix%i)\n",
               mpi->w, mpi->h, pic->width, pic->height, avctx->width, avctx->height);
        return NULL;
    }

    if (!mpi->planes[0])
        return NULL;

/* to comfirm with newer lavc style */
//    mpi->qscale = av_frame_get_qp_table(pic, &mpi->qstride, &mpi->qscale_type);
    mpi->pict_type=pic->pict_type;
    mpi->fields = MP_IMGFIELD_ORDERED;
    if(pic->interlaced_frame) mpi->fields |= MP_IMGFIELD_INTERLACED;
    if(pic->top_field_first ) mpi->fields |= MP_IMGFIELD_TOP_FIRST;
    if(pic->repeat_pict == 1) mpi->fields |= MP_IMGFIELD_REPEAT_FIRST;

    return mpi;
}

static enum AVPixelFormat get_format(struct AVCodecContext *avctx,
                                     const enum AVPixelFormat *fmt)
{
    enum AVPixelFormat selected_format;
    int imgfmt;
    sh_video_t *sh = avctx->opaque;
    vd_ffmpeg_ctx *ctx = sh->context;
    int i;

    // Try to select identical format to avoid reinitializations
    if (ctx->vo_initialized && ctx->pix_fmt != AV_PIX_FMT_NONE)
        for (i = 0; fmt[i] != AV_PIX_FMT_NONE; i++)
            if (fmt[i] == ctx->pix_fmt) return ctx->pix_fmt;

    for(i=0;fmt[i]!=AV_PIX_FMT_NONE;i++){
        imgfmt = pixfmt2imgfmt2(fmt[i], avctx->codec_id);
        if(!IMGFMT_IS_HWACCEL(imgfmt) || !is_in_format_list(sh, imgfmt)) continue;
        mp_msg(MSGT_DECVIDEO, MSGL_V, MSGTR_MPCODECS_TryingPixfmt, i);
        if(init_vo(sh, fmt[i], 1) >= 0) {
            break;
        }
    }
    selected_format = fmt[i];
/*    if (selected_format == AV_PIX_FMT_NONE) {
        selected_format = avcodec_default_get_format(avctx, fmt);
        update_configuration(sh, selected_format, 1);
    }*/
    set_format_params(avctx, selected_format);
    return selected_format;
}
hwsplit.diff (text/x-patch, 11.3 KB)
Index: Makefile
===================================================================
--- Makefile	(revisione 37838)
+++ Makefile	(copia locale)
@@ -56,6 +56,7 @@
                                         libmpcodecs/ad_ffmpeg.c         \
                                         libmpcodecs/ad_spdif.c          \
                                         libmpcodecs/vd_ffmpeg.c         \
+                                        libmpcodecs/vd_ffhw.c           \
                                         libmpcodecs/vf_geq.c            \
                                         libmpcodecs/vf_lavc.c           \
                                         libmpcodecs/vf_lavcdeint.c      \
Index: cfg-common.h
===================================================================
--- cfg-common.h	(revisione 37838)
+++ cfg-common.h	(copia locale)
@@ -544,6 +544,7 @@
 
 #ifdef CONFIG_FFMPEG
     {"lavdopts", lavc_decode_opts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
+    {"lavdhwopts", lavc_hwdecode_opts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
     {"lavfdopts",  lavfdopts_conf, CONF_TYPE_SUBCONFIG, CONF_GLOBAL, 0, 0, NULL},
 #endif
 #ifdef CONFIG_XVID4
Index: codec-cfg.c
===================================================================
--- codec-cfg.c	(revisione 37838)
+++ codec-cfg.c	(copia locale)
@@ -388,6 +388,7 @@
         "realvid",
         "xvid",
         "libdv",
+        "ffhw",
         NULL
     };
     char **drv=audioflag?audiodrv:videodrv;
Index: etc/codecs.conf
===================================================================
--- etc/codecs.conf	(revisione 37838)
+++ etc/codecs.conf	(copia locale)
@@ -407,8 +407,6 @@
   driver ffmpeg
   dll "mpeg1video"
   out YV12,I420,IYUV
-  out IDCT_MPEG2
-  out MOCO_MPEG2
 
 videocodec ffmpeg2
   info "FFmpeg MPEG-2"
@@ -446,8 +444,6 @@
   dll "mpeg2video"
   out YV12,I420,IYUV
   out 422P,444P
-  out IDCT_MPEG2
-  out MOCO_MPEG2
 
 ; for backward compatibility
 videocodec ffmpeg12
@@ -490,8 +486,6 @@
   dll "mpegvideo"
   out YV12,I420,IYUV
   out 422P,444P
-  out IDCT_MPEG2
-  out MOCO_MPEG2
 
 videocodec mpeg12
   info "MPEG-1 or 2 (libmpeg2)"
@@ -534,7 +528,7 @@
   out 422P
 
 videocodec ffmpeg12mc
-  info "FFmpeg MPEG-1/2 (XvMC) - deprecated, just use ffmpeg12"
+  info "FFmpeg MPEG-1/2 (XvMC)"
   status buggy
   format 0x10000001  ; MPEG-1
   format 0x10000002  ; MPEG-2
@@ -566,7 +560,7 @@
   fourcc m2v1,m1v1
   fourcc "m1v "
   fourcc LMP2 ; Lead mpeg2 in avi
-  driver ffmpeg
+  driver ffhw
   dll "mpegvideo_xvmc"
   out IDCT_MPEG2
   out MOCO_MPEG2
@@ -599,7 +593,7 @@
   fourcc LMP2 ; Lead mpeg2 in avi
   fourcc m2v1,m1v1
   fourcc "m1v "
-  driver ffmpeg
+  driver ffhw
   dll "mpegvideo"
   out VDPAU_MPEG1
   out VDPAU_MPEG2
@@ -1322,7 +1316,7 @@
   info "FFmpeg WMV3/WMV9 (VDPAU)"
   status buggy
   fourcc WMV3,wmv3
-  driver ffmpeg
+  driver ffhw
   dll wmv3
   out VDPAU_WMV3
 
@@ -1348,7 +1342,7 @@
   status buggy
   fourcc WVC1,wvc1,WMVA
   fourcc vc-1,VC-1
-  driver ffmpeg
+  driver ffhw
   dll vc1
   out VDPAU_VC1
 
@@ -1403,7 +1397,7 @@
   fourcc HEVC
   fourcc hvc1
   fourcc hev1
-  driver ffmpeg
+  driver ffhw
   dll hevc
   out VDPAU_HEVC
 
@@ -1448,7 +1442,7 @@
   fourcc GAVC,UMSV
   fourcc rv64 ; Radvision
   format 0x10000005
-  driver ffmpeg
+  driver ffhw
   dll h264
   out VDPAU_H264
 
@@ -1591,7 +1585,7 @@
   fourcc DreX,DM4V,LMP4,DP02
   fourcc QMP4
   fourcc DYM4
-  driver ffmpeg
+  driver ffhw
   dll mpeg4
   out VDPAU_MPEG4
 
Index: libmpcodecs/vd.c
===================================================================
--- libmpcodecs/vd.c	(revisione 37838)
+++ libmpcodecs/vd.c	(copia locale)
@@ -39,6 +39,7 @@
 extern const vd_functions_t mpcodecs_vd_null;
 extern const vd_functions_t mpcodecs_vd_black;
 extern const vd_functions_t mpcodecs_vd_ffmpeg;
+extern const vd_functions_t mpcodecs_vd_ffhw;
 extern const vd_functions_t mpcodecs_vd_theora;
 extern const vd_functions_t mpcodecs_vd_dshow;
 extern const vd_functions_t mpcodecs_vd_dmo;
@@ -69,6 +70,7 @@
     &mpcodecs_vd_black,
 #ifdef CONFIG_FFMPEG
     &mpcodecs_vd_ffmpeg,
+    &mpcodecs_vd_ffhw,
 #endif
 #ifdef CONFIG_OGGTHEORA
     &mpcodecs_vd_theora,
Index: libmpcodecs/vd.h
===================================================================
--- libmpcodecs/vd.h	(revisione 37838)
+++ libmpcodecs/vd.h	(copia locale)
@@ -50,6 +50,7 @@
 extern float screen_size_xy;
 
 extern const m_option_t lavc_decode_opts_conf[];
+extern const m_option_t lavc_hwdecode_opts_conf[];
 extern const m_option_t xvid_dec_opts[];
 
 #define VDCTRL_QUERY_FORMAT 3 /* test for availabilty of a format */
Index: libmpcodecs/vd_ffmpeg.c
===================================================================
--- libmpcodecs/vd_ffmpeg.c	(revisione 37838)
+++ libmpcodecs/vd_ffmpeg.c	(copia locale)
@@ -71,10 +71,6 @@
 #error palette too large, adapt libmpcodecs/vf.c:vf_get_image
 #endif
 
-#if CONFIG_XVMC
-#include "libavcodec/xvmc.h"
-#endif
-
 typedef struct {
     AVCodecContext *avctx;
     AVFrame *pic;
@@ -92,7 +88,6 @@
     int b_count;
     AVRational last_sample_aspect_ratio;
     int palette_sent;
-    int use_vdpau;
 } vd_ffmpeg_ctx;
 
 #include "m_option.h"
@@ -193,11 +188,6 @@
             if(ctx->best_csp == IMGFMT_YV12) return CONTROL_TRUE;// u/v swap
             if(ctx->best_csp == IMGFMT_422P && !ctx->do_dr1) return CONTROL_TRUE;// half stride
             break;
-#if CONFIG_XVMC
-        case IMGFMT_XVMC_IDCT_MPEG2:
-        case IMGFMT_XVMC_MOCO_MPEG2:
-            if(avctx->pix_fmt == AV_PIX_FMT_XVMC_MPEG2_IDCT) return CONTROL_TRUE;
-#endif
         }
         return CONTROL_FALSE;
     }
@@ -213,39 +203,6 @@
     return CONTROL_UNKNOWN;
 }
 
-#if CONFIG_VDPAU
-static int vdpau_render_wrapper(AVCodecContext *s, AVFrame *f,
-    const VdpPictureInfo *info, uint32_t count, const VdpBitstreamBuffer *buffers)
-{
-    mp_image_t *mpi = f->opaque;
-    sh_video_t *sh = s->opaque;
-    struct vdpau_frame_data data;
-    uint8_t *planes[4] = {(void *)&data};
-    data.surface = (VdpVideoSurface)mpi->priv;
-    data.info = info;
-    data.bitstream_buffers_used = count;
-    data.bitstream_buffers = buffers;
-    mpcodecs_draw_slice(sh, planes, NULL, sh->disp_w, sh->disp_h, 0, 0);
-    return 0;
-}
-#endif
-
-static int pixfmt2imgfmt2(enum AVPixelFormat fmt, enum AVCodecID cid)
-{
-    if (fmt == AV_PIX_FMT_VDPAU)
-        switch (cid) {
-        case AV_CODEC_ID_H264:       return IMGFMT_VDPAU_H264;
-        case AV_CODEC_ID_MPEG1VIDEO: return IMGFMT_VDPAU_MPEG1;
-        case AV_CODEC_ID_MPEG2VIDEO: return IMGFMT_VDPAU_MPEG2;
-        case AV_CODEC_ID_MPEG4:      return IMGFMT_VDPAU_MPEG4;
-        case AV_CODEC_ID_WMV3:       return IMGFMT_VDPAU_WMV3;
-        case AV_CODEC_ID_VC1:        return IMGFMT_VDPAU_VC1;
-        case AV_CODEC_ID_HEVC:       return IMGFMT_VDPAU_HEVC;
-        }
-    return pixfmt2imgfmt(fmt);
-}
-
-
 /**
  * Function to set slice/dr related settings that need to be reset after
  * initializing hardware acceleration failed */
@@ -290,37 +247,8 @@
     int imgfmt;
     if (fmt == AV_PIX_FMT_NONE)
         return;
-    ctx->use_vdpau = fmt == AV_PIX_FMT_VDPAU;
-    imgfmt = pixfmt2imgfmt2(fmt, avctx->codec_id);
-#if CONFIG_VDPAU
-    if (!ctx->use_vdpau) {
-        av_freep(&avctx->hwaccel_context);
-    } else {
-        AVVDPAUContext *vdpc = avctx->hwaccel_context;
-        if (!vdpc)
-            avctx->hwaccel_context = vdpc = av_alloc_vdpaucontext();
-        vdpc->render2 = vdpau_render_wrapper;
-    }
-#endif
-    if (IMGFMT_IS_HWACCEL(imgfmt)) {
-        ctx->do_dr1    = 1;
-        ctx->nonref_dr = 0;
-        avctx->get_buffer2 = get_buffer2;
-        mp_msg(MSGT_DECVIDEO, MSGL_V, IMGFMT_IS_XVMC(imgfmt) ?
-               MSGTR_MPCODECS_XVMCAcceleratedMPEG2 :
-               "[VD_FFMPEG] VDPAU accelerated decoding\n");
-        if (ctx->use_vdpau) {
-            avctx->draw_horiz_band = NULL;
-            avctx->slice_flags = 0;
-            ctx->do_slices = 0;
-        } else {
-            avctx->draw_horiz_band = draw_slice;
-            avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
-            ctx->do_slices = 1;
-        }
-    } else {
-        set_dr_slice_settings(avctx, avctx->codec);
-    }
+    imgfmt = pixfmt2imgfmt(fmt);
+    set_dr_slice_settings(avctx, avctx->codec);
 }
 
 // init driver
@@ -548,10 +476,6 @@
         mp_msg(MSGT_DECVIDEO, MSGL_FATAL, "BUG in FFmpeg, draw_slice called with NULL pointer!\n");
         return;
     }
-    if (mpi && ctx->use_vdpau) {
-        mp_msg(MSGT_DECVIDEO, MSGL_FATAL, "BUG in FFmpeg, draw_slice called for VDPAU!\n");
-        return;
-    }
     if (height < 0)
     {
         int i;
@@ -607,7 +531,7 @@
             ctx->last_sample_aspect_ratio = avctx->sample_aspect_ratio;
         }
         ctx->pix_fmt = pix_fmt;
-        ctx->best_csp = pixfmt2imgfmt2(pix_fmt, avctx->codec_id);
+        ctx->best_csp = pixfmt2imgfmt(pix_fmt);
     }
 }
 
@@ -625,7 +549,7 @@
     vd_ffmpeg_ctx *ctx = sh->context;
     const AVCodecContext *avctx = ctx->avctx;
     int width, height;
-    int imgfmt = pixfmt2imgfmt2(pix_fmt, avctx->codec_id);
+    int imgfmt = pixfmt2imgfmt(pix_fmt);
 
     // avoid initialization for formats not on the supported
     // list in the codecs.conf entry.
@@ -702,9 +626,7 @@
         goto disable_dr1;
     }
 
-    if (IMGFMT_IS_HWACCEL(ctx->best_csp)) {
-        type =  MP_IMGTYPE_NUMBERED;
-    } else if (avctx->has_b_frames) {
+    if (avctx->has_b_frames) {
         // HACK/TODO: slices currently do not work properly with B-frames,
         // causing out-of-order frames or crashes with e.g. -vf scale,unsharp
         // or -vf screenshot,unsharp.
@@ -737,28 +659,6 @@
         avctx->draw_horiz_band= draw_slice;
     } else
         avctx->draw_horiz_band= NULL;
-#if CONFIG_VDPAU
-    if (ctx->use_vdpau) {
-        VdpVideoSurface surface = (VdpVideoSurface)mpi->priv;
-        avctx->draw_horiz_band= NULL;
-        mpi->planes[3] = surface;
-    }
-#endif
-#if CONFIG_XVMC
-    if(IMGFMT_IS_XVMC(mpi->imgfmt)) {
-        struct xvmc_pix_fmt *render = mpi->priv; //same as data[2]
-        if(!(mpi->flags & MP_IMGFLAG_DIRECT)) {
-            mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_MPCODECS_OnlyBuffersAllocatedByVoXvmcAllowed);
-            assert(0);
-            return -1;//!!fixme check error conditions in ffmpeg
-        }
-        if(mp_msg_test(MSGT_DECVIDEO, MSGL_DBG5))
-            mp_msg(MSGT_DECVIDEO, MSGL_DBG5, "vd_ffmpeg::get_buffer (xvmc render=%p)\n", render);
-        assert(render != 0);
-        assert(render->xvmc_id == AV_XVMC_ID);
-        avctx->draw_horiz_band= draw_slice;
-    }
-#endif
 
     pic->data[0]= mpi->planes[0];
     pic->data[1]= mpi->planes[1];
@@ -1095,7 +995,7 @@
             if (fmt[i] == ctx->pix_fmt) return ctx->pix_fmt;
 
     for(i=0;fmt[i]!=AV_PIX_FMT_NONE;i++){
-        imgfmt = pixfmt2imgfmt2(fmt[i], avctx->codec_id);
+        imgfmt = pixfmt2imgfmt(fmt[i]);
         if(!IMGFMT_IS_HWACCEL(imgfmt) || !is_in_format_list(sh, imgfmt)) continue;
         mp_msg(MSGT_DECVIDEO, MSGL_V, MSGTR_MPCODECS_TryingPixfmt, i);
         if(init_vo(sh, fmt[i], 1) >= 0) {
@@ -1203,10 +1103,6 @@
         const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
 
         planes = av_pix_fmt_count_planes(frame->format);
-        /* workaround for AVHWAccel plane count of 0, buf[0] is used as
-           check for allocated buffers: make libavcodec happy */
-        if (desc && desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
-            planes = 1;
         if (!desc || planes <= 0) {
             ret = AVERROR(EINVAL);
             goto fail;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.