--- Changelog | 1 + MAINTAINERS | 1 + configure | 12 ++ libavcodec/Makefile | 7 + libavcodec/allcodecs.c | 4 + libavcodec/h264.c | 1 + libavcodec/mpeg12.c | 3 + libavcodec/mpegvideo.c | 1 + libavcodec/version.h | 2 +- libavcodec/vt.c | 388 ++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/vt.h | 185 ++++++++++++++++++++++ libavcodec/vt_h264.c | 94 +++++++++++ libavcodec/vt_internal.h | 44 ++++++ libavcodec/vt_mpeg2.c | 77 +++++++++ libavcodec/vt_mpeg4.c | 92 +++++++++++ libavutil/pixdesc.c | 6 + libavutil/pixfmt.h | 1 + 17 files changed, 918 insertions(+), 1 deletion(-) create mode 100644 libavcodec/vt.c create mode 100644 libavcodec/vt.h create mode 100644 libavcodec/vt_h264.c create mode 100644 libavcodec/vt_internal.h create mode 100644 libavcodec/vt_mpeg2.c create mode 100644 libavcodec/vt_mpeg4.c diff --git a/Changelog b/Changelog index 64cbf00..a6b61eb 100644 --- a/Changelog +++ b/Changelog @@ -59,6 +59,7 @@ version next: - smartblur filter ported from MPlayer - CPiA decoder - decimate filter ported from MPlayer +- OS X VideoToolbox (VT) support version 0.11: diff --git a/MAINTAINERS b/MAINTAINERS index 1860b6e..6233b1c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -257,6 +257,7 @@ Hardware acceleration: libstagefright.cpp Mohamed Naufal vaapi* Gwenole Beauchesne vda* Sebastien Zwickert + vt* Sebastien Zwickert vdpau* Carl Eugen Hoyos diff --git a/configure b/configure index 7fac4e9..ff49eec 100755 --- a/configure +++ b/configure @@ -133,6 +133,7 @@ Component options: --enable-dxva2 enable DXVA2 code --enable-vaapi enable VAAPI code [autodetect] --enable-vda enable VDA code [autodetect] + --enable-vt enable VideoToolbox code [autodetect] --enable-vdpau enable VDPAU code [autodetect] Individual component options: @@ -1171,6 +1172,7 @@ CONFIG_LIST=" thumb vaapi vda + vt vdpau version3 xmm_clobber_test @@ -1601,6 +1603,7 @@ h261_encoder_select="aandcttables mpegvideoenc" h263_decoder_select="error_resilience h263_parser mpegvideo" h263_encoder_select="aandcttables error_resilience mpegvideoenc" h263_vaapi_hwaccel_select="vaapi h263_decoder" +h263_vt_hwaccel_select="vt h263_decoder" h263i_decoder_select="h263_decoder" h263p_encoder_select="h263_encoder" h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser" @@ -1611,6 +1614,7 @@ h264_vaapi_hwaccel_select="vaapi h264_decoder" h264_vda_decoder_select="vda h264_parser h264_decoder" h264_vda_hwaccel_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" h264_vda_hwaccel_select="vda h264_decoder" +h264_vt_hwaccel_select="vt h264_decoder" h264_vdpau_decoder_select="vdpau h264_decoder" huffyuv_encoder_select="huffman" iac_decoder_select="fft mdct sinewin" @@ -1646,12 +1650,14 @@ mpeg2_dxva2_hwaccel_deps="dxva2api_h" mpeg2_dxva2_hwaccel_select="dxva2 mpeg2video_decoder" mpeg2_vdpau_hwaccel_select="vdpau mpeg2video_decoder" mpeg2_vaapi_hwaccel_select="vaapi mpeg2video_decoder" +mpeg2_vt_hwaccel_select="vt mpeg2video_decoder" mpeg2video_decoder_select="error_resilience mpegvideo" mpeg2video_encoder_select="aandcttables error_resilience mpegvideoenc" mpeg4_crystalhd_decoder_select="crystalhd" mpeg4_decoder_select="h263_decoder mpeg4video_parser" mpeg4_encoder_select="h263_encoder" mpeg4_vaapi_hwaccel_select="vaapi mpeg4_decoder" +mpeg4_vt_hwaccel_select="vt mpeg4_decoder" mpeg4_vdpau_decoder_select="vdpau mpeg4_decoder" msmpeg4_crystalhd_decoder_select="crystalhd" msmpeg4v1_decoder_select="h263_decoder" @@ -1732,6 +1738,7 @@ zmbv_encoder_select="zlib" crystalhd_deps="libcrystalhd_libcrystalhd_if_h" vaapi_deps="va_va_h" vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" +vt_deps="VideoToolbox_VideoToolbox_h" vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h" # parsers @@ -3532,6 +3539,11 @@ if ! disabled vda; then fi fi +# check for VideoToolbox header +if ! disabled vda && check_header VideoToolbox/VideoToolbox.h; then + enable vt && add_extralibs -framework CoreFoundation -framework VideoToolbox -framework CoreMedia -framework QuartzCore +fi + if ! disabled w32threads && ! enabled pthreads; then check_func _beginthreadex && enable w32threads fi diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ae2efb6..cef8c14 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -9,6 +9,7 @@ HEADERS = avcodec.h \ old_codec_ids.h \ vaapi.h \ vda.h \ + vt.h \ vdpau.h \ version.h \ xvmc.h \ @@ -65,6 +66,7 @@ RDFT-OBJS-$(CONFIG_HARDCODED_TABLES) += sin_tables.o OBJS-$(CONFIG_RDFT) += rdft.o $(RDFT-OBJS-yes) OBJS-$(CONFIG_SINEWIN) += sinewin.o OBJS-$(CONFIG_VAAPI) += vaapi.o +OBJS-$(CONFIG_VT) += vt.o OBJS-$(CONFIG_VDPAU) += vdpau.o OBJS-$(CONFIG_VP3DSP) += vp3dsp.o @@ -208,6 +210,7 @@ OBJS-$(CONFIG_H263_DECODER) += h263dec.o h263.o ituh263dec.o \ mpeg4video.o mpeg4videodec.o flvdec.o\ intelh263dec.o OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o +OBJS-$(CONFIG_H263_VT_HWACCEL) += vt_mpeg4.o OBJS-$(CONFIG_H263_ENCODER) += mpeg4videoenc.o mpeg4video.o \ h263.o ituh263enc.o flvenc.o OBJS-$(CONFIG_H264_DECODER) += h264.o \ @@ -218,6 +221,7 @@ 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_H264_VT_HWACCEL) += vt_h264.o OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o OBJS-$(CONFIG_IAC_DECODER) += imc.o @@ -291,10 +295,12 @@ OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpeg12.o \ timecode.o OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o +OBJS-$(CONFIG_MPEG2_VT_HWACCEL) += vt_mpeg2.o OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12.o mpeg12data.o OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o \ timecode.o OBJS-$(CONFIG_MPEG4_VAAPI_HWACCEL) += vaapi_mpeg4.o +OBJS-$(CONFIG_MPEG4_VT_HWACCEL) += vt_mpeg4.o OBJS-$(CONFIG_MSMPEG4V1_DECODER) += msmpeg4.o msmpeg4data.o OBJS-$(CONFIG_MSMPEG4V2_DECODER) += msmpeg4.o msmpeg4data.o h263dec.o \ h263.o ituh263dec.o mpeg4videodec.o @@ -766,6 +772,7 @@ SKIPHEADERS-$(CONFIG_LIBUTVIDEO) += libutvideo.h SKIPHEADERS-$(CONFIG_MPEG_XVMC_DECODER) += xvmc.h SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h SKIPHEADERS-$(CONFIG_VDA) += vda.h +SKIPHEADERS-$(CONFIG_VT) += vt.h vt_internal.h SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h SKIPHEADERS-$(HAVE_OS2THREADS) += os2threads.h SKIPHEADERS-$(HAVE_W32THREADS) += w32pthreads.h diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 8806c6a..6334060 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -56,14 +56,18 @@ void avcodec_register_all(void) /* hardware accelerators */ REGISTER_HWACCEL (H263_VAAPI, h263_vaapi); + REGISTER_HWACCEL (H263_VT, h263_vt); REGISTER_HWACCEL (H264_DXVA2, h264_dxva2); REGISTER_HWACCEL (H264_VAAPI, h264_vaapi); REGISTER_HWACCEL (H264_VDA, h264_vda); + REGISTER_HWACCEL (H264_VT, h264_vt); REGISTER_HWACCEL (MPEG1_VDPAU, mpeg1_vdpau); REGISTER_HWACCEL (MPEG2_DXVA2, mpeg2_dxva2); REGISTER_HWACCEL (MPEG2_VAAPI, mpeg2_vaapi); + REGISTER_HWACCEL (MPEG2_VT, mpeg2_vt); REGISTER_HWACCEL (MPEG2_VDPAU, mpeg2_vdpau); REGISTER_HWACCEL (MPEG4_VAAPI, mpeg4_vaapi); + REGISTER_HWACCEL (MPEG4_VT, mpeg4_vt); REGISTER_HWACCEL (VC1_DXVA2, vc1_dxva2); REGISTER_HWACCEL (VC1_VAAPI, vc1_vaapi); REGISTER_HWACCEL (WMV3_DXVA2, wmv3_dxva2); diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 713fda7..bb42323 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -70,6 +70,7 @@ static const enum PixelFormat hwaccel_pixfmt_list_h264_jpeg_420[] = { PIX_FMT_DXVA2_VLD, PIX_FMT_VAAPI_VLD, PIX_FMT_VDA_VLD, + PIX_FMT_VT_VLD, PIX_FMT_YUVJ420P, PIX_FMT_NONE }; diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 1bf857e..09532a8 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -1203,6 +1203,9 @@ static const enum PixelFormat mpeg2_hwaccel_pixfmt_list_420[] = { #if CONFIG_MPEG2_VAAPI_HWACCEL PIX_FMT_VAAPI_VLD, #endif +#if CONFIG_MPEG2_VT_HWACCEL + PIX_FMT_VT_VLD, +#endif PIX_FMT_YUV420P, PIX_FMT_NONE }; diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 6b3d4e7..88bd4fd 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -134,6 +134,7 @@ const enum PixelFormat ff_hwaccel_pixfmt_list_420[] = { PIX_FMT_DXVA2_VLD, PIX_FMT_VAAPI_VLD, PIX_FMT_VDA_VLD, + PIX_FMT_VT_VLD, PIX_FMT_YUV420P, PIX_FMT_NONE }; diff --git a/libavcodec/version.h b/libavcodec/version.h index a2e231b..3349789 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -27,7 +27,7 @@ */ #define LIBAVCODEC_VERSION_MAJOR 54 -#define LIBAVCODEC_VERSION_MINOR 55 +#define LIBAVCODEC_VERSION_MINOR 56 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavcodec/vt.c b/libavcodec/vt.c new file mode 100644 index 0000000..d8b9e0f --- /dev/null +++ b/libavcodec/vt.c @@ -0,0 +1,388 @@ +/* + * 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 "libavutil/avutil.h" +#include "vt_internal.h" + +static int vt_write_mp4_descr_length(PutBitContext *pb, int length, int compact) +{ + int i; + uint8_t b; + int nb; + + if (compact) { + if (length <= 0x7F) + nb = 1; + else if (length <= 0x3FFF) + nb = 2; + else if (length <= 0x1FFFFF) + nb = 3; + else + nb = 4; + } + else + nb = 4; + + for (i = nb-1; i >= 0; i--) { + b = (length >> (i * 7)) & 0x7F; + if (i != 0) { + b |= 0x80; + } + put_bits(pb, 8, b); + } + + return nb; +} + +static CFDataRef vt_esds_extradata_create(uint8_t *extradata, int size) +{ + CFDataRef data; + uint8_t *rw_extradata; + PutBitContext pb; + int full_size = 3 + (5 + (13 + (5 + size))) + 3; + int config_size = 13 + 5 + size; + int padding = 12; + int s, i = 0; + + if (!(rw_extradata = av_mallocz(sizeof(uint8_t)*(full_size+padding)))) + return NULL; + + init_put_bits(&pb, rw_extradata, full_size+padding); + put_bits(&pb, 8, 0); ///< version + put_bits(&pb, 24, 0); ///< flags + + // elementary stream descriptor + put_bits(&pb, 8, 0x03); ///< ES_DescrTag + vt_write_mp4_descr_length(&pb, full_size, 0); + put_bits(&pb, 16, 0); ///< esid + put_bits(&pb, 8, 0); ///< stream priority (0-32) + + // decoder configuration descriptor + put_bits(&pb, 8, 0x04); ///< DecoderConfigDescrTag + vt_write_mp4_descr_length(&pb, config_size, 0); + put_bits(&pb, 8, 32); ///< object type indication. 32 = CODEC_ID_MPEG4 + put_bits(&pb, 8, 0x11); ///< stream type + put_bits(&pb, 24, 0); ///< buffer size + put_bits32(&pb, 0); ///< max bitrate + put_bits32(&pb, 0); ///< avg bitrate + + // decoder specific descriptor + put_bits(&pb, 8, 0x05); ///< DecSpecificInfoTag + vt_write_mp4_descr_length(&pb, size, 0); + for (i = 0; i < size; i++) + put_bits(&pb, 8, extradata[i]); + + // SLConfigDescriptor + put_bits(&pb, 8, 0x06); ///< SLConfigDescrTag + put_bits(&pb, 8, 0x01); ///< length + put_bits(&pb, 8, 0x02); ///< + + flush_put_bits(&pb); + s = put_bits_count(&pb) / 8; + + data = CFDataCreate(kCFAllocatorDefault, rw_extradata, s); + + av_freep(&rw_extradata); + return data; +} + +static CFDataRef vt_avcc_extradata_create(uint8_t *extradata, int size) +{ + CFDataRef data; + /* 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 (size >= 4 && (extradata[4] & 0x03) != 0x03) { + uint8_t *rw_extradata; + + if (!(rw_extradata = av_malloc(size))) + return NULL; + + memcpy(rw_extradata, extradata, size); + + rw_extradata[4] |= 0x03; + + data = CFDataCreate(kCFAllocatorDefault, rw_extradata, size); + + av_freep(&rw_extradata); + } else { + data = CFDataCreate(kCFAllocatorDefault, extradata, size); + } + + return data; +} + +static CMSampleBufferRef vt_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 vt_decoder_callback(void *vt_hw_ctx, + void *sourceFrameRefCon, + OSStatus status, + VTDecodeInfoFlags flags, + CVImageBufferRef image_buffer, + CMTime pts, + CMTime duration) +{ + struct vt_context *vt_ctx = vt_hw_ctx; + vt_ctx->cv_buffer = NULL; + + if (!image_buffer) + return; + + if (vt_ctx->cv_pix_fmt != CVPixelBufferGetPixelFormatType(image_buffer)) + return; + + vt_ctx->cv_buffer = CVPixelBufferRetain(image_buffer); +} + +int ff_vt_session_decode_frame(struct vt_context *vt_ctx) +{ + OSStatus status; + CMSampleBufferRef sample_buf; + + sample_buf = vt_sample_buffer_create(vt_ctx->cm_fmt_desc, + vt_ctx->priv_bitstream, + vt_ctx->priv_bitstream_size); + + if (!sample_buf) + return -1; + + status = VTDecompressionSessionDecodeFrame(vt_ctx->session, + sample_buf, + 0, ///< decodeFlags + NULL, ///< sourceFrameRefCon + 0); ///< infoFlagsOut + if (status == noErr) + status = VTDecompressionSessionWaitForAsynchronousFrames(vt_ctx->session); + + CFRelease(sample_buf); + + return status; +} + +int ff_vt_buffer_copy(struct vt_context *vt_ctx, const uint8_t *buffer, uint32_t size) +{ + void *tmp; + tmp = av_fast_realloc(vt_ctx->priv_bitstream, + &vt_ctx->priv_allocated_size, + size); + if (!tmp) + return AVERROR(ENOMEM); + + vt_ctx->priv_bitstream = tmp; + + memcpy(vt_ctx->priv_bitstream, buffer, size); + + vt_ctx->priv_bitstream_size = size; + + return 0; +} + +void ff_vt_end_frame(MpegEncContext *s) +{ + struct vt_context * const vt_ctx = s->avctx->hwaccel_context; + AVFrame *frame = &s->current_picture_ptr->f; + + frame->data[3] = (void*)vt_ctx->cv_buffer; +} + +int ff_vt_session_create(struct vt_context *vt_ctx, + CMVideoFormatDescriptionRef fmt_desc, + CFDictionaryRef decoder_spec, + CFDictionaryRef buf_attr) +{ + OSStatus status; + VTDecompressionOutputCallbackRecord decoder_cb; + + if (!fmt_desc) + return -1; + + vt_ctx->cm_fmt_desc = CFRetain(fmt_desc); + + decoder_cb.decompressionOutputCallback = vt_decoder_callback; + decoder_cb.decompressionOutputRefCon = vt_ctx; + + status = VTDecompressionSessionCreate(NULL, ///< allocator + fmt_desc, ///< videoFormatDescription + decoder_spec, ///< videoDecoderSpecification + buf_attr, ///< destinationImageBufferAttributes + &decoder_cb, ///< outputCallback + &vt_ctx->session);///< decompressionSessionOut + if (noErr != status) + return status; + + return 0; +} + +void ff_vt_session_invalidate(struct vt_context *vt_ctx) +{ + if (vt_ctx->cm_fmt_desc) + CFRelease(vt_ctx->cm_fmt_desc); + + if (vt_ctx->session) + VTDecompressionSessionInvalidate(vt_ctx->session); + + av_freep(&vt_ctx->priv_bitstream); +} + +CFDictionaryRef ff_vt_decoder_config_create(CMVideoCodecType codec_type, + uint8_t *extradata, int size) +{ + CFMutableDictionaryRef config_info = NULL; + if (size) { + CFMutableDictionaryRef avc_info; + CFDataRef data; + + config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + avc_info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + switch (codec_type) { + case kCMVideoCodecType_MPEG4Video : + data = vt_esds_extradata_create(extradata, size); + if (data) + CFDictionarySetValue(avc_info, CFSTR("esds"), data); + break; + case kCMVideoCodecType_H264 : + data = vt_avcc_extradata_create(extradata, size); + 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; +} + +CFDictionaryRef ff_vt_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; +} + +CMVideoFormatDescriptionRef ff_vt_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; +} diff --git a/libavcodec/vt.h b/libavcodec/vt.h new file mode 100644 index 0000000..711216e --- /dev/null +++ b/libavcodec/vt.h @@ -0,0 +1,185 @@ +/* + * 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_VT_H +#define AVCODEC_VT_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vt + * Public libavcodec VideoToolbox header. + */ + +#include + +#define Picture QuickdrawPicture +#include +#undef Picture + +/** + * This structure is used to provide the necessary configurations and data + * to the VideoToolbox Libav HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct vt_context { + /** + * VideoToolbox decompression session. + * + * - encoding: unused. + * - decoding: Set/Unset by libavcodec. + */ + VTDecompressionSessionRef session; + + /** + * The width of encoded video. + * + * - encoding: unused. + * - decoding: Set/Unset by user. + */ + int width; + + /** + * The height of encoded video. + * + * - encoding: unused. + * - decoding: Set/Unset by user. + */ + int height; + + /** + * The type of video compression. + * + * - encoding: unused. + * - decoding: Set/Unset by user. + */ + int cm_codec_type; + + /** + * The pixel format for output image buffers. + * + * - encoding: unused. + * - decoding: Set/Unset by user. + */ + OSType cv_pix_fmt; + + /** + * The video format description. + * + * encoding: unused. + * decoding: Set by user. Unset by libavcodec. + */ + CMVideoFormatDescriptionRef cm_fmt_desc; + + /** + * The Core Video pixel buffer that contains the current image data. + * + * encoding: unused. + * decoding: Set by libavcodec. Unset by user. + */ + CVImageBufferRef cv_buffer; + + /** + * The current bitstream buffer. + */ + uint8_t *priv_bitstream; + + /** + * The current size of the bitstream. + */ + int priv_bitstream_size; + + /** + * The allocated size used for fast reallocation. + */ + int priv_allocated_size; +}; + +/** + * Create a decompression session. + * + * @param vt_ctx The VideoToolbox context. + * @param fmt_desc The video format description. + * @param decoder_spec The specific decoder configuration. + * @param buf_attr The output buffer attributes. + * @return Status. + */ +int ff_vt_session_create(struct vt_context *vt_ctx, + CMVideoFormatDescriptionRef fmt_desc, + CFDictionaryRef decoder_spec, + CFDictionaryRef buf_attr); + +/** + * Destroy a decompression session. + * + * @param vt_ctx The VideoToolbox context. + */ +void ff_vt_session_invalidate(struct vt_context *vt_ctx); + +/** + * Create the decoder configuration dictionary. + * + * It is the user's responsability to release the returned object (using CFRelease) when + * user has finished with it. + * + * @param codec_type The type of video compression. + * @param extradata The stream extradata. + * @param size The extradata size. + * @return A CoreFoundation dictionary or NULL if there was a problem creating the object. + */ +CFDictionaryRef ff_vt_decoder_config_create(CMVideoCodecType codec_type, + uint8_t *extradata, int size); + +/** + * Create the output buffer attributes. + * + * It is the user's responsability to release the returned object (using CFRelease) when + * user has finished with it. + * + * @param width The width of output image. + * @param height The height of output image. + * @param pix_fmt The pixel format of output image. + * @return A CoreFoundation dictionary. + */ +CFDictionaryRef ff_vt_buffer_attributes_create(int width, int height, OSType pix_fmt); + +/** + * Create the video format description. + * + * It is the user's responsability to release the returned object (using CFRelease) when + * user has finished with it. + * + * @param codec_type The type of video compression. + * @param decoder_spec The specific decoder configuration. + * @param width The width of encoded video. + * @param height The height of encoded video. + * @return A CoreMedia video format object. + */ +CMVideoFormatDescriptionRef ff_vt_format_desc_create(CMVideoCodecType codec_type, + CFDictionaryRef decoder_spec, + int width, int height); + +/** + * @} + */ + +#endif /* AVCODEC_VT_H */ diff --git a/libavcodec/vt_h264.c b/libavcodec/vt_h264.c new file mode 100644 index 0000000..763e091 --- /dev/null +++ b/libavcodec/vt_h264.c @@ -0,0 +1,94 @@ +/* + * VideoToolbox H264 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 "h264.h" +#include "vt_internal.h" + +static int start_frame(AVCodecContext *avctx, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + + if (!vt_ctx->session) + return -1; + + vt_ctx->priv_bitstream_size = 0; + + return 0; +} + +static int decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + void *tmp; + + if (!vt_ctx->session) + return -1; + + tmp = av_fast_realloc(vt_ctx->priv_bitstream, + &vt_ctx->priv_allocated_size, + vt_ctx->priv_bitstream_size+size+4); + if (!tmp) + return AVERROR(ENOMEM); + + vt_ctx->priv_bitstream = tmp; + + AV_WB32(vt_ctx->priv_bitstream + vt_ctx->priv_bitstream_size, size); + memcpy(vt_ctx->priv_bitstream + vt_ctx->priv_bitstream_size + 4, buffer, size); + + vt_ctx->priv_bitstream_size += size + 4; + + return 0; +} + +static int end_frame(AVCodecContext *avctx) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + int status; + + if (!vt_ctx->session || !vt_ctx->priv_bitstream) + return -1; + + status = ff_vt_session_decode_frame(vt_ctx); + + if (status) { + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); + return status; + } + + ff_vt_end_frame(avctx->priv_data); + + return status; +} + +AVHWAccel ff_h264_vt_hwaccel = { + .name = "h264_vt", + .type = AVMEDIA_TYPE_VIDEO, + .id = CODEC_ID_H264, + .pix_fmt = PIX_FMT_VT_VLD, + .start_frame = start_frame, + .decode_slice = decode_slice, + .end_frame = end_frame, +}; diff --git a/libavcodec/vt_internal.h b/libavcodec/vt_internal.h new file mode 100644 index 0000000..e882c8c --- /dev/null +++ b/libavcodec/vt_internal.h @@ -0,0 +1,44 @@ +/* + * 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_VT_INTERNAL_H +#define AVCODEC_VT_INTERNAL_H + +#include "vt.h" +#include "mpegvideo.h" + +/** + * @addtogroup VT_Decoding + * + * @{ + */ + +int ff_vt_session_decode_frame(struct vt_context *vt_ctx); + +int ff_vt_buffer_copy(struct vt_context *vt_ctx, + const uint8_t *buffer, + uint32_t size); +void ff_vt_end_frame(MpegEncContext *s); + +/* @} */ + +#endif /* AVCODEC_VT_INTERNAL_H */ diff --git a/libavcodec/vt_mpeg2.c b/libavcodec/vt_mpeg2.c new file mode 100644 index 0000000..c3ffba2 --- /dev/null +++ b/libavcodec/vt_mpeg2.c @@ -0,0 +1,77 @@ +/* + * VideoToolbox MPEG2 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 "vt_internal.h" + +static int start_frame(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + + if (!vt_ctx->session) + return -1; + + return ff_vt_buffer_copy(vt_ctx, buffer, size); +} + +static int decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + + if (!vt_ctx->session) + return -1; + + return 0; +} + +static int end_frame(AVCodecContext *avctx) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + int status; + + if (!vt_ctx->session || !vt_ctx->priv_bitstream) + return -1; + + status = ff_vt_session_decode_frame(vt_ctx); + + if (status) { + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); + return status; + } + + ff_vt_end_frame(avctx->priv_data); + + return status; +} + +AVHWAccel ff_mpeg2_vt_hwaccel = { + .name = "mpeg2_vt", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG2VIDEO, + .pix_fmt = PIX_FMT_VT_VLD, + .start_frame = start_frame, + .end_frame = end_frame, + .decode_slice = decode_slice, +}; diff --git a/libavcodec/vt_mpeg4.c b/libavcodec/vt_mpeg4.c new file mode 100644 index 0000000..43bde56 --- /dev/null +++ b/libavcodec/vt_mpeg4.c @@ -0,0 +1,92 @@ +/* + * VideoToolbox MPEG4 / H263 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 "vt_internal.h" + +static int start_frame(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + + if (!vt_ctx->session) + return -1; + + return ff_vt_buffer_copy(vt_ctx, buffer, size); +} + +static int decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + + if (!vt_ctx->session) + return -1; + + return 0; +} + +static int end_frame(AVCodecContext *avctx) +{ + struct vt_context *vt_ctx = avctx->hwaccel_context; + int status; + + if (!vt_ctx->session || !vt_ctx->priv_bitstream) + return -1; + + status = ff_vt_session_decode_frame(vt_ctx); + + if (status) { + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); + return status; + } + + ff_vt_end_frame(avctx->priv_data); + + return status; +} + +#if CONFIG_MPEG4_VT_HWACCEL +AVHWAccel ff_mpeg4_vt_hwaccel = { + .name = "mpeg4_vt", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG4, + .pix_fmt = PIX_FMT_VT_VLD, + .start_frame = start_frame, + .end_frame = end_frame, + .decode_slice = decode_slice, +}; +#endif + +#if CONFIG_H263_VT_HWACCEL +AVHWAccel ff_h263_vt_hwaccel = { + .name = "h263_vt", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H263, + .pix_fmt = PIX_FMT_VT_VLD, + .start_frame = start_frame, + .end_frame = end_frame, + .decode_slice = decode_slice, +}; +#endif + diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c index d64d300..1143bcc 100644 --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c @@ -1274,6 +1274,12 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[PIX_FMT_NB] = { .log2_chroma_h = 1, .flags = PIX_FMT_HWACCEL, }, + [PIX_FMT_VT_VLD] = { + .name = "vt_vld", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = PIX_FMT_HWACCEL, + }, [PIX_FMT_GRAY8A] = { .name = "gray8a", .nb_components = 2, diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h index fa771bc..d47d911 100644 --- a/libavutil/pixfmt.h +++ b/libavutil/pixfmt.h @@ -201,6 +201,7 @@ enum PixelFormat { PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little endian PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big endian PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little endian + PIX_FMT_VT_VLD, ///< hardware decoding through VideoToolbox 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 }; -- 1.7.9.6 (Apple Git-31.1)