X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fvideotoolbox.c;h=49e726a75fcd9ae679dd613806ccee5acdc5dfa2;hb=e625ae609206e0550ff733965c6f5447579320aa;hp=da7236f1002c75ecb0a7773cb2f437743b32d0d6;hpb=2ac399d7faa5ac80088715780769522d1141b549;p=ffmpeg diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c index da7236f1002..49e726a75fc 100644 --- a/libavcodec/videotoolbox.c +++ b/libavcodec/videotoolbox.c @@ -26,6 +26,7 @@ #include "vt_internal.h" #include "libavutil/avutil.h" #include "libavutil/hwcontext.h" +#include "libavutil/pixdesc.h" #include "bytestream.h" #include "decode.h" #include "h264dec.h" @@ -90,6 +91,11 @@ static int videotoolbox_postproc_frame(void *avctx, AVFrame *frame) return AVERROR_EXTERNAL; } + frame->crop_right = 0; + frame->crop_left = 0; + frame->crop_top = 0; + frame->crop_bottom = 0; + frame->data[3] = (uint8_t*)ref->pixbuf; if (ref->hw_frames_ctx) { @@ -176,26 +182,31 @@ CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx) CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) { HEVCContext *h = avctx->priv_data; - const HEVCVPS *vps = (const HEVCVPS *)h->ps.vps_list[0]->data; - const HEVCSPS *sps = (const HEVCSPS *)h->ps.sps_list[0]->data; - int i, num_pps = 0; + int i, num_vps = 0, num_sps = 0, num_pps = 0; + const HEVCVPS *vps = h->ps.vps; + const HEVCSPS *sps = h->ps.sps; const HEVCPPS *pps = h->ps.pps; PTLCommon ptlc = vps->ptl.general_ptl; VUI vui = sps->vui; uint8_t parallelismType; CFDataRef data = NULL; uint8_t *p; - int vt_extradata_size = 23 + 5 + vps->data_size + 5 + sps->data_size + 3; + int vt_extradata_size = 23 + 3 + 3 + 3; uint8_t *vt_extradata; - for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { - if (h->ps.pps_list[i]) { - const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; - vt_extradata_size += 2 + pps->data_size; - num_pps++; - } +#define COUNT_SIZE_PS(T, t) \ + for (i = 0; i < HEVC_MAX_##T##PS_COUNT; i++) { \ + if (h->ps.t##ps_list[i]) { \ + const HEVC##T##PS *lps = (const HEVC##T##PS *)h->ps.t##ps_list[i]->data; \ + vt_extradata_size += 2 + lps->data_size; \ + num_##t##ps++; \ + } \ } + COUNT_SIZE_PS(V, v) + COUNT_SIZE_PS(S, s) + COUNT_SIZE_PS(P, p) + vt_extradata = av_malloc(vt_extradata_size); if (!vt_extradata) return NULL; @@ -286,44 +297,33 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) AV_W8(p + 22, 3); p += 23; - /* vps */ - /* - * bit(1) array_completeness; - * unsigned int(1) reserved = 0; - * unsigned int(6) NAL_unit_type; - */ - AV_W8(p, 1 << 7 | - HEVC_NAL_VPS & 0x3f); - /* unsigned int(16) numNalus; */ - AV_WB16(p + 1, 1); - /* unsigned int(16) nalUnitLength; */ - AV_WB16(p + 3, vps->data_size); - /* bit(8*nalUnitLength) nalUnit; */ - memcpy(p + 5, vps->data, vps->data_size); - p += 5 + vps->data_size; - - /* sps */ - AV_W8(p, 1 << 7 | - HEVC_NAL_SPS & 0x3f); - AV_WB16(p + 1, 1); - AV_WB16(p + 3, sps->data_size); - memcpy(p + 5, sps->data, sps->data_size); - p += 5 + sps->data_size; - - /* pps */ - AV_W8(p, 1 << 7 | - HEVC_NAL_PPS & 0x3f); - AV_WB16(p + 1, num_pps); - p += 3; - for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { - if (h->ps.pps_list[i]) { - const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; - AV_WB16(p, pps->data_size); - memcpy(p + 2, pps->data, pps->data_size); - p += 2 + pps->data_size; - } + +#define APPEND_PS(T, t) \ + /* \ + * bit(1) array_completeness; \ + * unsigned int(1) reserved = 0; \ + * unsigned int(6) NAL_unit_type; \ + */ \ + AV_W8(p, 1 << 7 | \ + HEVC_NAL_##T##PS & 0x3f); \ + /* unsigned int(16) numNalus; */ \ + AV_WB16(p + 1, num_##t##ps); \ + p += 3; \ + for (i = 0; i < HEVC_MAX_##T##PS_COUNT; i++) { \ + if (h->ps.t##ps_list[i]) { \ + const HEVC##T##PS *lps = (const HEVC##T##PS *)h->ps.t##ps_list[i]->data; \ + /* unsigned int(16) nalUnitLength; */ \ + AV_WB16(p, lps->data_size); \ + /* bit(8*nalUnitLength) nalUnit; */ \ + memcpy(p + 2, lps->data, lps->data_size); \ + p += 2 + lps->data_size; \ + } \ } + APPEND_PS(V, v) + APPEND_PS(S, s) + APPEND_PS(P, p) + av_assert0(p - vt_extradata == vt_extradata_size); data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size); @@ -617,7 +617,7 @@ static void videotoolbox_decoder_callback(void *opaque, } if (!image_buffer) { - av_log(NULL, AV_LOG_DEBUG, "vt decoder cb: output image buffer is null\n"); + av_log(avctx, AV_LOG_DEBUG, "vt decoder cb: output image buffer is null\n"); return; } @@ -903,11 +903,6 @@ static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame) AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); VTContext *vtctx = avctx->internal->hwaccel_priv_data; - frame->crop_right = 0; - frame->crop_left = 0; - frame->crop_top = 0; - frame->crop_bottom = 0; - if (vtctx->reconfig_needed == true) { vtctx->reconfig_needed = false; av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox decoder needs reconfig, restarting..\n"); @@ -1026,6 +1021,19 @@ static int videotoolbox_uninit(AVCodecContext *avctx) return 0; } +static enum AVPixelFormat videotoolbox_best_pixel_format(AVCodecContext *avctx) { + const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(avctx->pix_fmt); + if (!descriptor) + return AV_PIX_FMT_NV12; // same as av_videotoolbox_alloc_context() + + int depth = descriptor->comp[0].depth; + if (depth > 8) { + return AV_PIX_FMT_P010; + } + + return AV_PIX_FMT_NV12; +} + static int videotoolbox_common_init(AVCodecContext *avctx) { VTContext *vtctx = avctx->internal->hwaccel_priv_data; @@ -1059,7 +1067,7 @@ static int videotoolbox_common_init(AVCodecContext *avctx) hw_frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; hw_frames->format = AV_PIX_FMT_VIDEOTOOLBOX; - hw_frames->sw_format = AV_PIX_FMT_NV12; // same as av_videotoolbox_alloc_context() + hw_frames->sw_format = videotoolbox_best_pixel_format(avctx); hw_frames->width = avctx->width; hw_frames->height = avctx->height; @@ -1076,10 +1084,17 @@ static int videotoolbox_common_init(AVCodecContext *avctx) goto fail; } + bool full_range = avctx->color_range == AVCOL_RANGE_JPEG; vtctx->vt_ctx->cv_pix_fmt_type = - av_map_videotoolbox_format_from_pixfmt(hw_frames->sw_format); + av_map_videotoolbox_format_from_pixfmt2(hw_frames->sw_format, full_range); if (!vtctx->vt_ctx->cv_pix_fmt_type) { - av_log(avctx, AV_LOG_ERROR, "Unknown sw_format.\n"); + const AVPixFmtDescriptor *attempted_format = + av_pix_fmt_desc_get(hw_frames->sw_format); + av_log(avctx, AV_LOG_ERROR, + "Failed to map underlying FFmpeg pixel format %s (%s range) to " + "a VideoToolbox format!\n", + attempted_format ? attempted_format->name : "", + av_color_range_name(avctx->color_range)); err = AVERROR(EINVAL); goto fail; } @@ -1103,7 +1118,7 @@ static int videotoolbox_frame_params(AVCodecContext *avctx, frames_ctx->format = AV_PIX_FMT_VIDEOTOOLBOX; frames_ctx->width = avctx->coded_width; frames_ctx->height = avctx->coded_height; - frames_ctx->sw_format = AV_PIX_FMT_NV12; + frames_ctx->sw_format = videotoolbox_best_pixel_format(avctx); return 0; } @@ -1135,7 +1150,7 @@ const AVHWAccel ff_hevc_videotoolbox_hwaccel = { .end_frame = videotoolbox_hevc_end_frame, .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, - .uninit = ff_videotoolbox_uninit, + .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; @@ -1200,18 +1215,29 @@ const AVHWAccel ff_mpeg4_videotoolbox_hwaccel = { .priv_data_size = sizeof(VTContext), }; -AVVideotoolboxContext *av_videotoolbox_alloc_context(void) +static AVVideotoolboxContext *av_videotoolbox_alloc_context_with_pix_fmt(enum AVPixelFormat pix_fmt, + bool full_range) { AVVideotoolboxContext *ret = av_mallocz(sizeof(*ret)); if (ret) { ret->output_callback = videotoolbox_decoder_callback; - ret->cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; + + OSType cv_pix_fmt_type = av_map_videotoolbox_format_from_pixfmt2(pix_fmt, full_range); + if (cv_pix_fmt_type == 0) { + cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; + } + ret->cv_pix_fmt_type = cv_pix_fmt_type; } return ret; } +AVVideotoolboxContext *av_videotoolbox_alloc_context(void) +{ + return av_videotoolbox_alloc_context_with_pix_fmt(AV_PIX_FMT_NONE, false); +} + int av_videotoolbox_default_init(AVCodecContext *avctx) { return av_videotoolbox_default_init2(avctx, NULL); @@ -1219,7 +1245,9 @@ int av_videotoolbox_default_init(AVCodecContext *avctx) int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx) { - avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context(); + enum AVPixelFormat pix_fmt = videotoolbox_best_pixel_format(avctx); + bool full_range = avctx->color_range == AVCOL_RANGE_JPEG; + avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context_with_pix_fmt(pix_fmt, full_range); if (!avctx->hwaccel_context) return AVERROR(ENOMEM); return videotoolbox_start(avctx);