[FFmpeg-devel] [PATCH] vdadec: implement vda decoder
Xidorn Quan
quanxunzhen at gmail.com
Fri Aug 24 03:46:18 CEST 2012
Hi,
This patch is the same implementation of vda decoder as which I submitted
yesterday without requiring osx.c
Regards,
Xidorn Quan
On Fri, Aug 24, 2012 at 9:43 AM, Xidorn Quan <quanxunzhen at gmail.com> wrote:
> ---
> configure | 1 +
> libavcodec/Makefile | 1 +
> libavcodec/allcodecs.c | 1 +
> libavcodec/vda_h264_dec.c | 259
> ++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 262 insertions(+)
> create mode 100644 libavcodec/vda_h264_dec.c
>
> diff --git a/configure b/configure
> index 0b95927..368530c 100755
> --- a/configure
> +++ b/configure
> @@ -1557,6 +1557,7 @@ h264_vaapi_hwaccel_select="vaapi h264_decoder"
> h264_vda_hwaccel_deps="VideoDecodeAcceleration_VDADecoder_h pthreads"
> h264_vda_hwaccel_select="vda h264_decoder"
> h264_vdpau_decoder_select="vdpau h264_decoder"
> +h264_vda_decoder_select="vda h264_parser h264_decoder"
> huffyuv_encoder_select="huffman"
> iac_decoder_select="fft mdct sinewin"
> imc_decoder_select="fft mdct sinewin"
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 450086d..3af0f9d 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -215,6 +215,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o
> \
> OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o
> OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o
> OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_h264.o
> +OBJS-$(CONFIG_H264_VDA_DECODER) += vda_h264_dec.o
> OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o
> OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o
> OBJS-$(CONFIG_IAC_DECODER) += imc.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index dcff2e8..af0521b 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -135,6 +135,7 @@ void avcodec_register_all(void)
> REGISTER_DECODER (H264, h264);
> REGISTER_DECODER (H264_CRYSTALHD, h264_crystalhd);
> REGISTER_DECODER (H264_VDPAU, h264_vdpau);
> + REGISTER_DECODER (H264_VDA, h264_vda);
> REGISTER_ENCDEC (HUFFYUV, huffyuv);
> REGISTER_DECODER (IDCIN, idcin);
> REGISTER_DECODER (IFF_BYTERUN1, iff_byterun1);
> diff --git a/libavcodec/vda_h264_dec.c b/libavcodec/vda_h264_dec.c
> new file mode 100644
> index 0000000..a4ce7fc
> --- /dev/null
> +++ b/libavcodec/vda_h264_dec.c
> @@ -0,0 +1,259 @@
> +/*
> + * Copyright (c) 2012, Xidorn Quan
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * 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.
> + *
> + * FFmpeg 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * H.264 decoder via VDA
> + * @author Xidorn Quan <quanxunzhen at gmail.com>
> + */
> +
> +#include <string.h>
> +#include <libkern/OSAtomic.h>
> +#include <CoreFoundation/CoreFoundation.h>
> +
> +#include "vda.h"
> +#include "h264.h"
> +#include "avcodec.h"
> +
> +#ifndef kCFCoreFoundationVersionNumber10_7
> +#define kCFCoreFoundationVersionNumber10_7 635.00
> +#endif
> +
> +extern AVCodec ff_h264_decoder, ff_h264_vda_decoder;
> +
> +static const enum PixelFormat vda_pixfmts_prior_10_7[] = {
> + PIX_FMT_UYVY422,
> + PIX_FMT_YUV420P,
> + PIX_FMT_NONE
> +};
> +
> +static const enum PixelFormat vda_pixfmts[] = {
> + PIX_FMT_UYVY422,
> + PIX_FMT_YUYV422,
> + PIX_FMT_NV12,
> + PIX_FMT_YUV420P,
> + PIX_FMT_NONE
> +};
> +
> +typedef struct {
> + H264Context h264ctx;
> + int h264_initialized;
> + struct vda_context vda_ctx;
> + enum PixelFormat pix_fmt;
> +} VDADecoderContext;
> +
> +static enum PixelFormat get_format(struct AVCodecContext *avctx,
> + const enum PixelFormat *fmt)
> +{
> + return PIX_FMT_VDA_VLD;
> +}
> +
> +static int get_buffer(AVCodecContext *avctx, AVFrame *pic)
> +{
> + pic->type = FF_BUFFER_TYPE_USER;
> + pic->data[0] = (void *)1;
> + return 0;
> +}
> +
> +static void release_buffer(AVCodecContext *avctx, AVFrame *pic)
> +{
> + int i;
> +
> + CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
> + CVPixelBufferUnlockBaseAddress(cv_buffer, 0);
> + CVPixelBufferRelease(cv_buffer);
> +
> + for (i = 0; i < 4; i++)
> + pic->data[i] = NULL;
> +}
> +
> +static int vdadec_decode(AVCodecContext *avctx,
> + void *data, int *data_size, AVPacket *avpkt)
> +{
> + VDADecoderContext *ctx = avctx->priv_data;
> + AVFrame *pic = data;
> + int ret;
> +
> + ret = ff_h264_decoder.decode(avctx, data, data_size, avpkt);
> + if (*data_size) {
> + CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
> + CVPixelBufferLockBaseAddress(cv_buffer, 0);
> + pic->format = ctx->pix_fmt;
> + if (CVPixelBufferIsPlanar(cv_buffer)) {
> + int i, count = CVPixelBufferGetPlaneCount(cv_buffer);
> + av_assert0(count < 4);
> + for (i = 0; i < count; i++) {
> + pic->data[i] =
> CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i);
> + pic->linesize[i] =
> CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i);
> + }
> + } else {
> + pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer);
> + pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer);
> + }
> + }
> + avctx->pix_fmt = ctx->pix_fmt;
> +
> + return ret;
> +}
> +
> +static av_cold int vdadec_close(AVCodecContext *avctx)
> +{
> + VDADecoderContext *ctx = avctx->priv_data;
> + /* release buffers and decoder */
> + ff_vda_destroy_decoder(&ctx->vda_ctx);
> + /* close H.264 decoder */
> + if (ctx->h264_initialized)
> + ff_h264_decoder.close(avctx);
> + return 0;
> +}
> +
> +static av_cold int check_format(AVCodecContext *avctx)
> +{
> + AVCodecParserContext *parser;
> + uint8_t *pout;
> + int psize;
> + int index;
> + H264Context *h;
> + int ret = -1;
> +
> + /* init parser & parse file */
> + parser = av_parser_init(avctx->codec->id);
> + if (!parser) {
> + av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 parser.\n");
> + goto final;
> + }
> + parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
> + index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0, 0, 0,
> 0);
> + if (index < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");
> + goto release_parser;
> + }
> +
> + /* check if support */
> + h = parser->priv_data;
> + switch (h->sps.bit_depth_luma) {
> + case 8:
> + if (!CHROMA444 && !CHROMA422) {
> + // only this will H.264 decoder switch to hwaccel
> + ret = 0;
> + break;
> + }
> + default:
> + av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
> + }
> +
> +release_parser:
> + av_parser_close(parser);
> +
> +final:
> + return ret;
> +}
> +
> +static av_cold int vdadec_init(AVCodecContext *avctx)
> +{
> + VDADecoderContext *ctx = avctx->priv_data;
> + struct vda_context *vda_ctx = &ctx->vda_ctx;
> + OSStatus status;
> + int ret;
> +
> + ctx->h264_initialized = 0;
> +
> + /* init pix_fmts of codec */
> + if (!ff_h264_vda_decoder.pix_fmts) {
> + if (kCFCoreFoundationVersionNumber <
> kCFCoreFoundationVersionNumber10_7)
> + ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7;
> + else
> + ff_h264_vda_decoder.pix_fmts = vda_pixfmts;
> + }
> +
> + /* check if VDA supports this file */
> + if (check_format(avctx) < 0)
> + goto failed;
> +
> + /* init vda */
> + memset(vda_ctx, 0, sizeof(struct vda_context));
> + vda_ctx->width = avctx->width;
> + vda_ctx->height = avctx->height;
> + vda_ctx->format = 'avc1';
> + vda_ctx->use_sync_decoding = 1;
> + ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
> + switch (ctx->pix_fmt) {
> + case PIX_FMT_UYVY422:
> + vda_ctx->cv_pix_fmt_type = '2vuy';
> + break;
> + case PIX_FMT_YUYV422:
> + vda_ctx->cv_pix_fmt_type = 'yuvs';
> + break;
> + case PIX_FMT_NV12:
> + vda_ctx->cv_pix_fmt_type = '420v';
> + break;
> + case PIX_FMT_YUV420P:
> + vda_ctx->cv_pix_fmt_type = 'y420';
> + break;
> + default:
> + av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n",
> avctx->pix_fmt);
> + goto failed;
> + }
> + status = ff_vda_create_decoder(vda_ctx,
> + avctx->extradata,
> avctx->extradata_size);
> + if (status != kVDADecoderNoErr) {
> + av_log(avctx, AV_LOG_ERROR,
> + "Failed to init VDA decoder: %d.\n", status);
> + goto failed;
> + }
> + avctx->hwaccel_context = vda_ctx;
> +
> + /* changes callback functions */
> + avctx->get_format = get_format;
> + avctx->get_buffer = get_buffer;
> + avctx->release_buffer = release_buffer;
> +
> + /* init H.264 decoder */
> + ret = ff_h264_decoder.init(avctx);
> + if (ret < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
> + goto failed;
> + }
> + ctx->h264_initialized = 1;
> +
> + return 0;
> +
> +failed:
> + vdadec_close(avctx);
> + return -1;
> +}
> +
> +static void vdadec_flush(AVCodecContext *avctx)
> +{
> + return ff_h264_decoder.flush(avctx);
> +}
> +
> +AVCodec ff_h264_vda_decoder = {
> + .name = "h264_vda",
> + .type = AVMEDIA_TYPE_VIDEO,
> + .id = AV_CODEC_ID_H264,
> + .priv_data_size = sizeof(VDADecoderContext),
> + .init = vdadec_init,
> + .close = vdadec_close,
> + .decode = vdadec_decode,
> + .capabilities = CODEC_CAP_DELAY,
> + .flush = vdadec_flush,
> + .long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"),
> +};
> --
> 1.7.12
>
>
More information about the ffmpeg-devel
mailing list