| @@ -407,6 +407,7 @@ static int count_nalus(size_t length_code_size, · 406 unmodified lines |
| 407 | } | 407 | } |
| 408 | | 408 | |
| 409 | static CMVideoCodecType get_cm_codec_type(AVCodecContext *avctx, | 409 | static CMVideoCodecType get_cm_codec_type(AVCodecContext *avctx, |
| | 410 | int64_t profile, |
| 410 | double alpha_quality) | 411 | double alpha_quality) |
| 411 | { | 412 | { |
| 412 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt == AV_PIX_FMT_VIDEOTOOLBOX ? avctx->sw_pix_fmt : avctx->pix_fmt); | 413 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt == AV_PIX_FMT_VIDEOTOOLBOX ? avctx->sw_pix_fmt : avctx->pix_fmt); |
| @@ -417,6 +418,31 @@ static CMVideoCodecType get_cm_codec_type(AVCodecContext *avctx, · 4 unmodified lines |
| 417 | return kCMVideoCodecType_HEVCWithAlpha; | 418 | return kCMVideoCodecType_HEVCWithAlpha; |
| 418 | } | 419 | } |
| 419 | return kCMVideoCodecType_HEVC; | 420 | return kCMVideoCodecType_HEVC; |
| | 421 | case AV_CODEC_ID_PRORES: |
| | 422 | switch (profile) { |
| | 423 | case FF_PROFILE_PRORES_PROXY: |
| | 424 | return MKBETAG('a','p','c','o'); // kCMVideoCodecType_AppleProRes422Proxy |
| | 425 | case FF_PROFILE_PRORES_LT: |
| | 426 | return MKBETAG('a','p','c','s'); // kCMVideoCodecType_AppleProRes422LT |
| | 427 | case FF_PROFILE_PRORES_STANDARD: |
| | 428 | return MKBETAG('a','p','c','n'); // kCMVideoCodecType_AppleProRes422 |
| | 429 | case FF_PROFILE_PRORES_HQ: |
| | 430 | return MKBETAG('a','p','c','h'); // kCMVideoCodecType_AppleProRes422HQ |
| | 431 | case FF_PROFILE_PRORES_4444: |
| | 432 | return MKBETAG('a','p','4','h'); // kCMVideoCodecType_AppleProRes4444 |
| | 433 | case FF_PROFILE_PRORES_XQ: |
| | 434 | return MKBETAG('a','p','4','x'); // kCMVideoCodecType_AppleProRes4444XQ |
| | 435 | |
| | 436 | default: |
| | 437 | av_log(avctx, AV_LOG_ERROR, "Unknown profile ID: %"PRId64", using auto\n", profile); |
| | 438 | case FF_PROFILE_UNKNOWN: |
| | 439 | if (desc && |
| | 440 | ((desc->flags & AV_PIX_FMT_FLAG_ALPHA) || |
| | 441 | desc->log2_chroma_w == 0)) |
| | 442 | return MKBETAG('a','p','4','h'); // kCMVideoCodecType_AppleProRes4444 |
| | 443 | else |
| | 444 | return MKBETAG('a','p','c','n'); // kCMVideoCodecType_AppleProRes422 |
| | 445 | } |
| 420 | default: return 0; | 446 | default: return 0; |
| 421 | } | 447 | } |
| 422 | } | 448 | } |
| @@ -1102,7 +1128,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, · 679 unmodified lines |
| 1102 | kVTCompressionPropertyKey_Quality, | 1128 | kVTCompressionPropertyKey_Quality, |
| 1103 | quality_num); | 1129 | quality_num); |
| 1104 | CFRelease(quality_num); | 1130 | CFRelease(quality_num); |
| 1105 | } else { | 1131 | } else if (avctx->codec_id != AV_CODEC_ID_PRORES) { |
| 1106 | bit_rate_num = CFNumberCreate(kCFAllocatorDefault, | 1132 | bit_rate_num = CFNumberCreate(kCFAllocatorDefault, |
| 1107 | kCFNumberSInt32Type, | 1133 | kCFNumberSInt32Type, |
| 1108 | &bit_rate); | 1134 | &bit_rate); |
| @@ -1189,7 +1215,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, · 80 unmodified lines |
| 1189 | } | 1215 | } |
| 1190 | } | 1216 | } |
| 1191 | | 1217 | |
| 1192 | if (avctx->gop_size > 0) { | 1218 | if (avctx->gop_size > 0 && avctx->codec_id != AV_CODEC_ID_PRORES) { |
| 1193 | CFNumberRef interval = CFNumberCreate(kCFAllocatorDefault, | 1219 | CFNumberRef interval = CFNumberCreate(kCFAllocatorDefault, |
| 1194 | kCFNumberIntType, | 1220 | kCFNumberIntType, |
| 1195 | &avctx->gop_size); | 1221 | &avctx->gop_size); |
| @@ -1338,7 +1364,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, · 142 unmodified lines |
| 1338 | } | 1364 | } |
| 1339 | } | 1365 | } |
| 1340 | | 1366 | |
| 1341 | if (!vtctx->has_b_frames) { | 1367 | if (!vtctx->has_b_frames && avctx->codec_id != AV_CODEC_ID_PRORES) { |
| 1342 | status = VTSessionSetProperty(vtctx->session, | 1368 | status = VTSessionSetProperty(vtctx->session, |
| 1343 | kVTCompressionPropertyKey_AllowFrameReordering, | 1369 | kVTCompressionPropertyKey_AllowFrameReordering, |
| 1344 | kCFBooleanFalse); | 1370 | kCFBooleanFalse); |
| @@ -1388,16 +1414,24 @@ static int vtenc_configure_encoder(AVCodecContext *avctx) · 43 unmodified lines |
| 1388 | CFMutableDictionaryRef pixel_buffer_info; | 1414 | CFMutableDictionaryRef pixel_buffer_info; |
| 1389 | CMVideoCodecType codec_type; | 1415 | CMVideoCodecType codec_type; |
| 1390 | VTEncContext *vtctx = avctx->priv_data; | 1416 | VTEncContext *vtctx = avctx->priv_data; |
| 1391 | CFStringRef profile_level; | 1417 | CFStringRef profile_level = NULL; |
| 1392 | CFNumberRef gamma_level = NULL; | 1418 | CFNumberRef gamma_level = NULL; |
| 1393 | int status; | 1419 | int status; |
| 1394 | | 1420 | |
| 1395 | codec_type = get_cm_codec_type(avctx, vtctx->alpha_quality); | 1421 | codec_type = get_cm_codec_type(avctx, vtctx->profile, vtctx->alpha_quality); |
| 1396 | if (!codec_type) { | 1422 | if (!codec_type) { |
| 1397 | av_log(avctx, AV_LOG_ERROR, "Error: no mapping for AVCodecID %d\n", avctx->codec_id); | 1423 | av_log(avctx, AV_LOG_ERROR, "Error: no mapping for AVCodecID %d\n", avctx->codec_id); |
| 1398 | return AVERROR(EINVAL); | 1424 | return AVERROR(EINVAL); |
| 1399 | } | 1425 | } |
| 1400 | | 1426 | |
| | 1427 | #if defined(MAC_OS_X_VERSION_10_9) && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9) |
| | 1428 | if (avctx->codec_id == AV_CODEC_ID_PRORES) { |
| | 1429 | if (__builtin_available(macOS 10.10, *)) { |
| | 1430 | VTRegisterProfessionalVideoWorkflowVideoEncoders(); |
| | 1431 | } |
| | 1432 | } |
| | 1433 | #endif |
| | 1434 | |
| 1401 | vtctx->codec_id = avctx->codec_id; | 1435 | vtctx->codec_id = avctx->codec_id; |
| 1402 | | 1436 | |
| 1403 | if (vtctx->codec_id == AV_CODEC_ID_H264) { | 1437 | if (vtctx->codec_id == AV_CODEC_ID_H264) { |
| @@ -1415,12 +1449,14 @@ static int vtenc_configure_encoder(AVCodecContext *avctx) · 11 unmodified lines |
| 1415 | } | 1449 | } |
| 1416 | | 1450 | |
| 1417 | if (!get_vt_h264_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); | 1451 | if (!get_vt_h264_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); |
| 1418 | } else { | 1452 | } else if (vtctx->codec_id == AV_CODEC_ID_HEVC) { |
| 1419 | vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; | 1453 | vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; |
| 1420 | if (!vtctx->get_param_set_func) return AVERROR(EINVAL); | 1454 | if (!vtctx->get_param_set_func) return AVERROR(EINVAL); |
| 1421 | if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); | 1455 | if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); |
| 1422 | // HEVC has b-byramid | 1456 | // HEVC has b-byramid |
| 1423 | vtctx->has_b_frames = avctx->max_b_frames > 0 ? 2 : 0; | 1457 | vtctx->has_b_frames = avctx->max_b_frames > 0 ? 2 : 0; |
| | 1458 | } else if (vtctx->codec_id == AV_CODEC_ID_PRORES) { |
| | 1459 | avctx->codec_tag = av_bswap32(codec_type); |
| 1424 | } | 1460 | } |
| 1425 | | 1461 | |
| 1426 | enc_info = CFDictionaryCreateMutable( | 1462 | enc_info = CFDictionaryCreateMutable( |
| @@ -2601,6 +2637,39 @@ static const enum AVPixelFormat hevc_pix_fmts[] = { · 1174 unmodified lines |
| 2601 | AV_PIX_FMT_NONE | 2637 | AV_PIX_FMT_NONE |
| 2602 | }; | 2638 | }; |
| 2603 | | 2639 | |
| | 2640 | static const enum AVPixelFormat prores_pix_fmts[] = { |
| | 2641 | AV_PIX_FMT_VIDEOTOOLBOX, |
| | 2642 | AV_PIX_FMT_YUV420P, |
| | 2643 | #ifdef kCFCoreFoundationVersionNumber10_7 |
| | 2644 | AV_PIX_FMT_NV12, |
| | 2645 | AV_PIX_FMT_AYUV64, |
| | 2646 | #endif |
| | 2647 | AV_PIX_FMT_UYVY422, |
| | 2648 | #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE |
| | 2649 | AV_PIX_FMT_P010, |
| | 2650 | #endif |
| | 2651 | #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE |
| | 2652 | AV_PIX_FMT_NV16, |
| | 2653 | #endif |
| | 2654 | #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE |
| | 2655 | AV_PIX_FMT_P210, |
| | 2656 | #endif |
| | 2657 | #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE |
| | 2658 | AV_PIX_FMT_P216, |
| | 2659 | #endif |
| | 2660 | #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE |
| | 2661 | AV_PIX_FMT_NV24, |
| | 2662 | #endif |
| | 2663 | #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE |
| | 2664 | AV_PIX_FMT_P410, |
| | 2665 | #endif |
| | 2666 | #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE |
| | 2667 | AV_PIX_FMT_P416, |
| | 2668 | #endif |
| | 2669 | AV_PIX_FMT_BGRA, |
| | 2670 | AV_PIX_FMT_NONE |
| | 2671 | }; |
| | 2672 | |
| 2604 | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM | 2673 | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM |
| 2605 | #define COMMON_OPTIONS \ | 2674 | #define COMMON_OPTIONS \ |
| 2606 | { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, \ | 2675 | { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, \ |
| @@ -2704,3 +2773,42 @@ const AVCodec ff_hevc_videotoolbox_encoder = { · 97 unmodified lines |
| 2704 | FF_CODEC_CAP_INIT_CLEANUP, | 2773 | FF_CODEC_CAP_INIT_CLEANUP, |
| 2705 | .wrapper_name = "videotoolbox", | 2774 | .wrapper_name = "videotoolbox", |
| 2706 | }; | 2775 | }; |
| | 2776 | |
| | 2777 | static const AVOption prores_options[] = { |
| | 2778 | { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT64, { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, FF_PROFILE_PRORES_XQ, VE, "profile" }, |
| | 2779 | { "auto", "Automatically determine based on input format", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, VE, "profile" }, |
| | 2780 | { "proxy", "ProRes 422 Proxy", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_PRORES_PROXY }, INT_MIN, INT_MAX, VE, "profile" }, |
| | 2781 | { "lt", "ProRes 422 LT", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_PRORES_LT }, INT_MIN, INT_MAX, VE, "profile" }, |
| | 2782 | { "standard", "ProRes 422", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_PRORES_STANDARD }, INT_MIN, INT_MAX, VE, "profile" }, |
| | 2783 | { "hq", "ProRes 422 HQ", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_PRORES_HQ }, INT_MIN, INT_MAX, VE, "profile" }, |
| | 2784 | { "4444", "ProRes 4444", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_PRORES_4444 }, INT_MIN, INT_MAX, VE, "profile" }, |
| | 2785 | { "xq", "ProRes 4444 XQ", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_PRORES_XQ }, INT_MIN, INT_MAX, VE, "profile" }, |
| | 2786 | |
| | 2787 | COMMON_OPTIONS |
| | 2788 | { NULL }, |
| | 2789 | }; |
| | 2790 | |
| | 2791 | static const AVClass prores_videotoolbox_class = { |
| | 2792 | .class_name = "prores_videotoolbox", |
| | 2793 | .item_name = av_default_item_name, |
| | 2794 | .option = prores_options, |
| | 2795 | .version = LIBAVUTIL_VERSION_INT, |
| | 2796 | }; |
| | 2797 | |
| | 2798 | const AVCodec ff_prores_videotoolbox_encoder = { |
| | 2799 | .name = "prores_videotoolbox", |
| | 2800 | .long_name = NULL_IF_CONFIG_SMALL("VideoToolbox ProRes Encoder"), |
| | 2801 | .type = AVMEDIA_TYPE_VIDEO, |
| | 2802 | .id = AV_CODEC_ID_PRORES, |
| | 2803 | .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | |
| | 2804 | AV_CODEC_CAP_HARDWARE, |
| | 2805 | .priv_data_size = sizeof(VTEncContext), |
| | 2806 | .pix_fmts = prores_pix_fmts, |
| | 2807 | .init = vtenc_init, |
| | 2808 | .encode2 = vtenc_frame, |
| | 2809 | .close = vtenc_close, |
| | 2810 | .priv_class = &prores_videotoolbox_class, |
| | 2811 | .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | |
| | 2812 | FF_CODEC_CAP_INIT_CLEANUP, |
| | 2813 | .wrapper_name = "videotoolbox", |
| | 2814 | }; |