mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-03-03 14:32:16 +02:00
avcodec: add new Videotoolbox hwaccel.
This commit is contained in:
parent
127203ba5a
commit
11d923d414
@ -29,6 +29,7 @@ version <next>:
|
||||
- acrossfade audio filter
|
||||
- allyuv video source
|
||||
- atadenoise video filter
|
||||
- OS X VideoToolbox support
|
||||
|
||||
|
||||
version 2.7:
|
||||
|
@ -305,6 +305,7 @@ Hardware acceleration:
|
||||
vaapi* Gwenole Beauchesne
|
||||
vda* Sebastien Zwickert
|
||||
vdpau* Carl Eugen Hoyos
|
||||
videotoolbox* Sebastien Zwickert
|
||||
|
||||
|
||||
libavdevice
|
||||
|
5
Makefile
5
Makefile
@ -31,7 +31,10 @@ $(foreach prog,$(AVBASENAMES),$(eval OBJS-$(prog)-$(CONFIG_OPENCL) += cmdutils_o
|
||||
OBJS-ffmpeg += ffmpeg_opt.o ffmpeg_filter.o
|
||||
OBJS-ffmpeg-$(HAVE_VDPAU_X11) += ffmpeg_vdpau.o
|
||||
OBJS-ffmpeg-$(HAVE_DXVA2_LIB) += ffmpeg_dxva2.o
|
||||
OBJS-ffmpeg-$(CONFIG_VDA) += ffmpeg_vda.o
|
||||
ifndef CONFIG_VIDEOTOOLBOX
|
||||
OBJS-ffmpeg-$(CONFIG_VDA) += ffmpeg_videotoolbox.o
|
||||
endif
|
||||
OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += ffmpeg_videotoolbox.o
|
||||
OBJS-ffserver += ffserver_config.o
|
||||
|
||||
TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64
|
||||
|
19
configure
vendored
19
configure
vendored
@ -155,6 +155,7 @@ Hardware accelerators:
|
||||
--disable-vaapi disable VAAPI code [autodetect]
|
||||
--disable-vda disable VDA code [autodetect]
|
||||
--disable-vdpau disable VDPAU code [autodetect]
|
||||
--enable-videotoolbox enable VideoToolbox code [autodetect]
|
||||
|
||||
Individual component options:
|
||||
--disable-everything disable all components listed below
|
||||
@ -1470,6 +1471,7 @@ HWACCEL_LIST="
|
||||
vaapi
|
||||
vda
|
||||
vdpau
|
||||
videotoolbox
|
||||
xvmc
|
||||
"
|
||||
|
||||
@ -2380,14 +2382,18 @@ d3d11va_deps="d3d11_h dxva_h ID3D11VideoDecoder"
|
||||
dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode"
|
||||
vaapi_deps="va_va_h"
|
||||
vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads"
|
||||
vda_extralibs="-framework CoreFoundation -framework VideoDecodeAcceleration -framework QuartzCore"
|
||||
vda_extralibs="-framework CoreFoundation -framework VideoDecodeAcceleration -framework QuartzCore -framework CoreServices"
|
||||
vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h"
|
||||
videotoolbox_deps="VideoToolbox_VideoToolbox_h pthreads"
|
||||
videotoolbox_extralibs="-framework CoreFoundation -framework VideoToolbox -framework CoreMedia -framework QuartzCore -framework CoreServices"
|
||||
xvmc_deps="X11_extensions_XvMClib_h"
|
||||
|
||||
h263_vaapi_hwaccel_deps="vaapi"
|
||||
h263_vaapi_hwaccel_select="h263_decoder"
|
||||
h263_vdpau_hwaccel_deps="vdpau"
|
||||
h263_vdpau_hwaccel_select="h263_decoder"
|
||||
h263_videotoolbox_hwaccel_deps="videotoolbox"
|
||||
h263_videotoolbox_hwaccel_select="h263_decoder"
|
||||
h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser"
|
||||
h264_d3d11va_hwaccel_deps="d3d11va"
|
||||
h264_d3d11va_hwaccel_select="h264_decoder"
|
||||
@ -2410,6 +2416,8 @@ h264_vdpau_decoder_deps="vdpau"
|
||||
h264_vdpau_decoder_select="h264_decoder"
|
||||
h264_vdpau_hwaccel_deps="vdpau"
|
||||
h264_vdpau_hwaccel_select="h264_decoder"
|
||||
h264_videotoolbox_hwaccel_deps="videotoolbox"
|
||||
h264_videotoolbox_hwaccel_select="h264_decoder"
|
||||
hevc_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_HEVC"
|
||||
hevc_d3d11va_hwaccel_select="hevc_decoder"
|
||||
hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC"
|
||||
@ -2425,6 +2433,8 @@ mpeg1_vdpau_decoder_deps="vdpau"
|
||||
mpeg1_vdpau_decoder_select="mpeg1video_decoder"
|
||||
mpeg1_vdpau_hwaccel_deps="vdpau"
|
||||
mpeg1_vdpau_hwaccel_select="mpeg1video_decoder"
|
||||
mpeg1_videotoolbox_hwaccel_deps="videotoolbox"
|
||||
mpeg1_videotoolbox_hwaccel_select="mpeg1video_decoder"
|
||||
mpeg1_xvmc_hwaccel_deps="xvmc"
|
||||
mpeg1_xvmc_hwaccel_select="mpeg1video_decoder"
|
||||
mpeg2_crystalhd_decoder_select="crystalhd"
|
||||
@ -2438,6 +2448,8 @@ mpeg2_vaapi_hwaccel_deps="vaapi"
|
||||
mpeg2_vaapi_hwaccel_select="mpeg2video_decoder"
|
||||
mpeg2_vdpau_hwaccel_deps="vdpau"
|
||||
mpeg2_vdpau_hwaccel_select="mpeg2video_decoder"
|
||||
mpeg2_videotoolbox_hwaccel_deps="videotoolbox"
|
||||
mpeg2_videotoolbox_hwaccel_select="mpeg2video_decoder"
|
||||
mpeg2_xvmc_hwaccel_deps="xvmc"
|
||||
mpeg2_xvmc_hwaccel_select="mpeg2video_decoder"
|
||||
mpeg4_crystalhd_decoder_select="crystalhd"
|
||||
@ -2447,6 +2459,8 @@ mpeg4_vdpau_decoder_deps="vdpau"
|
||||
mpeg4_vdpau_decoder_select="mpeg4_decoder"
|
||||
mpeg4_vdpau_hwaccel_deps="vdpau"
|
||||
mpeg4_vdpau_hwaccel_select="mpeg4_decoder"
|
||||
mpeg4_videotoolbox_hwaccel_deps="videotoolbox"
|
||||
mpeg4_videotoolbox_hwaccel_select="mpeg4_decoder"
|
||||
msmpeg4_crystalhd_decoder_select="crystalhd"
|
||||
vc1_crystalhd_decoder_select="crystalhd"
|
||||
vc1_d3d11va_hwaccel_deps="d3d11va"
|
||||
@ -2902,7 +2916,7 @@ sws_max_filter_size_default=256
|
||||
set_default sws_max_filter_size
|
||||
|
||||
# Enable hwaccels by default.
|
||||
enable d3d11va dxva2 vaapi vda vdpau xvmc
|
||||
enable d3d11va dxva2 vaapi vda vdpau videotoolbox xvmc
|
||||
enable xlib
|
||||
|
||||
# build settings
|
||||
@ -5108,6 +5122,7 @@ check_header valgrind/valgrind.h
|
||||
check_header vdpau/vdpau.h
|
||||
check_header vdpau/vdpau_x11.h
|
||||
check_header VideoDecodeAcceleration/VDADecoder.h
|
||||
check_header VideoToolbox/VideoToolbox.h
|
||||
check_header windows.h
|
||||
check_header X11/extensions/XvMClib.h
|
||||
check_header asm/types.h
|
||||
|
3
ffmpeg.h
3
ffmpeg.h
@ -63,6 +63,7 @@ enum HWAccelID {
|
||||
HWACCEL_VDPAU,
|
||||
HWACCEL_DXVA2,
|
||||
HWACCEL_VDA,
|
||||
HWACCEL_VIDEOTOOLBOX,
|
||||
};
|
||||
|
||||
typedef struct HWAccel {
|
||||
@ -520,6 +521,7 @@ extern int frame_bits_per_raw_sample;
|
||||
extern AVIOContext *progress_avio;
|
||||
extern float max_error_rate;
|
||||
extern int vdpau_api_ver;
|
||||
extern char *videotoolbox_pixfmt;
|
||||
|
||||
extern const AVIOInterruptCB int_cb;
|
||||
|
||||
@ -554,5 +556,6 @@ int ffmpeg_parse_options(int argc, char **argv);
|
||||
int vdpau_init(AVCodecContext *s);
|
||||
int dxva2_init(AVCodecContext *s);
|
||||
int vda_init(AVCodecContext *s);
|
||||
int videotoolbox_init(AVCodecContext *s);
|
||||
|
||||
#endif /* FFMPEG_H */
|
||||
|
@ -74,7 +74,10 @@ const HWAccel hwaccels[] = {
|
||||
{ "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD },
|
||||
#endif
|
||||
#if CONFIG_VDA
|
||||
{ "vda", vda_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
|
||||
{ "vda", videotoolbox_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
|
||||
#endif
|
||||
#if CONFIG_VIDEOTOOLBOX
|
||||
{ "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },
|
||||
#endif
|
||||
{ 0 },
|
||||
};
|
||||
@ -3232,6 +3235,9 @@ const OptionDef options[] = {
|
||||
"select a device for HW acceleration" "devicename" },
|
||||
#if HAVE_VDPAU_X11
|
||||
{ "vdpau_api_ver", HAS_ARG | OPT_INT | OPT_EXPERT, { &vdpau_api_ver }, "" },
|
||||
#endif
|
||||
#if CONFIG_VDA || CONFIG_VIDEOTOOLBOX
|
||||
{ "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" },
|
||||
#endif
|
||||
{ "autorotate", HAS_ARG | OPT_BOOL | OPT_SPEC |
|
||||
OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) },
|
||||
|
137
ffmpeg_vda.c
137
ffmpeg_vda.c
@ -1,137 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavcodec/vda.h"
|
||||
#include "libavutil/imgutils.h"
|
||||
|
||||
#include "ffmpeg.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,
|
||||
(const uint8_t **)data, linesize, vda->tmp_frame->format,
|
||||
frame->width, frame->height);
|
||||
|
||||
CVPixelBufferUnlockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
|
||||
|
||||
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;
|
||||
}
|
187
ffmpeg_videotoolbox.c
Normal file
187
ffmpeg_videotoolbox.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libavcodec/avcodec.h"
|
||||
#if CONFIG_VDA
|
||||
# include "libavcodec/vda.h"
|
||||
#endif
|
||||
#if CONFIG_VIDEOTOOLBOX
|
||||
# include "libavcodec/videotoolbox.h"
|
||||
#endif
|
||||
#include "libavutil/imgutils.h"
|
||||
#include "ffmpeg.h"
|
||||
|
||||
typedef struct VTContext {
|
||||
AVFrame *tmp_frame;
|
||||
} VTContext;
|
||||
|
||||
char *videotoolbox_pixfmt;
|
||||
|
||||
static int videotoolbox_retrieve_data(AVCodecContext *s, AVFrame *frame)
|
||||
{
|
||||
InputStream *ist = s->opaque;
|
||||
VTContext *vt = 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;
|
||||
char codec_str[32];
|
||||
|
||||
av_frame_unref(vt->tmp_frame);
|
||||
|
||||
switch (pixel_format) {
|
||||
case kCVPixelFormatType_420YpCbCr8Planar: vt->tmp_frame->format = AV_PIX_FMT_YUV420P; break;
|
||||
case kCVPixelFormatType_422YpCbCr8: vt->tmp_frame->format = AV_PIX_FMT_UYVY422; break;
|
||||
case kCVPixelFormatType_32BGRA: vt->tmp_frame->format = AV_PIX_FMT_BGRA; break;
|
||||
#ifdef kCFCoreFoundationVersionNumber10_7
|
||||
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: vt->tmp_frame->format = AV_PIX_FMT_NV12; break;
|
||||
#endif
|
||||
default:
|
||||
av_get_codec_tag_string(codec_str, sizeof(codec_str), s->codec_tag);
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"%s: Unsupported pixel format: %s\n", codec_str, videotoolbox_pixfmt);
|
||||
return AVERROR(ENOSYS);
|
||||
}
|
||||
|
||||
vt->tmp_frame->width = frame->width;
|
||||
vt->tmp_frame->height = frame->height;
|
||||
ret = av_frame_get_buffer(vt->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(vt->tmp_frame->data, vt->tmp_frame->linesize,
|
||||
(const uint8_t **)data, linesize, vt->tmp_frame->format,
|
||||
frame->width, frame->height);
|
||||
|
||||
ret = av_frame_copy_props(vt->tmp_frame, frame);
|
||||
CVPixelBufferUnlockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
av_frame_unref(frame);
|
||||
av_frame_move_ref(frame, vt->tmp_frame);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void videotoolbox_uninit(AVCodecContext *s)
|
||||
{
|
||||
InputStream *ist = s->opaque;
|
||||
VTContext *vt = ist->hwaccel_ctx;
|
||||
|
||||
ist->hwaccel_uninit = NULL;
|
||||
ist->hwaccel_retrieve_data = NULL;
|
||||
|
||||
av_frame_free(&vt->tmp_frame);
|
||||
|
||||
if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) {
|
||||
#if CONFIG_VIDEOTOOLBOX
|
||||
av_videotoolbox_default_free(s);
|
||||
#endif
|
||||
} else {
|
||||
#if CONFIG_VDA
|
||||
av_vda_default_free(s);
|
||||
#endif
|
||||
}
|
||||
av_freep(&ist->hwaccel_ctx);
|
||||
}
|
||||
|
||||
int videotoolbox_init(AVCodecContext *s)
|
||||
{
|
||||
InputStream *ist = s->opaque;
|
||||
int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
|
||||
int ret = 0;
|
||||
VTContext *vt;
|
||||
|
||||
vt = av_mallocz(sizeof(*vt));
|
||||
if (!vt)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ist->hwaccel_ctx = vt;
|
||||
ist->hwaccel_uninit = videotoolbox_uninit;
|
||||
ist->hwaccel_retrieve_data = videotoolbox_retrieve_data;
|
||||
|
||||
vt->tmp_frame = av_frame_alloc();
|
||||
if (!vt->tmp_frame) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) {
|
||||
#if CONFIG_VIDEOTOOLBOX
|
||||
if (!videotoolbox_pixfmt) {
|
||||
ret = av_videotoolbox_default_init(s);
|
||||
} else {
|
||||
AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context();
|
||||
CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
videotoolbox_pixfmt,
|
||||
kCFStringEncodingUTF8);
|
||||
vtctx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
|
||||
ret = av_videotoolbox_default_init2(s, vtctx);
|
||||
CFRelease(pixfmt_str);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if CONFIG_VDA
|
||||
if (!videotoolbox_pixfmt) {
|
||||
ret = av_vda_default_init(s);
|
||||
} else {
|
||||
AVVDAContext *vdactx = av_vda_alloc_context();
|
||||
CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
videotoolbox_pixfmt,
|
||||
kCFStringEncodingUTF8);
|
||||
vdactx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
|
||||
ret = av_vda_default_init2(s, vdactx);
|
||||
CFRelease(pixfmt_str);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (ret < 0) {
|
||||
av_log(NULL, loglevel,
|
||||
"Error creating %s decoder.\n", ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX ? "Videotoolbox" : "VDA");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
videotoolbox_uninit(s);
|
||||
return ret;
|
||||
}
|
@ -13,6 +13,7 @@ HEADERS = avcodec.h \
|
||||
vda.h \
|
||||
vdpau.h \
|
||||
version.h \
|
||||
videotoolbox.h \
|
||||
vorbis_parser.h \
|
||||
xvmc.h \
|
||||
|
||||
@ -696,28 +697,34 @@ OBJS-$(CONFIG_VIMA_DECODER) += vima.o adpcm_data.o
|
||||
OBJS-$(CONFIG_D3D11VA) += dxva2.o
|
||||
OBJS-$(CONFIG_DXVA2) += dxva2.o
|
||||
OBJS-$(CONFIG_VAAPI) += vaapi.o
|
||||
OBJS-$(CONFIG_VDA) += vda.o
|
||||
OBJS-$(CONFIG_VDA) += vda.o videotoolbox.o
|
||||
OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o
|
||||
OBJS-$(CONFIG_VDPAU) += vdpau.o
|
||||
|
||||
OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o
|
||||
OBJS-$(CONFIG_H263_VDPAU_HWACCEL) += vdpau_mpeg4.o
|
||||
OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
|
||||
OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_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_VDPAU_HWACCEL) += vdpau_h264.o
|
||||
OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
|
||||
OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o
|
||||
OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o
|
||||
OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o
|
||||
OBJS-$(CONFIG_MPEG1_VDPAU_HWACCEL) += vdpau_mpeg12.o
|
||||
OBJS-$(CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
|
||||
OBJS-$(CONFIG_MPEG1_XVMC_HWACCEL) += mpegvideo_xvmc.o
|
||||
OBJS-$(CONFIG_MPEG2_D3D11VA_HWACCEL) += dxva2_mpeg2.o
|
||||
OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o
|
||||
OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o
|
||||
OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL) += vdpau_mpeg12.o
|
||||
OBJS-$(CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
|
||||
OBJS-$(CONFIG_MPEG2_XVMC_HWACCEL) += mpegvideo_xvmc.o
|
||||
OBJS-$(CONFIG_MPEG4_VAAPI_HWACCEL) += vaapi_mpeg4.o
|
||||
OBJS-$(CONFIG_MPEG4_VDPAU_HWACCEL) += vdpau_mpeg4.o
|
||||
OBJS-$(CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
|
||||
OBJS-$(CONFIG_VC1_D3D11VA_HWACCEL) += dxva2_vc1.o
|
||||
OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o
|
||||
OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o
|
||||
@ -912,8 +919,9 @@ SKIPHEADERS-$(CONFIG_QSVDEC) += qsvdec.h
|
||||
SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h
|
||||
SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h
|
||||
SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h
|
||||
SKIPHEADERS-$(CONFIG_VDA) += vda.h vda_internal.h
|
||||
SKIPHEADERS-$(CONFIG_VDA) += vda.h vda_vt_internal.h
|
||||
SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h
|
||||
SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vda_vt_internal.h
|
||||
|
||||
TESTPROGS = imgconvert \
|
||||
jpeg2000dwt \
|
||||
|
@ -76,6 +76,7 @@ void avcodec_register_all(void)
|
||||
/* hardware accelerators */
|
||||
REGISTER_HWACCEL(H263_VAAPI, h263_vaapi);
|
||||
REGISTER_HWACCEL(H263_VDPAU, h263_vdpau);
|
||||
REGISTER_HWACCEL(H263_VIDEOTOOLBOX, h263_videotoolbox);
|
||||
REGISTER_HWACCEL(H264_D3D11VA, h264_d3d11va);
|
||||
REGISTER_HWACCEL(H264_DXVA2, h264_dxva2);
|
||||
REGISTER_HWACCEL(H264_MMAL, h264_mmal);
|
||||
@ -84,20 +85,24 @@ void avcodec_register_all(void)
|
||||
REGISTER_HWACCEL(H264_VDA, h264_vda);
|
||||
REGISTER_HWACCEL(H264_VDA_OLD, h264_vda_old);
|
||||
REGISTER_HWACCEL(H264_VDPAU, h264_vdpau);
|
||||
REGISTER_HWACCEL(H264_VIDEOTOOLBOX, h264_videotoolbox);
|
||||
REGISTER_HWACCEL(HEVC_D3D11VA, hevc_d3d11va);
|
||||
REGISTER_HWACCEL(HEVC_DXVA2, hevc_dxva2);
|
||||
REGISTER_HWACCEL(HEVC_QSV, hevc_qsv);
|
||||
REGISTER_HWACCEL(HEVC_VDPAU, hevc_vdpau);
|
||||
REGISTER_HWACCEL(MPEG1_XVMC, mpeg1_xvmc);
|
||||
REGISTER_HWACCEL(MPEG1_VDPAU, mpeg1_vdpau);
|
||||
REGISTER_HWACCEL(MPEG1_VIDEOTOOLBOX, mpeg1_videotoolbox);
|
||||
REGISTER_HWACCEL(MPEG2_XVMC, mpeg2_xvmc);
|
||||
REGISTER_HWACCEL(MPEG2_D3D11VA, mpeg2_d3d11va);
|
||||
REGISTER_HWACCEL(MPEG2_DXVA2, mpeg2_dxva2);
|
||||
REGISTER_HWACCEL(MPEG2_QSV, mpeg2_qsv);
|
||||
REGISTER_HWACCEL(MPEG2_VAAPI, mpeg2_vaapi);
|
||||
REGISTER_HWACCEL(MPEG2_VDPAU, mpeg2_vdpau);
|
||||
REGISTER_HWACCEL(MPEG2_VIDEOTOOLBOX, mpeg2_videotoolbox);
|
||||
REGISTER_HWACCEL(MPEG4_VAAPI, mpeg4_vaapi);
|
||||
REGISTER_HWACCEL(MPEG4_VDPAU, mpeg4_vdpau);
|
||||
REGISTER_HWACCEL(MPEG4_VIDEOTOOLBOX, mpeg4_videotoolbox);
|
||||
REGISTER_HWACCEL(VC1_D3D11VA, vc1_d3d11va);
|
||||
REGISTER_HWACCEL(VC1_DXVA2, vc1_dxva2);
|
||||
REGISTER_HWACCEL(VC1_VAAPI, vc1_vaapi);
|
||||
|
@ -722,6 +722,9 @@ const enum AVPixelFormat ff_h263_hwaccel_pixfmt_list_420[] = {
|
||||
#endif
|
||||
#if CONFIG_H263_VDPAU_HWACCEL || CONFIG_MPEG4_VDPAU_HWACCEL
|
||||
AV_PIX_FMT_VDPAU,
|
||||
#endif
|
||||
#if CONFIG_H263_VIDEOTOOLBOX_HWACCEL || CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL
|
||||
AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
#endif
|
||||
AV_PIX_FMT_YUV420P,
|
||||
AV_PIX_FMT_NONE
|
||||
|
@ -868,6 +868,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
|
||||
CONFIG_H264_D3D11VA_HWACCEL + \
|
||||
CONFIG_H264_VAAPI_HWACCEL + \
|
||||
(CONFIG_H264_VDA_HWACCEL * 2) + \
|
||||
CONFIG_H264_VIDEOTOOLBOX_HWACCEL + \
|
||||
CONFIG_H264_VDPAU_HWACCEL)
|
||||
enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
|
||||
const enum AVPixelFormat *choices = pix_fmts;
|
||||
@ -947,6 +948,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
|
||||
#if CONFIG_H264_VDA_HWACCEL
|
||||
*fmt++ = AV_PIX_FMT_VDA_VLD;
|
||||
*fmt++ = AV_PIX_FMT_VDA;
|
||||
#endif
|
||||
#if CONFIG_H264_VIDEOTOOLBOX_HWACCEL
|
||||
*fmt++ = AV_PIX_FMT_VIDEOTOOLBOX;
|
||||
#endif
|
||||
if (h->avctx->codec->pix_fmts)
|
||||
choices = h->avctx->codec->pix_fmts;
|
||||
|
@ -1210,6 +1210,9 @@ static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = {
|
||||
#endif
|
||||
#if CONFIG_MPEG2_VAAPI_HWACCEL
|
||||
AV_PIX_FMT_VAAPI_VLD,
|
||||
#endif
|
||||
#if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL
|
||||
AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
#endif
|
||||
AV_PIX_FMT_YUV420P,
|
||||
AV_PIX_FMT_NONE
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "libavutil/mem.h"
|
||||
|
||||
#include "vda.h"
|
||||
#include "vda_internal.h"
|
||||
#include "vda_vt_internal.h"
|
||||
|
||||
#if CONFIG_H264_VDA_HWACCEL
|
||||
AVVDAContext *av_vda_alloc_context(void)
|
||||
|
@ -32,20 +32,7 @@ struct vda_buffer {
|
||||
CVPixelBufferRef cv_buffer;
|
||||
};
|
||||
#include "internal.h"
|
||||
#include "vda_internal.h"
|
||||
|
||||
typedef struct VDAContext {
|
||||
// The current bitstream buffer.
|
||||
uint8_t *bitstream;
|
||||
|
||||
// The current size of the bitstream.
|
||||
int bitstream_size;
|
||||
|
||||
// The reference size used for fast reallocation.
|
||||
int allocated_size;
|
||||
|
||||
CVImageBufferRef frame;
|
||||
} VDAContext;
|
||||
#include "vda_vt_internal.h"
|
||||
|
||||
/* Decoder callback that adds the vda frame to the queue in display order. */
|
||||
static void vda_decoder_callback(void *vda_hw_ctx,
|
||||
@ -68,7 +55,7 @@ static void vda_decoder_callback(void *vda_hw_ctx,
|
||||
vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer);
|
||||
}
|
||||
|
||||
static int vda_sync_decode(VDAContext *ctx, struct vda_context *vda_ctx)
|
||||
static int vda_sync_decode(VTContext *ctx, struct vda_context *vda_ctx)
|
||||
{
|
||||
OSStatus status;
|
||||
CFDataRef coded_frame;
|
||||
@ -93,7 +80,7 @@ static int vda_old_h264_start_frame(AVCodecContext *avctx,
|
||||
av_unused const uint8_t *buffer,
|
||||
av_unused uint32_t size)
|
||||
{
|
||||
VDAContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
VTContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
struct vda_context *vda_ctx = avctx->hwaccel_context;
|
||||
|
||||
if (!vda_ctx->decoder)
|
||||
@ -108,7 +95,7 @@ static int vda_old_h264_decode_slice(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
VDAContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
VTContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
struct vda_context *vda_ctx = avctx->hwaccel_context;
|
||||
void *tmp;
|
||||
|
||||
@ -141,7 +128,7 @@ static void vda_h264_release_buffer(void *opaque, uint8_t *data)
|
||||
static int vda_old_h264_end_frame(AVCodecContext *avctx)
|
||||
{
|
||||
H264Context *h = avctx->priv_data;
|
||||
VDAContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
VTContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
struct vda_context *vda_ctx = avctx->hwaccel_context;
|
||||
AVFrame *frame = h->cur_pic_ptr->f;
|
||||
struct vda_buffer *context;
|
||||
@ -271,17 +258,6 @@ int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int vda_h264_uninit(AVCodecContext *avctx)
|
||||
{
|
||||
VDAContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
if (vda) {
|
||||
av_freep(&vda->bitstream);
|
||||
if (vda->frame)
|
||||
CVPixelBufferRelease(vda->frame);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVHWAccel ff_h264_vda_old_hwaccel = {
|
||||
.name = "h264_vda",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
@ -290,8 +266,8 @@ AVHWAccel ff_h264_vda_old_hwaccel = {
|
||||
.start_frame = vda_old_h264_start_frame,
|
||||
.decode_slice = vda_old_h264_decode_slice,
|
||||
.end_frame = vda_old_h264_end_frame,
|
||||
.uninit = vda_h264_uninit,
|
||||
.priv_data_size = sizeof(VDAContext),
|
||||
.uninit = ff_videotoolbox_uninit,
|
||||
.priv_data_size = sizeof(VTContext),
|
||||
};
|
||||
|
||||
void ff_vda_output_callback(void *opaque,
|
||||
@ -301,7 +277,7 @@ void ff_vda_output_callback(void *opaque,
|
||||
CVImageBufferRef image_buffer)
|
||||
{
|
||||
AVCodecContext *ctx = opaque;
|
||||
VDAContext *vda = ctx->internal->hwaccel_priv_data;
|
||||
VTContext *vda = ctx->internal->hwaccel_priv_data;
|
||||
|
||||
|
||||
if (vda->frame) {
|
||||
@ -315,65 +291,10 @@ void ff_vda_output_callback(void *opaque,
|
||||
vda->frame = CVPixelBufferRetain(image_buffer);
|
||||
}
|
||||
|
||||
static int vda_h264_start_frame(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
VDAContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
H264Context *h = avctx->priv_data;
|
||||
|
||||
if (h->is_avc == 1) {
|
||||
void *tmp;
|
||||
vda->bitstream_size = 0;
|
||||
tmp = av_fast_realloc(vda->bitstream,
|
||||
&vda->allocated_size,
|
||||
size);
|
||||
vda->bitstream = tmp;
|
||||
memcpy(vda->bitstream, buffer, size);
|
||||
vda->bitstream_size = size;
|
||||
} else {
|
||||
vda->bitstream_size = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vda_h264_decode_slice(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
VDAContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
H264Context *h = avctx->priv_data;
|
||||
void *tmp;
|
||||
|
||||
if (h->is_avc == 1)
|
||||
return 0;
|
||||
|
||||
tmp = av_fast_realloc(vda->bitstream,
|
||||
&vda->allocated_size,
|
||||
vda->bitstream_size + size + 4);
|
||||
if (!tmp)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
vda->bitstream = tmp;
|
||||
|
||||
AV_WB32(vda->bitstream + vda->bitstream_size, size);
|
||||
memcpy(vda->bitstream + vda->bitstream_size + 4, buffer, size);
|
||||
|
||||
vda->bitstream_size += size + 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_buffer(void *opaque, uint8_t *data)
|
||||
{
|
||||
CVImageBufferRef frame = (CVImageBufferRef)data;
|
||||
CVPixelBufferRelease(frame);
|
||||
}
|
||||
|
||||
static int vda_h264_end_frame(AVCodecContext *avctx)
|
||||
{
|
||||
H264Context *h = avctx->priv_data;
|
||||
VDAContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
VTContext *vda = avctx->internal->hwaccel_priv_data;
|
||||
AVVDAContext *vda_ctx = avctx->hwaccel_context;
|
||||
AVFrame *frame = h->cur_pic_ptr->f;
|
||||
uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames
|
||||
@ -403,19 +324,7 @@ static int vda_h264_end_frame(AVCodecContext *avctx)
|
||||
return AVERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
av_buffer_unref(&frame->buf[0]);
|
||||
|
||||
frame->buf[0] = av_buffer_create((uint8_t*)vda->frame,
|
||||
sizeof(vda->frame),
|
||||
release_buffer, NULL,
|
||||
AV_BUFFER_FLAG_READONLY);
|
||||
if (!frame->buf[0])
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
frame->data[3] = (uint8_t*)vda->frame;
|
||||
vda->frame = NULL;
|
||||
|
||||
return 0;
|
||||
return ff_videotoolbox_buffer_create(vda, frame);
|
||||
}
|
||||
|
||||
int ff_vda_default_init(AVCodecContext *avctx)
|
||||
@ -434,26 +343,7 @@ int ff_vda_default_init(AVCodecContext *avctx)
|
||||
|
||||
// kCVPixelFormatType_420YpCbCr8Planar;
|
||||
|
||||
/* Each VCL NAL in the bitstream sent to the decoder
|
||||
* is preceded by a 4 bytes length header.
|
||||
* Change the avcC atom header if needed, to signal headers of 4 bytes. */
|
||||
if (avctx->extradata_size >= 4 && (avctx->extradata[4] & 0x03) != 0x03) {
|
||||
uint8_t *rw_extradata;
|
||||
|
||||
if (!(rw_extradata = av_malloc(avctx->extradata_size)))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
memcpy(rw_extradata, avctx->extradata, avctx->extradata_size);
|
||||
|
||||
rw_extradata[4] |= 0x03;
|
||||
|
||||
avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, avctx->extradata_size);
|
||||
|
||||
av_freep(&rw_extradata);
|
||||
} else {
|
||||
avc_data = CFDataCreate(kCFAllocatorDefault,
|
||||
avctx->extradata, avctx->extradata_size);
|
||||
}
|
||||
avc_data = ff_videotoolbox_avcc_extradata_create(avctx);
|
||||
|
||||
config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
4,
|
||||
@ -521,27 +411,15 @@ int ff_vda_default_init(AVCodecContext *avctx)
|
||||
}
|
||||
}
|
||||
|
||||
static int vda_h264_alloc_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
{
|
||||
frame->width = avctx->width;
|
||||
frame->height = avctx->height;
|
||||
frame->format = avctx->pix_fmt;
|
||||
frame->buf[0] = av_buffer_alloc(1);
|
||||
|
||||
if (!frame->buf[0])
|
||||
return AVERROR(ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVHWAccel ff_h264_vda_hwaccel = {
|
||||
.name = "h264_vda",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.id = AV_CODEC_ID_H264,
|
||||
.pix_fmt = AV_PIX_FMT_VDA,
|
||||
.alloc_frame = vda_h264_alloc_frame,
|
||||
.start_frame = vda_h264_start_frame,
|
||||
.decode_slice = vda_h264_decode_slice,
|
||||
.alloc_frame = ff_videotoolbox_alloc_frame,
|
||||
.start_frame = ff_videotoolbox_h264_start_frame,
|
||||
.decode_slice = ff_videotoolbox_h264_decode_slice,
|
||||
.end_frame = vda_h264_end_frame,
|
||||
.uninit = vda_h264_uninit,
|
||||
.priv_data_size = sizeof(VDAContext),
|
||||
.uninit = ff_videotoolbox_uninit,
|
||||
.priv_data_size = sizeof(VTContext),
|
||||
};
|
||||
|
@ -16,10 +16,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VDA_INTERNAL_H
|
||||
#define AVCODEC_VDA_INTERNAL_H
|
||||
|
||||
#include "vda.h"
|
||||
#ifndef AVCODEC_VDA_VT_INTERNAL_H
|
||||
#define AVCODEC_VDA_VT_INTERNAL_H
|
||||
|
||||
void ff_vda_output_callback(void *vda_hw_ctx,
|
||||
CFDictionaryRef user_info,
|
||||
@ -30,4 +28,28 @@ void ff_vda_output_callback(void *vda_hw_ctx,
|
||||
int ff_vda_default_init(AVCodecContext *avctx);
|
||||
void ff_vda_default_free(AVCodecContext *avctx);
|
||||
|
||||
#endif /* AVCODEC_VDA_INTERNAL_H */
|
||||
typedef struct VTContext {
|
||||
// The current bitstream buffer.
|
||||
uint8_t *bitstream;
|
||||
|
||||
// The current size of the bitstream.
|
||||
int bitstream_size;
|
||||
|
||||
// The reference size used for fast reallocation.
|
||||
int allocated_size;
|
||||
|
||||
// The core video buffer
|
||||
CVImageBufferRef frame;
|
||||
} VTContext;
|
||||
|
||||
int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame);
|
||||
int ff_videotoolbox_uninit(AVCodecContext *avctx);
|
||||
int ff_videotoolbox_buffer_create(VTContext *vtctx, AVFrame *frame);
|
||||
int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size);
|
||||
int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size);
|
||||
CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx);
|
||||
#endif /* AVCODEC_VDA_VT_INTERNAL_H */
|
@ -29,8 +29,8 @@
|
||||
#include "libavutil/version.h"
|
||||
|
||||
#define LIBAVCODEC_VERSION_MAJOR 56
|
||||
#define LIBAVCODEC_VERSION_MINOR 56
|
||||
#define LIBAVCODEC_VERSION_MICRO 101
|
||||
#define LIBAVCODEC_VERSION_MINOR 57
|
||||
#define LIBAVCODEC_VERSION_MICRO 100
|
||||
|
||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||
LIBAVCODEC_VERSION_MINOR, \
|
||||
|
690
libavcodec/videotoolbox.c
Normal file
690
libavcodec/videotoolbox.c
Normal file
@ -0,0 +1,690 @@
|
||||
/*
|
||||
* Videotoolbox hardware acceleration
|
||||
*
|
||||
* copyright (c) 2012 Sebastien Zwickert
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if CONFIG_VIDEOTOOLBOX
|
||||
# include "videotoolbox.h"
|
||||
#else
|
||||
# include "vda.h"
|
||||
#endif
|
||||
#include "vda_vt_internal.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "bytestream.h"
|
||||
#include "h264.h"
|
||||
#include "mpegvideo.h"
|
||||
|
||||
#ifndef kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
|
||||
# define kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder CFSTR("EnableHardwareAcceleratedVideoDecoder")
|
||||
#endif
|
||||
|
||||
#define VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING 12
|
||||
|
||||
static void videotoolbox_buffer_release(void *opaque, uint8_t *data)
|
||||
{
|
||||
CVPixelBufferRef cv_buffer = (CVImageBufferRef)data;
|
||||
CVPixelBufferRelease(cv_buffer);
|
||||
}
|
||||
|
||||
static int videotoolbox_buffer_copy(VTContext *vtctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
void *tmp;
|
||||
|
||||
tmp = av_fast_realloc(vtctx->bitstream,
|
||||
&vtctx->allocated_size,
|
||||
size);
|
||||
|
||||
if (!tmp)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
vtctx->bitstream = tmp;
|
||||
memcpy(vtctx->bitstream, buffer, size);
|
||||
vtctx->bitstream_size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
{
|
||||
frame->width = avctx->width;
|
||||
frame->height = avctx->height;
|
||||
frame->format = avctx->pix_fmt;
|
||||
frame->buf[0] = av_buffer_alloc(1);
|
||||
|
||||
if (!frame->buf[0])
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx)
|
||||
{
|
||||
CFDataRef data = NULL;
|
||||
|
||||
/* Each VCL NAL in the bistream sent to the decoder
|
||||
* is preceded by a 4 bytes length header.
|
||||
* Change the avcC atom header if needed, to signal headers of 4 bytes. */
|
||||
if (avctx->extradata_size >= 4 && (avctx->extradata[4] & 0x03) != 0x03) {
|
||||
uint8_t *rw_extradata = av_memdup(avctx->extradata, avctx->extradata_size);
|
||||
|
||||
if (!rw_extradata)
|
||||
return NULL;
|
||||
|
||||
rw_extradata[4] |= 0x03;
|
||||
|
||||
data = CFDataCreate(kCFAllocatorDefault, rw_extradata, avctx->extradata_size);
|
||||
|
||||
av_freep(&rw_extradata);
|
||||
} else {
|
||||
data = CFDataCreate(kCFAllocatorDefault, avctx->extradata, avctx->extradata_size);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int ff_videotoolbox_buffer_create(VTContext *vtctx, AVFrame *frame)
|
||||
{
|
||||
av_buffer_unref(&frame->buf[0]);
|
||||
|
||||
frame->buf[0] = av_buffer_create((uint8_t*)vtctx->frame,
|
||||
sizeof(vtctx->frame),
|
||||
videotoolbox_buffer_release,
|
||||
NULL,
|
||||
AV_BUFFER_FLAG_READONLY);
|
||||
if (!frame->buf[0]) {
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
frame->data[3] = (uint8_t*)vtctx->frame;
|
||||
vtctx->frame = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
|
||||
H264Context *h = avctx->priv_data;
|
||||
|
||||
vtctx->bitstream_size = 0;
|
||||
|
||||
if (h->is_avc == 1) {
|
||||
return videotoolbox_buffer_copy(vtctx, buffer, size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
|
||||
H264Context *h = avctx->priv_data;
|
||||
void *tmp;
|
||||
|
||||
if (h->is_avc == 1)
|
||||
return 0;
|
||||
|
||||
tmp = av_fast_realloc(vtctx->bitstream,
|
||||
&vtctx->allocated_size,
|
||||
vtctx->bitstream_size+size+4);
|
||||
if (!tmp)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
vtctx->bitstream = tmp;
|
||||
|
||||
AV_WB32(vtctx->bitstream + vtctx->bitstream_size, size);
|
||||
memcpy(vtctx->bitstream + vtctx->bitstream_size + 4, buffer, size);
|
||||
|
||||
vtctx->bitstream_size += size + 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_videotoolbox_uninit(AVCodecContext *avctx)
|
||||
{
|
||||
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
|
||||
if (vtctx) {
|
||||
av_freep(&vtctx->bitstream);
|
||||
if (vtctx->frame)
|
||||
CVPixelBufferRelease(vtctx->frame);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_VIDEOTOOLBOX
|
||||
static void videotoolbox_write_mp4_descr_length(PutByteContext *pb, int length)
|
||||
{
|
||||
int i;
|
||||
uint8_t b;
|
||||
|
||||
for (i = 3; i >= 0; i--) {
|
||||
b = (length >> (i * 7)) & 0x7F;
|
||||
if (i != 0)
|
||||
b |= 0x80;
|
||||
|
||||
bytestream2_put_byteu(pb, b);
|
||||
}
|
||||
}
|
||||
|
||||
static CFDataRef videotoolbox_esds_extradata_create(AVCodecContext *avctx)
|
||||
{
|
||||
CFDataRef data;
|
||||
uint8_t *rw_extradata;
|
||||
PutByteContext pb;
|
||||
int full_size = 3 + 5 + 13 + 5 + avctx->extradata_size + 3;
|
||||
// ES_DescrTag data + DecoderConfigDescrTag + data + DecSpecificInfoTag + size + SLConfigDescriptor
|
||||
int config_size = 13 + 5 + avctx->extradata_size;
|
||||
int s;
|
||||
|
||||
if (!(rw_extradata = av_mallocz(full_size + VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING)))
|
||||
return NULL;
|
||||
|
||||
bytestream2_init_writer(&pb, rw_extradata, full_size + VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING);
|
||||
bytestream2_put_byteu(&pb, 0); // version
|
||||
bytestream2_put_ne24(&pb, 0); // flags
|
||||
|
||||
// elementary stream descriptor
|
||||
bytestream2_put_byteu(&pb, 0x03); // ES_DescrTag
|
||||
videotoolbox_write_mp4_descr_length(&pb, full_size);
|
||||
bytestream2_put_ne16(&pb, 0); // esid
|
||||
bytestream2_put_byteu(&pb, 0); // stream priority (0-32)
|
||||
|
||||
// decoder configuration descriptor
|
||||
bytestream2_put_byteu(&pb, 0x04); // DecoderConfigDescrTag
|
||||
videotoolbox_write_mp4_descr_length(&pb, config_size);
|
||||
bytestream2_put_byteu(&pb, 32); // object type indication. 32 = CODEC_ID_MPEG4
|
||||
bytestream2_put_byteu(&pb, 0x11); // stream type
|
||||
bytestream2_put_ne24(&pb, 0); // buffer size
|
||||
bytestream2_put_ne32(&pb, 0); // max bitrate
|
||||
bytestream2_put_ne32(&pb, 0); // avg bitrate
|
||||
|
||||
// decoder specific descriptor
|
||||
bytestream2_put_byteu(&pb, 0x05); ///< DecSpecificInfoTag
|
||||
videotoolbox_write_mp4_descr_length(&pb, avctx->extradata_size);
|
||||
|
||||
bytestream2_put_buffer(&pb, avctx->extradata, avctx->extradata_size);
|
||||
|
||||
// SLConfigDescriptor
|
||||
bytestream2_put_byteu(&pb, 0x06); // SLConfigDescrTag
|
||||
bytestream2_put_byteu(&pb, 0x01); // length
|
||||
bytestream2_put_byteu(&pb, 0x02); //
|
||||
|
||||
s = bytestream2_size_p(&pb);
|
||||
|
||||
data = CFDataCreate(kCFAllocatorDefault, rw_extradata, s);
|
||||
|
||||
av_freep(&rw_extradata);
|
||||
return data;
|
||||
}
|
||||
|
||||
static CMSampleBufferRef videotoolbox_sample_buffer_create(CMFormatDescriptionRef fmt_desc,
|
||||
void *buffer,
|
||||
int size)
|
||||
{
|
||||
OSStatus status;
|
||||
CMBlockBufferRef block_buf;
|
||||
CMSampleBufferRef sample_buf;
|
||||
|
||||
block_buf = NULL;
|
||||
sample_buf = NULL;
|
||||
|
||||
status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,// structureAllocator
|
||||
buffer, // memoryBlock
|
||||
size, // blockLength
|
||||
kCFAllocatorNull, // blockAllocator
|
||||
NULL, // customBlockSource
|
||||
0, // offsetToData
|
||||
size, // dataLength
|
||||
0, // flags
|
||||
&block_buf);
|
||||
|
||||
if (!status) {
|
||||
status = CMSampleBufferCreate(kCFAllocatorDefault, // allocator
|
||||
block_buf, // dataBuffer
|
||||
TRUE, // dataReady
|
||||
0, // makeDataReadyCallback
|
||||
0, // makeDataReadyRefcon
|
||||
fmt_desc, // formatDescription
|
||||
1, // numSamples
|
||||
0, // numSampleTimingEntries
|
||||
NULL, // sampleTimingArray
|
||||
0, // numSampleSizeEntries
|
||||
NULL, // sampleSizeArray
|
||||
&sample_buf);
|
||||
}
|
||||
|
||||
if (block_buf)
|
||||
CFRelease(block_buf);
|
||||
|
||||
return sample_buf;
|
||||
}
|
||||
|
||||
static void videotoolbox_decoder_callback(void *opaque,
|
||||
void *sourceFrameRefCon,
|
||||
OSStatus status,
|
||||
VTDecodeInfoFlags flags,
|
||||
CVImageBufferRef image_buffer,
|
||||
CMTime pts,
|
||||
CMTime duration)
|
||||
{
|
||||
AVCodecContext *avctx = opaque;
|
||||
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
|
||||
|
||||
if (vtctx->frame) {
|
||||
CVPixelBufferRelease(vtctx->frame);
|
||||
vtctx->frame = NULL;
|
||||
}
|
||||
|
||||
if (!image_buffer) {
|
||||
av_log(NULL, AV_LOG_DEBUG, "vt decoder cb: output image buffer is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vtctx->frame = CVPixelBufferRetain(image_buffer);
|
||||
}
|
||||
|
||||
static OSStatus videotoolbox_session_decode_frame(AVCodecContext *avctx)
|
||||
{
|
||||
OSStatus status;
|
||||
CMSampleBufferRef sample_buf;
|
||||
AVVideotoolboxContext *videotoolbox = avctx->hwaccel_context;
|
||||
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
|
||||
|
||||
sample_buf = videotoolbox_sample_buffer_create(videotoolbox->cm_fmt_desc,
|
||||
vtctx->bitstream,
|
||||
vtctx->bitstream_size);
|
||||
|
||||
if (!sample_buf)
|
||||
return -1;
|
||||
|
||||
status = VTDecompressionSessionDecodeFrame(videotoolbox->session,
|
||||
sample_buf,
|
||||
0, // decodeFlags
|
||||
NULL, // sourceFrameRefCon
|
||||
0); // infoFlagsOut
|
||||
if (status == noErr)
|
||||
status = VTDecompressionSessionWaitForAsynchronousFrames(videotoolbox->session);
|
||||
|
||||
CFRelease(sample_buf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
{
|
||||
int status;
|
||||
AVVideotoolboxContext *videotoolbox = avctx->hwaccel_context;
|
||||
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
|
||||
|
||||
if (!videotoolbox->session || !vtctx->bitstream)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
status = videotoolbox_session_decode_frame(avctx);
|
||||
|
||||
if (status) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
|
||||
return AVERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (!vtctx->frame)
|
||||
return AVERROR_UNKNOWN;
|
||||
|
||||
return ff_videotoolbox_buffer_create(vtctx, frame);
|
||||
}
|
||||
|
||||
static int videotoolbox_h264_end_frame(AVCodecContext *avctx)
|
||||
{
|
||||
H264Context *h = avctx->priv_data;
|
||||
AVFrame *frame = h->cur_pic_ptr->f;
|
||||
|
||||
return videotoolbox_common_end_frame(avctx, frame);
|
||||
}
|
||||
|
||||
static int videotoolbox_mpeg_start_frame(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
VTContext *vtctx = avctx->internal->hwaccel_priv_data;
|
||||
|
||||
return videotoolbox_buffer_copy(vtctx, buffer, size);
|
||||
}
|
||||
|
||||
static int videotoolbox_mpeg_decode_slice(AVCodecContext *avctx,
|
||||
const uint8_t *buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx)
|
||||
{
|
||||
MpegEncContext *s = avctx->priv_data;
|
||||
AVFrame *frame = s->current_picture_ptr->f;
|
||||
|
||||
return videotoolbox_common_end_frame(avctx, frame);
|
||||
}
|
||||
|
||||
static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec_type,
|
||||
AVCodecContext *avctx)
|
||||
{
|
||||
CFMutableDictionaryRef config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
1,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFDictionarySetValue(config_info,
|
||||
kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder,
|
||||
kCFBooleanTrue);
|
||||
|
||||
if (avctx->extradata_size) {
|
||||
CFMutableDictionaryRef avc_info;
|
||||
CFDataRef data = NULL;
|
||||
|
||||
avc_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
1,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
switch (codec_type) {
|
||||
case kCMVideoCodecType_MPEG4Video :
|
||||
data = videotoolbox_esds_extradata_create(avctx);
|
||||
if (data)
|
||||
CFDictionarySetValue(avc_info, CFSTR("esds"), data);
|
||||
break;
|
||||
case kCMVideoCodecType_H264 :
|
||||
data = ff_videotoolbox_avcc_extradata_create(avctx);
|
||||
if (data)
|
||||
CFDictionarySetValue(avc_info, CFSTR("avcC"), data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CFDictionarySetValue(config_info,
|
||||
kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
|
||||
avc_info);
|
||||
|
||||
if (data)
|
||||
CFRelease(data);
|
||||
|
||||
CFRelease(avc_info);
|
||||
}
|
||||
return config_info;
|
||||
}
|
||||
|
||||
static CFDictionaryRef videotoolbox_buffer_attributes_create(int width,
|
||||
int height,
|
||||
OSType pix_fmt)
|
||||
{
|
||||
CFMutableDictionaryRef buffer_attributes;
|
||||
CFMutableDictionaryRef io_surface_properties;
|
||||
CFNumberRef cv_pix_fmt;
|
||||
CFNumberRef w;
|
||||
CFNumberRef h;
|
||||
|
||||
w = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width);
|
||||
h = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height);
|
||||
cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pix_fmt);
|
||||
|
||||
buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
4,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFDictionarySetValue(buffer_attributes, kCVPixelBufferPixelFormatTypeKey, cv_pix_fmt);
|
||||
CFDictionarySetValue(buffer_attributes, kCVPixelBufferIOSurfacePropertiesKey, io_surface_properties);
|
||||
CFDictionarySetValue(buffer_attributes, kCVPixelBufferWidthKey, w);
|
||||
CFDictionarySetValue(buffer_attributes, kCVPixelBufferHeightKey, h);
|
||||
|
||||
CFRelease(io_surface_properties);
|
||||
CFRelease(cv_pix_fmt);
|
||||
CFRelease(w);
|
||||
CFRelease(h);
|
||||
|
||||
return buffer_attributes;
|
||||
}
|
||||
|
||||
static CMVideoFormatDescriptionRef videotoolbox_format_desc_create(CMVideoCodecType codec_type,
|
||||
CFDictionaryRef decoder_spec,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
CMFormatDescriptionRef cm_fmt_desc;
|
||||
OSStatus status;
|
||||
|
||||
status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
|
||||
codec_type,
|
||||
width,
|
||||
height,
|
||||
decoder_spec, // Dictionary of extension
|
||||
&cm_fmt_desc);
|
||||
|
||||
if (status)
|
||||
return NULL;
|
||||
|
||||
return cm_fmt_desc;
|
||||
}
|
||||
|
||||
static int videotoolbox_default_init(AVCodecContext *avctx)
|
||||
{
|
||||
AVVideotoolboxContext *videotoolbox = avctx->hwaccel_context;
|
||||
OSStatus status;
|
||||
VTDecompressionOutputCallbackRecord decoder_cb;
|
||||
CFDictionaryRef decoder_spec;
|
||||
CFDictionaryRef buf_attr;
|
||||
int32_t pix_fmt;
|
||||
|
||||
if (!videotoolbox) {
|
||||
av_log(avctx, AV_LOG_ERROR, "hwaccel context is not set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch( avctx->codec_id ) {
|
||||
case AV_CODEC_ID_H263 :
|
||||
videotoolbox->cm_codec_type = kCMVideoCodecType_H263;
|
||||
break;
|
||||
case AV_CODEC_ID_H264 :
|
||||
videotoolbox->cm_codec_type = kCMVideoCodecType_H264;
|
||||
break;
|
||||
case AV_CODEC_ID_MPEG1VIDEO :
|
||||
videotoolbox->cm_codec_type = kCMVideoCodecType_MPEG1Video;
|
||||
break;
|
||||
case AV_CODEC_ID_MPEG2VIDEO :
|
||||
videotoolbox->cm_codec_type = kCMVideoCodecType_MPEG2Video;
|
||||
break;
|
||||
case AV_CODEC_ID_MPEG4 :
|
||||
videotoolbox->cm_codec_type = kCMVideoCodecType_MPEG4Video;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
pix_fmt = videotoolbox->cv_pix_fmt_type;
|
||||
|
||||
decoder_spec = videotoolbox_decoder_config_create(videotoolbox->cm_codec_type, avctx);
|
||||
|
||||
videotoolbox->cm_fmt_desc = videotoolbox_format_desc_create(videotoolbox->cm_codec_type,
|
||||
decoder_spec,
|
||||
avctx->width,
|
||||
avctx->height);
|
||||
if (!videotoolbox->cm_fmt_desc) {
|
||||
if (decoder_spec)
|
||||
CFRelease(decoder_spec);
|
||||
|
||||
av_log(avctx, AV_LOG_ERROR, "format description creation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf_attr = videotoolbox_buffer_attributes_create(avctx->width,
|
||||
avctx->height,
|
||||
videotoolbox->cv_pix_fmt_type);
|
||||
|
||||
decoder_cb.decompressionOutputCallback = videotoolbox_decoder_callback;
|
||||
decoder_cb.decompressionOutputRefCon = avctx;
|
||||
|
||||
status = VTDecompressionSessionCreate(NULL, // allocator
|
||||
videotoolbox->cm_fmt_desc, // videoFormatDescription
|
||||
decoder_spec, // videoDecoderSpecification
|
||||
buf_attr, // destinationImageBufferAttributes
|
||||
&decoder_cb, // outputCallback
|
||||
&videotoolbox->session); // decompressionSessionOut
|
||||
|
||||
if (decoder_spec)
|
||||
CFRelease(decoder_spec);
|
||||
if (buf_attr)
|
||||
CFRelease(buf_attr);
|
||||
|
||||
switch (status) {
|
||||
case kVTVideoDecoderNotAvailableNowErr:
|
||||
case kVTVideoDecoderUnsupportedDataFormatErr:
|
||||
return AVERROR(ENOSYS);
|
||||
case kVTVideoDecoderMalfunctionErr:
|
||||
return AVERROR(EINVAL);
|
||||
case kVTVideoDecoderBadDataErr :
|
||||
return AVERROR_INVALIDDATA;
|
||||
case 0:
|
||||
return 0;
|
||||
default:
|
||||
return AVERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void videotoolbox_default_free(AVCodecContext *avctx)
|
||||
{
|
||||
AVVideotoolboxContext *videotoolbox = avctx->hwaccel_context;
|
||||
|
||||
if (videotoolbox) {
|
||||
if (videotoolbox->cm_fmt_desc)
|
||||
CFRelease(videotoolbox->cm_fmt_desc);
|
||||
|
||||
if (videotoolbox->session)
|
||||
VTDecompressionSessionInvalidate(videotoolbox->session);
|
||||
}
|
||||
}
|
||||
|
||||
AVHWAccel ff_h263_videotoolbox_hwaccel = {
|
||||
.name = "h263_videotoolbox",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.id = AV_CODEC_ID_H263,
|
||||
.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
.alloc_frame = ff_videotoolbox_alloc_frame,
|
||||
.start_frame = videotoolbox_mpeg_start_frame,
|
||||
.decode_slice = videotoolbox_mpeg_decode_slice,
|
||||
.end_frame = videotoolbox_mpeg_end_frame,
|
||||
.uninit = ff_videotoolbox_uninit,
|
||||
.priv_data_size = sizeof(VTContext),
|
||||
};
|
||||
|
||||
AVHWAccel ff_h264_videotoolbox_hwaccel = {
|
||||
.name = "h264_videotoolbox",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.id = AV_CODEC_ID_H264,
|
||||
.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
.alloc_frame = ff_videotoolbox_alloc_frame,
|
||||
.start_frame = ff_videotoolbox_h264_start_frame,
|
||||
.decode_slice = ff_videotoolbox_h264_decode_slice,
|
||||
.end_frame = videotoolbox_h264_end_frame,
|
||||
.uninit = ff_videotoolbox_uninit,
|
||||
.priv_data_size = sizeof(VTContext),
|
||||
};
|
||||
|
||||
AVHWAccel ff_mpeg1_videotoolbox_hwaccel = {
|
||||
.name = "mpeg1_videotoolbox",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.id = AV_CODEC_ID_MPEG1VIDEO,
|
||||
.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
.alloc_frame = ff_videotoolbox_alloc_frame,
|
||||
.start_frame = videotoolbox_mpeg_start_frame,
|
||||
.decode_slice = videotoolbox_mpeg_decode_slice,
|
||||
.end_frame = videotoolbox_mpeg_end_frame,
|
||||
.uninit = ff_videotoolbox_uninit,
|
||||
.priv_data_size = sizeof(VTContext),
|
||||
};
|
||||
|
||||
AVHWAccel ff_mpeg2_videotoolbox_hwaccel = {
|
||||
.name = "mpeg2_videotoolbox",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.id = AV_CODEC_ID_MPEG2VIDEO,
|
||||
.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
.alloc_frame = ff_videotoolbox_alloc_frame,
|
||||
.start_frame = videotoolbox_mpeg_start_frame,
|
||||
.decode_slice = videotoolbox_mpeg_decode_slice,
|
||||
.end_frame = videotoolbox_mpeg_end_frame,
|
||||
.uninit = ff_videotoolbox_uninit,
|
||||
.priv_data_size = sizeof(VTContext),
|
||||
};
|
||||
|
||||
AVHWAccel ff_mpeg4_videotoolbox_hwaccel = {
|
||||
.name = "mpeg4_videotoolbox",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.id = AV_CODEC_ID_MPEG4,
|
||||
.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX,
|
||||
.alloc_frame = ff_videotoolbox_alloc_frame,
|
||||
.start_frame = videotoolbox_mpeg_start_frame,
|
||||
.decode_slice = videotoolbox_mpeg_decode_slice,
|
||||
.end_frame = videotoolbox_mpeg_end_frame,
|
||||
.uninit = ff_videotoolbox_uninit,
|
||||
.priv_data_size = sizeof(VTContext),
|
||||
};
|
||||
|
||||
AVVideotoolboxContext *av_videotoolbox_alloc_context(void)
|
||||
{
|
||||
AVVideotoolboxContext *ret = av_mallocz(sizeof(*ret));
|
||||
|
||||
if (ret) {
|
||||
ret->output_callback = videotoolbox_decoder_callback;
|
||||
ret->cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int av_videotoolbox_default_init(AVCodecContext *avctx)
|
||||
{
|
||||
return av_videotoolbox_default_init2(avctx, NULL);
|
||||
}
|
||||
|
||||
int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx)
|
||||
{
|
||||
avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context();
|
||||
if (!avctx->hwaccel_context)
|
||||
return AVERROR(ENOMEM);
|
||||
return videotoolbox_default_init(avctx);
|
||||
}
|
||||
|
||||
void av_videotoolbox_default_free(AVCodecContext *avctx)
|
||||
{
|
||||
|
||||
videotoolbox_default_free(avctx);
|
||||
av_freep(&avctx->hwaccel_context);
|
||||
}
|
||||
#endif /* CONFIG_VIDEOTOOLBOX */
|
126
libavcodec/videotoolbox.h
Normal file
126
libavcodec/videotoolbox.h
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Videotoolbox hardware acceleration
|
||||
*
|
||||
* copyright (c) 2012 Sebastien Zwickert
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VIDEOTOOLBOX_H
|
||||
#define AVCODEC_VIDEOTOOLBOX_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavc_codec_hwaccel_videotoolbox
|
||||
* Public libavcodec Videotoolbox header.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define Picture QuickdrawPicture
|
||||
#include <VideoToolbox/VideoToolbox.h>
|
||||
#undef Picture
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
|
||||
/**
|
||||
* This struct holds all the information that needs to be passed
|
||||
* between the caller and libavcodec for initializing Videotoolbox decoding.
|
||||
* Its size is not a part of the public ABI, it must be allocated with
|
||||
* av_videotoolbox_alloc_context() and freed with av_free().
|
||||
*/
|
||||
typedef struct AVVideotoolboxContext {
|
||||
/**
|
||||
* Videotoolbox decompression session object.
|
||||
* Created and freed the caller.
|
||||
*/
|
||||
VTDecompressionSessionRef session;
|
||||
|
||||
/**
|
||||
* The output callback that must be passed to the session.
|
||||
* Set by av_videottoolbox_default_init()
|
||||
*/
|
||||
VTDecompressionOutputCallback output_callback;
|
||||
|
||||
/**
|
||||
* CVPixelBuffer Format Type that Videotoolbox will use for decoded frames.
|
||||
* set by the caller.
|
||||
*/
|
||||
OSType cv_pix_fmt_type;
|
||||
|
||||
/**
|
||||
* CoreMedia Format Description that Videotoolbox will use to create the decompression session.
|
||||
* Set by the caller.
|
||||
*/
|
||||
CMVideoFormatDescriptionRef cm_fmt_desc;
|
||||
|
||||
/**
|
||||
* CoreMedia codec type that Videotoolbox will use to create the decompression session.
|
||||
* Set by the caller.
|
||||
*/
|
||||
int cm_codec_type;
|
||||
} AVVideotoolboxContext;
|
||||
|
||||
/**
|
||||
* Allocate and initialize a Videotoolbox context.
|
||||
*
|
||||
* This function should be called from the get_format() callback when the caller
|
||||
* selects the AV_PIX_FMT_VIDETOOLBOX format. The caller must then create
|
||||
* the decoder object (using the output callback provided by libavcodec) that
|
||||
* will be used for Videotoolbox-accelerated decoding.
|
||||
*
|
||||
* When decoding with Videotoolbox is finished, the caller must destroy the decoder
|
||||
* object and free the Videotoolbox context using av_free().
|
||||
*
|
||||
* @return the newly allocated context or NULL on failure
|
||||
*/
|
||||
AVVideotoolboxContext *av_videotoolbox_alloc_context(void);
|
||||
|
||||
/**
|
||||
* This is a convenience function that creates and sets up the Videotoolbox context using
|
||||
* an internal implementation.
|
||||
*
|
||||
* @param avctx the corresponding codec context
|
||||
*
|
||||
* @return >= 0 on success, a negative AVERROR code on failure
|
||||
*/
|
||||
int av_videotoolbox_default_init(AVCodecContext *avctx);
|
||||
|
||||
/**
|
||||
* This is a convenience function that creates and sets up the Videotoolbox context using
|
||||
* an internal implementation.
|
||||
*
|
||||
* @param avctx the corresponding codec context
|
||||
* @param vtctx the Videotoolbox context to use
|
||||
*
|
||||
* @return >= 0 on success, a negative AVERROR code on failure
|
||||
*/
|
||||
int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx);
|
||||
|
||||
/**
|
||||
* This function must be called to free the Videotoolbox context initialized with
|
||||
* av_videotoolbox_default_init().
|
||||
*
|
||||
* @param avctx the corresponding codec context
|
||||
*/
|
||||
void av_videotoolbox_default_free(AVCodecContext *avctx);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVCODEC_VIDEOTOOLBOX_H */
|
@ -1632,6 +1632,10 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
|
||||
},
|
||||
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_ALPHA,
|
||||
},
|
||||
[AV_PIX_FMT_VIDEOTOOLBOX] = {
|
||||
.name = "videotoolbox_vld",
|
||||
.flags = AV_PIX_FMT_FLAG_HWACCEL,
|
||||
},
|
||||
[AV_PIX_FMT_GBRP] = {
|
||||
.name = "gbrp",
|
||||
.nb_components = 3,
|
||||
|
@ -311,6 +311,8 @@ enum AVPixelFormat {
|
||||
AV_PIX_FMT_AYUV64LE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), little-endian
|
||||
AV_PIX_FMT_AYUV64BE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), big-endian
|
||||
|
||||
AV_PIX_FMT_VIDEOTOOLBOX, ///< hardware decoding through Videotoolbox
|
||||
|
||||
AV_PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
|
||||
|
||||
#if FF_API_PIX_FMT
|
||||
|
Loading…
x
Reference in New Issue
Block a user