| @@ -407,6 +407,7 @@ static int count_nalus(size_t length_code_size, · 406 unmodified lines |
| 407 | 407 | } |
| 408 | 408 | |
| 409 | 409 | static CMVideoCodecType get_cm_codec_type(AVCodecContext *avctx, |
| 410 | + int64_t profile, |
| 410 | 411 | double alpha_quality) |
| 411 | 412 | { |
| 412 | 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 | 418 | return kCMVideoCodecType_HEVCWithAlpha; |
| 418 | 419 | } |
| 419 | 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 | 446 | default: return 0; |
| 421 | 447 | } |
| 422 | 448 | } |
| @@ -1102,7 +1128,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, · 679 unmodified lines |
| 1102 | 1128 | kVTCompressionPropertyKey_Quality, |
| 1103 | 1129 | quality_num); |
| 1104 | 1130 | CFRelease(quality_num); |
| 1105 | | − } else { |
| 1131 | + } else if (avctx->codec_id != AV_CODEC_ID_PRORES) { |
| 1106 | 1132 | bit_rate_num = CFNumberCreate(kCFAllocatorDefault, |
| 1107 | 1133 | kCFNumberSInt32Type, |
| 1108 | 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 | 1219 | CFNumberRef interval = CFNumberCreate(kCFAllocatorDefault, |
| 1194 | 1220 | kCFNumberIntType, |
| 1195 | 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 | 1368 | status = VTSessionSetProperty(vtctx->session, |
| 1343 | 1369 | kVTCompressionPropertyKey_AllowFrameReordering, |
| 1344 | 1370 | kCFBooleanFalse); |
| @@ -1388,16 +1414,24 @@ static int vtenc_configure_encoder(AVCodecContext *avctx) · 43 unmodified lines |
| 1388 | 1414 | CFMutableDictionaryRef pixel_buffer_info; |
| 1389 | 1415 | CMVideoCodecType codec_type; |
| 1390 | 1416 | VTEncContext *vtctx = avctx->priv_data; |
| 1391 | | − CFStringRef profile_level; |
| 1417 | + CFStringRef profile_level = NULL; |
| 1392 | 1418 | CFNumberRef gamma_level = NULL; |
| 1393 | 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 | 1422 | if (!codec_type) { |
| 1397 | 1423 | av_log(avctx, AV_LOG_ERROR, "Error: no mapping for AVCodecID %d\n", avctx->codec_id); |
| 1398 | 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 | 1435 | vtctx->codec_id = avctx->codec_id; |
| 1402 | 1436 | |
| 1403 | 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 | 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 | 1453 | vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; |
| 1420 | 1454 | if (!vtctx->get_param_set_func) return AVERROR(EINVAL); |
| 1421 | 1455 | if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); |
| 1422 | 1456 | // HEVC has b-byramid |
| 1423 | 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 | 1462 | enc_info = CFDictionaryCreateMutable( |
| @@ -2601,6 +2637,39 @@ static const enum AVPixelFormat hevc_pix_fmts[] = { · 1174 unmodified lines |
| 2601 | 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 | 2673 | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM |
| 2605 | 2674 | #define COMMON_OPTIONS \ |
| 2606 | 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 | 2773 | FF_CODEC_CAP_INIT_CLEANUP, |
| 2705 | 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 | +}; |