FFmpeg
Loading...
Searching...
No Matches
videotoolboxenc.c
Go to the documentation of this file.
1/*
2 * copyright (c) 2015 Rick Kern <kernrj@gmail.com>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <Availability.h>
22#include <CoreMedia/CoreMedia.h>
23#include <CoreVideo/CoreVideo.h>
24#include <dlfcn.h>
25#include <pthread.h>
26#include <TargetConditionals.h>
27#include <VideoToolbox/VideoToolbox.h>
28
30#include "libavutil/avassert.h"
31#include "libavutil/imgutils.h"
32#include "libavutil/mem.h"
33#include "libavutil/opt.h"
34#include "libavutil/pixdesc.h"
36
37#include "atsc_a53.h"
38#include "codec_internal.h"
39#include "encode.h"
40#include "h264.h"
41#include "h264_sei.h"
42#include "hwconfig.h"
43#include "internal.h"
44
45#if !HAVE_KCMVIDEOCODECTYPE_HEVC
46enum { kCMVideoCodecType_HEVC = 'hvc1' };
47#endif
48
49#if !HAVE_KCMVIDEOCODECTYPE_HEVCWITHALPHA
51#endif
52
53#if !HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
56#endif
57
58#if !HAVE_KVTQPMODULATIONLEVEL_DEFAULT
61#endif
62
63#ifndef TARGET_CPU_ARM64
64# define TARGET_CPU_ARM64 0
65#endif
66
67typedef OSStatus (*getParameterSetAtIndex)(CMFormatDescriptionRef videoDesc,
68 size_t parameterSetIndex,
69 const uint8_t **parameterSetPointerOut,
70 size_t *parameterSetSizeOut,
71 size_t *parameterSetCountOut,
72 int *NALUnitHeaderLengthOut);
73
74/*
75 * Symbols that aren't available in MacOS 10.8 and iOS 8.0 need to be accessed
76 * from compat_keys, or it will cause compiler errors when compiling for older
77 * OS versions.
78 *
79 * For example, kVTCompressionPropertyKey_H264EntropyMode was added in
80 * MacOS 10.9. If this constant were used directly, a compiler would generate
81 * an error when it has access to the MacOS 10.8 headers, but does not have
82 * 10.9 headers.
83 *
84 * Runtime errors will still occur when unknown keys are set. A warning is
85 * logged and encoding continues where possible.
86 *
87 * When adding new symbols, they should be loaded/set in loadVTEncSymbols().
88 */
89static struct{
93
97
121
125
132
141
144
145#define GET_SYM(symbol, defaultVal) \
146do{ \
147 CFStringRef* handle = (CFStringRef*)dlsym(RTLD_DEFAULT, #symbol); \
148 if(!handle) \
149 compat_keys.symbol = CFSTR(defaultVal); \
150 else \
151 compat_keys.symbol = *handle; \
152}while(0)
153
155
156static void loadVTEncSymbols(void){
157 compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex =
159 RTLD_DEFAULT,
160 "CMVideoFormatDescriptionGetHEVCParameterSetAtIndex"
161 );
162
166
170
171 GET_SYM(kVTProfileLevel_H264_Baseline_4_0, "H264_Baseline_4_0");
172 GET_SYM(kVTProfileLevel_H264_Baseline_4_2, "H264_Baseline_4_2");
173 GET_SYM(kVTProfileLevel_H264_Baseline_5_0, "H264_Baseline_5_0");
174 GET_SYM(kVTProfileLevel_H264_Baseline_5_1, "H264_Baseline_5_1");
175 GET_SYM(kVTProfileLevel_H264_Baseline_5_2, "H264_Baseline_5_2");
176 GET_SYM(kVTProfileLevel_H264_Baseline_AutoLevel, "H264_Baseline_AutoLevel");
177 GET_SYM(kVTProfileLevel_H264_Main_4_2, "H264_Main_4_2");
178 GET_SYM(kVTProfileLevel_H264_Main_5_1, "H264_Main_5_1");
179 GET_SYM(kVTProfileLevel_H264_Main_5_2, "H264_Main_5_2");
180 GET_SYM(kVTProfileLevel_H264_Main_AutoLevel, "H264_Main_AutoLevel");
181 GET_SYM(kVTProfileLevel_H264_High_3_0, "H264_High_3_0");
182 GET_SYM(kVTProfileLevel_H264_High_3_1, "H264_High_3_1");
183 GET_SYM(kVTProfileLevel_H264_High_3_2, "H264_High_3_2");
184 GET_SYM(kVTProfileLevel_H264_High_4_0, "H264_High_4_0");
185 GET_SYM(kVTProfileLevel_H264_High_4_1, "H264_High_4_1");
186 GET_SYM(kVTProfileLevel_H264_High_4_2, "H264_High_4_2");
187 GET_SYM(kVTProfileLevel_H264_High_5_1, "H264_High_5_1");
188 GET_SYM(kVTProfileLevel_H264_High_5_2, "H264_High_5_2");
189 GET_SYM(kVTProfileLevel_H264_High_AutoLevel, "H264_High_AutoLevel");
190 GET_SYM(kVTProfileLevel_H264_Extended_5_0, "H264_Extended_5_0");
191 GET_SYM(kVTProfileLevel_H264_Extended_AutoLevel, "H264_Extended_AutoLevel");
192 GET_SYM(kVTProfileLevel_H264_ConstrainedBaseline_AutoLevel, "H264_ConstrainedBaseline_AutoLevel");
193 GET_SYM(kVTProfileLevel_H264_ConstrainedHigh_AutoLevel, "H264_ConstrainedHigh_AutoLevel");
194
195 GET_SYM(kVTProfileLevel_HEVC_Main_AutoLevel, "HEVC_Main_AutoLevel");
196 GET_SYM(kVTProfileLevel_HEVC_Main10_AutoLevel, "HEVC_Main10_AutoLevel");
197 GET_SYM(kVTProfileLevel_HEVC_Main42210_AutoLevel, "HEVC_Main42210_AutoLevel");
198
201 "TargetQualityForAlpha");
203 "PrioritizeEncodingSpeedOverQuality");
206
208 "EnableHardwareAcceleratedVideoEncoder");
210 "RequireHardwareAcceleratedVideoEncoder");
212 "EnableLowLatencyRateControl");
215 "MaximizePowerEfficiency");
217 "ReferenceBufferCount");
221}
222
223#define H264_PROFILE_CONSTRAINED_HIGH (AV_PROFILE_H264_HIGH | AV_PROFILE_H264_CONSTRAINED)
224
230
231static const uint8_t start_code[] = { 0, 0, 0, 1 };
232
233typedef struct ExtraSEI {
234 void *data;
235 size_t size;
236} ExtraSEI;
237
238typedef struct BufNode {
239 CMSampleBufferRef cm_buffer;
242 struct BufNode* next;
243} BufNode;
244
294
295static void vtenc_free_buf_node(BufNode *info)
296{
297 if (!info)
298 return;
299
300 av_free(info->sei.data);
301 if (info->cm_buffer)
302 CFRelease(info->cm_buffer);
304 av_free(info);
305}
306
308{
309 VTEncContext *vtctx = avctx->priv_data;
310 CFStringRef encoder_id = NULL;
311 int status;
312 CFIndex length, max_size;
313 char *name;
314
315 status = VTSessionCopyProperty(vtctx->session,
316 compat_keys.kVTCompressionPropertyKey_EncoderID,
317 kCFAllocatorDefault,
318 &encoder_id);
319 // OK if not supported
320 if (status != noErr)
321 return 0;
322
323 length = CFStringGetLength(encoder_id);
324 max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
325 name = av_malloc(max_size);
326 if (!name) {
327 CFRelease(encoder_id);
328 return AVERROR(ENOMEM);
329 }
330
331 CFStringGetCString(encoder_id,
332 name,
333 max_size,
334 kCFStringEncodingUTF8);
335 av_log(avctx, AV_LOG_DEBUG, "Init the encoder: %s\n", name);
336 av_freep(&name);
337 CFRelease(encoder_id);
338
339 return 0;
340}
341
343 CMVideoCodecType codec_type,
344 CFStringRef profile_level,
345 CFNumberRef gamma_level,
346 CFDictionaryRef enc_info,
347 CFDictionaryRef pixel_buffer_info);
348
349/**
350 * NULL-safe release of *refPtr, and sets value to NULL.
351 */
352static void vt_release_num(CFNumberRef* refPtr){
353 if (!*refPtr) {
354 return;
355 }
356
357 CFRelease(*refPtr);
358 *refPtr = NULL;
359}
360
361static void set_async_error(VTEncContext *vtctx, int err)
362{
363 BufNode *info;
364
365 pthread_mutex_lock(&vtctx->lock);
366
367 vtctx->async_error = err;
368
369 info = vtctx->q_head;
370 vtctx->q_head = vtctx->q_tail = NULL;
371
372 while (info) {
373 BufNode *next = info->next;
375 info = next;
376 }
377
378 pthread_mutex_unlock(&vtctx->lock);
379}
380
382{
383 set_async_error(vtctx, 0);
384}
385
386static void vtenc_reset(VTEncContext *vtctx)
387{
388 if (vtctx->session) {
389 CFRelease(vtctx->session);
390 vtctx->session = NULL;
391 }
392
393 if (vtctx->supported_props) {
394 CFRelease(vtctx->supported_props);
395 vtctx->supported_props = NULL;
396 }
397
398 if (vtctx->color_primaries) {
399 CFRelease(vtctx->color_primaries);
400 vtctx->color_primaries = NULL;
401 }
402
403 if (vtctx->transfer_function) {
404 CFRelease(vtctx->transfer_function);
405 vtctx->transfer_function = NULL;
406 }
407
408 if (vtctx->ycbcr_matrix) {
409 CFRelease(vtctx->ycbcr_matrix);
410 vtctx->ycbcr_matrix = NULL;
411 }
412}
413
414static int vtenc_q_pop(VTEncContext *vtctx, bool wait, CMSampleBufferRef *buf, ExtraSEI *sei)
415{
416 BufNode *info;
417
418 pthread_mutex_lock(&vtctx->lock);
419
420 if (vtctx->async_error) {
421 pthread_mutex_unlock(&vtctx->lock);
422 return vtctx->async_error;
423 }
424
425 if (vtctx->flushing && vtctx->frame_ct_in == vtctx->frame_ct_out) {
426 *buf = NULL;
427
428 pthread_mutex_unlock(&vtctx->lock);
429 return 0;
430 }
431
432 while (!vtctx->q_head && !vtctx->async_error && wait && !vtctx->flushing) {
433 pthread_cond_wait(&vtctx->cv_sample_sent, &vtctx->lock);
434 }
435
436 if (!vtctx->q_head) {
437 pthread_mutex_unlock(&vtctx->lock);
438 *buf = NULL;
439 return 0;
440 }
441
442 info = vtctx->q_head;
443 vtctx->q_head = vtctx->q_head->next;
444 if (!vtctx->q_head) {
445 vtctx->q_tail = NULL;
446 }
447
448 vtctx->frame_ct_out++;
449 pthread_mutex_unlock(&vtctx->lock);
450
451 *buf = info->cm_buffer;
452 info->cm_buffer = NULL;
453 if (sei && *buf) {
454 *sei = info->sei;
455 info->sei = (ExtraSEI) {0};
456 }
458
459 return 0;
460}
461
462static void vtenc_q_push(VTEncContext *vtctx, BufNode *info)
463{
464 pthread_mutex_lock(&vtctx->lock);
465
466 if (!vtctx->q_head) {
467 vtctx->q_head = info;
468 } else {
469 vtctx->q_tail->next = info;
470 }
471
472 vtctx->q_tail = info;
473
475 pthread_mutex_unlock(&vtctx->lock);
476}
477
478static int count_nalus(size_t length_code_size,
479 CMSampleBufferRef sample_buffer,
480 int *count)
481{
482 size_t offset = 0;
483 int status;
484 int nalu_ct = 0;
485 uint8_t size_buf[4];
486 size_t src_size = CMSampleBufferGetTotalSampleSize(sample_buffer);
487 CMBlockBufferRef block = CMSampleBufferGetDataBuffer(sample_buffer);
488
489 if (length_code_size > 4)
490 return AVERROR_INVALIDDATA;
491
492 while (offset < src_size) {
493 size_t curr_src_len;
494 size_t box_len = 0;
495 size_t i;
496
497 status = CMBlockBufferCopyDataBytes(block,
498 offset,
499 length_code_size,
500 size_buf);
501
502 if (status != kCMBlockBufferNoErr) {
503 return AVERROR_EXTERNAL;
504 }
505
506 for (i = 0; i < length_code_size; i++) {
507 box_len <<= 8;
508 box_len |= size_buf[i];
509 }
510
511 curr_src_len = box_len + length_code_size;
512 offset += curr_src_len;
513
514 nalu_ct++;
515 }
516
517 *count = nalu_ct;
518 return 0;
519}
520
521static CMVideoCodecType get_cm_codec_type(AVCodecContext *avctx,
522 int profile,
523 double alpha_quality)
524{
526 switch (avctx->codec_id) {
527 case AV_CODEC_ID_H264: return kCMVideoCodecType_H264;
528 case AV_CODEC_ID_HEVC:
529 if (desc && (desc->flags & AV_PIX_FMT_FLAG_ALPHA) && alpha_quality > 0.0) {
531 }
534 if (desc && (desc->flags & AV_PIX_FMT_FLAG_ALPHA))
535 avctx->bits_per_coded_sample = 32;
536 switch (profile) {
538 return MKBETAG('a','p','c','o'); // kCMVideoCodecType_AppleProRes422Proxy
540 return MKBETAG('a','p','c','s'); // kCMVideoCodecType_AppleProRes422LT
542 return MKBETAG('a','p','c','n'); // kCMVideoCodecType_AppleProRes422
544 return MKBETAG('a','p','c','h'); // kCMVideoCodecType_AppleProRes422HQ
546 return MKBETAG('a','p','4','h'); // kCMVideoCodecType_AppleProRes4444
548 return MKBETAG('a','p','4','x'); // kCMVideoCodecType_AppleProRes4444XQ
549
550 default:
551 av_log(avctx, AV_LOG_ERROR, "Unknown profile ID: %d, using auto\n", profile);
554 if (desc &&
555 ((desc->flags & AV_PIX_FMT_FLAG_ALPHA) ||
556 desc->log2_chroma_w == 0))
557 return MKBETAG('a','p','4','h'); // kCMVideoCodecType_AppleProRes4444
558 else
559 return MKBETAG('a','p','c','n'); // kCMVideoCodecType_AppleProRes422
560 }
561 default: return 0;
562 }
563}
564
565/**
566 * Get the parameter sets from a CMSampleBufferRef.
567 * @param dst If *dst isn't NULL, the parameters are copied into existing
568 * memory. *dst_size must be set accordingly when *dst != NULL.
569 * If *dst is NULL, it will be allocated.
570 * In all cases, *dst_size is set to the number of bytes used starting
571 * at *dst.
572 */
574 AVCodecContext *avctx,
575 CMVideoFormatDescriptionRef vid_fmt,
576 size_t *size)
577{
578 VTEncContext *vtctx = avctx->priv_data;
579 size_t total_size = 0;
580 size_t ps_count;
581 int is_count_bad = 0;
582 size_t i;
583 int status;
584 status = vtctx->get_param_set_func(vid_fmt,
585 0,
586 NULL,
587 NULL,
588 &ps_count,
589 NULL);
590 if (status) {
591 is_count_bad = 1;
592 ps_count = 0;
593 status = 0;
594 }
595
596 for (i = 0; i < ps_count || is_count_bad; i++) {
597 const uint8_t *ps;
598 size_t ps_size;
599 status = vtctx->get_param_set_func(vid_fmt,
600 i,
601 &ps,
602 &ps_size,
603 NULL,
604 NULL);
605 if (status) {
606 /*
607 * When ps_count is invalid, status != 0 ends the loop normally
608 * unless we didn't get any parameter sets.
609 */
610 if (i > 0 && is_count_bad) status = 0;
611
612 break;
613 }
614
615 total_size += ps_size + sizeof(start_code);
616 }
617
618 if (status) {
619 av_log(avctx, AV_LOG_ERROR, "Error getting parameter set sizes: %d\n", status);
620 return AVERROR_EXTERNAL;
621 }
622
623 *size = total_size;
624 return 0;
625}
626
628 AVCodecContext *avctx,
629 CMVideoFormatDescriptionRef vid_fmt,
630 uint8_t *dst,
631 size_t dst_size)
632{
633 VTEncContext *vtctx = avctx->priv_data;
634 size_t ps_count;
635 int is_count_bad = 0;
636 int status;
637 size_t offset = 0;
638 size_t i;
639
640 status = vtctx->get_param_set_func(vid_fmt,
641 0,
642 NULL,
643 NULL,
644 &ps_count,
645 NULL);
646 if (status) {
647 is_count_bad = 1;
648 ps_count = 0;
649 status = 0;
650 }
651
652
653 for (i = 0; i < ps_count || is_count_bad; i++) {
654 const uint8_t *ps;
655 size_t ps_size;
656 size_t next_offset;
657
658 status = vtctx->get_param_set_func(vid_fmt,
659 i,
660 &ps,
661 &ps_size,
662 NULL,
663 NULL);
664 if (status) {
665 if (i > 0 && is_count_bad) status = 0;
666
667 break;
668 }
669
670 next_offset = offset + sizeof(start_code) + ps_size;
671 if (dst_size < next_offset) {
672 av_log(avctx, AV_LOG_ERROR, "Buffer too small for parameter sets.\n");
674 }
675
676 memcpy(dst + offset, start_code, sizeof(start_code));
677 offset += sizeof(start_code);
678
679 memcpy(dst + offset, ps, ps_size);
680 offset = next_offset;
681 }
682
683 if (status) {
684 av_log(avctx, AV_LOG_ERROR, "Error getting parameter set data: %d\n", status);
685 return AVERROR_EXTERNAL;
686 }
687
688 return 0;
689}
690
691static int set_extradata(AVCodecContext *avctx, CMSampleBufferRef sample_buffer)
692{
693 VTEncContext *vtctx = avctx->priv_data;
694 CMVideoFormatDescriptionRef vid_fmt;
695 size_t total_size;
696 int status;
697
698 vid_fmt = CMSampleBufferGetFormatDescription(sample_buffer);
699 if (!vid_fmt) {
700 av_log(avctx, AV_LOG_ERROR, "No video format.\n");
701 return AVERROR_EXTERNAL;
702 }
703
704 if (vtctx->get_param_set_func) {
705 status = get_params_size(avctx, vid_fmt, &total_size);
706 if (status) {
707 av_log(avctx, AV_LOG_ERROR, "Could not get parameter sets.\n");
708 return status;
709 }
710
712 if (!avctx->extradata) {
713 return AVERROR(ENOMEM);
714 }
715 avctx->extradata_size = total_size;
716
717 status = copy_param_sets(avctx, vid_fmt, avctx->extradata, total_size);
718
719 if (status) {
720 av_log(avctx, AV_LOG_ERROR, "Could not copy param sets.\n");
721 return status;
722 }
723 } else {
724 CFDataRef data = CMFormatDescriptionGetExtension(vid_fmt, kCMFormatDescriptionExtension_VerbatimSampleDescription);
725 if (data && CFGetTypeID(data) == CFDataGetTypeID()) {
726 CFIndex size = CFDataGetLength(data);
727
729 if (!avctx->extradata)
730 return AVERROR(ENOMEM);
731 avctx->extradata_size = size;
732
733 CFDataGetBytes(data, CFRangeMake(0, size), avctx->extradata);
734 }
735 }
736
737 return 0;
738}
739
741 void *ctx,
742 void *sourceFrameCtx,
743 OSStatus status,
744 VTEncodeInfoFlags flags,
745 CMSampleBufferRef sample_buffer)
746{
747 AVCodecContext *avctx = ctx;
748 VTEncContext *vtctx = avctx->priv_data;
749 BufNode *info = sourceFrameCtx;
750
752 if (vtctx->async_error) {
754 return;
755 }
756
757 if (status) {
759 av_log(avctx, AV_LOG_ERROR, "Error encoding frame: %d\n", (int)status);
761 return;
762 }
763
764 if (!sample_buffer) {
765 return;
766 }
767
768 CFRetain(sample_buffer);
769 info->cm_buffer = sample_buffer;
770
771 if (!avctx->extradata && (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) {
772 int set_status = set_extradata(avctx, sample_buffer);
773 if (set_status) {
775 set_async_error(vtctx, set_status);
776 return;
777 }
778 }
779
780 vtenc_q_push(vtctx, info);
781}
782
784 AVCodecContext *avctx,
785 CMSampleBufferRef sample_buffer,
786 size_t *size)
787{
788 VTEncContext *vtctx = avctx->priv_data;
789 CMVideoFormatDescriptionRef vid_fmt;
790 int isize;
791 int status;
792
793 vid_fmt = CMSampleBufferGetFormatDescription(sample_buffer);
794 if (!vid_fmt) {
795 av_log(avctx, AV_LOG_ERROR, "Error getting buffer format description.\n");
796 return AVERROR_EXTERNAL;
797 }
798
799 status = vtctx->get_param_set_func(vid_fmt,
800 0,
801 NULL,
802 NULL,
803 NULL,
804 &isize);
805 if (status) {
806 av_log(avctx, AV_LOG_ERROR, "Error getting length code size: %d\n", status);
807 return AVERROR_EXTERNAL;
808 }
809
810 *size = isize;
811 return 0;
812}
813
814/*
815 * Returns true on success.
816 *
817 * If profile_level_val is NULL and this method returns true, don't specify the
818 * profile/level to the encoder.
819 */
821 CFStringRef *profile_level_val)
822{
823 VTEncContext *vtctx = avctx->priv_data;
824 int profile = vtctx->profile;
825
826 if (profile == AV_PROFILE_UNKNOWN && vtctx->level) {
827 //Need to pick a profile if level is not auto-selected.
829 }
830
831 *profile_level_val = NULL;
832
833 switch (profile) {
835 return true;
836
838 switch (vtctx->level) {
839 case 0: *profile_level_val =
840 compat_keys.kVTProfileLevel_H264_Baseline_AutoLevel; break;
841 case 13: *profile_level_val = kVTProfileLevel_H264_Baseline_1_3; break;
842 case 30: *profile_level_val = kVTProfileLevel_H264_Baseline_3_0; break;
843 case 31: *profile_level_val = kVTProfileLevel_H264_Baseline_3_1; break;
844 case 32: *profile_level_val = kVTProfileLevel_H264_Baseline_3_2; break;
845 case 40: *profile_level_val =
846 compat_keys.kVTProfileLevel_H264_Baseline_4_0; break;
847 case 41: *profile_level_val = kVTProfileLevel_H264_Baseline_4_1; break;
848 case 42: *profile_level_val =
849 compat_keys.kVTProfileLevel_H264_Baseline_4_2; break;
850 case 50: *profile_level_val =
851 compat_keys.kVTProfileLevel_H264_Baseline_5_0; break;
852 case 51: *profile_level_val =
853 compat_keys.kVTProfileLevel_H264_Baseline_5_1; break;
854 case 52: *profile_level_val =
855 compat_keys.kVTProfileLevel_H264_Baseline_5_2; break;
856 }
857 break;
858
860 *profile_level_val = compat_keys.kVTProfileLevel_H264_ConstrainedBaseline_AutoLevel;
861
862 if (vtctx->level != 0) {
863 av_log(avctx,
865 "Level is auto-selected when constrained-baseline "
866 "profile is used. The output may be encoded with a "
867 "different level.\n");
868 }
869 break;
870
872 switch (vtctx->level) {
873 case 0: *profile_level_val =
874 compat_keys.kVTProfileLevel_H264_Main_AutoLevel; break;
875 case 30: *profile_level_val = kVTProfileLevel_H264_Main_3_0; break;
876 case 31: *profile_level_val = kVTProfileLevel_H264_Main_3_1; break;
877 case 32: *profile_level_val = kVTProfileLevel_H264_Main_3_2; break;
878 case 40: *profile_level_val = kVTProfileLevel_H264_Main_4_0; break;
879 case 41: *profile_level_val = kVTProfileLevel_H264_Main_4_1; break;
880 case 42: *profile_level_val =
881 compat_keys.kVTProfileLevel_H264_Main_4_2; break;
882 case 50: *profile_level_val = kVTProfileLevel_H264_Main_5_0; break;
883 case 51: *profile_level_val =
884 compat_keys.kVTProfileLevel_H264_Main_5_1; break;
885 case 52: *profile_level_val =
886 compat_keys.kVTProfileLevel_H264_Main_5_2; break;
887 }
888 break;
889
891 *profile_level_val = compat_keys.kVTProfileLevel_H264_ConstrainedHigh_AutoLevel;
892
893 if (vtctx->level != 0) {
894 av_log(avctx,
896 "Level is auto-selected when constrained-high profile "
897 "is used. The output may be encoded with a different "
898 "level.\n");
899 }
900 break;
901
903 switch (vtctx->level) {
904 case 0: *profile_level_val =
905 compat_keys.kVTProfileLevel_H264_High_AutoLevel; break;
906 case 30: *profile_level_val =
907 compat_keys.kVTProfileLevel_H264_High_3_0; break;
908 case 31: *profile_level_val =
909 compat_keys.kVTProfileLevel_H264_High_3_1; break;
910 case 32: *profile_level_val =
911 compat_keys.kVTProfileLevel_H264_High_3_2; break;
912 case 40: *profile_level_val =
913 compat_keys.kVTProfileLevel_H264_High_4_0; break;
914 case 41: *profile_level_val =
915 compat_keys.kVTProfileLevel_H264_High_4_1; break;
916 case 42: *profile_level_val =
917 compat_keys.kVTProfileLevel_H264_High_4_2; break;
918 case 50: *profile_level_val = kVTProfileLevel_H264_High_5_0; break;
919 case 51: *profile_level_val =
920 compat_keys.kVTProfileLevel_H264_High_5_1; break;
921 case 52: *profile_level_val =
922 compat_keys.kVTProfileLevel_H264_High_5_2; break;
923 }
924 break;
926 switch (vtctx->level) {
927 case 0: *profile_level_val =
928 compat_keys.kVTProfileLevel_H264_Extended_AutoLevel; break;
929 case 50: *profile_level_val =
930 compat_keys.kVTProfileLevel_H264_Extended_5_0; break;
931 }
932 break;
933 }
934
935 if (!*profile_level_val) {
936 av_log(avctx, AV_LOG_ERROR, "Invalid Profile/Level.\n");
937 return false;
938 }
939
940 return true;
941}
942
943/*
944 * Returns true on success.
945 *
946 * If profile_level_val is NULL and this method returns true, don't specify the
947 * profile/level to the encoder.
948 */
950 CFStringRef *profile_level_val)
951{
952 VTEncContext *vtctx = avctx->priv_data;
953 int profile = vtctx->profile;
956 : avctx->pix_fmt);
957 int bit_depth = desc ? desc->comp[0].depth : 0;
958
959 *profile_level_val = NULL;
960
961 switch (profile) {
963 // Set profile automatically if user don't specify
964 if (bit_depth == 10) {
965 *profile_level_val =
966 compat_keys.kVTProfileLevel_HEVC_Main10_AutoLevel;
967 break;
968 }
969 return true;
971 if (bit_depth > 0 && bit_depth != 8)
972 av_log(avctx, AV_LOG_WARNING,
973 "main profile with %d bit input\n", bit_depth);
974 *profile_level_val =
975 compat_keys.kVTProfileLevel_HEVC_Main_AutoLevel;
976 break;
978 if (bit_depth > 0 && bit_depth != 10) {
979 av_log(avctx, AV_LOG_ERROR,
980 "Invalid main10 profile with %d bit input\n", bit_depth);
981 return false;
982 }
983 *profile_level_val =
984 compat_keys.kVTProfileLevel_HEVC_Main10_AutoLevel;
985 break;
987 // only main42210 is supported, omit depth and chroma subsampling
988 *profile_level_val =
989 compat_keys.kVTProfileLevel_HEVC_Main42210_AutoLevel;
990 break;
991 }
992
993 if (!*profile_level_val) {
994 av_log(avctx, AV_LOG_ERROR, "Invalid Profile/Level.\n");
995 return false;
996 }
997
998 return true;
999}
1000
1002 enum AVPixelFormat fmt,
1003 enum AVColorRange range,
1004 int* av_pixel_format,
1005 int* range_guessed)
1006{
1007 const char *range_name;
1008 if (range_guessed) *range_guessed = range != AVCOL_RANGE_MPEG &&
1010
1011 //MPEG range is used when no range is set
1013 if (*av_pixel_format)
1014 return 0;
1015
1016 range_name = av_color_range_name(range);
1017 av_log(avctx, AV_LOG_ERROR,
1018 "Could not get pixel format for color format '%s' range '%s'.\n",
1020 range_name ? range_name : "Unknown");
1021
1022 return AVERROR(EINVAL);
1023}
1024
1025static void add_color_attr(AVCodecContext *avctx, CFMutableDictionaryRef dict) {
1026 VTEncContext *vtctx = avctx->priv_data;
1027
1028 if (vtctx->color_primaries) {
1029 CFDictionarySetValue(dict,
1030 kCVImageBufferColorPrimariesKey,
1031 vtctx->color_primaries);
1032 }
1033
1034 if (vtctx->transfer_function) {
1035 CFDictionarySetValue(dict,
1036 kCVImageBufferTransferFunctionKey,
1037 vtctx->transfer_function);
1038 }
1039
1040 if (vtctx->ycbcr_matrix) {
1041 CFDictionarySetValue(dict,
1042 kCVImageBufferYCbCrMatrixKey,
1043 vtctx->ycbcr_matrix);
1044 }
1045}
1046
1048 CFMutableDictionaryRef* dict)
1049{
1050 CFNumberRef cv_color_format_num = NULL;
1051 CFNumberRef width_num = NULL;
1052 CFNumberRef height_num = NULL;
1053 CFMutableDictionaryRef pixel_buffer_info = NULL;
1054 int cv_color_format;
1055 int status = get_cv_pixel_format(avctx,
1056 avctx->pix_fmt,
1057 avctx->color_range,
1058 &cv_color_format,
1059 NULL);
1060 if (status) return status;
1061
1062 pixel_buffer_info = CFDictionaryCreateMutable(
1063 kCFAllocatorDefault,
1064 20,
1065 &kCFCopyStringDictionaryKeyCallBacks,
1066 &kCFTypeDictionaryValueCallBacks);
1067
1068 if (!pixel_buffer_info) goto pbinfo_nomem;
1069
1070 cv_color_format_num = CFNumberCreate(kCFAllocatorDefault,
1071 kCFNumberSInt32Type,
1072 &cv_color_format);
1073 if (!cv_color_format_num) goto pbinfo_nomem;
1074
1075 CFDictionarySetValue(pixel_buffer_info,
1076 kCVPixelBufferPixelFormatTypeKey,
1077 cv_color_format_num);
1078 vt_release_num(&cv_color_format_num);
1079
1080 width_num = CFNumberCreate(kCFAllocatorDefault,
1081 kCFNumberSInt32Type,
1082 &avctx->width);
1083 if (!width_num) goto pbinfo_nomem;
1084
1085 CFDictionarySetValue(pixel_buffer_info,
1086 kCVPixelBufferWidthKey,
1087 width_num);
1088 vt_release_num(&width_num);
1089
1090 height_num = CFNumberCreate(kCFAllocatorDefault,
1091 kCFNumberSInt32Type,
1092 &avctx->height);
1093 if (!height_num) goto pbinfo_nomem;
1094
1095 CFDictionarySetValue(pixel_buffer_info,
1096 kCVPixelBufferHeightKey,
1097 height_num);
1098 vt_release_num(&height_num);
1099
1100 add_color_attr(avctx, pixel_buffer_info);
1101
1102 *dict = pixel_buffer_info;
1103 return 0;
1104
1105pbinfo_nomem:
1106 vt_release_num(&cv_color_format_num);
1107 vt_release_num(&width_num);
1108 vt_release_num(&height_num);
1109 if (pixel_buffer_info) CFRelease(pixel_buffer_info);
1110
1111 return AVERROR(ENOMEM);
1112}
1113
1115 CFNumberRef *gamma_level)
1116{
1117 enum AVColorTransferCharacteristic trc = avctx->color_trc;
1118 Float32 gamma = 0;
1119 *gamma_level = NULL;
1120
1121 if (trc == AVCOL_TRC_GAMMA22)
1122 gamma = 2.2;
1123 else if (trc == AVCOL_TRC_GAMMA28)
1124 gamma = 2.8;
1125
1126 if (gamma != 0)
1127 *gamma_level = CFNumberCreate(NULL, kCFNumberFloat32Type, &gamma);
1128 return 0;
1129}
1130
1131// constant quality only on Macs with Apple Silicon
1132static bool vtenc_qscale_enabled(void)
1133{
1134 return !TARGET_OS_IPHONE && TARGET_CPU_ARM64;
1135}
1136
1138 CFStringRef key,
1139 const char *print_option_name,
1140 CFTypeRef value) {
1141 int status;
1142 VTEncContext *vtctx = avctx->priv_data;
1143
1144 status = VTSessionSetProperty(vtctx->session, key, value);
1145 if (status == kVTPropertyNotSupportedErr) {
1146 av_log(avctx,
1148 "This device does not support the %s option. Value ignored.\n",
1149 print_option_name);
1150 } else if (status != 0) {
1151 av_log(avctx,
1153 "Error setting %s: Error %d\n",
1154 print_option_name,
1155 status);
1156 }
1157}
1158
1160 CFStringRef key,
1161 const char* print_option_name,
1162 int value) {
1163 CFNumberRef value_cfnum = CFNumberCreate(kCFAllocatorDefault,
1164 kCFNumberIntType,
1165 &value);
1166
1167 if (value_cfnum == NULL) {
1168 return AVERROR(ENOMEM);
1169 }
1170
1171 set_encoder_property_or_log(avctx, key, print_option_name, value_cfnum);
1172
1173 CFRelease(value_cfnum);
1174
1175 return 0;
1176}
1177
1179 CMVideoCodecType codec_type,
1180 CFStringRef profile_level,
1181 CFNumberRef gamma_level,
1182 CFDictionaryRef enc_info,
1183 CFDictionaryRef pixel_buffer_info,
1184 bool constant_bit_rate,
1185 VTCompressionSessionRef *session)
1186{
1187 VTEncContext *vtctx = avctx->priv_data;
1188 SInt32 bit_rate = avctx->bit_rate;
1189 SInt32 max_rate = avctx->rc_max_rate;
1190 CFNumberRef bit_rate_num;
1191 CFNumberRef bytes_per_second;
1192 CFNumberRef one_second;
1193 CFArrayRef data_rate_limits;
1194 int64_t bytes_per_second_value = 0;
1195 int64_t one_second_value = 0;
1196 void *nums[2];
1197
1198 int status = VTCompressionSessionCreate(kCFAllocatorDefault,
1199 avctx->width,
1200 avctx->height,
1201 codec_type,
1202 enc_info,
1203 pixel_buffer_info,
1204 kCFAllocatorDefault,
1206 avctx,
1207 session);
1208
1209 if (status || !vtctx->session) {
1210 av_log(avctx, AV_LOG_ERROR, "Cannot create compression session: %d\n", status);
1211
1212#if !TARGET_OS_IPHONE
1213 if (!vtctx->allow_sw) {
1214 av_log(avctx, AV_LOG_ERROR, "Try -allow_sw 1. The hardware encoder may be busy, or not supported.\n");
1215 }
1216#endif
1217
1218 return AVERROR_EXTERNAL;
1219 }
1220
1221#if defined (MAC_OS_X_VERSION_10_13) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13)
1222 if (__builtin_available(macOS 10.13, iOS 11.0, *)) {
1223 if (vtctx->supported_props) {
1224 CFRelease(vtctx->supported_props);
1225 vtctx->supported_props = NULL;
1226 }
1227 status = VTCopySupportedPropertyDictionaryForEncoder(avctx->width,
1228 avctx->height,
1229 codec_type,
1230 enc_info,
1231 NULL,
1232 &vtctx->supported_props);
1233
1234 if (status != noErr) {
1235 av_log(avctx, AV_LOG_ERROR,"Error retrieving the supported property dictionary err=%"PRId64"\n", (int64_t)status);
1236 return AVERROR_EXTERNAL;
1237 }
1238 }
1239#endif
1240
1241 status = vt_dump_encoder(avctx);
1242 if (status < 0)
1243 return status;
1244
1245 if (avctx->flags & AV_CODEC_FLAG_QSCALE && !vtenc_qscale_enabled()) {
1246 av_log(avctx, AV_LOG_ERROR, "-q:v qscale not available for encoder. Use -b:v bitrate instead.\n");
1247 return AVERROR_EXTERNAL;
1248 }
1249
1250 if (avctx->flags & AV_CODEC_FLAG_QSCALE || avctx->global_quality > 0) {
1251 float factor = (avctx->flags & AV_CODEC_FLAG_QSCALE) ?
1252 FF_QP2LAMBDA * 100.0f : 100.0f;
1253 Float32 quality = fminf(avctx->global_quality / factor, 1.0f);
1254 CFNumberRef quality_num = CFNumberCreate(kCFAllocatorDefault,
1255 kCFNumberFloat32Type,
1256 &quality);
1257 if (!quality_num) return AVERROR(ENOMEM);
1258
1259 status = VTSessionSetProperty(vtctx->session,
1260 kVTCompressionPropertyKey_Quality,
1261 quality_num);
1262 CFRelease(quality_num);
1263 } else if (avctx->codec_id != AV_CODEC_ID_PRORES) {
1264 bit_rate_num = CFNumberCreate(kCFAllocatorDefault,
1265 kCFNumberSInt32Type,
1266 &bit_rate);
1267 if (!bit_rate_num) return AVERROR(ENOMEM);
1268
1269 if (constant_bit_rate) {
1270 status = VTSessionSetProperty(vtctx->session,
1271 compat_keys.kVTCompressionPropertyKey_ConstantBitRate,
1272 bit_rate_num);
1273 if (status == kVTPropertyNotSupportedErr) {
1274 av_log(avctx, AV_LOG_ERROR, "-constant_bit_rate true is not supported by the encoder.\n");
1275 return AVERROR_EXTERNAL;
1276 }
1277 } else {
1278 status = VTSessionSetProperty(vtctx->session,
1279 kVTCompressionPropertyKey_AverageBitRate,
1280 bit_rate_num);
1281 }
1282
1283 CFRelease(bit_rate_num);
1284 }
1285
1286 if (status) {
1287 av_log(avctx, AV_LOG_ERROR, "Error setting bitrate property: %d\n", status);
1288 return AVERROR_EXTERNAL;
1289 }
1290
1291 if (vtctx->prio_speed >= 0) {
1292 status = VTSessionSetProperty(vtctx->session,
1293 compat_keys.kVTCompressionPropertyKey_PrioritizeEncodingSpeedOverQuality,
1294 vtctx->prio_speed ? kCFBooleanTrue : kCFBooleanFalse);
1295 if (status) {
1296 av_log(avctx, AV_LOG_WARNING, "PrioritizeEncodingSpeedOverQuality property is not supported on this device. Ignoring.\n");
1297 }
1298 }
1299
1300 if ((vtctx->codec_id == AV_CODEC_ID_H264 || vtctx->codec_id == AV_CODEC_ID_HEVC)
1301 && max_rate > 0) {
1302 bytes_per_second_value = max_rate >> 3;
1303 bytes_per_second = CFNumberCreate(kCFAllocatorDefault,
1304 kCFNumberSInt64Type,
1305 &bytes_per_second_value);
1306 if (!bytes_per_second) {
1307 return AVERROR(ENOMEM);
1308 }
1309 one_second_value = 1;
1310 one_second = CFNumberCreate(kCFAllocatorDefault,
1311 kCFNumberSInt64Type,
1312 &one_second_value);
1313 if (!one_second) {
1314 CFRelease(bytes_per_second);
1315 return AVERROR(ENOMEM);
1316 }
1317 nums[0] = (void *)bytes_per_second;
1318 nums[1] = (void *)one_second;
1319 data_rate_limits = CFArrayCreate(kCFAllocatorDefault,
1320 (const void **)nums,
1321 2,
1322 &kCFTypeArrayCallBacks);
1323
1324 if (!data_rate_limits) {
1325 CFRelease(bytes_per_second);
1326 CFRelease(one_second);
1327 return AVERROR(ENOMEM);
1328 }
1329 status = VTSessionSetProperty(vtctx->session,
1330 kVTCompressionPropertyKey_DataRateLimits,
1331 data_rate_limits);
1332
1333 CFRelease(bytes_per_second);
1334 CFRelease(one_second);
1335 CFRelease(data_rate_limits);
1336
1337 if (status) {
1338 av_log(avctx, AV_LOG_ERROR, "Error setting max bitrate property: %d\n", status);
1339 // kVTCompressionPropertyKey_DataRateLimits is available for HEVC
1340 // now but not on old release. There is no document about since
1341 // when. So ignore the error if it failed for hevc.
1342 if (vtctx->codec_id != AV_CODEC_ID_HEVC)
1343 return AVERROR_EXTERNAL;
1344 }
1345 }
1346
1347 if (vtctx->codec_id == AV_CODEC_ID_HEVC && vtctx->alpha_quality > 0.0) {
1348 const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(avctx->pix_fmt);
1349
1350 if (descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) {
1351 CFNumberRef alpha_quality_num = CFNumberCreate(kCFAllocatorDefault,
1352 kCFNumberDoubleType,
1353 &vtctx->alpha_quality);
1354 if (!alpha_quality_num) return AVERROR(ENOMEM);
1355
1356 status = VTSessionSetProperty(vtctx->session,
1357 compat_keys.kVTCompressionPropertyKey_TargetQualityForAlpha,
1358 alpha_quality_num);
1359 CFRelease(alpha_quality_num);
1360
1361 if (status) {
1362 av_log(avctx,
1364 "Error setting alpha quality: %d\n",
1365 status);
1366 }
1367 }
1368 }
1369
1370 if (profile_level) {
1371 status = VTSessionSetProperty(vtctx->session,
1372 kVTCompressionPropertyKey_ProfileLevel,
1373 profile_level);
1374 if (status) {
1375 av_log(avctx, AV_LOG_ERROR, "Error setting profile/level property: %d. Output will be encoded using a supported profile/level combination.\n", status);
1376 }
1377 }
1378
1379 if (avctx->gop_size > 0 && avctx->codec_id != AV_CODEC_ID_PRORES) {
1380 CFNumberRef interval = CFNumberCreate(kCFAllocatorDefault,
1381 kCFNumberIntType,
1382 &avctx->gop_size);
1383 if (!interval) {
1384 return AVERROR(ENOMEM);
1385 }
1386
1387 status = VTSessionSetProperty(vtctx->session,
1388 kVTCompressionPropertyKey_MaxKeyFrameInterval,
1389 interval);
1390 CFRelease(interval);
1391
1392 if (status) {
1393 av_log(avctx, AV_LOG_ERROR, "Error setting 'max key-frame interval' property: %d\n", status);
1394 return AVERROR_EXTERNAL;
1395 }
1396 }
1397
1398 if (vtctx->frames_before) {
1399 status = VTSessionSetProperty(vtctx->session,
1400 kVTCompressionPropertyKey_MoreFramesBeforeStart,
1401 kCFBooleanTrue);
1402
1403 if (status == kVTPropertyNotSupportedErr) {
1404 av_log(avctx, AV_LOG_WARNING, "frames_before property is not supported on this device. Ignoring.\n");
1405 } else if (status) {
1406 av_log(avctx, AV_LOG_ERROR, "Error setting frames_before property: %d\n", status);
1407 }
1408 }
1409
1410 if (vtctx->frames_after) {
1411 status = VTSessionSetProperty(vtctx->session,
1412 kVTCompressionPropertyKey_MoreFramesAfterEnd,
1413 kCFBooleanTrue);
1414
1415 if (status == kVTPropertyNotSupportedErr) {
1416 av_log(avctx, AV_LOG_WARNING, "frames_after property is not supported on this device. Ignoring.\n");
1417 } else if (status) {
1418 av_log(avctx, AV_LOG_ERROR, "Error setting frames_after property: %d\n", status);
1419 }
1420 }
1421
1422 if (avctx->sample_aspect_ratio.num != 0) {
1423 CFNumberRef num;
1424 CFNumberRef den;
1425 CFMutableDictionaryRef par;
1426 AVRational *avpar = &avctx->sample_aspect_ratio;
1427
1428 av_reduce(&avpar->num, &avpar->den,
1429 avpar->num, avpar->den,
1430 0xFFFFFFFF);
1431
1432 num = CFNumberCreate(kCFAllocatorDefault,
1433 kCFNumberIntType,
1434 &avpar->num);
1435
1436 den = CFNumberCreate(kCFAllocatorDefault,
1437 kCFNumberIntType,
1438 &avpar->den);
1439
1440
1441
1442 par = CFDictionaryCreateMutable(kCFAllocatorDefault,
1443 2,
1444 &kCFCopyStringDictionaryKeyCallBacks,
1445 &kCFTypeDictionaryValueCallBacks);
1446
1447 if (!par || !num || !den) {
1448 if (par) CFRelease(par);
1449 if (num) CFRelease(num);
1450 if (den) CFRelease(den);
1451
1452 return AVERROR(ENOMEM);
1453 }
1454
1455 CFDictionarySetValue(
1456 par,
1457 kCMFormatDescriptionKey_PixelAspectRatioHorizontalSpacing,
1458 num);
1459
1460 CFDictionarySetValue(
1461 par,
1462 kCMFormatDescriptionKey_PixelAspectRatioVerticalSpacing,
1463 den);
1464
1465 status = VTSessionSetProperty(vtctx->session,
1466 kVTCompressionPropertyKey_PixelAspectRatio,
1467 par);
1468
1469 CFRelease(par);
1470 CFRelease(num);
1471 CFRelease(den);
1472
1473 if (status) {
1474 av_log(avctx,
1476 "Error setting pixel aspect ratio to %d:%d: %d.\n",
1477 avctx->sample_aspect_ratio.num,
1478 avctx->sample_aspect_ratio.den,
1479 status);
1480
1481 return AVERROR_EXTERNAL;
1482 }
1483 }
1484
1485
1486 if (vtctx->transfer_function) {
1487 status = VTSessionSetProperty(vtctx->session,
1488 kVTCompressionPropertyKey_TransferFunction,
1489 vtctx->transfer_function);
1490
1491 if (status) {
1492 av_log(avctx, AV_LOG_WARNING, "Could not set transfer function: %d\n", status);
1493 }
1494 }
1495
1496
1497 if (vtctx->ycbcr_matrix) {
1498 status = VTSessionSetProperty(vtctx->session,
1499 kVTCompressionPropertyKey_YCbCrMatrix,
1500 vtctx->ycbcr_matrix);
1501
1502 if (status) {
1503 av_log(avctx, AV_LOG_WARNING, "Could not set ycbcr matrix: %d\n", status);
1504 }
1505 }
1506
1507
1508 if (vtctx->color_primaries) {
1509 status = VTSessionSetProperty(vtctx->session,
1510 kVTCompressionPropertyKey_ColorPrimaries,
1511 vtctx->color_primaries);
1512
1513 if (status) {
1514 av_log(avctx, AV_LOG_WARNING, "Could not set color primaries: %d\n", status);
1515 }
1516 }
1517
1518 if (gamma_level) {
1519 status = VTSessionSetProperty(vtctx->session,
1520 kCVImageBufferGammaLevelKey,
1521 gamma_level);
1522
1523 if (status) {
1524 av_log(avctx, AV_LOG_WARNING, "Could not set gamma level: %d\n", status);
1525 }
1526 }
1527
1528 if (!vtctx->has_b_frames && avctx->codec_id != AV_CODEC_ID_PRORES) {
1529 status = VTSessionSetProperty(vtctx->session,
1530 kVTCompressionPropertyKey_AllowFrameReordering,
1531 kCFBooleanFalse);
1532
1533 if (status) {
1534 av_log(avctx, AV_LOG_ERROR, "Error setting 'allow frame reordering' property: %d\n", status);
1535 return AVERROR_EXTERNAL;
1536 }
1537 }
1538
1539 if (vtctx->entropy != VT_ENTROPY_NOT_SET) {
1540 CFStringRef entropy = vtctx->entropy == VT_CABAC ?
1541 compat_keys.kVTH264EntropyMode_CABAC:
1542 compat_keys.kVTH264EntropyMode_CAVLC;
1543
1544 status = VTSessionSetProperty(vtctx->session,
1545 compat_keys.kVTCompressionPropertyKey_H264EntropyMode,
1546 entropy);
1547
1548 if (status) {
1549 av_log(avctx, AV_LOG_ERROR, "Error setting entropy property: %d\n", status);
1550 }
1551 }
1552
1553 if (vtctx->realtime >= 0) {
1554 status = VTSessionSetProperty(vtctx->session,
1555 compat_keys.kVTCompressionPropertyKey_RealTime,
1556 vtctx->realtime ? kCFBooleanTrue : kCFBooleanFalse);
1557
1558 if (status) {
1559 av_log(avctx, AV_LOG_ERROR, "Error setting realtime property: %d\n", status);
1560 }
1561 }
1562
1563 if ((avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) != 0) {
1565 compat_keys.kVTCompressionPropertyKey_AllowOpenGOP,
1566 "AllowOpenGop",
1567 kCFBooleanFalse);
1568 }
1569
1570 if (avctx->qmin >= 0) {
1571 status = set_encoder_int_property_or_log(avctx,
1572 compat_keys.kVTCompressionPropertyKey_MinAllowedFrameQP,
1573 "qmin",
1574 avctx->qmin);
1575
1576 if (status != 0) {
1577 return status;
1578 }
1579 }
1580
1581 if (avctx->qmax >= 0) {
1582 status = set_encoder_int_property_or_log(avctx,
1583 compat_keys.kVTCompressionPropertyKey_MaxAllowedFrameQP,
1584 "qmax",
1585 avctx->qmax);
1586
1587 if (status != 0) {
1588 return status;
1589 }
1590 }
1591
1592 if (vtctx->max_slice_bytes >= 0 && avctx->codec_id == AV_CODEC_ID_H264) {
1593 status = set_encoder_int_property_or_log(avctx,
1594 kVTCompressionPropertyKey_MaxH264SliceBytes,
1595 "max_slice_bytes",
1596 vtctx->max_slice_bytes);
1597
1598 if (status != 0) {
1599 return status;
1600 }
1601 }
1602
1603 if (vtctx->power_efficient >= 0) {
1605 compat_keys.kVTCompressionPropertyKey_MaximizePowerEfficiency,
1606 "power_efficient",
1607 vtctx->power_efficient ? kCFBooleanTrue : kCFBooleanFalse);
1608 }
1609
1610 if (vtctx->max_ref_frames > 0) {
1611 status = set_encoder_int_property_or_log(avctx,
1612 compat_keys.kVTCompressionPropertyKey_ReferenceBufferCount,
1613 "max_ref_frames",
1614 vtctx->max_ref_frames);
1615
1616 if (status != 0) {
1617 return status;
1618 }
1619 }
1620
1621 if (vtctx->spatialaq >= 0) {
1623 compat_keys.kVTCompressionPropertyKey_SpatialAdaptiveQPLevel,
1624 "spatialaq",
1626 }
1627
1628 status = VTCompressionSessionPrepareToEncodeFrames(vtctx->session);
1629 if (status) {
1630 av_log(avctx, AV_LOG_ERROR, "Cannot prepare encoder: %d\n", status);
1631 return AVERROR_EXTERNAL;
1632 }
1633
1634 return 0;
1635}
1636
1638{
1639 CFMutableDictionaryRef enc_info;
1640 CFMutableDictionaryRef pixel_buffer_info = NULL;
1641 CMVideoCodecType codec_type;
1642 VTEncContext *vtctx = avctx->priv_data;
1643 CFStringRef profile_level = NULL;
1644 CFNumberRef gamma_level = NULL;
1645 int status;
1646
1647 codec_type = get_cm_codec_type(avctx, vtctx->profile, vtctx->alpha_quality);
1648 if (!codec_type) {
1649 av_log(avctx, AV_LOG_ERROR, "No mapping for AVCodecID %d\n", avctx->codec_id);
1650 return AVERROR(EINVAL);
1651 }
1652
1653#if defined(MAC_OS_X_VERSION_10_9) && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9)
1654 if (avctx->codec_id == AV_CODEC_ID_PRORES) {
1655 if (__builtin_available(macOS 10.10, *)) {
1656 VTRegisterProfessionalVideoWorkflowVideoEncoders();
1657 }
1658 }
1659#endif
1660
1661 vtctx->codec_id = avctx->codec_id;
1662
1663 if (vtctx->codec_id == AV_CODEC_ID_H264) {
1664 vtctx->get_param_set_func = CMVideoFormatDescriptionGetH264ParameterSetAtIndex;
1665
1666 vtctx->has_b_frames = avctx->max_b_frames > 0;
1667 if(vtctx->has_b_frames && (0xFF & vtctx->profile) == AV_PROFILE_H264_BASELINE){
1668 av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline profile. Output will not contain B-frames.\n");
1669 vtctx->has_b_frames = 0;
1670 }
1671
1672 if (vtctx->entropy == VT_CABAC && (0xFF & vtctx->profile) == AV_PROFILE_H264_BASELINE) {
1673 av_log(avctx, AV_LOG_WARNING, "CABAC entropy requires 'main' or 'high' profile, but baseline was requested. Encode will not use CABAC entropy.\n");
1674 vtctx->entropy = VT_ENTROPY_NOT_SET;
1675 }
1676
1677 if (!get_vt_h264_profile_level(avctx, &profile_level)) return AVERROR(EINVAL);
1678 } else if (vtctx->codec_id == AV_CODEC_ID_HEVC) {
1679 vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex;
1680 if (!vtctx->get_param_set_func) return AVERROR(EINVAL);
1681 if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL);
1682 // HEVC has b-byramid
1683 vtctx->has_b_frames = avctx->max_b_frames > 0 ? 2 : 0;
1684 } else if (vtctx->codec_id == AV_CODEC_ID_PRORES) {
1686 }
1687
1688 enc_info = CFDictionaryCreateMutable(
1689 kCFAllocatorDefault,
1690 20,
1691 &kCFCopyStringDictionaryKeyCallBacks,
1692 &kCFTypeDictionaryValueCallBacks
1693 );
1694
1695 if (!enc_info) return AVERROR(ENOMEM);
1696
1697#if !TARGET_OS_IPHONE
1698 if(vtctx->require_sw) {
1699 CFDictionarySetValue(enc_info,
1700 compat_keys.kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder,
1701 kCFBooleanFalse);
1702 } else if (!vtctx->allow_sw) {
1703 CFDictionarySetValue(enc_info,
1704 compat_keys.kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder,
1705 kCFBooleanTrue);
1706 } else {
1707 CFDictionarySetValue(enc_info,
1708 compat_keys.kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder,
1709 kCFBooleanTrue);
1710 }
1711#endif
1712
1713 // low-latency mode: eliminate frame reordering, follow a one-in-one-out encoding mode
1714 if ((avctx->flags & AV_CODEC_FLAG_LOW_DELAY) &&
1715 ((avctx->codec_id == AV_CODEC_ID_H264) || (TARGET_CPU_ARM64 && avctx->codec_id == AV_CODEC_ID_HEVC))) {
1716 if (!avctx->bit_rate) {
1717 av_log(avctx, AV_LOG_ERROR, "Doesn't support automatic bitrate in low_delay mode, "
1718 "please specify bitrate explicitly\n");
1719 status = AVERROR(EINVAL);
1720 goto init_cleanup;
1721 }
1722 CFDictionarySetValue(enc_info,
1723 compat_keys.kVTVideoEncoderSpecification_EnableLowLatencyRateControl,
1724 kCFBooleanTrue);
1725 }
1726
1727 if (avctx->pix_fmt != AV_PIX_FMT_VIDEOTOOLBOX) {
1728 status = create_cv_pixel_buffer_info(avctx, &pixel_buffer_info);
1729 if (status)
1730 goto init_cleanup;
1731 }
1732
1733 vtctx->dts_delta = vtctx->has_b_frames ? -1 : 0;
1734
1735 get_cv_gamma(avctx, &gamma_level);
1739
1740
1741 if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
1742 status = vtenc_populate_extradata(avctx,
1743 codec_type,
1744 profile_level,
1745 gamma_level,
1746 enc_info,
1747 pixel_buffer_info);
1748 if (status)
1749 goto init_cleanup;
1750 }
1751
1752 status = vtenc_create_encoder(avctx,
1753 codec_type,
1754 profile_level,
1755 gamma_level,
1756 enc_info,
1757 pixel_buffer_info,
1758 vtctx->constant_bit_rate,
1759 &vtctx->session);
1760
1761init_cleanup:
1762 if (gamma_level)
1763 CFRelease(gamma_level);
1764
1765 if (pixel_buffer_info)
1766 CFRelease(pixel_buffer_info);
1767
1768 CFRelease(enc_info);
1769
1770 return status;
1771}
1772
1774{
1775 VTEncContext *vtctx = avctx->priv_data;
1776 CFBooleanRef has_b_frames_cfbool;
1777 int status;
1778
1780
1781 pthread_mutex_init(&vtctx->lock, NULL);
1783
1784 // It can happen when user set avctx->profile directly.
1785 if (vtctx->profile == AV_PROFILE_UNKNOWN)
1786 vtctx->profile = avctx->profile;
1787 status = vtenc_configure_encoder(avctx);
1788 if (status) return status;
1789
1790 status = VTSessionCopyProperty(vtctx->session,
1791 kVTCompressionPropertyKey_AllowFrameReordering,
1792 kCFAllocatorDefault,
1793 &has_b_frames_cfbool);
1794
1795 if (!status && has_b_frames_cfbool) {
1796 //Some devices don't output B-frames for main profile, even if requested.
1797 // HEVC has b-pyramid
1798 if (CFBooleanGetValue(has_b_frames_cfbool))
1799 vtctx->has_b_frames = avctx->codec_id == AV_CODEC_ID_HEVC ? 2 : 1;
1800 else
1801 vtctx->has_b_frames = 0;
1802 CFRelease(has_b_frames_cfbool);
1803 }
1804 avctx->has_b_frames = vtctx->has_b_frames;
1805
1806 return 0;
1807}
1808
1809static void vtenc_get_frame_info(CMSampleBufferRef buffer, bool *is_key_frame)
1810{
1811 CFArrayRef attachments;
1812 CFDictionaryRef attachment;
1813 CFBooleanRef not_sync;
1814 CFIndex len;
1815
1816 attachments = CMSampleBufferGetSampleAttachmentsArray(buffer, false);
1817 len = !attachments ? 0 : CFArrayGetCount(attachments);
1818
1819 if (!len) {
1820 *is_key_frame = true;
1821 return;
1822 }
1823
1824 attachment = CFArrayGetValueAtIndex(attachments, 0);
1825
1826 if (CFDictionaryGetValueIfPresent(attachment,
1827 kCMSampleAttachmentKey_NotSync,
1828 (const void **)&not_sync))
1829 {
1830 *is_key_frame = !CFBooleanGetValue(not_sync);
1831 } else {
1832 *is_key_frame = true;
1833 }
1834}
1835
1836static int is_post_sei_nal_type(int nal_type){
1837 return nal_type != H264_NAL_SEI &&
1838 nal_type != H264_NAL_SPS &&
1839 nal_type != H264_NAL_PPS &&
1840 nal_type != H264_NAL_AUD;
1841}
1842
1843/*
1844 * Finds the sei message start/size of type find_sei_type.
1845 * If more than one of that type exists, the last one is returned.
1846 */
1848 uint8_t *nal_data,
1849 size_t nal_size,
1850 uint8_t **sei_end)
1851{
1852 int nal_type;
1853 size_t sei_payload_size = 0;
1854 uint8_t *nal_start = nal_data;
1855 *sei_end = NULL;
1856
1857 if (!nal_size)
1858 return 0;
1859
1860 nal_type = *nal_data & 0x1F;
1861 if (nal_type != H264_NAL_SEI)
1862 return 0;
1863
1864 nal_data++;
1865 nal_size--;
1866
1867 if (nal_data[nal_size - 1] == 0x80)
1868 nal_size--;
1869
1870 while (nal_size > 0 && *nal_data > 0) {
1871 do{
1872 nal_data++;
1873 nal_size--;
1874 } while (nal_size > 0 && *nal_data == 0xFF);
1875
1876 if (!nal_size) {
1877 av_log(avctx, AV_LOG_ERROR, "Unexpected end of SEI NAL Unit parsing type.\n");
1878 return AVERROR_INVALIDDATA;
1879 }
1880
1881 do{
1882 sei_payload_size += *nal_data;
1883 nal_data++;
1884 nal_size--;
1885 } while (nal_size > 0 && *nal_data == 0xFF);
1886
1887 if (nal_size < sei_payload_size) {
1888 av_log(avctx, AV_LOG_ERROR, "Unexpected end of SEI NAL Unit parsing size.\n");
1889 return AVERROR_INVALIDDATA;
1890 }
1891
1892 nal_data += sei_payload_size;
1893 nal_size -= sei_payload_size;
1894 }
1895
1896 *sei_end = nal_data;
1897
1898 return nal_data - nal_start + 1;
1899}
1900
1901/**
1902 * Copies the data inserting emulation prevention bytes as needed.
1903 * Existing data in the destination can be taken into account by providing
1904 * dst with a dst_offset > 0.
1905 *
1906 * @return The number of bytes copied on success. On failure, the negative of
1907 * the number of bytes needed to copy src is returned.
1908 */
1909static int copy_emulation_prev(const uint8_t *src,
1910 size_t src_size,
1911 uint8_t *dst,
1912 ssize_t dst_offset,
1913 size_t dst_size)
1914{
1915 int zeros = 0;
1916 int wrote_bytes;
1917 uint8_t* dst_start;
1918 uint8_t* dst_end = dst + dst_size;
1919 const uint8_t* src_end = src + src_size;
1920 int start_at = dst_offset > 2 ? dst_offset - 2 : 0;
1921 int i;
1922 for (i = start_at; i < dst_offset && i < dst_size; i++) {
1923 if (!dst[i])
1924 zeros++;
1925 else
1926 zeros = 0;
1927 }
1928
1929 dst += dst_offset;
1930 dst_start = dst;
1931 for (; src < src_end; src++, dst++) {
1932 if (zeros == 2) {
1933 int insert_ep3_byte = *src <= 3;
1934 if (insert_ep3_byte) {
1935 if (dst < dst_end)
1936 *dst = 3;
1937 dst++;
1938 }
1939
1940 zeros = 0;
1941 }
1942
1943 if (dst < dst_end)
1944 *dst = *src;
1945
1946 if (!*src)
1947 zeros++;
1948 else
1949 zeros = 0;
1950 }
1951
1952 wrote_bytes = dst - dst_start;
1953
1954 if (dst > dst_end)
1955 return -wrote_bytes;
1956
1957 return wrote_bytes;
1958}
1959
1960static int write_sei(const ExtraSEI *sei,
1961 int sei_type,
1962 uint8_t *dst,
1963 size_t dst_size)
1964{
1965 uint8_t *sei_start = dst;
1966 size_t remaining_sei_size = sei->size;
1967 size_t remaining_dst_size = dst_size;
1968 int header_bytes;
1969 int bytes_written;
1970 ssize_t offset;
1971
1972 if (!remaining_dst_size)
1974
1975 while (sei_type && remaining_dst_size != 0) {
1976 int sei_byte = sei_type > 255 ? 255 : sei_type;
1977 *dst = sei_byte;
1978
1979 sei_type -= sei_byte;
1980 dst++;
1981 remaining_dst_size--;
1982 }
1983
1984 if (!dst_size)
1986
1987 while (remaining_sei_size && remaining_dst_size != 0) {
1988 int size_byte = remaining_sei_size > 255 ? 255 : remaining_sei_size;
1989 *dst = size_byte;
1990
1991 remaining_sei_size -= size_byte;
1992 dst++;
1993 remaining_dst_size--;
1994 }
1995
1996 if (remaining_dst_size < sei->size)
1998
1999 header_bytes = dst - sei_start;
2000
2001 offset = header_bytes;
2002 bytes_written = copy_emulation_prev(sei->data,
2003 sei->size,
2004 sei_start,
2005 offset,
2006 dst_size);
2007 if (bytes_written < 0)
2009
2010 bytes_written += header_bytes;
2011 return bytes_written;
2012}
2013
2014/**
2015 * Copies NAL units and replaces length codes with
2016 * H.264 Annex B start codes. On failure, the contents of
2017 * dst_data may have been modified.
2018 *
2019 * @param length_code_size Byte length of each length code
2020 * @param sample_buffer NAL units prefixed with length codes.
2021 * @param sei Optional A53 closed captions SEI data.
2022 * @param dst_data Must be zeroed before calling this function.
2023 * Contains the copied NAL units prefixed with
2024 * start codes when the function returns
2025 * successfully.
2026 * @param dst_size Length of dst_data
2027 * @return 0 on success
2028 * AVERROR_INVALIDDATA if length_code_size is invalid
2029 * AVERROR_BUFFER_TOO_SMALL if dst_data is too small
2030 * or if a length_code in src_data specifies data beyond
2031 * the end of its buffer.
2032 */
2034 AVCodecContext *avctx,
2035 size_t length_code_size,
2036 CMSampleBufferRef sample_buffer,
2037 ExtraSEI *sei,
2038 uint8_t *dst_data,
2039 size_t dst_size)
2040{
2041 size_t src_size = CMSampleBufferGetTotalSampleSize(sample_buffer);
2042 size_t remaining_src_size = src_size;
2043 size_t remaining_dst_size = dst_size;
2044 size_t src_offset = 0;
2045 int wrote_sei = 0;
2046 int status;
2047 uint8_t size_buf[4];
2048 uint8_t nal_type;
2049 CMBlockBufferRef block = CMSampleBufferGetDataBuffer(sample_buffer);
2050
2051 if (length_code_size > 4) {
2052 return AVERROR_INVALIDDATA;
2053 }
2054
2055 while (remaining_src_size > 0) {
2056 size_t curr_src_len;
2057 size_t curr_dst_len;
2058 size_t box_len = 0;
2059 size_t i;
2060
2061 uint8_t *dst_box;
2062
2063 status = CMBlockBufferCopyDataBytes(block,
2064 src_offset,
2065 length_code_size,
2066 size_buf);
2067 if (status) {
2068 av_log(avctx, AV_LOG_ERROR, "Cannot copy length: %d\n", status);
2069 return AVERROR_EXTERNAL;
2070 }
2071
2072 status = CMBlockBufferCopyDataBytes(block,
2073 src_offset + length_code_size,
2074 1,
2075 &nal_type);
2076
2077 if (status) {
2078 av_log(avctx, AV_LOG_ERROR, "Cannot copy type: %d\n", status);
2079 return AVERROR_EXTERNAL;
2080 }
2081
2082 nal_type &= 0x1F;
2083
2084 for (i = 0; i < length_code_size; i++) {
2085 box_len <<= 8;
2086 box_len |= size_buf[i];
2087 }
2088
2089 if (sei && !wrote_sei && is_post_sei_nal_type(nal_type)) {
2090 //No SEI NAL unit - insert.
2091 int wrote_bytes;
2092
2093 memcpy(dst_data, start_code, sizeof(start_code));
2094 dst_data += sizeof(start_code);
2095 remaining_dst_size -= sizeof(start_code);
2096
2097 *dst_data = H264_NAL_SEI;
2098 dst_data++;
2099 remaining_dst_size--;
2100
2101 wrote_bytes = write_sei(sei,
2103 dst_data,
2104 remaining_dst_size);
2105
2106 if (wrote_bytes < 0)
2107 return wrote_bytes;
2108
2109 remaining_dst_size -= wrote_bytes;
2110 dst_data += wrote_bytes;
2111
2112 if (remaining_dst_size <= 0)
2114
2115 *dst_data = 0x80;
2116
2117 dst_data++;
2118 remaining_dst_size--;
2119
2120 wrote_sei = 1;
2121 }
2122
2123 curr_src_len = box_len + length_code_size;
2124 curr_dst_len = box_len + sizeof(start_code);
2125
2126 if (remaining_src_size < curr_src_len) {
2128 }
2129
2130 if (remaining_dst_size < curr_dst_len) {
2132 }
2133
2134 dst_box = dst_data + sizeof(start_code);
2135
2136 memcpy(dst_data, start_code, sizeof(start_code));
2137 status = CMBlockBufferCopyDataBytes(block,
2138 src_offset + length_code_size,
2139 box_len,
2140 dst_box);
2141
2142 if (status) {
2143 av_log(avctx, AV_LOG_ERROR, "Cannot copy data: %d\n", status);
2144 return AVERROR_EXTERNAL;
2145 }
2146
2147 if (sei && !wrote_sei && nal_type == H264_NAL_SEI) {
2148 //Found SEI NAL unit - append.
2149 int wrote_bytes;
2150 int old_sei_length;
2151 int extra_bytes;
2152 uint8_t *new_sei;
2153 old_sei_length = find_sei_end(avctx, dst_box, box_len, &new_sei);
2154 if (old_sei_length < 0)
2155 return old_sei_length;
2156
2157 wrote_bytes = write_sei(sei,
2159 new_sei,
2160 remaining_dst_size - old_sei_length);
2161 if (wrote_bytes < 0)
2162 return wrote_bytes;
2163
2164 if (new_sei + wrote_bytes >= dst_data + remaining_dst_size)
2166
2167 new_sei[wrote_bytes++] = 0x80;
2168 extra_bytes = wrote_bytes - (dst_box + box_len - new_sei);
2169
2170 dst_data += extra_bytes;
2171 remaining_dst_size -= extra_bytes;
2172
2173 wrote_sei = 1;
2174 }
2175
2176 src_offset += curr_src_len;
2177 dst_data += curr_dst_len;
2178
2179 remaining_src_size -= curr_src_len;
2180 remaining_dst_size -= curr_dst_len;
2181 }
2182
2183 return 0;
2184}
2185
2186/**
2187 * Returns a sufficient number of bytes to contain the sei data.
2188 * It may be greater than the minimum required.
2189 */
2190static int get_sei_msg_bytes(const ExtraSEI* sei, int type){
2191 int copied_size;
2192 if (sei->size == 0)
2193 return 0;
2194
2195 copied_size = -copy_emulation_prev(sei->data,
2196 sei->size,
2197 NULL,
2198 0,
2199 0);
2200
2201 if ((sei->size % 255) == 0) //may result in an extra byte
2202 copied_size++;
2203
2204 return copied_size + sei->size / 255 + 1 + type / 255 + 1;
2205}
2206
2208 AVCodecContext *avctx,
2209 CMSampleBufferRef sample_buffer,
2210 AVPacket *pkt,
2211 ExtraSEI *sei)
2212{
2213 VTEncContext *vtctx = avctx->priv_data;
2214
2215 int status;
2216 bool is_key_frame;
2217 bool add_header;
2218 size_t length_code_size;
2219 size_t header_size = 0;
2220 size_t in_buf_size;
2221 size_t out_buf_size;
2222 size_t sei_nalu_size = 0;
2223 int64_t dts_delta;
2224 int nalu_count;
2225 CMTime pts;
2226 CMTime dts;
2227 CMVideoFormatDescriptionRef vid_fmt;
2228
2229 vtenc_get_frame_info(sample_buffer, &is_key_frame);
2230
2231 if (vtctx->get_param_set_func) {
2232 status = get_length_code_size(avctx, sample_buffer, &length_code_size);
2233 if (status) return status;
2234
2235 add_header = is_key_frame && !(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER);
2236
2237 if (add_header) {
2238 vid_fmt = CMSampleBufferGetFormatDescription(sample_buffer);
2239 if (!vid_fmt) {
2240 av_log(avctx, AV_LOG_ERROR, "Cannot get format description.\n");
2241 return AVERROR_EXTERNAL;
2242 }
2243
2244 status = get_params_size(avctx, vid_fmt, &header_size);
2245 if (status) return status;
2246 }
2247
2248 status = count_nalus(length_code_size, sample_buffer, &nalu_count);
2249 if(status)
2250 return status;
2251
2252 if (sei) {
2253 size_t msg_size = get_sei_msg_bytes(sei,
2255
2256 sei_nalu_size = sizeof(start_code) + 1 + msg_size + 1;
2257 }
2258
2259 in_buf_size = CMSampleBufferGetTotalSampleSize(sample_buffer);
2260 out_buf_size = header_size +
2261 in_buf_size +
2262 sei_nalu_size +
2263 nalu_count * ((int)sizeof(start_code) - (int)length_code_size);
2264
2265 status = ff_get_encode_buffer(avctx, pkt, out_buf_size, 0);
2266 if (status < 0)
2267 return status;
2268
2269 if (add_header) {
2270 status = copy_param_sets(avctx, vid_fmt, pkt->data, out_buf_size);
2271 if(status) return status;
2272 }
2273
2275 avctx,
2276 length_code_size,
2277 sample_buffer,
2278 sei,
2279 pkt->data + header_size,
2280 pkt->size - header_size
2281 );
2282
2283 if (status) {
2284 av_log(avctx, AV_LOG_ERROR, "Error copying packet data: %d\n", status);
2285 return status;
2286 }
2287 } else {
2288 size_t len;
2289 CMBlockBufferRef buf = CMSampleBufferGetDataBuffer(sample_buffer);
2290 if (!buf) {
2291 av_log(avctx, AV_LOG_ERROR, "Error getting block buffer\n");
2292 return AVERROR_EXTERNAL;
2293 }
2294
2295 len = CMBlockBufferGetDataLength(buf);
2296
2297 status = ff_get_encode_buffer(avctx, pkt, len, 0);
2298 if (status < 0)
2299 return status;
2300
2301 status = CMBlockBufferCopyDataBytes(buf, 0, len, pkt->data);
2302 if (status) {
2303 av_log(avctx, AV_LOG_ERROR, "Error copying packet data: %d\n", status);
2304 return AVERROR_EXTERNAL;
2305 }
2306 }
2307
2308 if (is_key_frame) {
2309 pkt->flags |= AV_PKT_FLAG_KEY;
2310 }
2311
2312 pts = CMSampleBufferGetPresentationTimeStamp(sample_buffer);
2313 dts = CMSampleBufferGetDecodeTimeStamp (sample_buffer);
2314
2315 if (CMTIME_IS_INVALID(pts)) {
2316 av_log(avctx, AV_LOG_ERROR, "PTS is invalid.\n");
2317 return AVERROR_EXTERNAL;
2318 }
2319
2320 if (CMTIME_IS_INVALID(dts)) {
2321 if (!vtctx->has_b_frames) {
2322 dts = pts;
2323 } else {
2324 av_log(avctx, AV_LOG_ERROR, "DTS is invalid.\n");
2325 return AVERROR_EXTERNAL;
2326 }
2327 }
2328
2329 dts_delta = vtctx->dts_delta >= 0 ? vtctx->dts_delta : 0;
2330 pkt->pts = av_rescale_q(pts.value, (AVRational){1, pts.timescale}, avctx->time_base);
2331 pkt->dts = av_rescale_q(dts.value, (AVRational){1, dts.timescale}, avctx->time_base)
2332 - dts_delta;
2333
2334 return 0;
2335}
2336
2338 const AVFrame *frame,
2339 CVPixelBufferRef cv_img)
2340{
2341 int status;
2342
2343 int num_planes = av_pix_fmt_count_planes(frame->format);
2344 size_t num_cv_plane = CVPixelBufferIsPlanar(cv_img) ?
2345 CVPixelBufferGetPlaneCount(cv_img) : 1;
2346 if (num_planes != num_cv_plane) {
2347 av_log(avctx, AV_LOG_ERROR,
2348 "Different number of planes in AVFrame and CVPixelBuffer.\n");
2349 return AVERROR_BUG;
2350 }
2351
2352 status = CVPixelBufferLockBaseAddress(cv_img, 0);
2353 if (status) {
2354 av_log(avctx, AV_LOG_ERROR, "Could not lock base address of CVPixelBuffer: %d.\n", status);
2355 return AVERROR_EXTERNAL;
2356 }
2357
2358 int dst_stride[4] = {0};
2359 uint8_t *dst_addr[4] = {0};
2360 for (int i = 0; i < num_planes; i++) {
2361 dst_addr[i] = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(cv_img, i);
2362 dst_stride[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_img, i);
2363 }
2364 av_image_copy2(dst_addr, dst_stride, frame->data, frame->linesize,
2365 frame->format, frame->width, frame->height);
2366
2367 status = CVPixelBufferUnlockBaseAddress(cv_img, 0);
2368 if (status) {
2369 av_log(avctx, AV_LOG_ERROR, "Could not unlock CVPixelBuffer base address: %d.\n", status);
2370 return AVERROR_EXTERNAL;
2371 }
2372
2373 return 0;
2374}
2375
2377 const AVFrame *frame,
2378 CVPixelBufferRef *cv_img,
2379 BufNode *node)
2380{
2381 int status;
2382 CVPixelBufferPoolRef pix_buf_pool;
2383 VTEncContext* vtctx = avctx->priv_data;
2384
2385 if (avctx->pix_fmt == AV_PIX_FMT_VIDEOTOOLBOX) {
2387
2388 *cv_img = (CVPixelBufferRef)frame->data[3];
2389 av_assert0(*cv_img);
2390
2391 CFRetain(*cv_img);
2392 if (frame->buf[0]) {
2393 node->frame_buf = av_buffer_ref(frame->buf[0]);
2394 if (!node->frame_buf)
2395 return AVERROR(ENOMEM);
2396 }
2397
2398 return 0;
2399 }
2400
2401 int range_guessed;
2402 status = get_cv_pixel_format(avctx, frame->format, avctx->color_range,
2403 &(int) {0}, &range_guessed);
2404 if (status) {
2405 av_log(avctx, AV_LOG_ERROR, "Cannot convert format %d color_range %d: %d\n",
2406 frame->format, frame->color_range, status);
2407 return status;
2408 }
2409 if (range_guessed) {
2410 if (!vtctx->warned_color_range) {
2411 vtctx->warned_color_range = true;
2412 av_log(avctx, AV_LOG_WARNING, "Color range not set for %s. Using MPEG range.\n",
2413 av_get_pix_fmt_name(frame->format));
2414 }
2415 }
2416
2417 pix_buf_pool = VTCompressionSessionGetPixelBufferPool(vtctx->session);
2418 if (!pix_buf_pool) {
2419 /* On iOS, the VT session is invalidated when the APP switches from
2420 * foreground to background and vice versa. Fetch the actual error code
2421 * of the VT session to detect that case and restart the VT session
2422 * accordingly. */
2423 OSStatus vtstatus;
2424
2425 vtstatus = VTCompressionSessionPrepareToEncodeFrames(vtctx->session);
2426 if (vtstatus == kVTInvalidSessionErr) {
2427 vtenc_reset(vtctx);
2428
2429 status = vtenc_configure_encoder(avctx);
2430 if (status == 0)
2431 pix_buf_pool = VTCompressionSessionGetPixelBufferPool(vtctx->session);
2432 }
2433 if (!pix_buf_pool) {
2434 av_log(avctx, AV_LOG_ERROR, "Could not get pixel buffer pool.\n");
2435 return AVERROR_EXTERNAL;
2436 }
2437 else
2438 av_log(avctx, AV_LOG_WARNING, "VT session restarted because of a "
2439 "kVTInvalidSessionErr error.\n");
2440 }
2441
2442 status = CVPixelBufferPoolCreatePixelBuffer(NULL,
2443 pix_buf_pool,
2444 cv_img);
2445
2446
2447 if (status) {
2448 av_log(avctx, AV_LOG_ERROR, "Could not create pixel buffer from pool: %d.\n", status);
2449 return AVERROR_EXTERNAL;
2450 }
2451
2452 status = copy_avframe_to_pixel_buffer(avctx, frame, *cv_img);
2453 if (status) {
2454 CFRelease(*cv_img);
2455 *cv_img = NULL;
2456 return status;
2457 }
2458
2459 return 0;
2460}
2461
2463 CFDictionaryRef* dict_out)
2464{
2465 CFDictionaryRef dict = NULL;
2466 if (frame->pict_type == AV_PICTURE_TYPE_I) {
2467 const void *keys[] = { kVTEncodeFrameOptionKey_ForceKeyFrame };
2468 const void *vals[] = { kCFBooleanTrue };
2469
2470 dict = CFDictionaryCreate(NULL, keys, vals, 1, NULL, NULL);
2471 if(!dict) return AVERROR(ENOMEM);
2472 }
2473
2474 *dict_out = dict;
2475 return 0;
2476}
2477
2479 VTEncContext *vtctx,
2480 const AVFrame *frame)
2481{
2482 CMTime time;
2483 CFDictionaryRef frame_dict = NULL;
2484 CVPixelBufferRef cv_img = NULL;
2485 AVFrameSideData *side_data = NULL;
2486 BufNode *node = av_mallocz(sizeof(*node));
2487 int status;
2488
2489 if (!node)
2490 return AVERROR(ENOMEM);
2491
2492 status = create_cv_pixel_buffer(avctx, frame, &cv_img, node);
2493 if (status)
2494 goto out;
2495
2496 status = create_encoder_dict_h264(frame, &frame_dict);
2497 if (status)
2498 goto out;
2499
2500#if CONFIG_ATSC_A53
2502 if (vtctx->a53_cc && side_data && side_data->size) {
2503 status = ff_alloc_a53_sei(frame, 0, &node->sei.data, &node->sei.size);
2504 if (status < 0) {
2505 goto out;
2506 }
2507 }
2508#endif
2509
2510 time = CMTimeMake(frame->pts * avctx->time_base.num, avctx->time_base.den);
2511 status = VTCompressionSessionEncodeFrame(
2512 vtctx->session,
2513 cv_img,
2514 time,
2515 kCMTimeInvalid,
2516 frame_dict,
2517 node,
2518 NULL
2519 );
2520
2521 if (status) {
2522 av_log(avctx, AV_LOG_ERROR, "Cannot encode frame: %d\n", status);
2523 status = AVERROR_EXTERNAL;
2524 // Not necessary, just in case new code put after here
2525 goto out;
2526 }
2527
2528out:
2529 if (frame_dict)
2530 CFRelease(frame_dict);
2531 if (cv_img)
2532 CFRelease(cv_img);
2533 if (status)
2534 vtenc_free_buf_node(node);
2535
2536 return status;
2537}
2538
2540 AVCodecContext *avctx,
2541 AVPacket *pkt,
2542 const AVFrame *frame,
2543 int *got_packet)
2544{
2545 VTEncContext *vtctx = avctx->priv_data;
2546 bool get_frame;
2547 int status;
2548 CMSampleBufferRef buf = NULL;
2549 ExtraSEI sei = {0};
2550
2551 if (frame) {
2552 status = vtenc_send_frame(avctx, vtctx, frame);
2553
2554 if (status) {
2555 status = AVERROR_EXTERNAL;
2556 goto end_nopkt;
2557 }
2558
2559 if (vtctx->frame_ct_in == 0) {
2560 vtctx->first_pts = frame->pts;
2561 } else if(vtctx->frame_ct_in == vtctx->has_b_frames) {
2562 vtctx->dts_delta = frame->pts - vtctx->first_pts;
2563 }
2564
2565 vtctx->frame_ct_in++;
2566 } else if(!vtctx->flushing) {
2567 vtctx->flushing = true;
2568
2569 status = VTCompressionSessionCompleteFrames(vtctx->session,
2570 kCMTimeIndefinite);
2571
2572 if (status) {
2573 av_log(avctx, AV_LOG_ERROR, "Error flushing frames: %d\n", status);
2574 status = AVERROR_EXTERNAL;
2575 goto end_nopkt;
2576 }
2577 }
2578
2579 *got_packet = 0;
2580 get_frame = vtctx->dts_delta >= 0 || !frame;
2581 if (!get_frame) {
2582 status = 0;
2583 goto end_nopkt;
2584 }
2585
2586 status = vtenc_q_pop(vtctx, !frame, &buf, &sei);
2587 if (status) goto end_nopkt;
2588 if (!buf) goto end_nopkt;
2589
2590 status = vtenc_cm_to_avpacket(avctx, buf, pkt, sei.data ? &sei : NULL);
2591 av_free(sei.data);
2592 CFRelease(buf);
2593 if (status) goto end_nopkt;
2594
2595 *got_packet = 1;
2596 return 0;
2597
2598end_nopkt:
2600 return status;
2601}
2602
2604 CMVideoCodecType codec_type,
2605 CFStringRef profile_level,
2606 CFNumberRef gamma_level,
2607 CFDictionaryRef enc_info,
2608 CFDictionaryRef pixel_buffer_info)
2609{
2610 VTEncContext *vtctx = avctx->priv_data;
2611 int status;
2612 CVPixelBufferPoolRef pool = NULL;
2613 CVPixelBufferRef pix_buf = NULL;
2614 CMTime time;
2615 CMSampleBufferRef buf = NULL;
2616 BufNode *node = av_mallocz(sizeof(*node));
2617
2618 if (!node)
2619 return AVERROR(ENOMEM);
2620
2621 status = vtenc_create_encoder(avctx,
2622 codec_type,
2623 profile_level,
2624 gamma_level,
2625 enc_info,
2626 pixel_buffer_info,
2627 vtctx->constant_bit_rate,
2628 &vtctx->session);
2629 if (status)
2630 goto pe_cleanup;
2631
2632 pool = VTCompressionSessionGetPixelBufferPool(vtctx->session);
2633 if(!pool){
2634 av_log(avctx, AV_LOG_ERROR, "Error getting pixel buffer pool.\n");
2635 status = AVERROR_EXTERNAL;
2636 goto pe_cleanup;
2637 }
2638
2639 status = CVPixelBufferPoolCreatePixelBuffer(NULL,
2640 pool,
2641 &pix_buf);
2642
2643 if(status != kCVReturnSuccess){
2644 av_log(avctx, AV_LOG_ERROR, "Error creating frame from pool: %d\n", status);
2645 status = AVERROR_EXTERNAL;
2646 goto pe_cleanup;
2647 }
2648
2649 time = CMTimeMake(0, avctx->time_base.den);
2650 status = VTCompressionSessionEncodeFrame(vtctx->session,
2651 pix_buf,
2652 time,
2653 kCMTimeInvalid,
2654 NULL,
2655 node,
2656 NULL);
2657
2658 if (status) {
2659 av_log(avctx,
2661 "Error sending frame for extradata: %d\n",
2662 status);
2663 status = AVERROR_EXTERNAL;
2664 goto pe_cleanup;
2665 }
2666 node = NULL;
2667
2668 //Populates extradata - output frames are flushed and param sets are available.
2669 status = VTCompressionSessionCompleteFrames(vtctx->session,
2670 kCMTimeIndefinite);
2671
2672 if (status) {
2673 status = AVERROR_EXTERNAL;
2674 goto pe_cleanup;
2675 }
2676
2677 status = vtenc_q_pop(vtctx, 0, &buf, NULL);
2678 if (status) {
2679 av_log(avctx, AV_LOG_ERROR, "popping: %d\n", status);
2680 goto pe_cleanup;
2681 }
2682
2683 CFRelease(buf);
2684
2685
2686
2687pe_cleanup:
2688 CVPixelBufferRelease(pix_buf);
2689
2690 if (status) {
2691 vtenc_reset(vtctx);
2692 } else if (vtctx->session) {
2693 CFRelease(vtctx->session);
2694 vtctx->session = NULL;
2695 }
2696
2697 vtctx->frame_ct_out = 0;
2698
2699 av_assert0(status != 0 || (avctx->extradata && avctx->extradata_size > 0));
2700 if (!status)
2701 vtenc_free_buf_node(node);
2702
2703 return status;
2704}
2705
2707{
2708 VTEncContext *vtctx = avctx->priv_data;
2709
2710 if(!vtctx->session) {
2712 pthread_mutex_destroy(&vtctx->lock);
2713 return 0;
2714 }
2715
2716 VTCompressionSessionCompleteFrames(vtctx->session,
2717 kCMTimeIndefinite);
2718 clear_frame_queue(vtctx);
2720 pthread_mutex_destroy(&vtctx->lock);
2721
2722 vtenc_reset(vtctx);
2723
2724 return 0;
2725}
2726
2733
2744
2745static const enum AVPixelFormat prores_pix_fmts[] = {
2748#ifdef kCFCoreFoundationVersionNumber10_7
2751#endif
2753#if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
2755#endif
2756#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
2758#endif
2759#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
2761#endif
2762#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
2764#endif
2765#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
2767#endif
2768#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
2770#endif
2771#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
2773#endif
2776};
2777
2778#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
2779#define COMMON_OPTIONS \
2780 { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, \
2781 { .i64 = 0 }, 0, 1, VE }, \
2782 { "require_sw", "Require software encoding", OFFSET(require_sw), AV_OPT_TYPE_BOOL, \
2783 { .i64 = 0 }, 0, 1, VE }, \
2784 { "realtime", "Hint that encoding should happen in real-time if not faster (e.g. capturing from camera).", \
2785 OFFSET(realtime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, -1, 1, VE }, \
2786 { "frames_before", "Other frames will come before the frames in this session. This helps smooth concatenation issues.", \
2787 OFFSET(frames_before), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \
2788 { "frames_after", "Other frames will come after the frames in this session. This helps smooth concatenation issues.", \
2789 OFFSET(frames_after), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \
2790 { "prio_speed", "prioritize encoding speed", OFFSET(prio_speed), AV_OPT_TYPE_BOOL, \
2791 { .i64 = -1 }, -1, 1, VE }, \
2792 { "power_efficient", "Set to 1 to enable more power-efficient encoding if supported.", \
2793 OFFSET(power_efficient), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \
2794 { "spatial_aq", "Set to 1 to enable spatial AQ if supported.", \
2795 OFFSET(spatialaq), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \
2796 { "max_ref_frames", \
2797 "Sets the maximum number of reference frames. This only has an effect when the value is less than the maximum allowed by the profile/level.", \
2798 OFFSET(max_ref_frames), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
2799
2801 HW_CONFIG_ENCODER_FRAMES(VIDEOTOOLBOX, VIDEOTOOLBOX),
2802 NULL,
2803};
2804
2805#define OFFSET(x) offsetof(VTEncContext, x)
2806static const AVOption h264_options[] = {
2807 { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, INT_MAX, VE, .unit = "profile" },
2808 { "baseline", "Baseline Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_H264_BASELINE }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2809 { "constrained_baseline", "Constrained Baseline Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_H264_CONSTRAINED_BASELINE }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2810 { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_H264_MAIN }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2811 { "high", "High Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_H264_HIGH }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2812 { "constrained_high", "Constrained High Profile", 0, AV_OPT_TYPE_CONST, { .i64 = H264_PROFILE_CONSTRAINED_HIGH }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2813 { "extended", "Extend Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_H264_EXTENDED }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2814
2815 { "level", "Level", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 52, VE, .unit = "level" },
2816 { "1.3", "Level 1.3, only available with Baseline Profile", 0, AV_OPT_TYPE_CONST, { .i64 = 13 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2817 { "3.0", "Level 3.0", 0, AV_OPT_TYPE_CONST, { .i64 = 30 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2818 { "3.1", "Level 3.1", 0, AV_OPT_TYPE_CONST, { .i64 = 31 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2819 { "3.2", "Level 3.2", 0, AV_OPT_TYPE_CONST, { .i64 = 32 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2820 { "4.0", "Level 4.0", 0, AV_OPT_TYPE_CONST, { .i64 = 40 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2821 { "4.1", "Level 4.1", 0, AV_OPT_TYPE_CONST, { .i64 = 41 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2822 { "4.2", "Level 4.2", 0, AV_OPT_TYPE_CONST, { .i64 = 42 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2823 { "5.0", "Level 5.0", 0, AV_OPT_TYPE_CONST, { .i64 = 50 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2824 { "5.1", "Level 5.1", 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2825 { "5.2", "Level 5.2", 0, AV_OPT_TYPE_CONST, { .i64 = 52 }, INT_MIN, INT_MAX, VE, .unit = "level" },
2826
2827 { "coder", "Entropy coding", OFFSET(entropy), AV_OPT_TYPE_INT, { .i64 = VT_ENTROPY_NOT_SET }, VT_ENTROPY_NOT_SET, VT_CABAC, VE, .unit = "coder" },
2828 { "cavlc", "CAVLC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CAVLC }, INT_MIN, INT_MAX, VE, .unit = "coder" },
2829 { "vlc", "CAVLC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CAVLC }, INT_MIN, INT_MAX, VE, .unit = "coder" },
2830 { "cabac", "CABAC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CABAC }, INT_MIN, INT_MAX, VE, .unit = "coder" },
2831 { "ac", "CABAC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CABAC }, INT_MIN, INT_MAX, VE, .unit = "coder" },
2832
2833 { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, VE },
2834
2835 { "constant_bit_rate", "Require constant bit rate (macOS 13 or newer)", OFFSET(constant_bit_rate), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
2836 { "max_slice_bytes", "Set the maximum number of bytes in an H.264 slice.", OFFSET(max_slice_bytes), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE },
2838 { NULL },
2839};
2840
2841static const FFCodecDefault vt_defaults[] = {
2842 {"b", "0"},
2843 {"qmin", "-1"},
2844 {"qmax", "-1"},
2845 {NULL},
2846};
2847
2849 .class_name = "h264_videotoolbox",
2850 .item_name = av_default_item_name,
2851 .option = h264_options,
2852 .version = LIBAVUTIL_VERSION_INT,
2853};
2854
2856 .p.name = "h264_videotoolbox",
2857 CODEC_LONG_NAME("VideoToolbox H.264 Encoder"),
2858 .p.type = AVMEDIA_TYPE_VIDEO,
2859 .p.id = AV_CODEC_ID_H264,
2860 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
2862 .priv_data_size = sizeof(VTEncContext),
2864 .defaults = vt_defaults,
2865 .init = vtenc_init,
2867 .close = vtenc_close,
2868 .p.priv_class = &h264_videotoolbox_class,
2869 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
2870 .p.wrapper_name = "videotoolbox",
2871 .hw_configs = vt_encode_hw_configs,
2872};
2873
2874static const AVOption hevc_options[] = {
2875 { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, INT_MAX, VE, .unit = "profile" },
2876 { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_MAIN }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2877 { "main10", "Main10 Profile", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_MAIN_10 }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2878 { "main42210","Main 4:2:2 10 Profile",0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_REXT }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2879 { "rext", "Main 4:2:2 10 Profile",0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_HEVC_REXT }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2880
2881 { "alpha_quality", "Compression quality for the alpha channel", OFFSET(alpha_quality), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0.0, 1.0, VE },
2882
2883 { "constant_bit_rate", "Require constant bit rate (macOS 13 or newer)", OFFSET(constant_bit_rate), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
2884
2886 { NULL },
2887};
2888
2890 .class_name = "hevc_videotoolbox",
2891 .item_name = av_default_item_name,
2892 .option = hevc_options,
2893 .version = LIBAVUTIL_VERSION_INT,
2894};
2895
2897 .p.name = "hevc_videotoolbox",
2898 CODEC_LONG_NAME("VideoToolbox H.265 Encoder"),
2899 .p.type = AVMEDIA_TYPE_VIDEO,
2900 .p.id = AV_CODEC_ID_HEVC,
2901 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
2903 .priv_data_size = sizeof(VTEncContext),
2905 .defaults = vt_defaults,
2906 .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG,
2907 .init = vtenc_init,
2909 .close = vtenc_close,
2910 .p.priv_class = &hevc_videotoolbox_class,
2911 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
2912 .p.wrapper_name = "videotoolbox",
2913 .hw_configs = vt_encode_hw_configs,
2914};
2915
2916static const AVOption prores_options[] = {
2917 { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, AV_PROFILE_PRORES_XQ, VE, .unit = "profile" },
2918 { "auto", "Automatically determine based on input format", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2919 { "proxy", "ProRes 422 Proxy", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_PRORES_PROXY }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2920 { "lt", "ProRes 422 LT", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_PRORES_LT }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2921 { "standard", "ProRes 422", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_PRORES_STANDARD }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2922 { "hq", "ProRes 422 HQ", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_PRORES_HQ }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2923 { "4444", "ProRes 4444", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_PRORES_4444 }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2924 { "xq", "ProRes 4444 XQ", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PROFILE_PRORES_XQ }, INT_MIN, INT_MAX, VE, .unit = "profile" },
2925
2927 { NULL },
2928};
2929
2931 .class_name = "prores_videotoolbox",
2932 .item_name = av_default_item_name,
2933 .option = prores_options,
2934 .version = LIBAVUTIL_VERSION_INT,
2935};
2936
2938 .p.name = "prores_videotoolbox",
2939 CODEC_LONG_NAME("VideoToolbox ProRes Encoder"),
2940 .p.type = AVMEDIA_TYPE_VIDEO,
2941 .p.id = AV_CODEC_ID_PRORES,
2942 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
2944 .priv_data_size = sizeof(VTEncContext),
2946 .defaults = vt_defaults,
2947 .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG,
2948 .init = vtenc_init,
2950 .close = vtenc_close,
2951 .p.priv_class = &prores_videotoolbox_class,
2952 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
2953 .p.wrapper_name = "videotoolbox",
2954 .hw_configs = vt_encode_hw_configs,
2955};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static void bit_depth(AudioStatsContext *s, const uint64_t *const mask, uint8_t *depth)
Definition af_astats.c:246
const FFCodec ff_h264_videotoolbox_encoder
const FFCodec ff_hevc_videotoolbox_encoder
const FFCodec ff_prores_videotoolbox_encoder
#define VE
Definition amfenc_av1.c:30
int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len, void **data, size_t *sei_size)
Check AVFrame for A53 side data and allocate and fill SEI message with A53 info.
Definition atsc_a53.c:26
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
static int FUNC sei(CodedBitstreamContext *ctx, RWContext *rw, H264RawSEI *current)
#define CODEC_PIXFMTS_ARRAY(array)
#define FF_CODEC_ENCODE_CB(func)
#define CODEC_LONG_NAME(str)
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static int16_t block[64]
Definition dct.c:125
#define AV_PROFILE_PRORES_STANDARD
Definition defs.h:183
#define AV_PROFILE_PRORES_4444
Definition defs.h:185
#define AV_PROFILE_H264_MAIN
Definition defs.h:112
#define AV_PROFILE_PRORES_LT
Definition defs.h:182
#define AV_PROFILE_H264_EXTENDED
Definition defs.h:113
#define AV_PROFILE_UNKNOWN
Definition defs.h:65
#define AV_PROFILE_PRORES_PROXY
Definition defs.h:181
#define AV_PROFILE_HEVC_REXT
Definition defs.h:162
#define AV_PROFILE_HEVC_MAIN
Definition defs.h:159
#define AV_PROFILE_HEVC_MAIN_10
Definition defs.h:160
#define AV_PROFILE_H264_HIGH
Definition defs.h:114
#define AV_PROFILE_H264_CONSTRAINED_BASELINE
Definition defs.h:111
#define AV_PROFILE_PRORES_XQ
Definition defs.h:186
#define AV_PROFILE_PRORES_HQ
Definition defs.h:184
#define AV_PROFILE_H264_BASELINE
Definition defs.h:110
static AVPacket * pkt
static AVFrame * frame
float fminf(float, float)
int ff_get_encode_buffer(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int flags)
Get a buffer for a packet.
Definition encode.c:106
double value
Definition eval.c:102
const char * key
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_DOUBLE
Underlying C type is double.
Definition opt.h:266
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
#define AV_CODEC_CAP_DELAY
Encoder or decoder requires flushing with NULL input at the end in order to give the complete and cor...
Definition codec.h:79
#define AV_CODEC_FLAG_CLOSED_GOP
Definition avcodec.h:332
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
#define AV_CODEC_FLAG_QSCALE
Use fixed qscale.
Definition avcodec.h:213
#define AV_CODEC_FLAG_GLOBAL_HEADER
Place global headers in extradata instead of every keyframe.
Definition avcodec.h:318
#define AV_CODEC_FLAG_LOW_DELAY
Force low delay.
Definition avcodec.h:314
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition codec_id.h:47
#define AV_CODEC_CAP_HYBRID
Codec is potentially backed by a hardware implementation, but not necessarily.
Definition codec.h:140
@ AV_CODEC_ID_H264
Definition codec_id.h:77
@ AV_CODEC_ID_HEVC
Definition codec_id.h:223
@ AV_CODEC_ID_PRORES
Definition codec_id.h:198
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding.
Definition defs.h:40
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:434
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition packet.h:650
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition buffer.c:139
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition buffer.c:103
#define FF_QP2LAMBDA
factor to convert from H.263 QP to lambda
Definition avutil.h:226
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition error.h:53
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition error.h:52
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
Definition frame.c:659
@ AV_FRAME_DATA_A53_CC
ATSC A53 Part 4 Closed Captions.
Definition frame.h:59
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
Definition rational.c:35
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
static void av_image_copy2(uint8_t *const dst_data[4], const int dst_linesizes[4], uint8_t *const src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Wrapper around av_image_copy() to workaround the limitation that the conversion from uint8_t * const ...
Definition imgutils.h:184
@ AV_PICTURE_TYPE_I
Intra.
Definition avutil.h:278
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
H.264 common definitions.
@ H264_NAL_PPS
Definition h264.h:42
@ H264_NAL_SPS
Definition h264.h:41
@ H264_NAL_SEI
Definition h264.h:40
@ H264_NAL_AUD
Definition h264.h:43
#define HW_CONFIG_ENCODER_FRAMES(format, device_type_)
Definition hwconfig.h:100
cl_device_type type
CFStringRef av_map_videotoolbox_color_matrix_from_av(enum AVColorSpace space)
Convert an AVColorSpace to a VideoToolbox/CoreVideo color matrix string.
CFStringRef av_map_videotoolbox_color_primaries_from_av(enum AVColorPrimaries pri)
Convert an AVColorPrimaries to a VideoToolbox/CoreVideo color primaries string.
uint32_t av_map_videotoolbox_format_from_pixfmt2(enum AVPixelFormat pix_fmt, bool full_range)
Same as av_map_videotoolbox_format_from_pixfmt function, but can map and return full range pixel form...
CFStringRef av_map_videotoolbox_color_trc_from_av(enum AVColorTransferCharacteristic trc)
Convert an AVColorTransferCharacteristic to a VideoToolbox/CoreVideo color transfer function string.
An API-specific header for AV_HWDEVICE_TYPE_VIDEOTOOLBOX.
misc image utilities
unsigned offset
Definition libaomenc.c:763
static const AVOption h264_options[]
Definition h264dec.c:1092
common internal api header.
static const int factor[16]
Definition vf_pp7.c:98
Macro definitions for various function/variable attributes.
#define av_fallthrough
Definition attributes.h:67
#define av_cold
Definition attributes.h:117
const char * desc
Definition libsvtav1.c:83
#define COMMON_OPTIONS
Definition libvpxenc.c:1986
#define MKBETAG(a, b, c, d)
Definition macros.h:56
enum AVColorRange range
static enum AVPixelFormat avc_pix_fmts[]
Memory handling functions.
const char data[16]
Definition mxf.c:149
int profile
Definition mxfenc.c:2299
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
Definition os2threads.h:152
static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
Definition os2threads.h:119
static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
Definition os2threads.h:144
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Definition os2threads.h:104
#define PTHREAD_ONCE_INIT
Definition os2threads.h:71
static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
Definition os2threads.h:133
static av_always_inline int pthread_once(pthread_once_t *once_control, void(*init_routine)(void))
Definition os2threads.h:210
_fmutex pthread_mutex_t
Definition os2threads.h:53
static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
Definition os2threads.h:126
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
Definition os2threads.h:192
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
Definition os2threads.h:112
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3500
const char * av_color_range_name(enum AVColorRange range)
Definition pixdesc.c:3776
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition pixdesc.c:3380
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_FLAG_ALPHA
The pixel format has an alpha channel.
Definition pixdesc.h:147
AVColorRange
Visual content value range.
Definition pixfmt.h:748
@ AVCOL_RANGE_MPEG
Narrow or limited range content.
Definition pixfmt.h:766
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:783
#define AV_PIX_FMT_P210
Definition pixfmt.h:622
#define AV_PIX_FMT_P216
Definition pixfmt.h:626
#define AV_PIX_FMT_P010
Definition pixfmt.h:608
#define AV_PIX_FMT_P410
Definition pixfmt.h:623
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition pixfmt.h:96
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_P010LE
like NV12, with 10bpp per component, data in the high bits, zeros in the low bits,...
Definition pixfmt.h:307
@ AV_PIX_FMT_VIDEOTOOLBOX
hardware decoding through Videotoolbox
Definition pixfmt.h:305
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition pixfmt.h:102
@ AV_PIX_FMT_UYVY422
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition pixfmt.h:88
@ AV_PIX_FMT_NV24
planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition pixfmt.h:371
@ AV_PIX_FMT_NV16
interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:198
@ AV_PIX_FMT_AYUV
packed AYUV 4:4:4:4, 32bpp (1 Cr & Cb sample per 1x1 Y & A samples), AYUVAYUV...
Definition pixfmt.h:442
#define AV_PIX_FMT_P416
Definition pixfmt.h:627
AVColorTransferCharacteristic
Color Transfer Characteristic.
Definition pixfmt.h:672
@ AVCOL_TRC_GAMMA22
also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM
Definition pixfmt.h:677
@ AVCOL_TRC_GAMMA28
also ITU-R BT470BG
Definition pixfmt.h:678
#define AV_PIX_FMT_AYUV64
Definition pixfmt.h:607
const char * name
Definition qsvenc.c:142
#define av_bswap32
Definition bswap.h:47
enum AVMediaType codec_type
Definition rtp.c:37
@ SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35
Definition sei.h:34
A reference to a data buffer.
Definition buffer.h:82
Describe the class of an AVClass context structure.
Definition log.h:76
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
enum AVPixelFormat sw_pix_fmt
Nominal unaccelerated pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:650
int global_quality
Global quality for codecs which cannot change it per frame.
Definition avcodec.h:1235
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition avcodec.h:681
unsigned int codec_tag
fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A').
Definition avcodec.h:468
enum AVColorPrimaries color_primaries
Chromaticity coordinates of the source primaries.
Definition avcodec.h:657
int max_b_frames
maximum number of B-frames between non-B-frames Note: The output will be delayed by max_b_frames+1 re...
Definition avcodec.h:781
int qmin
minimum quantizer
Definition avcodec.h:1252
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown) That is the width of a pixel divided by the height of the pixel.
Definition avcodec.h:628
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition avcodec.h:1564
int has_b_frames
Size of the frame reordering buffer in the decoder.
Definition avcodec.h:709
int64_t bit_rate
the average bitrate
Definition avcodec.h:493
int profile
profile
Definition avcodec.h:1636
enum AVColorSpace colorspace
YUV colorspace type.
Definition avcodec.h:671
int gop_size
the number of pictures in a group of pictures, or 0 for intra_only
Definition avcodec.h:1021
int64_t rc_max_rate
maximum bitrate
Definition avcodec.h:1288
int qmax
maximum quantizer
Definition avcodec.h:1259
enum AVColorTransferCharacteristic color_trc
Color Transfer Characteristic.
Definition avcodec.h:664
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition avcodec.h:547
int flags
AV_CODEC_FLAG_*.
Definition avcodec.h:500
uint8_t * extradata
Out-of-band global headers that may be used by some codecs.
Definition avcodec.h:526
enum AVCodecID codec_id
Definition avcodec.h:453
int extradata_size
Definition avcodec.h:527
void * priv_data
Definition avcodec.h:470
Structure to hold side data for an AVFrame.
Definition frame.h:327
size_t size
Definition frame.h:330
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
uint64_t flags
Combination of AV_PIX_FMT_FLAG_... flags.
Definition pixdesc.h:94
Rational number (pair of numerator and denominator).
Definition rational.h:58
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
ExtraSEI sei
AVBufferRef * frame_buf
CMSampleBufferRef cm_buffer
struct BufNode * next
pthread_cond_t cv_sample_sent
CFStringRef transfer_function
getParameterSetAtIndex get_param_set_func
CFStringRef ycbcr_matrix
CFDictionaryRef supported_props
enum AVCodecID codec_id
pthread_mutex_t lock
VTCompressionSessionRef session
CFStringRef color_primaries
uint8_t level
Definition svq3.c:208
#define av_free(p)
#define av_mallocz(s)
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static FILE * out
Definition movenc.c:55
static AVFormatContext * ctx
Definition movenc.c:49
static char buffer[20]
Definition seek.c:32
static int64_t pts
int size
static int get_frame(AVFilterContext *ctx, int is_second)
Definition vf_nnedi.c:661
@ kCMVideoCodecType_HEVC
static int create_cv_pixel_buffer(AVCodecContext *avctx, const AVFrame *frame, CVPixelBufferRef *cv_img, BufNode *node)
CFStringRef kVTCompressionPropertyKey_ConstantBitRate
static int write_sei(const ExtraSEI *sei, int sei_type, uint8_t *dst, size_t dst_size)
static const AVClass prores_videotoolbox_class
static const AVClass h264_videotoolbox_class
CFStringRef kVTCompressionPropertyKey_MaximizePowerEfficiency
CFStringRef kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder
static int copy_avframe_to_pixel_buffer(AVCodecContext *avctx, const AVFrame *frame, CVPixelBufferRef cv_img)
@ kCMVideoCodecType_HEVCWithAlpha
static av_cold int vtenc_init(AVCodecContext *avctx)
CFStringRef kVTProfileLevel_H264_High_4_0
CFStringRef kVTCompressionPropertyKey_ReferenceBufferCount
static int create_encoder_dict_h264(const AVFrame *frame, CFDictionaryRef *dict_out)
CFStringRef kVTProfileLevel_H264_Main_5_2
@ kVTQPModulationLevel_Default
static struct @270163022166130316376344224307060235304065252011 compat_keys
static int create_cv_pixel_buffer_info(AVCodecContext *avctx, CFMutableDictionaryRef *dict)
static int set_extradata(AVCodecContext *avctx, CMSampleBufferRef sample_buffer)
CFStringRef kCVImageBufferYCbCrMatrix_ITU_R_2020
@ kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange
static int is_post_sei_nal_type(int nal_type)
CFStringRef kVTProfileLevel_H264_High_3_0
static int set_encoder_int_property_or_log(AVCodecContext *avctx, CFStringRef key, const char *print_option_name, int value)
CFStringRef kVTProfileLevel_H264_Main_5_1
CFStringRef kVTProfileLevel_H264_Baseline_4_2
static void vtenc_output_callback(void *ctx, void *sourceFrameCtx, OSStatus status, VTEncodeInfoFlags flags, CMSampleBufferRef sample_buffer)
CFStringRef kVTProfileLevel_H264_High_4_1
static void set_async_error(VTEncContext *vtctx, int err)
static av_cold int vtenc_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet)
getParameterSetAtIndex CMVideoFormatDescriptionGetHEVCParameterSetAtIndex
CFStringRef kVTCompressionPropertyKey_RealTime
CFStringRef kVTCompressionPropertyKey_PrioritizeEncodingSpeedOverQuality
static int vtenc_create_encoder(AVCodecContext *avctx, CMVideoCodecType codec_type, CFStringRef profile_level, CFNumberRef gamma_level, CFDictionaryRef enc_info, CFDictionaryRef pixel_buffer_info, bool constant_bit_rate, VTCompressionSessionRef *session)
CFStringRef kVTProfileLevel_H264_ConstrainedHigh_AutoLevel
CFStringRef kVTProfileLevel_HEVC_Main42210_AutoLevel
CFStringRef kVTProfileLevel_H264_Baseline_5_1
CFStringRef kVTProfileLevel_H264_High_3_1
static int copy_emulation_prev(const uint8_t *src, size_t src_size, uint8_t *dst, ssize_t dst_offset, size_t dst_size)
Copies the data inserting emulation prevention bytes as needed.
static CMVideoCodecType get_cm_codec_type(AVCodecContext *avctx, int profile, double alpha_quality)
static void add_color_attr(AVCodecContext *avctx, CFMutableDictionaryRef dict)
static void clear_frame_queue(VTEncContext *vtctx)
CFStringRef kVTH264EntropyMode_CAVLC
static pthread_once_t once_ctrl
#define H264_PROFILE_CONSTRAINED_HIGH
static const FFCodecDefault vt_defaults[]
static bool get_vt_h264_profile_level(AVCodecContext *avctx, CFStringRef *profile_level_val)
static int vtenc_send_frame(AVCodecContext *avctx, VTEncContext *vtctx, const AVFrame *frame)
CFStringRef kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder
CFStringRef kVTProfileLevel_H264_Baseline_5_2
static void vt_release_num(CFNumberRef *refPtr)
NULL-safe release of *refPtr, and sets value to NULL.
static const AVOption hevc_options[]
static enum AVPixelFormat hevc_pix_fmts[]
static bool get_vt_hevc_profile_level(AVCodecContext *avctx, CFStringRef *profile_level_val)
static int vt_dump_encoder(AVCodecContext *avctx)
static void vtenc_get_frame_info(CMSampleBufferRef buffer, bool *is_key_frame)
static int vtenc_cm_to_avpacket(AVCodecContext *avctx, CMSampleBufferRef sample_buffer, AVPacket *pkt, ExtraSEI *sei)
CFStringRef kVTProfileLevel_H264_High_4_2
CFStringRef kVTProfileLevel_H264_High_3_2
OSStatus(* getParameterSetAtIndex)(CMFormatDescriptionRef videoDesc, size_t parameterSetIndex, const uint8_t **parameterSetPointerOut, size_t *parameterSetSizeOut, size_t *parameterSetCountOut, int *NALUnitHeaderLengthOut)
static void vtenc_q_push(VTEncContext *vtctx, BufNode *info)
@ kVTQPModulationLevel_Disable
static int find_sei_end(AVCodecContext *avctx, uint8_t *nal_data, size_t nal_size, uint8_t **sei_end)
CFStringRef kVTProfileLevel_H264_Baseline_4_0
CFStringRef kVTProfileLevel_H264_Extended_AutoLevel
static void set_encoder_property_or_log(AVCodecContext *avctx, CFStringRef key, const char *print_option_name, CFTypeRef value)
CFStringRef kCVImageBufferColorPrimaries_ITU_R_2020
VTH264Entropy
@ VT_CAVLC
@ VT_ENTROPY_NOT_SET
@ VT_CABAC
static const uint8_t start_code[]
CFStringRef kVTCompressionPropertyKey_EncoderID
CFStringRef kVTCompressionPropertyKey_MinAllowedFrameQP
CFStringRef kVTCompressionPropertyKey_SpatialAdaptiveQPLevel
static int copy_param_sets(AVCodecContext *avctx, CMVideoFormatDescriptionRef vid_fmt, uint8_t *dst, size_t dst_size)
static bool vtenc_qscale_enabled(void)
CFStringRef kVTProfileLevel_HEVC_Main_AutoLevel
static int get_cv_gamma(AVCodecContext *avctx, CFNumberRef *gamma_level)
static void vtenc_reset(VTEncContext *vtctx)
CFStringRef kCVImageBufferTransferFunction_ITU_R_2020
CFStringRef kVTVideoEncoderSpecification_EnableLowLatencyRateControl
static int count_nalus(size_t length_code_size, CMSampleBufferRef sample_buffer, int *count)
CFStringRef kVTProfileLevel_H264_High_AutoLevel
static int get_length_code_size(AVCodecContext *avctx, CMSampleBufferRef sample_buffer, size_t *size)
static av_cold int vtenc_close(AVCodecContext *avctx)
CFStringRef kVTCompressionPropertyKey_H264EntropyMode
static int vtenc_populate_extradata(AVCodecContext *avctx, CMVideoCodecType codec_type, CFStringRef profile_level, CFNumberRef gamma_level, CFDictionaryRef enc_info, CFDictionaryRef pixel_buffer_info)
CFStringRef kVTH264EntropyMode_CABAC
CFStringRef kVTProfileLevel_H264_Main_AutoLevel
static const AVClass hevc_videotoolbox_class
#define OFFSET(x)
static enum AVPixelFormat prores_pix_fmts[]
CFStringRef kVTCompressionPropertyKey_TargetQualityForAlpha
#define TARGET_CPU_ARM64
static const AVCodecHWConfigInternal *const vt_encode_hw_configs[]
static int copy_replace_length_codes(AVCodecContext *avctx, size_t length_code_size, CMSampleBufferRef sample_buffer, ExtraSEI *sei, uint8_t *dst_data, size_t dst_size)
Copies NAL units and replaces length codes with H.264 Annex B start codes.
static void loadVTEncSymbols(void)
static int get_cv_pixel_format(AVCodecContext *avctx, enum AVPixelFormat fmt, enum AVColorRange range, int *av_pixel_format, int *range_guessed)
CFStringRef kVTProfileLevel_H264_High_5_2
CFStringRef kVTProfileLevel_H264_High_5_1
static int get_sei_msg_bytes(const ExtraSEI *sei, int type)
Returns a sufficient number of bytes to contain the sei data.
#define GET_SYM(symbol, defaultVal)
static int vtenc_q_pop(VTEncContext *vtctx, bool wait, CMSampleBufferRef *buf, ExtraSEI *sei)
static int get_params_size(AVCodecContext *avctx, CMVideoFormatDescriptionRef vid_fmt, size_t *size)
Get the parameter sets from a CMSampleBufferRef.
CFStringRef kVTProfileLevel_HEVC_Main10_AutoLevel
CFStringRef kVTCompressionPropertyKey_MaxAllowedFrameQP
CFStringRef kVTCompressionPropertyKey_AllowOpenGOP
CFStringRef kVTProfileLevel_H264_Baseline_5_0
CFStringRef kVTProfileLevel_H264_Baseline_AutoLevel
@ kCVPixelFormatType_420YpCbCr10BiPlanarFullRange
static int vtenc_configure_encoder(AVCodecContext *avctx)
CFStringRef kVTProfileLevel_H264_Main_4_2
static void vtenc_free_buf_node(BufNode *info)
CFStringRef kVTProfileLevel_H264_ConstrainedBaseline_AutoLevel
static const AVOption prores_options[]
CFStringRef kVTProfileLevel_H264_Extended_5_0
static const uint8_t quality[]
Definition vmixdec.c:58
int len