[FFmpeg-devel] [PATCH v2 01/12] lavc/videotoolboxenc: Use shared pixel buffer pool
Rick Kern
kernrj at gmail.com
Fri Apr 22 18:14:03 CEST 2016
This reduces the chance of a memcpy in the media server.
Signed-off-by: Rick Kern <kernrj at gmail.com>
---
libavcodec/videotoolboxenc.c | 224 ++++++++++++++++++++++++++++++++++---------
1 file changed, 180 insertions(+), 44 deletions(-)
diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c
index 3177074..b578260 100644
--- a/libavcodec/videotoolboxenc.c
+++ b/libavcodec/videotoolboxenc.c
@@ -29,6 +29,7 @@
#include "libavutil/atomic.h"
#include "libavutil/avstring.h"
#include "libavcodec/avcodec.h"
+#include "libavutil/pixdesc.h"
#include "internal.h"
#include <pthread.h>
@@ -74,6 +75,15 @@ typedef struct VTEncContext {
bool warned_color_range;
} VTEncContext;
+/**
+ * NULL-safe release of *refPtr, and sets value to NULL.
+ */
+static void vt_release_num(CFNumberRef* refPtr){
+ if(!*refPtr) return;
+ CFRelease(*refPtr);
+ *refPtr = NULL;
+}
+
static void set_async_error(VTEncContext *vtctx, int err)
{
BufNode *info;
@@ -477,9 +487,123 @@ static bool get_vt_profile_level(AVCodecContext *avctx,
return true;
}
+static int get_cv_pixel_format(
+ AVCodecContext* avctx,
+ enum AVPixelFormat fmt,
+ enum AVColorRange range,
+ int* av_pixel_format,
+ int* range_guessed)
+{
+ if (range_guessed) *range_guessed = 0;
+
+ switch (fmt) {
+ case AV_PIX_FMT_NV12:
+ switch (range) {
+ case AVCOL_RANGE_MPEG:
+ *av_pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+ break;
+
+ case AVCOL_RANGE_JPEG:
+ *av_pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
+ break;
+
+ default:
+ if (range_guessed) *range_guessed = 1;
+ *av_pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+ }
+ break;
+
+ case AV_PIX_FMT_YUV420P:
+ switch (range) {
+ case AVCOL_RANGE_MPEG:
+ *av_pixel_format = kCVPixelFormatType_420YpCbCr8Planar;
+ break;
+
+ case AVCOL_RANGE_JPEG:
+ *av_pixel_format = kCVPixelFormatType_420YpCbCr8PlanarFullRange;
+ break;
+
+ default:
+ if(range_guessed) *range_guessed = 1;
+ *av_pixel_format = kCVPixelFormatType_420YpCbCr8Planar;
+ }
+ break;
+
+ default: return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int create_cv_pixel_buffer_info(AVCodecContext* avctx,
+ CFMutableDictionaryRef* dict)
+{
+ CFNumberRef cv_color_format_num = NULL;
+ CFNumberRef width_num = NULL;
+ CFNumberRef height_num = NULL;
+ CFMutableDictionaryRef pixel_buffer_info = NULL;
+ int cv_color_format;
+ int status = get_cv_pixel_format(avctx,
+ avctx->pix_fmt,
+ avctx->color_range,
+ &cv_color_format,
+ NULL);
+ if (status) return status;
+
+ pixel_buffer_info = CFDictionaryCreateMutable(
+ kCFAllocatorDefault,
+ 20,
+ &kCFCopyStringDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ if (!pixel_buffer_info) goto pbinfo_nomem;
+
+ cv_color_format_num = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type,
+ &cv_color_format);
+ if (!cv_color_format_num) goto pbinfo_nomem;
+
+ CFDictionarySetValue(pixel_buffer_info,
+ kCVPixelBufferPixelFormatTypeKey,
+ cv_color_format_num);
+ vt_release_num(&cv_color_format_num);
+
+ width_num = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type,
+ &avctx->width);
+ if (!width_num) return AVERROR(ENOMEM);
+
+ CFDictionarySetValue(pixel_buffer_info,
+ kCVPixelBufferWidthKey,
+ width_num);
+ vt_release_num(&width_num);
+
+ height_num = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type,
+ &avctx->height);
+ if (!height_num) goto pbinfo_nomem;
+
+ CFDictionarySetValue(pixel_buffer_info,
+ kCVPixelBufferHeightKey,
+ height_num);
+ vt_release_num(&height_num);
+
+ *dict = pixel_buffer_info;
+ return 0;
+
+pbinfo_nomem:
+ vt_release_num(&cv_color_format_num);
+ vt_release_num(&width_num);
+ vt_release_num(&height_num);
+ if (pixel_buffer_info) CFRelease(pixel_buffer_info);
+
+ return AVERROR(ENOMEM);
+}
+
static av_cold int vtenc_init(AVCodecContext *avctx)
{
CFMutableDictionaryRef enc_info;
+ CFMutableDictionaryRef pixel_buffer_info;
CMVideoCodecType codec_type;
VTEncContext *vtctx = avctx->priv_data;
CFStringRef profile_level;
@@ -517,13 +641,19 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
CFDictionarySetValue(enc_info, kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, kCFBooleanTrue);
#endif
+ status = create_cv_pixel_buffer_info(avctx, &pixel_buffer_info);
+ if (status) {
+ CFRelease(enc_info);
+ return status;
+ }
+
status = VTCompressionSessionCreate(
kCFAllocatorDefault,
avctx->width,
avctx->height,
codec_type,
enc_info,
- NULL,
+ pixel_buffer_info,
kCFAllocatorDefault,
vtenc_output_callback,
avctx,
@@ -549,6 +679,7 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
}
#endif
+ CFRelease(pixel_buffer_info);
CFRelease(enc_info);
if (status || !vtctx->session) {
@@ -912,26 +1043,37 @@ static int get_cv_pixel_info(
int av_format = frame->format;
int av_color_range = av_frame_get_color_range(frame);
int i;
+ int range_guessed;
+ int status;
- switch (av_format) {
- case AV_PIX_FMT_NV12:
- switch (av_color_range) {
- case AVCOL_RANGE_MPEG:
- *color = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
- break;
+ status = get_cv_pixel_format(avctx, av_format, av_color_range, color, &range_guessed);
+ if (status) {
+ av_log(avctx,
+ AV_LOG_ERROR,
+ "Could not get pixel format for color format '%s' range '%s'.\n",
+ av_get_pix_fmt_name(av_format),
+ av_color_range > AVCOL_RANGE_UNSPECIFIED &&
+ av_color_range < AVCOL_RANGE_NB ?
+ av_color_range_name(av_color_range) :
+ "Unknown");
- case AVCOL_RANGE_JPEG:
- *color = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
- break;
+ return AVERROR(EINVAL);
+ }
- default:
- if (!vtctx->warned_color_range) {
- vtctx->warned_color_range = true;
- av_log(avctx, AV_LOG_WARNING, "Color range not set for NV12. Using MPEG range.\n");
- }
- *color = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+ if (range_guessed) {
+ if (!vtctx->warned_color_range) {
+ vtctx->warned_color_range = true;
+ av_log(avctx,
+ AV_LOG_WARNING,
+ "Color range not set for %s. Using MPEG range.\n",
+ av_get_pix_fmt_name(av_format));
}
+ av_log(avctx, AV_LOG_WARNING, "");
+ }
+
+ switch (av_format) {
+ case AV_PIX_FMT_NV12:
*plane_count = 2;
widths [0] = avctx->width;
@@ -944,23 +1086,6 @@ static int get_cv_pixel_info(
break;
case AV_PIX_FMT_YUV420P:
- switch (av_color_range) {
- case AVCOL_RANGE_MPEG:
- *color = kCVPixelFormatType_420YpCbCr8Planar;
- break;
-
- case AVCOL_RANGE_JPEG:
- *color = kCVPixelFormatType_420YpCbCr8PlanarFullRange;
- break;
-
- default:
- if (!vtctx->warned_color_range) {
- vtctx->warned_color_range = true;
- av_log(avctx, AV_LOG_WARNING, "Color range not set for YUV 4:2:0. Using MPEG range.\n");
- }
- *color = kCVPixelFormatType_420YpCbCr8Planar;
- }
-
*plane_count = 3;
widths [0] = avctx->width;
@@ -976,7 +1101,15 @@ static int get_cv_pixel_info(
strides[2] = frame ? frame->linesize[2] : (avctx->width + 1) / 2;
break;
- default: return AVERROR(EINVAL);
+ default:
+ av_log(
+ avctx,
+ AV_LOG_ERROR,
+ "Could not get frame format info for color %d range %d.\n",
+ av_format,
+ av_color_range);
+
+ return AVERROR(EINVAL);
}
*contiguous_buf_size = 0;
@@ -1111,6 +1244,8 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx,
size_t strides[AV_NUM_DATA_POINTERS];
int status;
size_t contiguous_buf_size;
+ CVPixelBufferPoolRef pix_buf_pool;
+ VTEncContext* vtctx = avctx->priv_data;
memset(widths, 0, sizeof(widths));
memset(heights, 0, sizeof(heights));
@@ -1141,16 +1276,19 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx,
}
#if TARGET_OS_IPHONE
- status = CVPixelBufferCreate(
- kCFAllocatorDefault,
- frame->width,
- frame->height,
- color,
- NULL,
- cv_img
- );
+ pix_buf_pool = VTCompressionSessionGetPixelBufferPool(vtctx->session);
+ if (!pix_buf_pool) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get pixel buffer pool.\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ status = CVPixelBufferPoolCreatePixelBuffer(NULL,
+ pix_buf_pool,
+ cv_img);
+
if (status) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create pixel buffer from pool: %d.\n", status);
return AVERROR_EXTERNAL;
}
@@ -1306,9 +1444,7 @@ static av_cold int vtenc_close(AVCodecContext *avctx)
static const enum AVPixelFormat pix_fmts[] = {
AV_PIX_FMT_NV12,
-#if !TARGET_OS_IPHONE
AV_PIX_FMT_YUV420P,
-#endif
AV_PIX_FMT_NONE
};
--
2.7.4
More information about the ffmpeg-devel
mailing list