mirror of https://github.com/FFmpeg/FFmpeg.git
Deprecated (aka removed) in OSX 10.11, and we have a replacement for it (VideoToolbox).pull/272/head
parent
3605b312f6
commit
2b32031827
19 changed files with 14 additions and 1117 deletions
@ -1,84 +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 "config.h" |
||||
|
||||
#include "libavutil/mem.h" |
||||
|
||||
#include "vda.h" |
||||
#include "vda_vt_internal.h" |
||||
|
||||
#if CONFIG_H264_VDA_HWACCEL |
||||
AVVDAContext *av_vda_alloc_context(void) |
||||
{ |
||||
AVVDAContext *ret = av_mallocz(sizeof(*ret)); |
||||
|
||||
if (ret) { |
||||
ret->output_callback = ff_vda_output_callback; |
||||
ret->cv_pix_fmt_type = kCVPixelFormatType_422YpCbCr8; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int av_vda_default_init(AVCodecContext *avctx) |
||||
{ |
||||
return av_vda_default_init2(avctx, NULL); |
||||
} |
||||
|
||||
int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx) |
||||
{ |
||||
avctx->hwaccel_context = vdactx ?: av_vda_alloc_context(); |
||||
if (!avctx->hwaccel_context) |
||||
return AVERROR(ENOMEM); |
||||
return ff_vda_default_init(avctx); |
||||
} |
||||
|
||||
void av_vda_default_free(AVCodecContext *avctx) |
||||
{ |
||||
ff_vda_default_free(avctx); |
||||
av_freep(&avctx->hwaccel_context); |
||||
} |
||||
|
||||
void ff_vda_default_free(AVCodecContext *avctx) |
||||
{ |
||||
AVVDAContext *vda = avctx->hwaccel_context; |
||||
if (vda && vda->decoder) |
||||
VDADecoderDestroy(vda->decoder); |
||||
} |
||||
|
||||
#else |
||||
AVVDAContext *av_vda_alloc_context(void) |
||||
{ |
||||
return NULL; |
||||
} |
||||
|
||||
int av_vda_default_init(AVCodecContext *avctx) |
||||
{ |
||||
return AVERROR(ENOSYS); |
||||
} |
||||
|
||||
int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx) |
||||
{ |
||||
return AVERROR(ENOSYS); |
||||
} |
||||
|
||||
void av_vda_default_free(AVCodecContext *ctx) |
||||
{ |
||||
} |
||||
#endif |
@ -1,230 +0,0 @@ |
||||
/*
|
||||
* VDA HW acceleration |
||||
* |
||||
* copyright (c) 2011 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_VDA_H |
||||
#define AVCODEC_VDA_H |
||||
|
||||
/**
|
||||
* @file |
||||
* @ingroup lavc_codec_hwaccel_vda |
||||
* Public libavcodec VDA header. |
||||
*/ |
||||
|
||||
#include "libavcodec/avcodec.h" |
||||
|
||||
#include <stdint.h> |
||||
|
||||
// emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes
|
||||
// http://openradar.appspot.com/8026390
|
||||
#undef __GNUC_STDC_INLINE__ |
||||
|
||||
#define Picture QuickdrawPicture |
||||
#include <VideoDecodeAcceleration/VDADecoder.h> |
||||
#undef Picture |
||||
|
||||
#include "libavcodec/version.h" |
||||
|
||||
// extra flags not defined in VDADecoder.h
|
||||
enum { |
||||
kVDADecodeInfo_Asynchronous = 1UL << 0, |
||||
kVDADecodeInfo_FrameDropped = 1UL << 1 |
||||
}; |
||||
|
||||
/**
|
||||
* @defgroup lavc_codec_hwaccel_vda VDA |
||||
* @ingroup lavc_codec_hwaccel |
||||
* |
||||
* @{ |
||||
*/ |
||||
|
||||
/**
|
||||
* This structure is used to provide the necessary configurations and data |
||||
* to the VDA FFmpeg HWAccel implementation. |
||||
* |
||||
* The application must make it available as AVCodecContext.hwaccel_context. |
||||
*/ |
||||
struct vda_context { |
||||
/**
|
||||
* VDA decoder object. |
||||
* |
||||
* - encoding: unused |
||||
* - decoding: Set/Unset by libavcodec. |
||||
*/ |
||||
VDADecoder decoder; |
||||
|
||||
/**
|
||||
* The Core Video pixel buffer that contains the current image data. |
||||
* |
||||
* encoding: unused |
||||
* decoding: Set by libavcodec. Unset by user. |
||||
*/ |
||||
CVPixelBufferRef cv_buffer; |
||||
|
||||
/**
|
||||
* Use the hardware decoder in synchronous mode. |
||||
* |
||||
* encoding: unused |
||||
* decoding: Set by user. |
||||
*/ |
||||
int use_sync_decoding; |
||||
|
||||
/**
|
||||
* The frame width. |
||||
* |
||||
* - encoding: unused |
||||
* - decoding: Set/Unset by user. |
||||
*/ |
||||
int width; |
||||
|
||||
/**
|
||||
* The frame height. |
||||
* |
||||
* - encoding: unused |
||||
* - decoding: Set/Unset by user. |
||||
*/ |
||||
int height; |
||||
|
||||
/**
|
||||
* The frame format. |
||||
* |
||||
* - encoding: unused |
||||
* - decoding: Set/Unset by user. |
||||
*/ |
||||
int format; |
||||
|
||||
/**
|
||||
* The pixel format for output image buffers. |
||||
* |
||||
* - encoding: unused |
||||
* - decoding: Set/Unset by user. |
||||
*/ |
||||
OSType cv_pix_fmt_type; |
||||
|
||||
/**
|
||||
* unused |
||||
*/ |
||||
uint8_t *priv_bitstream; |
||||
|
||||
/**
|
||||
* unused |
||||
*/ |
||||
int priv_bitstream_size; |
||||
|
||||
/**
|
||||
* unused |
||||
*/ |
||||
int priv_allocated_size; |
||||
|
||||
/**
|
||||
* Use av_buffer to manage buffer. |
||||
* When the flag is set, the CVPixelBuffers returned by the decoder will |
||||
* be released automatically, so you have to retain them if necessary. |
||||
* Not setting this flag may cause memory leak. |
||||
* |
||||
* encoding: unused |
||||
* decoding: Set by user. |
||||
*/ |
||||
int use_ref_buffer; |
||||
}; |
||||
|
||||
/** Create the video decoder. */ |
||||
int ff_vda_create_decoder(struct vda_context *vda_ctx, |
||||
uint8_t *extradata, |
||||
int extradata_size); |
||||
|
||||
/** Destroy the video decoder. */ |
||||
int ff_vda_destroy_decoder(struct vda_context *vda_ctx); |
||||
|
||||
/**
|
||||
* This struct holds all the information that needs to be passed |
||||
* between the caller and libavcodec for initializing VDA decoding. |
||||
* Its size is not a part of the public ABI, it must be allocated with |
||||
* av_vda_alloc_context() and freed with av_free(). |
||||
*/ |
||||
typedef struct AVVDAContext { |
||||
/**
|
||||
* VDA decoder object. Created and freed by the caller. |
||||
*/ |
||||
VDADecoder decoder; |
||||
|
||||
/**
|
||||
* The output callback that must be passed to VDADecoderCreate. |
||||
* Set by av_vda_alloc_context(). |
||||
*/ |
||||
VDADecoderOutputCallback output_callback; |
||||
|
||||
/**
|
||||
* CVPixelBuffer Format Type that VDA will use for decoded frames; set by |
||||
* the caller. |
||||
*/ |
||||
OSType cv_pix_fmt_type; |
||||
} AVVDAContext; |
||||
|
||||
/**
|
||||
* Allocate and initialize a VDA context. |
||||
* |
||||
* This function should be called from the get_format() callback when the caller |
||||
* selects the AV_PIX_FMT_VDA format. The caller must then create the decoder |
||||
* object (using the output callback provided by libavcodec) that will be used |
||||
* for VDA-accelerated decoding. |
||||
* |
||||
* When decoding with VDA is finished, the caller must destroy the decoder |
||||
* object and free the VDA context using av_free(). |
||||
* |
||||
* @return the newly allocated context or NULL on failure |
||||
*/ |
||||
AVVDAContext *av_vda_alloc_context(void); |
||||
|
||||
/**
|
||||
* This is a convenience function that creates and sets up the VDA context using |
||||
* an internal implementation. |
||||
* |
||||
* @param avctx the corresponding codec context |
||||
* |
||||
* @return >= 0 on success, a negative AVERROR code on failure |
||||
*/ |
||||
int av_vda_default_init(AVCodecContext *avctx); |
||||
|
||||
/**
|
||||
* This is a convenience function that creates and sets up the VDA context using |
||||
* an internal implementation. |
||||
* |
||||
* @param avctx the corresponding codec context |
||||
* @param vdactx the VDA context to use |
||||
* |
||||
* @return >= 0 on success, a negative AVERROR code on failure |
||||
*/ |
||||
int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx); |
||||
|
||||
/**
|
||||
* This function must be called to free the VDA context initialized with |
||||
* av_vda_default_init(). |
||||
* |
||||
* @param avctx the corresponding codec context |
||||
*/ |
||||
void av_vda_default_free(AVCodecContext *avctx); |
||||
|
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
||||
#endif /* AVCODEC_VDA_H */ |
@ -1,425 +0,0 @@ |
||||
/*
|
||||
* VDA H264 HW acceleration. |
||||
* |
||||
* copyright (c) 2011 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 <CoreFoundation/CFDictionary.h> |
||||
#include <CoreFoundation/CFNumber.h> |
||||
#include <CoreFoundation/CFData.h> |
||||
|
||||
#include "vda.h" |
||||
#include "libavutil/avutil.h" |
||||
#include "h264dec.h" |
||||
|
||||
struct vda_buffer { |
||||
CVPixelBufferRef cv_buffer; |
||||
}; |
||||
#include "internal.h" |
||||
#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, |
||||
CFDictionaryRef user_info, |
||||
OSStatus status, |
||||
uint32_t infoFlags, |
||||
CVImageBufferRef image_buffer) |
||||
{ |
||||
struct vda_context *vda_ctx = vda_hw_ctx; |
||||
|
||||
if (infoFlags & kVDADecodeInfo_FrameDropped) |
||||
vda_ctx->cv_buffer = NULL; |
||||
|
||||
if (!image_buffer) |
||||
return; |
||||
|
||||
if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer)) |
||||
return; |
||||
|
||||
vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer); |
||||
} |
||||
|
||||
static int vda_sync_decode(VTContext *ctx, struct vda_context *vda_ctx) |
||||
{ |
||||
OSStatus status; |
||||
CFDataRef coded_frame; |
||||
uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames
|
||||
|
||||
coded_frame = CFDataCreate(kCFAllocatorDefault, |
||||
ctx->bitstream, |
||||
ctx->bitstream_size); |
||||
|
||||
status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL); |
||||
|
||||
if (kVDADecoderNoErr == status) |
||||
status = VDADecoderFlush(vda_ctx->decoder, flush_flags); |
||||
|
||||
CFRelease(coded_frame); |
||||
|
||||
return status; |
||||
} |
||||
|
||||
|
||||
static int vda_old_h264_start_frame(AVCodecContext *avctx, |
||||
av_unused const uint8_t *buffer, |
||||
av_unused uint32_t size) |
||||
{ |
||||
VTContext *vda = avctx->internal->hwaccel_priv_data; |
||||
struct vda_context *vda_ctx = avctx->hwaccel_context; |
||||
|
||||
if (!vda_ctx->decoder) |
||||
return -1; |
||||
|
||||
vda->bitstream_size = 0; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int vda_old_h264_decode_slice(AVCodecContext *avctx, |
||||
const uint8_t *buffer, |
||||
uint32_t size) |
||||
{ |
||||
VTContext *vda = avctx->internal->hwaccel_priv_data; |
||||
struct vda_context *vda_ctx = avctx->hwaccel_context; |
||||
void *tmp; |
||||
|
||||
if (!vda_ctx->decoder) |
||||
return -1; |
||||
|
||||
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 vda_h264_release_buffer(void *opaque, uint8_t *data) |
||||
{ |
||||
struct vda_buffer *context = opaque; |
||||
CVPixelBufferRelease(context->cv_buffer); |
||||
av_free(context); |
||||
} |
||||
|
||||
static int vda_old_h264_end_frame(AVCodecContext *avctx) |
||||
{ |
||||
H264Context *h = avctx->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; |
||||
AVBufferRef *buffer; |
||||
int status; |
||||
|
||||
if (!vda_ctx->decoder || !vda->bitstream) |
||||
return -1; |
||||
|
||||
status = vda_sync_decode(vda, vda_ctx); |
||||
frame->data[3] = (void*)vda_ctx->cv_buffer; |
||||
|
||||
if (status) |
||||
av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); |
||||
|
||||
if (!vda_ctx->use_ref_buffer || status) |
||||
return status; |
||||
|
||||
context = av_mallocz(sizeof(*context)); |
||||
buffer = av_buffer_create(NULL, 0, vda_h264_release_buffer, context, 0); |
||||
if (!context || !buffer) { |
||||
CVPixelBufferRelease(vda_ctx->cv_buffer); |
||||
av_free(context); |
||||
return -1; |
||||
} |
||||
|
||||
context->cv_buffer = vda_ctx->cv_buffer; |
||||
frame->buf[3] = buffer; |
||||
|
||||
return status; |
||||
} |
||||
|
||||
int ff_vda_create_decoder(struct vda_context *vda_ctx, |
||||
uint8_t *extradata, |
||||
int extradata_size) |
||||
{ |
||||
OSStatus status; |
||||
CFNumberRef height; |
||||
CFNumberRef width; |
||||
CFNumberRef format; |
||||
CFDataRef avc_data; |
||||
CFMutableDictionaryRef config_info; |
||||
CFMutableDictionaryRef buffer_attributes; |
||||
CFMutableDictionaryRef io_surface_properties; |
||||
CFNumberRef cv_pix_fmt; |
||||
|
||||
vda_ctx->priv_bitstream = NULL; |
||||
vda_ctx->priv_allocated_size = 0; |
||||
|
||||
/* 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 (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) { |
||||
uint8_t *rw_extradata; |
||||
|
||||
if (!(rw_extradata = av_malloc(extradata_size))) |
||||
return AVERROR(ENOMEM); |
||||
|
||||
memcpy(rw_extradata, extradata, extradata_size); |
||||
|
||||
rw_extradata[4] |= 0x03; |
||||
|
||||
avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size); |
||||
|
||||
av_freep(&rw_extradata); |
||||
} else { |
||||
avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size); |
||||
} |
||||
|
||||
config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, |
||||
4, |
||||
&kCFTypeDictionaryKeyCallBacks, |
||||
&kCFTypeDictionaryValueCallBacks); |
||||
|
||||
height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height); |
||||
width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width); |
||||
format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format); |
||||
|
||||
CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); |
||||
CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); |
||||
CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); |
||||
CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); |
||||
|
||||
buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, |
||||
2, |
||||
&kCFTypeDictionaryKeyCallBacks, |
||||
&kCFTypeDictionaryValueCallBacks); |
||||
io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, |
||||
0, |
||||
&kCFTypeDictionaryKeyCallBacks, |
||||
&kCFTypeDictionaryValueCallBacks); |
||||
cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, |
||||
kCFNumberSInt32Type, |
||||
&vda_ctx->cv_pix_fmt_type); |
||||
CFDictionarySetValue(buffer_attributes, |
||||
kCVPixelBufferPixelFormatTypeKey, |
||||
cv_pix_fmt); |
||||
CFDictionarySetValue(buffer_attributes, |
||||
kCVPixelBufferIOSurfacePropertiesKey, |
||||
io_surface_properties); |
||||
|
||||
status = VDADecoderCreate(config_info, |
||||
buffer_attributes, |
||||
(VDADecoderOutputCallback *)vda_decoder_callback, |
||||
vda_ctx, |
||||
&vda_ctx->decoder); |
||||
|
||||
CFRelease(height); |
||||
CFRelease(width); |
||||
CFRelease(format); |
||||
CFRelease(avc_data); |
||||
CFRelease(config_info); |
||||
CFRelease(io_surface_properties); |
||||
CFRelease(cv_pix_fmt); |
||||
CFRelease(buffer_attributes); |
||||
|
||||
return status; |
||||
} |
||||
|
||||
int ff_vda_destroy_decoder(struct vda_context *vda_ctx) |
||||
{ |
||||
OSStatus status = kVDADecoderNoErr; |
||||
|
||||
if (vda_ctx->decoder) |
||||
status = VDADecoderDestroy(vda_ctx->decoder); |
||||
|
||||
return status; |
||||
} |
||||
|
||||
AVHWAccel ff_h264_vda_old_hwaccel = { |
||||
.name = "h264_vda", |
||||
.type = AVMEDIA_TYPE_VIDEO, |
||||
.id = AV_CODEC_ID_H264, |
||||
.pix_fmt = AV_PIX_FMT_VDA_VLD, |
||||
.start_frame = vda_old_h264_start_frame, |
||||
.decode_slice = vda_old_h264_decode_slice, |
||||
.end_frame = vda_old_h264_end_frame, |
||||
.uninit = ff_videotoolbox_uninit, |
||||
.priv_data_size = sizeof(VTContext), |
||||
}; |
||||
|
||||
void ff_vda_output_callback(void *opaque, |
||||
CFDictionaryRef user_info, |
||||
OSStatus status, |
||||
uint32_t infoFlags, |
||||
CVImageBufferRef image_buffer) |
||||
{ |
||||
AVCodecContext *ctx = opaque; |
||||
VTContext *vda = ctx->internal->hwaccel_priv_data; |
||||
|
||||
|
||||
if (vda->frame) { |
||||
CVPixelBufferRelease(vda->frame); |
||||
vda->frame = NULL; |
||||
} |
||||
|
||||
if (!image_buffer) |
||||
return; |
||||
|
||||
vda->frame = CVPixelBufferRetain(image_buffer); |
||||
} |
||||
|
||||
static int vda_h264_end_frame(AVCodecContext *avctx) |
||||
{ |
||||
H264Context *h = avctx->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
|
||||
CFDataRef coded_frame; |
||||
OSStatus status; |
||||
|
||||
if (!vda->bitstream_size) |
||||
return AVERROR_INVALIDDATA; |
||||
|
||||
|
||||
coded_frame = CFDataCreate(kCFAllocatorDefault, |
||||
vda->bitstream, |
||||
vda->bitstream_size); |
||||
|
||||
status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL); |
||||
|
||||
if (status == kVDADecoderNoErr) |
||||
status = VDADecoderFlush(vda_ctx->decoder, flush_flags); |
||||
|
||||
CFRelease(coded_frame); |
||||
|
||||
if (!vda->frame) |
||||
return AVERROR_UNKNOWN; |
||||
|
||||
if (status != kVDADecoderNoErr) { |
||||
av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); |
||||
return AVERROR_UNKNOWN; |
||||
} |
||||
|
||||
return ff_videotoolbox_buffer_create(vda, frame); |
||||
} |
||||
|
||||
int ff_vda_default_init(AVCodecContext *avctx) |
||||
{ |
||||
AVVDAContext *vda_ctx = avctx->hwaccel_context; |
||||
OSStatus status = kVDADecoderNoErr; |
||||
CFNumberRef height; |
||||
CFNumberRef width; |
||||
CFNumberRef format; |
||||
CFDataRef avc_data; |
||||
CFMutableDictionaryRef config_info; |
||||
CFMutableDictionaryRef buffer_attributes; |
||||
CFMutableDictionaryRef io_surface_properties; |
||||
CFNumberRef cv_pix_fmt; |
||||
int32_t fmt = 'avc1', pix_fmt = vda_ctx->cv_pix_fmt_type; |
||||
|
||||
// kCVPixelFormatType_420YpCbCr8Planar;
|
||||
|
||||
avc_data = ff_videotoolbox_avcc_extradata_create(avctx); |
||||
|
||||
config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, |
||||
4, |
||||
&kCFTypeDictionaryKeyCallBacks, |
||||
&kCFTypeDictionaryValueCallBacks); |
||||
|
||||
height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->height); |
||||
width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->width); |
||||
format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &fmt); |
||||
CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); |
||||
CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); |
||||
CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); |
||||
CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); |
||||
|
||||
buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, |
||||
2, |
||||
&kCFTypeDictionaryKeyCallBacks, |
||||
&kCFTypeDictionaryValueCallBacks); |
||||
io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, |
||||
0, |
||||
&kCFTypeDictionaryKeyCallBacks, |
||||
&kCFTypeDictionaryValueCallBacks); |
||||
cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, |
||||
kCFNumberSInt32Type, |
||||
&pix_fmt); |
||||
|
||||
CFDictionarySetValue(buffer_attributes, |
||||
kCVPixelBufferPixelFormatTypeKey, |
||||
cv_pix_fmt); |
||||
CFDictionarySetValue(buffer_attributes, |
||||
kCVPixelBufferIOSurfacePropertiesKey, |
||||
io_surface_properties); |
||||
|
||||
status = VDADecoderCreate(config_info, |
||||
buffer_attributes, |
||||
(VDADecoderOutputCallback *)ff_vda_output_callback, |
||||
avctx, |
||||
&vda_ctx->decoder); |
||||
|
||||
CFRelease(format); |
||||
CFRelease(height); |
||||
CFRelease(width); |
||||
CFRelease(avc_data); |
||||
CFRelease(config_info); |
||||
CFRelease(cv_pix_fmt); |
||||
CFRelease(io_surface_properties); |
||||
CFRelease(buffer_attributes); |
||||
|
||||
if (status != kVDADecoderNoErr) { |
||||
av_log(avctx, AV_LOG_ERROR, "Cannot initialize VDA %d\n", status); |
||||
} |
||||
|
||||
switch (status) { |
||||
case kVDADecoderHardwareNotSupportedErr: |
||||
case kVDADecoderFormatNotSupportedErr: |
||||
return AVERROR(ENOSYS); |
||||
case kVDADecoderConfigurationError: |
||||
return AVERROR(EINVAL); |
||||
case kVDADecoderDecoderFailedErr: |
||||
return AVERROR_INVALIDDATA; |
||||
case kVDADecoderNoErr: |
||||
return 0; |
||||
default: |
||||
return AVERROR_UNKNOWN; |
||||
} |
||||
} |
||||
|
||||
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 = 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 = ff_videotoolbox_uninit, |
||||
.priv_data_size = sizeof(VTContext), |
||||
}; |
@ -1,263 +0,0 @@ |
||||
/*
|
||||
* Copyright (c) 2012, Xidorn Quan |
||||
* |
||||
* This file is part of FFmpeg. |
||||
* |
||||
* FFmpeg is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU Lesser General Public |
||||
* License as published by the Free Software Foundation; either |
||||
* version 2.1 of the License, or (at your option) any later version. |
||||
* |
||||
* FFmpeg is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
* Lesser General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public |
||||
* License along with FFmpeg; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/**
|
||||
* @file |
||||
* H.264 decoder via VDA |
||||
* @author Xidorn Quan <quanxunzhen@gmail.com> |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include <CoreFoundation/CoreFoundation.h> |
||||
|
||||
#include "vda.h" |
||||
#include "h264dec.h" |
||||
#include "avcodec.h" |
||||
|
||||
#ifndef kCFCoreFoundationVersionNumber10_7 |
||||
#define kCFCoreFoundationVersionNumber10_7 635.00 |
||||
#endif |
||||
|
||||
extern AVCodec ff_h264_decoder, ff_h264_vda_decoder; |
||||
|
||||
static const enum AVPixelFormat vda_pixfmts_prior_10_7[] = { |
||||
AV_PIX_FMT_UYVY422, |
||||
AV_PIX_FMT_YUV420P, |
||||
AV_PIX_FMT_NONE |
||||
}; |
||||
|
||||
static const enum AVPixelFormat vda_pixfmts[] = { |
||||
AV_PIX_FMT_UYVY422, |
||||
AV_PIX_FMT_YUYV422, |
||||
AV_PIX_FMT_NV12, |
||||
AV_PIX_FMT_YUV420P, |
||||
AV_PIX_FMT_NONE |
||||
}; |
||||
|
||||
typedef struct { |
||||
H264Context h264ctx; |
||||
int h264_initialized; |
||||
struct vda_context vda_ctx; |
||||
enum AVPixelFormat pix_fmt; |
||||
|
||||
/* for backing-up fields set by user.
|
||||
* we have to gain full control of such fields here */ |
||||
void *hwaccel_context; |
||||
enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); |
||||
int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags); |
||||
} VDADecoderContext; |
||||
|
||||
static enum AVPixelFormat get_format(struct AVCodecContext *avctx, |
||||
const enum AVPixelFormat *fmt) |
||||
{ |
||||
return AV_PIX_FMT_VDA_VLD; |
||||
} |
||||
|
||||
typedef struct { |
||||
CVPixelBufferRef cv_buffer; |
||||
} VDABufferContext; |
||||
|
||||
static void release_buffer(void *opaque, uint8_t *data) |
||||
{ |
||||
VDABufferContext *context = opaque; |
||||
CVPixelBufferUnlockBaseAddress(context->cv_buffer, 0); |
||||
CVPixelBufferRelease(context->cv_buffer); |
||||
av_free(context); |
||||
} |
||||
|
||||
static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flag) |
||||
{ |
||||
VDABufferContext *context = av_mallocz(sizeof(VDABufferContext)); |
||||
AVBufferRef *buffer = av_buffer_create(NULL, 0, release_buffer, context, 0); |
||||
if (!context || !buffer) { |
||||
av_free(context); |
||||
return AVERROR(ENOMEM); |
||||
} |
||||
|
||||
pic->buf[0] = buffer; |
||||
pic->data[0] = (void *)1; |
||||
return 0; |
||||
} |
||||
|
||||
static inline void set_context(AVCodecContext *avctx) |
||||
{ |
||||
VDADecoderContext *ctx = avctx->priv_data; |
||||
ctx->hwaccel_context = avctx->hwaccel_context; |
||||
avctx->hwaccel_context = &ctx->vda_ctx; |
||||
ctx->get_format = avctx->get_format; |
||||
avctx->get_format = get_format; |
||||
ctx->get_buffer2 = avctx->get_buffer2; |
||||
avctx->get_buffer2 = get_buffer2; |
||||
} |
||||
|
||||
static inline void restore_context(AVCodecContext *avctx) |
||||
{ |
||||
VDADecoderContext *ctx = avctx->priv_data; |
||||
avctx->hwaccel_context = ctx->hwaccel_context; |
||||
avctx->get_format = ctx->get_format; |
||||
avctx->get_buffer2 = ctx->get_buffer2; |
||||
} |
||||
|
||||
static int vdadec_decode(AVCodecContext *avctx, |
||||
void *data, int *got_frame, AVPacket *avpkt) |
||||
{ |
||||
VDADecoderContext *ctx = avctx->priv_data; |
||||
AVFrame *pic = data; |
||||
int ret; |
||||
|
||||
set_context(avctx); |
||||
ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt); |
||||
restore_context(avctx); |
||||
if (*got_frame) { |
||||
AVBufferRef *buffer = pic->buf[0]; |
||||
VDABufferContext *context = av_buffer_get_opaque(buffer); |
||||
CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3]; |
||||
|
||||
CVPixelBufferRetain(cv_buffer); |
||||
CVPixelBufferLockBaseAddress(cv_buffer, 0); |
||||
context->cv_buffer = cv_buffer; |
||||
pic->format = ctx->pix_fmt; |
||||
if (CVPixelBufferIsPlanar(cv_buffer)) { |
||||
int i, count = CVPixelBufferGetPlaneCount(cv_buffer); |
||||
av_assert0(count < 4); |
||||
for (i = 0; i < count; i++) { |
||||
pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i); |
||||
pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i); |
||||
} |
||||
} else { |
||||
pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer); |
||||
pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer); |
||||
} |
||||
} |
||||
avctx->pix_fmt = ctx->pix_fmt; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
static av_cold int vdadec_close(AVCodecContext *avctx) |
||||
{ |
||||
VDADecoderContext *ctx = avctx->priv_data; |
||||
/* release buffers and decoder */ |
||||
ff_vda_destroy_decoder(&ctx->vda_ctx); |
||||
/* close H.264 decoder */ |
||||
if (ctx->h264_initialized) { |
||||
set_context(avctx); |
||||
ff_h264_decoder.close(avctx); |
||||
restore_context(avctx); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static av_cold int vdadec_init(AVCodecContext *avctx) |
||||
{ |
||||
VDADecoderContext *ctx = avctx->priv_data; |
||||
struct vda_context *vda_ctx = &ctx->vda_ctx; |
||||
OSStatus status; |
||||
int ret, i; |
||||
|
||||
ctx->h264_initialized = 0; |
||||
|
||||
/* init pix_fmts of codec */ |
||||
if (!ff_h264_vda_decoder.pix_fmts) { |
||||
if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7) |
||||
ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7; |
||||
else |
||||
ff_h264_vda_decoder.pix_fmts = vda_pixfmts; |
||||
} |
||||
|
||||
/* init vda */ |
||||
memset(vda_ctx, 0, sizeof(struct vda_context)); |
||||
vda_ctx->width = avctx->width; |
||||
vda_ctx->height = avctx->height; |
||||
vda_ctx->format = 'avc1'; |
||||
vda_ctx->use_sync_decoding = 1; |
||||
vda_ctx->use_ref_buffer = 1; |
||||
ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts); |
||||
switch (ctx->pix_fmt) { |
||||
case AV_PIX_FMT_UYVY422: |
||||
vda_ctx->cv_pix_fmt_type = '2vuy'; |
||||
break; |
||||
case AV_PIX_FMT_YUYV422: |
||||
vda_ctx->cv_pix_fmt_type = 'yuvs'; |
||||
break; |
||||
case AV_PIX_FMT_NV12: |
||||
vda_ctx->cv_pix_fmt_type = '420v'; |
||||
break; |
||||
case AV_PIX_FMT_YUV420P: |
||||
vda_ctx->cv_pix_fmt_type = 'y420'; |
||||
break; |
||||
default: |
||||
av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt); |
||||
goto failed; |
||||
} |
||||
status = ff_vda_create_decoder(vda_ctx, |
||||
avctx->extradata, avctx->extradata_size); |
||||
if (status != kVDADecoderNoErr) { |
||||
av_log(avctx, AV_LOG_ERROR, |
||||
"Failed to init VDA decoder: %d.\n", status); |
||||
goto failed; |
||||
} |
||||
|
||||
/* init H.264 decoder */ |
||||
set_context(avctx); |
||||
ret = ff_h264_decoder.init(avctx); |
||||
restore_context(avctx); |
||||
if (ret < 0) { |
||||
av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n"); |
||||
goto failed; |
||||
} |
||||
ctx->h264_initialized = 1; |
||||
|
||||
for (i = 0; i < MAX_SPS_COUNT; i++) { |
||||
const SPS *sps = ctx->h264ctx.ps.sps_list[i] ? (const SPS*)ctx->h264ctx.ps.sps_list[i]->data : NULL; |
||||
if (sps && (sps->bit_depth_luma != 8 || |
||||
sps->chroma_format_idc == 2 || |
||||
sps->chroma_format_idc == 3)) { |
||||
av_log(avctx, AV_LOG_ERROR, "Format is not supported.\n"); |
||||
goto failed; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
|
||||
failed: |
||||
vdadec_close(avctx); |
||||
return -1; |
||||
} |
||||
|
||||
static void vdadec_flush(AVCodecContext *avctx) |
||||
{ |
||||
set_context(avctx); |
||||
ff_h264_decoder.flush(avctx); |
||||
restore_context(avctx); |
||||
} |
||||
|
||||
AVCodec ff_h264_vda_decoder = { |
||||
.name = "h264_vda", |
||||
.type = AVMEDIA_TYPE_VIDEO, |
||||
.id = AV_CODEC_ID_H264, |
||||
.priv_data_size = sizeof(VDADecoderContext), |
||||
.init = vdadec_init, |
||||
.close = vdadec_close, |
||||
.decode = vdadec_decode, |
||||
.capabilities = AV_CODEC_CAP_DELAY, |
||||
.flush = vdadec_flush, |
||||
.long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"), |
||||
}; |
Loading…
Reference in new issue