clang-format: Apply formatting
Code submissions have continually suffered from formatting inconsistencies that constantly have to be addressed. Using clang-format simplifies this by making code formatting more consistent, and allows automation of the code formatting so that maintainers can focus more on the code itself instead of code formatting.
This commit is contained in:
@@ -12,13 +12,11 @@
|
||||
|
||||
#define VT_LOG(level, format, ...) \
|
||||
blog(level, "[VideoToolbox encoder]: " format, ##__VA_ARGS__)
|
||||
#define VT_LOG_ENCODER(encoder, level, format, ...) \
|
||||
#define VT_LOG_ENCODER(encoder, level, format, ...) \
|
||||
blog(level, "[VideoToolbox %s: 'h264']: " format, \
|
||||
obs_encoder_get_name(encoder), \
|
||||
##__VA_ARGS__)
|
||||
obs_encoder_get_name(encoder), ##__VA_ARGS__)
|
||||
#define VT_BLOG(level, format, ...) \
|
||||
VT_LOG_ENCODER(enc->encoder, level, format, \
|
||||
##__VA_ARGS__)
|
||||
VT_LOG_ENCODER(enc->encoder, level, format, ##__VA_ARGS__)
|
||||
|
||||
// Clipped from NSApplication as it is in a ObjC header
|
||||
extern const double NSAppKitVersionNumber;
|
||||
@@ -28,8 +26,7 @@ extern const double NSAppKitVersionNumber;
|
||||
#define APPLE_H264_ENC_ID_SW "com.apple.videotoolbox.videoencoder.h264"
|
||||
|
||||
// Get around missing symbol on 10.8 during compilation
|
||||
enum {
|
||||
kCMFormatDescriptionBridgeError_InvalidParameter_ = -12712,
|
||||
enum { kCMFormatDescriptionBridgeError_InvalidParameter_ = -12712,
|
||||
};
|
||||
|
||||
static bool is_appkit10_9_or_greater()
|
||||
@@ -44,8 +41,7 @@ static DARRAY(struct vt_encoder {
|
||||
const char *codec_name;
|
||||
}) vt_encoders;
|
||||
|
||||
struct vt_h264_encoder
|
||||
{
|
||||
struct vt_h264_encoder {
|
||||
obs_encoder_t *encoder;
|
||||
|
||||
const char *vt_encoder_id;
|
||||
@@ -74,11 +70,11 @@ struct vt_h264_encoder
|
||||
};
|
||||
|
||||
static void log_osstatus(int log_level, struct vt_h264_encoder *enc,
|
||||
const char *context, OSStatus code)
|
||||
const char *context, OSStatus code)
|
||||
{
|
||||
char *c_str = NULL;
|
||||
CFErrorRef err = CFErrorCreate(kCFAllocatorDefault,
|
||||
kCFErrorDomainOSStatus, code, NULL);
|
||||
kCFErrorDomainOSStatus, code, NULL);
|
||||
CFStringRef str = CFErrorCopyDescription(err);
|
||||
|
||||
c_str = cfstr_copy_cstr(str, kCFStringEncodingUTF8);
|
||||
@@ -116,17 +112,19 @@ static CFStringRef obs_to_vt_colorspace(enum video_colorspace cs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define STATUS_CHECK(c) \
|
||||
code = c; \
|
||||
if (code) { \
|
||||
#define STATUS_CHECK(c) \
|
||||
code = c; \
|
||||
if (code) { \
|
||||
log_osstatus(LOG_ERROR, enc, #c, code); \
|
||||
goto fail; \
|
||||
goto fail; \
|
||||
}
|
||||
|
||||
#define SESSION_CHECK(x) if ((code = (x)) != noErr) return code;
|
||||
#define SESSION_CHECK(x) \
|
||||
if ((code = (x)) != noErr) \
|
||||
return code;
|
||||
|
||||
static OSStatus session_set_prop_int(VTCompressionSessionRef session,
|
||||
CFStringRef key, int32_t val)
|
||||
CFStringRef key, int32_t val)
|
||||
{
|
||||
CFNumberRef n = CFNumberCreate(NULL, kCFNumberSInt32Type, &val);
|
||||
OSStatus code = VTSessionSetProperty(session, key, n);
|
||||
@@ -136,7 +134,7 @@ static OSStatus session_set_prop_int(VTCompressionSessionRef session,
|
||||
}
|
||||
|
||||
static OSStatus session_set_prop_str(VTCompressionSessionRef session,
|
||||
CFStringRef key, char *val)
|
||||
CFStringRef key, char *val)
|
||||
{
|
||||
CFStringRef s = CFStringCreateWithFileSystemRepresentation(NULL, val);
|
||||
OSStatus code = VTSessionSetProperty(session, key, s);
|
||||
@@ -146,39 +144,38 @@ static OSStatus session_set_prop_str(VTCompressionSessionRef session,
|
||||
}
|
||||
|
||||
static OSStatus session_set_prop(VTCompressionSessionRef session,
|
||||
CFStringRef key, CFTypeRef val)
|
||||
CFStringRef key, CFTypeRef val)
|
||||
{
|
||||
return VTSessionSetProperty(session, key, val);
|
||||
}
|
||||
|
||||
static OSStatus session_set_bitrate(VTCompressionSessionRef session,
|
||||
int new_bitrate, bool limit_bitrate, int max_bitrate,
|
||||
float max_bitrate_window)
|
||||
int new_bitrate, bool limit_bitrate,
|
||||
int max_bitrate, float max_bitrate_window)
|
||||
{
|
||||
OSStatus code;
|
||||
|
||||
SESSION_CHECK(session_set_prop_int(session,
|
||||
kVTCompressionPropertyKey_AverageBitRate,
|
||||
new_bitrate * 1000));
|
||||
SESSION_CHECK(session_set_prop_int(
|
||||
session, kVTCompressionPropertyKey_AverageBitRate,
|
||||
new_bitrate * 1000));
|
||||
|
||||
if (limit_bitrate) {
|
||||
int32_t cpb_size = max_bitrate * 125 * max_bitrate_window;
|
||||
|
||||
CFNumberRef cf_cpb_size = CFNumberCreate(NULL,
|
||||
kCFNumberIntType, &cpb_size);
|
||||
CFNumberRef cf_cpb_window_s = CFNumberCreate(NULL,
|
||||
kCFNumberFloatType, &max_bitrate_window);
|
||||
CFNumberRef cf_cpb_size =
|
||||
CFNumberCreate(NULL, kCFNumberIntType, &cpb_size);
|
||||
CFNumberRef cf_cpb_window_s = CFNumberCreate(
|
||||
NULL, kCFNumberFloatType, &max_bitrate_window);
|
||||
|
||||
CFMutableArrayRef rate_control = CFArrayCreateMutable(
|
||||
kCFAllocatorDefault, 2,
|
||||
&kCFTypeArrayCallBacks);
|
||||
kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks);
|
||||
|
||||
CFArrayAppendValue(rate_control, cf_cpb_size);
|
||||
CFArrayAppendValue(rate_control, cf_cpb_window_s);
|
||||
|
||||
code = session_set_prop(session,
|
||||
kVTCompressionPropertyKey_DataRateLimits,
|
||||
rate_control);
|
||||
code = session_set_prop(
|
||||
session, kVTCompressionPropertyKey_DataRateLimits,
|
||||
rate_control);
|
||||
|
||||
CFRelease(cf_cpb_size);
|
||||
CFRelease(cf_cpb_window_s);
|
||||
@@ -186,7 +183,7 @@ static OSStatus session_set_bitrate(VTCompressionSessionRef session,
|
||||
|
||||
if (code == kVTPropertyNotSupportedErr) {
|
||||
log_osstatus(LOG_WARNING, NULL,
|
||||
"setting DataRateLimits on session", code);
|
||||
"setting DataRateLimits on session", code);
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
@@ -195,21 +192,21 @@ static OSStatus session_set_bitrate(VTCompressionSessionRef session,
|
||||
}
|
||||
|
||||
static OSStatus session_set_colorspace(VTCompressionSessionRef session,
|
||||
enum video_colorspace cs)
|
||||
enum video_colorspace cs)
|
||||
{
|
||||
CFStringRef matrix = obs_to_vt_colorspace(cs);
|
||||
OSStatus code;
|
||||
|
||||
if (matrix != NULL) {
|
||||
SESSION_CHECK(session_set_prop(session,
|
||||
kVTCompressionPropertyKey_ColorPrimaries,
|
||||
kCVImageBufferColorPrimaries_ITU_R_709_2));
|
||||
SESSION_CHECK(session_set_prop(session,
|
||||
kVTCompressionPropertyKey_TransferFunction,
|
||||
kCVImageBufferTransferFunction_ITU_R_709_2));
|
||||
SESSION_CHECK(session_set_prop(session,
|
||||
kVTCompressionPropertyKey_YCbCrMatrix,
|
||||
matrix));
|
||||
SESSION_CHECK(session_set_prop(
|
||||
session, kVTCompressionPropertyKey_ColorPrimaries,
|
||||
kCVImageBufferColorPrimaries_ITU_R_709_2));
|
||||
SESSION_CHECK(session_set_prop(
|
||||
session, kVTCompressionPropertyKey_TransferFunction,
|
||||
kCVImageBufferTransferFunction_ITU_R_709_2));
|
||||
SESSION_CHECK(session_set_prop(
|
||||
session, kVTCompressionPropertyKey_YCbCrMatrix,
|
||||
matrix));
|
||||
}
|
||||
|
||||
return noErr;
|
||||
@@ -218,7 +215,8 @@ static OSStatus session_set_colorspace(VTCompressionSessionRef session,
|
||||
#undef SESSION_CHECK
|
||||
|
||||
void sample_encoded_callback(void *data, void *source, OSStatus status,
|
||||
VTEncodeInfoFlags info_flags, CMSampleBufferRef buffer)
|
||||
VTEncodeInfoFlags info_flags,
|
||||
CMSampleBufferRef buffer)
|
||||
{
|
||||
UNUSED_PARAMETER(status);
|
||||
UNUSED_PARAMETER(info_flags);
|
||||
@@ -231,23 +229,20 @@ void sample_encoded_callback(void *data, void *source, OSStatus status,
|
||||
}
|
||||
CFRelease(pixbuf);
|
||||
}
|
||||
#define ENCODER_ID \
|
||||
kVTVideoEncoderSpecification_EncoderID
|
||||
#define ENCODER_ID kVTVideoEncoderSpecification_EncoderID
|
||||
#define ENABLE_HW_ACCEL \
|
||||
kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder
|
||||
#define REQUIRE_HW_ACCEL \
|
||||
kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder
|
||||
static inline CFMutableDictionaryRef create_encoder_spec(
|
||||
const char *vt_encoder_id)
|
||||
static inline CFMutableDictionaryRef
|
||||
create_encoder_spec(const char *vt_encoder_id)
|
||||
{
|
||||
CFMutableDictionaryRef encoder_spec = CFDictionaryCreateMutable(
|
||||
kCFAllocatorDefault,
|
||||
3,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFStringRef id = CFStringCreateWithFileSystemRepresentation(
|
||||
NULL, vt_encoder_id);
|
||||
CFStringRef id =
|
||||
CFStringCreateWithFileSystemRepresentation(NULL, vt_encoder_id);
|
||||
CFDictionaryAddValue(encoder_spec, ENCODER_ID, id);
|
||||
CFRelease(id);
|
||||
|
||||
@@ -260,17 +255,15 @@ static inline CFMutableDictionaryRef create_encoder_spec(
|
||||
#undef REQUIRE_HW_ACCEL
|
||||
#undef ENABLE_HW_ACCEL
|
||||
|
||||
static inline CFMutableDictionaryRef create_pixbuf_spec(
|
||||
struct vt_h264_encoder *enc)
|
||||
static inline CFMutableDictionaryRef
|
||||
create_pixbuf_spec(struct vt_h264_encoder *enc)
|
||||
{
|
||||
CFMutableDictionaryRef pixbuf_spec = CFDictionaryCreateMutable(
|
||||
kCFAllocatorDefault,
|
||||
3,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFNumberRef n = CFNumberCreate(NULL, kCFNumberSInt32Type,
|
||||
&enc->vt_pix_fmt);
|
||||
CFNumberRef n =
|
||||
CFNumberCreate(NULL, kCFNumberSInt32Type, &enc->vt_pix_fmt);
|
||||
CFDictionaryAddValue(pixbuf_spec, kCVPixelBufferPixelFormatTypeKey, n);
|
||||
CFRelease(n);
|
||||
|
||||
@@ -295,22 +288,16 @@ static bool create_encoder(struct vt_h264_encoder *enc)
|
||||
CFDictionaryRef pixbuf_spec = create_pixbuf_spec(enc);
|
||||
|
||||
STATUS_CHECK(VTCompressionSessionCreate(
|
||||
kCFAllocatorDefault,
|
||||
enc->width,
|
||||
enc->height,
|
||||
kCMVideoCodecType_H264,
|
||||
encoder_spec,
|
||||
pixbuf_spec,
|
||||
NULL,
|
||||
&sample_encoded_callback,
|
||||
enc->queue,
|
||||
&s));
|
||||
kCFAllocatorDefault, enc->width, enc->height,
|
||||
kCMVideoCodecType_H264, encoder_spec, pixbuf_spec, NULL,
|
||||
&sample_encoded_callback, enc->queue, &s));
|
||||
|
||||
CFRelease(encoder_spec);
|
||||
CFRelease(pixbuf_spec);
|
||||
|
||||
CFBooleanRef b = NULL;
|
||||
code = VTSessionCopyProperty(s,
|
||||
code = VTSessionCopyProperty(
|
||||
s,
|
||||
kVTCompressionPropertyKey_UsingHardwareAcceleratedVideoEncoder,
|
||||
NULL, &b);
|
||||
|
||||
@@ -322,35 +309,35 @@ static bool create_encoder(struct vt_h264_encoder *enc)
|
||||
if (b != NULL)
|
||||
CFRelease(b);
|
||||
|
||||
STATUS_CHECK(session_set_prop_int(s,
|
||||
kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration,
|
||||
enc->keyint));
|
||||
STATUS_CHECK(session_set_prop_int(s,
|
||||
kVTCompressionPropertyKey_MaxKeyFrameInterval,
|
||||
enc->keyint * ((float)enc->fps_num/enc->fps_den)));
|
||||
STATUS_CHECK(session_set_prop_int(s,
|
||||
kVTCompressionPropertyKey_ExpectedFrameRate,
|
||||
ceil((float)enc->fps_num/ enc->fps_den)));
|
||||
STATUS_CHECK(session_set_prop(s,
|
||||
kVTCompressionPropertyKey_AllowFrameReordering,
|
||||
enc->bframes ? kCFBooleanTrue : kCFBooleanFalse));
|
||||
STATUS_CHECK(session_set_prop_int(
|
||||
s, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration,
|
||||
enc->keyint));
|
||||
STATUS_CHECK(session_set_prop_int(
|
||||
s, kVTCompressionPropertyKey_MaxKeyFrameInterval,
|
||||
enc->keyint * ((float)enc->fps_num / enc->fps_den)));
|
||||
STATUS_CHECK(session_set_prop_int(
|
||||
s, kVTCompressionPropertyKey_ExpectedFrameRate,
|
||||
ceil((float)enc->fps_num / enc->fps_den)));
|
||||
STATUS_CHECK(session_set_prop(
|
||||
s, kVTCompressionPropertyKey_AllowFrameReordering,
|
||||
enc->bframes ? kCFBooleanTrue : kCFBooleanFalse));
|
||||
|
||||
// This can fail depending on hardware configuration
|
||||
code = session_set_prop(s, kVTCompressionPropertyKey_RealTime,
|
||||
kCFBooleanTrue);
|
||||
kCFBooleanTrue);
|
||||
if (code != noErr)
|
||||
log_osstatus(LOG_WARNING, enc,
|
||||
"setting "
|
||||
"kVTCompressionPropertyKey_RealTime, "
|
||||
"frame delay might be increased",
|
||||
code);
|
||||
"setting "
|
||||
"kVTCompressionPropertyKey_RealTime, "
|
||||
"frame delay might be increased",
|
||||
code);
|
||||
|
||||
STATUS_CHECK(session_set_prop(s,
|
||||
kVTCompressionPropertyKey_ProfileLevel,
|
||||
obs_to_vt_profile(enc->profile)));
|
||||
STATUS_CHECK(session_set_prop(s, kVTCompressionPropertyKey_ProfileLevel,
|
||||
obs_to_vt_profile(enc->profile)));
|
||||
|
||||
STATUS_CHECK(session_set_bitrate(s, enc->bitrate, enc->limit_bitrate,
|
||||
enc->rc_max_bitrate, enc->rc_max_bitrate_window));
|
||||
enc->rc_max_bitrate,
|
||||
enc->rc_max_bitrate_window));
|
||||
|
||||
STATUS_CHECK(session_set_colorspace(s, enc->colorspace));
|
||||
|
||||
@@ -386,7 +373,8 @@ static void vt_h264_destroy(void *data)
|
||||
|
||||
static void dump_encoder_info(struct vt_h264_encoder *enc)
|
||||
{
|
||||
VT_BLOG(LOG_INFO, "settings:\n"
|
||||
VT_BLOG(LOG_INFO,
|
||||
"settings:\n"
|
||||
"\tvt_encoder_id %s\n"
|
||||
"\tbitrate: %d (kbps)\n"
|
||||
"\tfps_num: %d\n"
|
||||
@@ -399,19 +387,12 @@ static void dump_encoder_info(struct vt_h264_encoder *enc)
|
||||
"\trc_max_bitrate_window: %f (s)\n"
|
||||
"\thw_enc: %s\n"
|
||||
"\tprofile: %s\n",
|
||||
enc->vt_encoder_id,
|
||||
enc->bitrate,
|
||||
enc->fps_num,
|
||||
enc->fps_den,
|
||||
enc->width,
|
||||
enc->height,
|
||||
enc->keyint,
|
||||
enc->limit_bitrate ? "on" : "off",
|
||||
enc->rc_max_bitrate,
|
||||
enc->rc_max_bitrate_window,
|
||||
enc->hw_enc ? "on" : "off",
|
||||
(enc->profile != NULL && !!strlen(enc->profile))
|
||||
? enc->profile : "default");
|
||||
enc->vt_encoder_id, enc->bitrate, enc->fps_num, enc->fps_den,
|
||||
enc->width, enc->height, enc->keyint,
|
||||
enc->limit_bitrate ? "on" : "off", enc->rc_max_bitrate,
|
||||
enc->rc_max_bitrate_window, enc->hw_enc ? "on" : "off",
|
||||
(enc->profile != NULL && !!strlen(enc->profile)) ? enc->profile
|
||||
: "default");
|
||||
}
|
||||
|
||||
static void vt_h264_video_info(void *data, struct video_scale_info *info)
|
||||
@@ -420,8 +401,9 @@ static void vt_h264_video_info(void *data, struct video_scale_info *info)
|
||||
|
||||
if (info->format == VIDEO_FORMAT_I420) {
|
||||
enc->obs_pix_fmt = info->format;
|
||||
enc->vt_pix_fmt = enc->fullrange ?
|
||||
kCVPixelFormatType_420YpCbCr8PlanarFullRange
|
||||
enc->vt_pix_fmt =
|
||||
enc->fullrange
|
||||
? kCVPixelFormatType_420YpCbCr8PlanarFullRange
|
||||
: kCVPixelFormatType_420YpCbCr8Planar;
|
||||
return;
|
||||
}
|
||||
@@ -431,8 +413,9 @@ static void vt_h264_video_info(void *data, struct video_scale_info *info)
|
||||
|
||||
// Anything else, return default
|
||||
enc->obs_pix_fmt = VIDEO_FORMAT_NV12;
|
||||
enc->vt_pix_fmt = enc->fullrange ?
|
||||
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
|
||||
enc->vt_pix_fmt =
|
||||
enc->fullrange
|
||||
? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
|
||||
: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
|
||||
|
||||
info->format = enc->obs_pix_fmt;
|
||||
@@ -443,7 +426,7 @@ static void update_params(struct vt_h264_encoder *enc, obs_data_t *settings)
|
||||
video_t *video = obs_encoder_video(enc->encoder);
|
||||
const struct video_output_info *voi = video_output_get_info(video);
|
||||
|
||||
struct video_scale_info info = { .format = voi->format };
|
||||
struct video_scale_info info = {.format = voi->format};
|
||||
|
||||
enc->fullrange = voi->range == VIDEO_RANGE_FULL;
|
||||
|
||||
@@ -461,8 +444,8 @@ static void update_params(struct vt_h264_encoder *enc, obs_data_t *settings)
|
||||
enc->profile = obs_data_get_string(settings, "profile");
|
||||
enc->limit_bitrate = obs_data_get_bool(settings, "limit_bitrate");
|
||||
enc->rc_max_bitrate = obs_data_get_int(settings, "max_bitrate");
|
||||
enc->rc_max_bitrate_window = obs_data_get_double(settings,
|
||||
"max_bitrate_window");
|
||||
enc->rc_max_bitrate_window =
|
||||
obs_data_get_double(settings, "max_bitrate_window");
|
||||
enc->bframes = obs_data_get_bool(settings, "bframes");
|
||||
}
|
||||
|
||||
@@ -479,34 +462,35 @@ static bool vt_h264_update(void *data, obs_data_t *settings)
|
||||
old_limit_bitrate == enc->limit_bitrate)
|
||||
return true;
|
||||
|
||||
OSStatus code = session_set_bitrate(enc->session,
|
||||
enc->bitrate, enc->limit_bitrate, enc->rc_max_bitrate,
|
||||
enc->rc_max_bitrate_window);
|
||||
OSStatus code = session_set_bitrate(enc->session, enc->bitrate,
|
||||
enc->limit_bitrate,
|
||||
enc->rc_max_bitrate,
|
||||
enc->rc_max_bitrate_window);
|
||||
if (code != noErr)
|
||||
VT_BLOG(LOG_WARNING,
|
||||
"failed to set bitrate to session");
|
||||
VT_BLOG(LOG_WARNING, "failed to set bitrate to session");
|
||||
|
||||
CFNumberRef n;
|
||||
VTSessionCopyProperty(enc->session,
|
||||
kVTCompressionPropertyKey_AverageBitRate, NULL,
|
||||
&n);
|
||||
kVTCompressionPropertyKey_AverageBitRate, NULL,
|
||||
&n);
|
||||
|
||||
uint32_t session_bitrate;
|
||||
CFNumberGetValue(n, kCFNumberIntType, &session_bitrate);
|
||||
CFRelease(n);
|
||||
|
||||
if (session_bitrate == old_bitrate) {
|
||||
VT_BLOG(LOG_WARNING, "failed to update current session "
|
||||
" bitrate from %d->%d",
|
||||
old_bitrate, enc->bitrate);
|
||||
VT_BLOG(LOG_WARNING,
|
||||
"failed to update current session "
|
||||
" bitrate from %d->%d",
|
||||
old_bitrate, enc->bitrate);
|
||||
}
|
||||
|
||||
dump_encoder_info(enc);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *vt_h264_create(obs_data_t *settings,
|
||||
obs_encoder_t *encoder, const char *vt_encoder_id)
|
||||
static void *vt_h264_create(obs_data_t *settings, obs_encoder_t *encoder,
|
||||
const char *vt_encoder_id)
|
||||
{
|
||||
struct vt_h264_encoder *enc = bzalloc(sizeof(struct vt_h264_encoder));
|
||||
|
||||
@@ -556,27 +540,28 @@ static void packet_put_startcode(struct darray *packet, int size)
|
||||
}
|
||||
|
||||
static void convert_block_nals_to_annexb(struct vt_h264_encoder *enc,
|
||||
struct darray *packet, CMBlockBufferRef block,
|
||||
int nal_length_bytes)
|
||||
struct darray *packet,
|
||||
CMBlockBufferRef block,
|
||||
int nal_length_bytes)
|
||||
{
|
||||
size_t block_size;
|
||||
uint8_t *block_buf;
|
||||
|
||||
CMBlockBufferGetDataPointer(block, 0, NULL, &block_size,
|
||||
(char **)&block_buf);
|
||||
(char **)&block_buf);
|
||||
|
||||
size_t bytes_remaining = block_size;
|
||||
|
||||
while(bytes_remaining > 0) {
|
||||
while (bytes_remaining > 0) {
|
||||
uint32_t nal_size;
|
||||
if (nal_length_bytes == 1)
|
||||
nal_size = block_buf[0];
|
||||
else if (nal_length_bytes == 2)
|
||||
nal_size = CFSwapInt16BigToHost(
|
||||
((uint16_t *)block_buf)[0]);
|
||||
((uint16_t *)block_buf)[0]);
|
||||
else if (nal_length_bytes == 4)
|
||||
nal_size = CFSwapInt32BigToHost(
|
||||
((uint32_t *)block_buf)[0]);
|
||||
((uint32_t *)block_buf)[0]);
|
||||
else
|
||||
return;
|
||||
|
||||
@@ -597,21 +582,22 @@ static void convert_block_nals_to_annexb(struct vt_h264_encoder *enc,
|
||||
}
|
||||
|
||||
static bool handle_keyframe(struct vt_h264_encoder *enc,
|
||||
CMFormatDescriptionRef format_desc, size_t param_count,
|
||||
struct darray *packet, struct darray *extra_data)
|
||||
CMFormatDescriptionRef format_desc,
|
||||
size_t param_count, struct darray *packet,
|
||||
struct darray *extra_data)
|
||||
{
|
||||
OSStatus code;
|
||||
const uint8_t *param;
|
||||
size_t param_size;
|
||||
|
||||
for(size_t i = 0; i < param_count; i++) {
|
||||
for (size_t i = 0; i < param_count; i++) {
|
||||
code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
|
||||
format_desc, i, ¶m, ¶m_size,
|
||||
NULL, NULL);
|
||||
format_desc, i, ¶m, ¶m_size, NULL, NULL);
|
||||
if (code != noErr) {
|
||||
log_osstatus(LOG_ERROR, enc,
|
||||
"getting NAL parameter "
|
||||
"at index", code);
|
||||
"getting NAL parameter "
|
||||
"at index",
|
||||
code);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -628,35 +614,35 @@ static bool handle_keyframe(struct vt_h264_encoder *enc,
|
||||
}
|
||||
|
||||
static bool convert_sample_to_annexb(struct vt_h264_encoder *enc,
|
||||
struct darray *packet, struct darray *extra_data,
|
||||
CMSampleBufferRef buffer, bool keyframe)
|
||||
struct darray *packet,
|
||||
struct darray *extra_data,
|
||||
CMSampleBufferRef buffer, bool keyframe)
|
||||
{
|
||||
OSStatus code;
|
||||
CMFormatDescriptionRef format_desc =
|
||||
CMSampleBufferGetFormatDescription(buffer);
|
||||
CMSampleBufferGetFormatDescription(buffer);
|
||||
|
||||
size_t param_count;
|
||||
int nal_length_bytes;
|
||||
code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format_desc,
|
||||
0, NULL, NULL, ¶m_count, &nal_length_bytes);
|
||||
code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
|
||||
format_desc, 0, NULL, NULL, ¶m_count, &nal_length_bytes);
|
||||
// it is not clear what errors this function can return
|
||||
// so we check the two most reasonable
|
||||
if (code == kCMFormatDescriptionBridgeError_InvalidParameter_ ||
|
||||
code == kCMFormatDescriptionError_InvalidParameter) {
|
||||
VT_BLOG(LOG_WARNING, "assuming 2 parameter sets "
|
||||
"and 4 byte NAL length header");
|
||||
"and 4 byte NAL length header");
|
||||
param_count = 2;
|
||||
nal_length_bytes = 4;
|
||||
|
||||
} else if (code != noErr) {
|
||||
log_osstatus(LOG_ERROR, enc,
|
||||
"getting parameter count from sample",
|
||||
code);
|
||||
"getting parameter count from sample", code);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyframe && !handle_keyframe(enc, format_desc, param_count,
|
||||
packet, extra_data))
|
||||
if (keyframe &&
|
||||
!handle_keyframe(enc, format_desc, param_count, packet, extra_data))
|
||||
return false;
|
||||
|
||||
CMBlockBufferRef block = CMSampleBufferGetDataBuffer(buffer);
|
||||
@@ -667,13 +653,13 @@ static bool convert_sample_to_annexb(struct vt_h264_encoder *enc,
|
||||
|
||||
static bool is_sample_keyframe(CMSampleBufferRef buffer)
|
||||
{
|
||||
CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(
|
||||
buffer, false);
|
||||
if(attachments != NULL) {
|
||||
CFArrayRef attachments =
|
||||
CMSampleBufferGetSampleAttachmentsArray(buffer, false);
|
||||
if (attachments != NULL) {
|
||||
CFDictionaryRef attachment;
|
||||
CFBooleanRef has_dependencies;
|
||||
attachment = (CFDictionaryRef)CFArrayGetValueAtIndex(
|
||||
attachments, 0);
|
||||
attachment =
|
||||
(CFDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
|
||||
has_dependencies = (CFBooleanRef)CFDictionaryGetValue(
|
||||
attachment, kCMSampleAttachmentKey_DependsOnOthers);
|
||||
return has_dependencies == kCFBooleanFalse;
|
||||
@@ -683,15 +669,15 @@ static bool is_sample_keyframe(CMSampleBufferRef buffer)
|
||||
}
|
||||
|
||||
static bool parse_sample(struct vt_h264_encoder *enc, CMSampleBufferRef buffer,
|
||||
struct encoder_packet *packet, CMTime off)
|
||||
struct encoder_packet *packet, CMTime off)
|
||||
{
|
||||
CMTime pts = CMSampleBufferGetPresentationTimeStamp(buffer);
|
||||
CMTime dts = CMSampleBufferGetDecodeTimeStamp(buffer);
|
||||
|
||||
pts = CMTimeMultiplyByFloat64(pts,
|
||||
((Float64)enc->fps_num/enc->fps_den));
|
||||
((Float64)enc->fps_num / enc->fps_den));
|
||||
dts = CMTimeMultiplyByFloat64(dts,
|
||||
((Float64)enc->fps_num/enc->fps_den));
|
||||
((Float64)enc->fps_num / enc->fps_den));
|
||||
|
||||
// imitate x264's negative dts when bframes might have pts < dts
|
||||
if (enc->bframes)
|
||||
@@ -707,7 +693,7 @@ static bool parse_sample(struct vt_h264_encoder *enc, CMSampleBufferRef buffer,
|
||||
extra_data = &enc->extra_data.da;
|
||||
|
||||
if (!convert_sample_to_annexb(enc, &enc->packet_data.da, extra_data,
|
||||
buffer, keyframe))
|
||||
buffer, keyframe))
|
||||
goto fail;
|
||||
|
||||
packet->type = OBS_ENCODER_VIDEO;
|
||||
@@ -725,20 +711,16 @@ fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_cached_pixel_buffer(struct vt_h264_encoder *enc,
|
||||
CVPixelBufferRef *buf)
|
||||
bool get_cached_pixel_buffer(struct vt_h264_encoder *enc, CVPixelBufferRef *buf)
|
||||
{
|
||||
OSStatus code;
|
||||
CVPixelBufferPoolRef pool =
|
||||
VTCompressionSessionGetPixelBufferPool(
|
||||
enc->session);
|
||||
VTCompressionSessionGetPixelBufferPool(enc->session);
|
||||
if (!pool)
|
||||
return kCVReturnError;
|
||||
|
||||
CVPixelBufferRef pixbuf;
|
||||
STATUS_CHECK(CVPixelBufferPoolCreatePixelBuffer(NULL, pool,
|
||||
&pixbuf));
|
||||
|
||||
STATUS_CHECK(CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &pixbuf));
|
||||
|
||||
// Why aren't these already set on the pixel buffer?
|
||||
// I would have expected pixel buffers from the session's
|
||||
@@ -746,18 +728,14 @@ bool get_cached_pixel_buffer(struct vt_h264_encoder *enc,
|
||||
|
||||
CFStringRef matrix = obs_to_vt_colorspace(enc->colorspace);
|
||||
|
||||
CVBufferSetAttachment(pixbuf,
|
||||
kCVImageBufferYCbCrMatrixKey,
|
||||
matrix,
|
||||
kCVAttachmentMode_ShouldPropagate);
|
||||
CVBufferSetAttachment(pixbuf,
|
||||
kCVImageBufferColorPrimariesKey,
|
||||
kCVImageBufferColorPrimaries_ITU_R_709_2,
|
||||
kCVAttachmentMode_ShouldPropagate);
|
||||
CVBufferSetAttachment(pixbuf,
|
||||
kCVImageBufferTransferFunctionKey,
|
||||
kCVImageBufferTransferFunction_ITU_R_709_2,
|
||||
kCVAttachmentMode_ShouldPropagate);
|
||||
CVBufferSetAttachment(pixbuf, kCVImageBufferYCbCrMatrixKey, matrix,
|
||||
kCVAttachmentMode_ShouldPropagate);
|
||||
CVBufferSetAttachment(pixbuf, kCVImageBufferColorPrimariesKey,
|
||||
kCVImageBufferColorPrimaries_ITU_R_709_2,
|
||||
kCVAttachmentMode_ShouldPropagate);
|
||||
CVBufferSetAttachment(pixbuf, kCVImageBufferTransferFunctionKey,
|
||||
kCVImageBufferTransferFunction_ITU_R_709_2,
|
||||
kCVAttachmentMode_ShouldPropagate);
|
||||
|
||||
*buf = pixbuf;
|
||||
return true;
|
||||
@@ -767,7 +745,7 @@ fail:
|
||||
}
|
||||
|
||||
static bool vt_h264_encode(void *data, struct encoder_frame *frame,
|
||||
struct encoder_packet *packet, bool *received_packet)
|
||||
struct encoder_packet *packet, bool *received_packet)
|
||||
{
|
||||
struct vt_h264_encoder *enc = data;
|
||||
|
||||
@@ -786,17 +764,17 @@ static bool vt_h264_encode(void *data, struct encoder_frame *frame,
|
||||
|
||||
STATUS_CHECK(CVPixelBufferLockBaseAddress(pixbuf, 0));
|
||||
|
||||
for(int i = 0; i < MAX_AV_PLANES; i++) {
|
||||
for (int i = 0; i < MAX_AV_PLANES; i++) {
|
||||
if (frame->data[i] == NULL)
|
||||
break;
|
||||
uint8_t *p = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(
|
||||
pixbuf, i);
|
||||
pixbuf, i);
|
||||
uint8_t *f = frame->data[i];
|
||||
size_t plane_linesize = CVPixelBufferGetBytesPerRowOfPlane(
|
||||
pixbuf, i);
|
||||
size_t plane_linesize =
|
||||
CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
|
||||
size_t plane_height = CVPixelBufferGetHeightOfPlane(pixbuf, i);
|
||||
|
||||
for(size_t j = 0; j < plane_height; j++) {
|
||||
for (size_t j = 0; j < plane_height; j++) {
|
||||
memcpy(p, f, frame->linesize[i]);
|
||||
p += plane_linesize;
|
||||
f += frame->linesize[i];
|
||||
@@ -806,10 +784,10 @@ static bool vt_h264_encode(void *data, struct encoder_frame *frame,
|
||||
STATUS_CHECK(CVPixelBufferUnlockBaseAddress(pixbuf, 0));
|
||||
|
||||
STATUS_CHECK(VTCompressionSessionEncodeFrame(enc->session, pixbuf, pts,
|
||||
dur, NULL, pixbuf, NULL));
|
||||
dur, NULL, pixbuf, NULL));
|
||||
|
||||
CMSampleBufferRef buffer =
|
||||
(CMSampleBufferRef)CMSimpleQueueDequeue(enc->queue);
|
||||
(CMSampleBufferRef)CMSimpleQueueDequeue(enc->queue);
|
||||
|
||||
// No samples waiting in the queue
|
||||
if (buffer == NULL)
|
||||
@@ -845,19 +823,19 @@ static const char *vt_h264_getname_sw(void *unused)
|
||||
return obs_module_text("VTH264EncSW");
|
||||
}
|
||||
|
||||
#define TEXT_VT_ENCODER obs_module_text("VTEncoder")
|
||||
#define TEXT_BITRATE obs_module_text("Bitrate")
|
||||
#define TEXT_USE_MAX_BITRATE obs_module_text("UseMaxBitrate")
|
||||
#define TEXT_MAX_BITRATE obs_module_text("MaxBitrate")
|
||||
#define TEXT_VT_ENCODER obs_module_text("VTEncoder")
|
||||
#define TEXT_BITRATE obs_module_text("Bitrate")
|
||||
#define TEXT_USE_MAX_BITRATE obs_module_text("UseMaxBitrate")
|
||||
#define TEXT_MAX_BITRATE obs_module_text("MaxBitrate")
|
||||
#define TEXT_MAX_BITRATE_WINDOW obs_module_text("MaxBitrateWindow")
|
||||
#define TEXT_KEYINT_SEC obs_module_text("KeyframeIntervalSec")
|
||||
#define TEXT_PROFILE obs_module_text("Profile")
|
||||
#define TEXT_NONE obs_module_text("None")
|
||||
#define TEXT_DEFAULT obs_module_text("DefaultEncoder")
|
||||
#define TEXT_BFRAMES obs_module_text("UseBFrames")
|
||||
#define TEXT_KEYINT_SEC obs_module_text("KeyframeIntervalSec")
|
||||
#define TEXT_PROFILE obs_module_text("Profile")
|
||||
#define TEXT_NONE obs_module_text("None")
|
||||
#define TEXT_DEFAULT obs_module_text("DefaultEncoder")
|
||||
#define TEXT_BFRAMES obs_module_text("UseBFrames")
|
||||
|
||||
static bool limit_bitrate_modified(obs_properties_t *ppts, obs_property_t *p,
|
||||
obs_data_t *settings)
|
||||
obs_data_t *settings)
|
||||
{
|
||||
bool use_max_bitrate = obs_data_get_bool(settings, "limit_bitrate");
|
||||
p = obs_properties_get(ppts, "max_bitrate");
|
||||
@@ -874,25 +852,26 @@ static obs_properties_t *vt_h264_properties(void *unused)
|
||||
obs_properties_t *props = obs_properties_create();
|
||||
obs_property_t *p;
|
||||
|
||||
p = obs_properties_add_int(props, "bitrate",
|
||||
TEXT_BITRATE, 50, 10000000, 50);
|
||||
p = obs_properties_add_int(props, "bitrate", TEXT_BITRATE, 50, 10000000,
|
||||
50);
|
||||
obs_property_int_set_suffix(p, " Kbps");
|
||||
|
||||
p = obs_properties_add_bool(props, "limit_bitrate",
|
||||
TEXT_USE_MAX_BITRATE);
|
||||
TEXT_USE_MAX_BITRATE);
|
||||
obs_property_set_modified_callback(p, limit_bitrate_modified);
|
||||
|
||||
p = obs_properties_add_int(props, "max_bitrate", TEXT_MAX_BITRATE, 50,
|
||||
10000000, 50);
|
||||
10000000, 50);
|
||||
obs_property_int_set_suffix(p, " Kbps");
|
||||
|
||||
obs_properties_add_float(props, "max_bitrate_window",
|
||||
TEXT_MAX_BITRATE_WINDOW, 0.10f, 10.0f, 0.25f);
|
||||
TEXT_MAX_BITRATE_WINDOW, 0.10f, 10.0f, 0.25f);
|
||||
|
||||
obs_properties_add_int(props, "keyint_sec", TEXT_KEYINT_SEC, 0, 20, 1);
|
||||
|
||||
p = obs_properties_add_list(props, "profile", TEXT_PROFILE,
|
||||
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
|
||||
OBS_COMBO_TYPE_LIST,
|
||||
OBS_COMBO_FORMAT_STRING);
|
||||
obs_property_list_add_string(p, TEXT_NONE, "");
|
||||
obs_property_list_add_string(p, "baseline", "baseline");
|
||||
obs_property_list_add_string(p, "main", "main");
|
||||
@@ -923,15 +902,15 @@ void encoder_list_create()
|
||||
VTCopyVideoEncoderList(NULL, &encoder_list);
|
||||
CFIndex size = CFArrayGetCount(encoder_list);
|
||||
|
||||
for(CFIndex i = 0; i < size; i++) {
|
||||
for (CFIndex i = 0; i < size; i++) {
|
||||
CFDictionaryRef encoder_dict =
|
||||
CFArrayGetValueAtIndex(encoder_list, i);
|
||||
CFArrayGetValueAtIndex(encoder_list, i);
|
||||
|
||||
#define VT_DICTSTR(key, name) \
|
||||
CFStringRef name ## _ref = CFDictionaryGetValue(encoder_dict, key); \
|
||||
CFIndex name ## _len = CFStringGetLength(name ## _ref); \
|
||||
char * name = bzalloc(name ## _len + 1); \
|
||||
CFStringGetFileSystemRepresentation(name ## _ref, name, name ## _len);
|
||||
#define VT_DICTSTR(key, name) \
|
||||
CFStringRef name##_ref = CFDictionaryGetValue(encoder_dict, key); \
|
||||
CFIndex name##_len = CFStringGetLength(name##_ref); \
|
||||
char *name = bzalloc(name##_len + 1); \
|
||||
CFStringGetFileSystemRepresentation(name##_ref, name, name##_len);
|
||||
|
||||
VT_DICTSTR(kVTVideoEncoderList_CodecName, codec_name);
|
||||
if (strcmp("H.264", codec_name) != 0) {
|
||||
@@ -945,7 +924,7 @@ void encoder_list_create()
|
||||
.name = name,
|
||||
.id = id,
|
||||
.disp_name = disp_name,
|
||||
.codec_name = codec_name
|
||||
.codec_name = codec_name,
|
||||
};
|
||||
da_push_back(vt_encoders, &enc);
|
||||
#undef VT_DICTSTR
|
||||
@@ -954,7 +933,7 @@ void encoder_list_create()
|
||||
|
||||
void encoder_list_destroy()
|
||||
{
|
||||
for(size_t i = 0; i < vt_encoders.num; i++) {
|
||||
for (size_t i = 0; i < vt_encoders.num; i++) {
|
||||
bfree((char *)vt_encoders.array[i].name);
|
||||
bfree((char *)vt_encoders.array[i].id);
|
||||
bfree((char *)vt_encoders.array[i].codec_name);
|
||||
@@ -966,26 +945,26 @@ void encoder_list_destroy()
|
||||
void register_encoders()
|
||||
{
|
||||
struct obs_encoder_info info = {
|
||||
.type = OBS_ENCODER_VIDEO,
|
||||
.codec = "h264",
|
||||
.destroy = vt_h264_destroy,
|
||||
.encode = vt_h264_encode,
|
||||
.update = vt_h264_update,
|
||||
.type = OBS_ENCODER_VIDEO,
|
||||
.codec = "h264",
|
||||
.destroy = vt_h264_destroy,
|
||||
.encode = vt_h264_encode,
|
||||
.update = vt_h264_update,
|
||||
.get_properties = vt_h264_properties,
|
||||
.get_defaults = vt_h264_defaults,
|
||||
.get_defaults = vt_h264_defaults,
|
||||
.get_video_info = vt_h264_video_info,
|
||||
.get_extra_data = vt_h264_extra_data
|
||||
.get_extra_data = vt_h264_extra_data,
|
||||
};
|
||||
|
||||
for(size_t i = 0; i < vt_encoders.num; i++) {
|
||||
if (strcmp(vt_encoders.array[i].id,
|
||||
APPLE_H264_ENC_ID_HW) == 0) {
|
||||
for (size_t i = 0; i < vt_encoders.num; i++) {
|
||||
if (strcmp(vt_encoders.array[i].id, APPLE_H264_ENC_ID_HW) ==
|
||||
0) {
|
||||
info.id = "vt_h264_hw";
|
||||
info.get_name = vt_h264_getname_hw;
|
||||
info.create = vt_h264_create_hw;
|
||||
obs_register_encoder(&info);
|
||||
} else if (strcmp(vt_encoders.array[i].id,
|
||||
APPLE_H264_ENC_ID_SW) == 0) {
|
||||
APPLE_H264_ENC_ID_SW) == 0) {
|
||||
info.id = "vt_h264_sw";
|
||||
info.get_name = vt_h264_getname_sw;
|
||||
info.create = vt_h264_create_sw;
|
||||
@@ -998,7 +977,7 @@ bool obs_module_load(void)
|
||||
{
|
||||
if (!is_appkit10_9_or_greater()) {
|
||||
VT_LOG(LOG_WARNING, "Not adding VideoToolbox H264 encoder; "
|
||||
"AppKit must be version 10.9 or greater");
|
||||
"AppKit must be version 10.9 or greater");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user