Commit 98478c05 authored by Rick Kern's avatar Rick Kern Committed by Rick Kern

lavc/videotoolboxenc: Add support for 10-bit HEVC encoding.

Hardware-accelerated encoding may not support 10-bit encoding. Use
'-require_sw 1' in this case.

Fixes: #7581
Signed-off-by: 's avatarRick Kern <kernrj@gmail.com>
parent 714c8b07
...@@ -762,6 +762,11 @@ static int get_cv_pixel_format(AVCodecContext* avctx, ...@@ -762,6 +762,11 @@ static int get_cv_pixel_format(AVCodecContext* avctx,
*av_pixel_format = range == AVCOL_RANGE_JPEG ? *av_pixel_format = range == AVCOL_RANGE_JPEG ?
kCVPixelFormatType_420YpCbCr8PlanarFullRange : kCVPixelFormatType_420YpCbCr8PlanarFullRange :
kCVPixelFormatType_420YpCbCr8Planar; kCVPixelFormatType_420YpCbCr8Planar;
} else if (fmt == AV_PIX_FMT_P010LE) {
*av_pixel_format = range == AVCOL_RANGE_JPEG ?
kCVPixelFormatType_420YpCbCr10BiPlanarFullRange :
kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange;
*av_pixel_format = kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange;
} else { } else {
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
...@@ -1986,6 +1991,17 @@ static int get_cv_pixel_info( ...@@ -1986,6 +1991,17 @@ static int get_cv_pixel_info(
strides[2] = frame ? frame->linesize[2] : (avctx->width + 1) / 2; strides[2] = frame ? frame->linesize[2] : (avctx->width + 1) / 2;
break; break;
case AV_PIX_FMT_P010LE:
*plane_count = 2;
widths[0] = avctx->width;
heights[0] = avctx->height;
strides[0] = frame ? frame->linesize[0] : (avctx->width * 2 + 63) & -64;
widths[1] = (avctx->width + 1) / 2;
heights[1] = (avctx->height + 1) / 2;
strides[1] = frame ? frame->linesize[1] : ((avctx->width + 1) / 2 + 63) & -64;
break;
default: default:
av_log( av_log(
avctx, avctx,
...@@ -2348,21 +2364,11 @@ static int vtenc_populate_extradata(AVCodecContext *avctx, ...@@ -2348,21 +2364,11 @@ static int vtenc_populate_extradata(AVCodecContext *avctx,
CFDictionaryRef pixel_buffer_info) CFDictionaryRef pixel_buffer_info)
{ {
VTEncContext *vtctx = avctx->priv_data; VTEncContext *vtctx = avctx->priv_data;
AVFrame *frame = av_frame_alloc();
int y_size = avctx->width * avctx->height;
int chroma_size = (avctx->width / 2) * (avctx->height / 2);
CMSampleBufferRef buf = NULL;
int status; int status;
CVPixelBufferPoolRef pool = NULL;
if (!frame) CVPixelBufferRef pix_buf = NULL;
return AVERROR(ENOMEM); CMTime time;
CMSampleBufferRef buf = NULL;
frame->buf[0] = av_buffer_alloc(y_size + 2 * chroma_size);
if(!frame->buf[0]){
status = AVERROR(ENOMEM);
goto pe_cleanup;
}
status = vtenc_create_encoder(avctx, status = vtenc_create_encoder(avctx,
codec_type, codec_type,
...@@ -2374,39 +2380,38 @@ static int vtenc_populate_extradata(AVCodecContext *avctx, ...@@ -2374,39 +2380,38 @@ static int vtenc_populate_extradata(AVCodecContext *avctx,
if (status) if (status)
goto pe_cleanup; goto pe_cleanup;
frame->data[0] = frame->buf[0]->data; pool = VTCompressionSessionGetPixelBufferPool(vtctx->session);
memset(frame->data[0], 0, y_size); if(!pool){
av_log(avctx, AV_LOG_ERROR, "Error getting pixel buffer pool.\n");
frame->data[1] = frame->buf[0]->data + y_size; goto pe_cleanup;
memset(frame->data[1], 128, chroma_size);
if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) {
frame->data[2] = frame->buf[0]->data + y_size + chroma_size;
memset(frame->data[2], 128, chroma_size);
} }
frame->linesize[0] = avctx->width; status = CVPixelBufferPoolCreatePixelBuffer(NULL,
pool,
&pix_buf);
if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { if(status != kCVReturnSuccess){
frame->linesize[1] = av_log(avctx, AV_LOG_ERROR, "Error creating frame from pool: %d\n", status);
frame->linesize[2] = (avctx->width + 1) / 2; goto pe_cleanup;
} else {
frame->linesize[1] = (avctx->width + 1) / 2;
} }
frame->format = avctx->pix_fmt; unsigned pbuftype = CVPixelBufferGetPixelFormatType(pix_buf);
frame->width = avctx->width;
frame->height = avctx->height; time = CMTimeMake(0, avctx->time_base.den);
frame->colorspace = avctx->colorspace; status = VTCompressionSessionEncodeFrame(vtctx->session,
frame->color_range = avctx->color_range; pix_buf,
frame->color_trc = avctx->color_trc; time,
frame->color_primaries = avctx->color_primaries; kCMTimeInvalid,
NULL,
NULL,
NULL);
frame->pts = 0;
status = vtenc_send_frame(avctx, vtctx, frame);
if (status) { if (status) {
av_log(avctx, AV_LOG_ERROR, "Error sending frame: %d\n", status); av_log(avctx,
AV_LOG_ERROR,
"Error sending frame for extradata: %d\n",
status);
goto pe_cleanup; goto pe_cleanup;
} }
...@@ -2434,9 +2439,6 @@ pe_cleanup: ...@@ -2434,9 +2439,6 @@ pe_cleanup:
vtctx->session = NULL; vtctx->session = NULL;
vtctx->frame_ct_out = 0; vtctx->frame_ct_out = 0;
av_frame_unref(frame);
av_frame_free(&frame);
av_assert0(status != 0 || (avctx->extradata && avctx->extradata_size > 0)); av_assert0(status != 0 || (avctx->extradata && avctx->extradata_size > 0));
return status; return status;
...@@ -2475,10 +2477,18 @@ static av_cold int vtenc_close(AVCodecContext *avctx) ...@@ -2475,10 +2477,18 @@ static av_cold int vtenc_close(AVCodecContext *avctx)
return 0; return 0;
} }
static const enum AVPixelFormat pix_fmts[] = { static const enum AVPixelFormat avc_pix_fmts[] = {
AV_PIX_FMT_VIDEOTOOLBOX,
AV_PIX_FMT_NV12,
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
};
static const enum AVPixelFormat hevc_pix_fmts[] = {
AV_PIX_FMT_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX,
AV_PIX_FMT_NV12, AV_PIX_FMT_NV12,
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P,
AV_PIX_FMT_P010LE,
AV_PIX_FMT_NONE AV_PIX_FMT_NONE
}; };
...@@ -2539,7 +2549,7 @@ AVCodec ff_h264_videotoolbox_encoder = { ...@@ -2539,7 +2549,7 @@ AVCodec ff_h264_videotoolbox_encoder = {
.type = AVMEDIA_TYPE_VIDEO, .type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_H264, .id = AV_CODEC_ID_H264,
.priv_data_size = sizeof(VTEncContext), .priv_data_size = sizeof(VTEncContext),
.pix_fmts = pix_fmts, .pix_fmts = avc_pix_fmts,
.init = vtenc_init, .init = vtenc_init,
.encode2 = vtenc_frame, .encode2 = vtenc_frame,
.close = vtenc_close, .close = vtenc_close,
...@@ -2571,7 +2581,7 @@ AVCodec ff_hevc_videotoolbox_encoder = { ...@@ -2571,7 +2581,7 @@ AVCodec ff_hevc_videotoolbox_encoder = {
.type = AVMEDIA_TYPE_VIDEO, .type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_HEVC, .id = AV_CODEC_ID_HEVC,
.priv_data_size = sizeof(VTEncContext), .priv_data_size = sizeof(VTEncContext),
.pix_fmts = pix_fmts, .pix_fmts = hevc_pix_fmts,
.init = vtenc_init, .init = vtenc_init,
.encode2 = vtenc_frame, .encode2 = vtenc_frame,
.close = vtenc_close, .close = vtenc_close,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment