From 1839fafa951308237c4672ffd9a94f927b26eac7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 24 Mar 2014 02:02:33 +0100 Subject: [PATCH] avconv: Support VDA hwaccel Signed-off-by: Luca Barbato --- Makefile | 1 + avconv.h | 2 + avconv_opt.c | 3 ++ avconv_vda.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++ doc/avconv.texi | 3 ++ 5 files changed, 143 insertions(+) create mode 100644 avconv_vda.c diff --git a/Makefile b/Makefile index c34320b243..fd605218cf 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,7 @@ $(foreach prog,$(AVBASENAMES),$(eval OBJS-$(prog) += cmdutils.o)) OBJS-avconv += avconv_opt.o avconv_filter.o OBJS-avconv-$(HAVE_VDPAU_X11) += avconv_vdpau.o OBJS-avconv-$(HAVE_DXVA2_LIB) += avconv_dxva2.o +OBJS-avconv-$(CONFIG_VDA) += avconv_vda.o TESTTOOLS = audiogen videogen rotozoom tiny_psnr base64 HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options diff --git a/avconv.h b/avconv.h index 319291319a..56ce9f01ff 100644 --- a/avconv.h +++ b/avconv.h @@ -53,6 +53,7 @@ enum HWAccelID { HWACCEL_AUTO, HWACCEL_VDPAU, HWACCEL_DXVA2, + HWACCEL_VDA, }; typedef struct HWAccel { @@ -423,5 +424,6 @@ int avconv_parse_options(int argc, char **argv); int vdpau_init(AVCodecContext *s); int dxva2_init(AVCodecContext *s); +int vda_init(AVCodecContext *s); #endif /* AVCONV_H */ diff --git a/avconv_opt.c b/avconv_opt.c index f400e75cd7..12d676054d 100644 --- a/avconv_opt.c +++ b/avconv_opt.c @@ -59,6 +59,9 @@ const HWAccel hwaccels[] = { #endif #if HAVE_DXVA2_LIB { "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD }, +#endif +#if CONFIG_VDA + { "vda", vda_init, HWACCEL_VDA, AV_PIX_FMT_VDA }, #endif { 0 }, }; diff --git a/avconv_vda.c b/avconv_vda.c new file mode 100644 index 0000000000..40f87c4f76 --- /dev/null +++ b/avconv_vda.c @@ -0,0 +1,134 @@ +/* + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/avcodec.h" +#include "libavcodec/vda.h" +#include "libavutil/imgutils.h" + +#include "avconv.h" + +typedef struct VDAContext { + AVFrame *tmp_frame; +} VDAContext; + +static int vda_retrieve_data(AVCodecContext *s, AVFrame *frame) +{ + InputStream *ist = s->opaque; + VDAContext *vda = ist->hwaccel_ctx; + CVPixelBufferRef pixbuf = (CVPixelBufferRef)frame->data[3]; + OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf); + CVReturn err; + uint8_t *data[4] = { 0 }; + int linesize[4] = { 0 }; + int planes, ret, i; + + av_frame_unref(vda->tmp_frame); + + switch (pixel_format) { + case kCVPixelFormatType_420YpCbCr8Planar: vda->tmp_frame->format = AV_PIX_FMT_YUV420P; break; + case kCVPixelFormatType_422YpCbCr8: vda->tmp_frame->format = AV_PIX_FMT_UYVY422; break; + default: + av_log(NULL, AV_LOG_ERROR, + "Unsupported pixel format: %u\n", pixel_format); + return AVERROR(ENOSYS); + } + + vda->tmp_frame->width = frame->width; + vda->tmp_frame->height = frame->height; + ret = av_frame_get_buffer(vda->tmp_frame, 32); + if (ret < 0) + return ret; + + err = CVPixelBufferLockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly); + if (err != kCVReturnSuccess) { + av_log(NULL, AV_LOG_ERROR, "Error locking the pixel buffer.\n"); + return AVERROR_UNKNOWN; + } + + if (CVPixelBufferIsPlanar(pixbuf)) { + + planes = CVPixelBufferGetPlaneCount(pixbuf); + for (i = 0; i < planes; i++) { + data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i); + linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i); + } + } else { + data[0] = CVPixelBufferGetBaseAddress(pixbuf); + linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf); + } + + av_image_copy(vda->tmp_frame->data, vda->tmp_frame->linesize, + data, linesize, vda->tmp_frame->format, + frame->width, frame->height); + + ret = av_frame_copy_props(vda->tmp_frame, frame); + if (ret < 0) + return ret; + + av_frame_unref(frame); + av_frame_move_ref(frame, vda->tmp_frame); + + return 0; +} + +static void vda_uninit(AVCodecContext *s) +{ + InputStream *ist = s->opaque; + VDAContext *vda = ist->hwaccel_ctx; + + ist->hwaccel_uninit = NULL; + ist->hwaccel_retrieve_data = NULL; + + av_frame_free(&vda->tmp_frame); + + av_vda_default_free(s); + av_freep(&ist->hwaccel_ctx); +} + +int vda_init(AVCodecContext *s) +{ + InputStream *ist = s->opaque; + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; + VDAContext *vda; + int ret; + + vda = av_mallocz(sizeof(*vda)); + if (!vda) + return AVERROR(ENOMEM); + + ist->hwaccel_ctx = vda; + ist->hwaccel_uninit = vda_uninit; + ist->hwaccel_retrieve_data = vda_retrieve_data; + + vda->tmp_frame = av_frame_alloc(); + if (!vda->tmp_frame) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = av_vda_default_init(s); + if (ret < 0) { + av_log(NULL, loglevel, "Error creating VDA decoder.\n"); + goto fail; + } + + return 0; +fail: + vda_uninit(s); + return ret; +} diff --git a/doc/avconv.texi b/doc/avconv.texi index f3bb6050a8..6efec55978 100644 --- a/doc/avconv.texi +++ b/doc/avconv.texi @@ -580,6 +580,9 @@ Do not use any hardware acceleration (the default). @item auto Automatically select the hardware acceleration method. +@item vda +Use Apple VDA hardware acceleration. + @item vdpau Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration.