From patchwork Sun Nov 12 18:22:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aman Karmani X-Patchwork-Id: 6017 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.161.94 with SMTP id m30csp1302420jah; Sun, 12 Nov 2017 10:29:05 -0800 (PST) X-Google-Smtp-Source: AGs4zMacngAud9HkqzXrbt+k00g9fh+fBqLgu/HnoBeq9sxZoysiVEoXjP/6OMMAVlM8oeFR9X8Z X-Received: by 10.28.24.203 with SMTP id 194mr4757712wmy.34.1510511345363; Sun, 12 Nov 2017 10:29:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1510511345; cv=none; d=google.com; s=arc-20160816; b=XIcPhzYFVpsVsLF3a7eA2Y1kRfxlM4fhb3WlVsGagNUGg3aU5gZ00JzAX2syYIw+GK F5vIe5eMUQSbkXMegZK4HSNPzcvLDrS04easLawwrtqfP/OXluOTSQoVabX6Gc4fQTPu 7AoEXXe8UQ/PzIZ9GKx7WEbfnaEXvhvKGbnBuOafhDvoM03ZUMMw+Bhjm5v0W5gl2T9r RTZrGrsP9WN8vl2KernnBWj7VP6xQldHBymMb2sp1doDVtYJ6aB+sBjz5AbT3h6EML6D bwE1yPZYLzZjmmBcxY+200ZIlN2y71Kt+V3QPjGNX2j2hUNNRuWwiWOqPgm4JXlkGjZZ bcNg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:message-id:date:to:from:dkim-signature :delivered-to:arc-authentication-results; bh=QCkdTHG/fFDBEI7vsY98WphUEWRsrXvQEBWUspwDBk0=; b=Hfv+BXM4CK22308tnBozaIfoSQkLHDMDZE8yywtwJo87jdnAqJ8qv1w88iV0RhtkeM JyiCuZ6kcInkPN9f3W4CVxegVOjCcEX3ByhSAL+JYoGTg8jUGb0/oTyOhdrS9TT0Tmoq 6pxYS0LButzEIzD0xk4+orWzE9H8UWIhv6i6pGlL7IE3xb0Msh4F0LfdG6kAHzAHXZKE sSz1i6abhTJUctP+7Sb6nZRLM/GJYZBosBH4DkRpB6VZF43Pa37ag4Esp2N9Trh458ep EU0qdfUDHpVhSJ4PY7/NrlySFVcDOqzr9Icz5EpaKS5C32pJ6mXHsLB0kyf4vcUhm3nl DRgw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@tmm1-net.20150623.gappssmtp.com header.s=20150623 header.b=QP7gxgYC; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id 203si4968797wmx.27.2017.11.12.10.29.04; Sun, 12 Nov 2017 10:29:05 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@tmm1-net.20150623.gappssmtp.com header.s=20150623 header.b=QP7gxgYC; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D813068A4B3; Sun, 12 Nov 2017 20:28:49 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf0-f173.google.com (mail-pf0-f173.google.com [209.85.192.173]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C8DCC689DC6 for ; Sun, 12 Nov 2017 20:28:42 +0200 (EET) Received: by mail-pf0-f173.google.com with SMTP id n89so10252578pfk.11 for ; Sun, 12 Nov 2017 10:28:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tmm1-net.20150623.gappssmtp.com; s=20150623; h=sender:from:to:cc:subject:date:message-id; bh=L2zriTjXc6TznNUHBr5iUnDHDwkIniL9017dvYwz1ds=; b=QP7gxgYCr86elitWuXlTmxrN+QUsfuiSAAY9bAmqvV+lVzfFZWw0+dN9TNdfLyOtnM Bhf/QG16MgxSEuhFvY694G//jpZ5cRIlGofcJ0wJDzyVdsj/mfGlsCXb279yMSsXDxPr khuJtfsw6ih30ok2IpOSoohs50gl4VXclWe3KPnRLblyD/LQ/Lg2RIiQDIPBGgEvXYXY B0mRgyeUF7JuT9+M63R12HywGbu4KLg/olpkuE6Y3hRd3qRV7TMa2E8dQ13A3lpM+bK8 6ZNXa/cEs3DRIQ2Wi7oNz0THRjUQmHb3S1hRxKK3ga4YRvYT1ckl0AG4nSWgO5fo/r0F 1urg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id; bh=L2zriTjXc6TznNUHBr5iUnDHDwkIniL9017dvYwz1ds=; b=RvGwJeXlTZU4IZXHG4FH4LfolVstH/BAGlvclDpb1ivDbnNb4vr3La3Mnhrg9UhGUH EscrArz5Iw66ahrCnI8jCXkBy8HT2/BeQcZ0iidMXyMSDICMbFtWpFAfSsD+7bWfgERH d+0dayHoqR5er4NcqYNn0Y2xT4f07mT0FVglXRQ92zToz5sZ5fWph1W9pK1oJa4oOuNr S1xvbaQ2u7hMeIabPNhPtGgo9lEowL01ytSpcpfi/JgFE8XsPT248Ey7z0Qm8J88Z82K iDWmgfr00hXzVhep1q2WWn2Uj2SzybBxmHzC4F9OxlL09GQHPEx3uEwI56RLaZJKmwSU piBg== X-Gm-Message-State: AJaThX67lgfTPV0JX8lM4lgk0EPpsTYHYT3KIIwLUSOhcojYGut00tQ3 PslgE439tedvPCWugV/aebax08op X-Received: by 10.84.218.204 with SMTP id g12mr6620710plm.213.1510510961757; Sun, 12 Nov 2017 10:22:41 -0800 (PST) Received: from tmm1-imac.local.net (c-73-252-174-83.hsd1.ca.comcast.net. [73.252.174.83]) by smtp.gmail.com with ESMTPSA id q8sm31842553pfk.100.2017.11.12.10.22.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 12 Nov 2017 10:22:41 -0800 (PST) From: Aman Gupta To: ffmpeg-devel@ffmpeg.org Date: Sun, 12 Nov 2017 10:22:34 -0800 Message-Id: <20171112182235.28162-1-ffmpeg@tmm1.net> X-Mailer: git-send-email 2.14.2 Subject: [FFmpeg-devel] [PATCH v2 1/2] avcodec/videotoolboxenc: add hevc_videotoolbox encoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: ceffmpeg@gmail.com, Aman Gupta MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Aman Gupta --- configure | 2 + libavcodec/allcodecs.c | 1 + libavcodec/videotoolboxenc.c | 153 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 143 insertions(+), 13 deletions(-) diff --git a/configure b/configure index 2cf18ecc12..39b9d4cb0c 100755 --- a/configure +++ b/configure @@ -2928,6 +2928,8 @@ pcm_mulaw_at_encoder_select="audio_frame_queue" chromaprint_muxer_deps="chromaprint" h264_videotoolbox_encoder_deps="pthreads" h264_videotoolbox_encoder_select="videotoolbox_encoder" +hevc_videotoolbox_encoder_deps="pthreads" +hevc_videotoolbox_encoder_select="videotoolbox_encoder" libcelt_decoder_deps="libcelt" libfdk_aac_decoder_deps="libfdk_aac" libfdk_aac_encoder_deps="libfdk_aac" diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index c817003693..d8be53a52a 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -670,6 +670,7 @@ static void register_all(void) REGISTER_ENCODER(HEVC_QSV, hevc_qsv); REGISTER_ENCODER(HEVC_V4L2M2M, hevc_v4l2m2m); REGISTER_ENCODER(HEVC_VAAPI, hevc_vaapi); + REGISTER_ENCODER(HEVC_VIDEOTOOLBOX, hevc_videotoolbox); REGISTER_ENCODER(LIBKVAZAAR, libkvazaar); REGISTER_DECODER(MJPEG_CUVID, mjpeg_cuvid); REGISTER_ENCODER(MJPEG_QSV, mjpeg_qsv); diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index eba6cc672f..5f6a382672 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -35,6 +35,17 @@ #include "h264_sei.h" #include +#if !HAVE_KCMVIDEOCODECTYPE_HEVC +enum { kCMVideoCodecType_HEVC = 'hvc1' }; +#endif + +typedef OSStatus (*getParameterSetAtIndex)(CMFormatDescriptionRef videoDesc, + size_t parameterSetIndex, + const uint8_t * _Nullable *parameterSetPointerOut, + size_t *parameterSetSizeOut, + size_t *parameterSetCountOut, + int *NALUnitHeaderLengthOut); + //These symbols may not be present static struct{ CFStringRef kCVImageBufferColorPrimaries_ITU_R_2020; @@ -65,10 +76,15 @@ static struct{ CFStringRef kVTProfileLevel_H264_High_5_2; CFStringRef kVTProfileLevel_H264_High_AutoLevel; + CFStringRef kVTProfileLevel_HEVC_Main_AutoLevel; + CFStringRef kVTProfileLevel_HEVC_Main10_AutoLevel; + CFStringRef kVTCompressionPropertyKey_RealTime; CFStringRef kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder; CFStringRef kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder; + + getParameterSetAtIndex CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; } compat_keys; #define GET_SYM(symbol, defaultVal) \ @@ -83,6 +99,12 @@ do{ \ static pthread_once_t once_ctrl = PTHREAD_ONCE_INIT; static void loadVTEncSymbols(){ + compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex = + (getParameterSetAtIndex)dlsym( + RTLD_DEFAULT, + "CMVideoFormatDescriptionGetHEVCParameterSetAtIndex" + ); + GET_SYM(kCVImageBufferColorPrimaries_ITU_R_2020, "ITU_R_2020"); GET_SYM(kCVImageBufferTransferFunction_ITU_R_2020, "ITU_R_2020"); GET_SYM(kCVImageBufferYCbCrMatrix_ITU_R_2020, "ITU_R_2020"); @@ -111,6 +133,9 @@ static void loadVTEncSymbols(){ GET_SYM(kVTProfileLevel_H264_High_5_2, "H264_High_5_2"); GET_SYM(kVTProfileLevel_H264_High_AutoLevel, "H264_High_AutoLevel"); + GET_SYM(kVTProfileLevel_HEVC_Main_AutoLevel, "HEVC_Main_AutoLevel"); + GET_SYM(kVTProfileLevel_HEVC_Main10_AutoLevel, "HEVC_Main10_AutoLevel"); + GET_SYM(kVTCompressionPropertyKey_RealTime, "RealTime"); GET_SYM(kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, @@ -133,6 +158,13 @@ typedef enum VTH264Entropy{ VT_CABAC } VTH264Entropy; +typedef enum VT_HEVCProfile { + HEVC_PROF_AUTO, + HEVC_PROF_MAIN, + HEVC_PROF_MAIN10, + HEVC_PROF_COUNT +} VT_HEVCProfile; + static const uint8_t start_code[] = { 0, 0, 0, 1 }; typedef struct ExtraSEI { @@ -149,10 +181,12 @@ typedef struct BufNode { typedef struct VTEncContext { AVClass *class; + enum AVCodecID codec_id; VTCompressionSessionRef session; CFStringRef ycbcr_matrix; CFStringRef color_primaries; CFStringRef transfer_function; + getParameterSetAtIndex get_param_set_func; pthread_mutex_t lock; pthread_cond_t cv_sample_sent; @@ -348,6 +382,7 @@ static CMVideoCodecType get_cm_codec_type(enum AVCodecID id) { switch (id) { case AV_CODEC_ID_H264: return kCMVideoCodecType_H264; + case AV_CODEC_ID_HEVC: return kCMVideoCodecType_HEVC; default: return 0; } } @@ -365,12 +400,13 @@ static int get_params_size( CMVideoFormatDescriptionRef vid_fmt, size_t *size) { + VTEncContext *vtctx = avctx->priv_data; size_t total_size = 0; size_t ps_count; int is_count_bad = 0; size_t i; int status; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, + status = vtctx->get_param_set_func(vid_fmt, 0, NULL, NULL, @@ -385,7 +421,7 @@ static int get_params_size( for (i = 0; i < ps_count || is_count_bad; i++) { const uint8_t *ps; size_t ps_size; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, + status = vtctx->get_param_set_func(vid_fmt, i, &ps, &ps_size, @@ -419,13 +455,14 @@ static int copy_param_sets( uint8_t *dst, size_t dst_size) { + VTEncContext *vtctx = avctx->priv_data; size_t ps_count; int is_count_bad = 0; int status; size_t offset = 0; size_t i; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, + status = vtctx->get_param_set_func(vid_fmt, 0, NULL, NULL, @@ -443,7 +480,7 @@ static int copy_param_sets( size_t ps_size; size_t next_offset; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, + status = vtctx->get_param_set_func(vid_fmt, i, &ps, &ps_size, @@ -548,6 +585,7 @@ static int get_length_code_size( CMSampleBufferRef sample_buffer, size_t *size) { + VTEncContext *vtctx = avctx->priv_data; CMVideoFormatDescriptionRef vid_fmt; int isize; int status; @@ -558,7 +596,7 @@ static int get_length_code_size( return AVERROR_EXTERNAL; } - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, + status = vtctx->get_param_set_func(vid_fmt, 0, NULL, NULL, @@ -579,8 +617,8 @@ static int get_length_code_size( * If profile_level_val is NULL and this method returns true, don't specify the * profile/level to the encoder. */ -static bool get_vt_profile_level(AVCodecContext *avctx, - CFStringRef *profile_level_val) +static bool get_vt_h264_profile_level(AVCodecContext *avctx, + CFStringRef *profile_level_val) { VTEncContext *vtctx = avctx->priv_data; int64_t profile = vtctx->profile; @@ -670,6 +708,41 @@ static bool get_vt_profile_level(AVCodecContext *avctx, return true; } +/* + * Returns true on success. + * + * If profile_level_val is NULL and this method returns true, don't specify the + * profile/level to the encoder. + */ +static bool get_vt_hevc_profile_level(AVCodecContext *avctx, + CFStringRef *profile_level_val) +{ + VTEncContext *vtctx = avctx->priv_data; + int64_t profile = vtctx->profile; + + *profile_level_val = NULL; + + switch (profile) { + case HEVC_PROF_AUTO: + return true; + case HEVC_PROF_MAIN: + *profile_level_val = + compat_keys.kVTProfileLevel_HEVC_Main_AutoLevel; + break; + case HEVC_PROF_MAIN10: + *profile_level_val = + compat_keys.kVTProfileLevel_HEVC_Main10_AutoLevel; + break; + } + + if (!*profile_level_val) { + av_log(avctx, AV_LOG_ERROR, "Invalid Profile/Level.\n"); + return false; + } + + return true; +} + static int get_cv_pixel_format(AVCodecContext* avctx, enum AVPixelFormat fmt, enum AVColorRange range, @@ -944,6 +1017,8 @@ static int vtenc_create_encoder(AVCodecContext *avctx, return AVERROR_EXTERNAL; } + if (vtctx->codec_id == AV_CODEC_ID_H264) { + // kVTCompressionPropertyKey_DataRateLimits is not available for HEVC bytes_per_second_value = max_rate >> 3; bytes_per_second = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, @@ -959,10 +1034,10 @@ static int vtenc_create_encoder(AVCodecContext *avctx, CFRelease(bytes_per_second); return AVERROR(ENOMEM); } - nums[0] = bytes_per_second; - nums[1] = one_second; + nums[0] = (void *)bytes_per_second; + nums[1] = (void *)one_second; data_rate_limits = CFArrayCreate(kCFAllocatorDefault, - nums, + (const void **)nums, 2, &kCFTypeArrayCallBacks); @@ -992,6 +1067,7 @@ static int vtenc_create_encoder(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "Error setting profile/level property: %d\n", status); } } + } if (avctx->gop_size > 0) { CFNumberRef interval = CFNumberCreate(kCFAllocatorDefault, @@ -1205,6 +1281,11 @@ static av_cold int vtenc_init(AVCodecContext *avctx) return AVERROR(EINVAL); } + vtctx->codec_id = avctx->codec_id; + + if (vtctx->codec_id == AV_CODEC_ID_H264) { + vtctx->get_param_set_func = CMVideoFormatDescriptionGetH264ParameterSetAtIndex; + vtctx->has_b_frames = avctx->max_b_frames > 0; if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){ av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline profile. Output will not contain B-frames.\n"); @@ -1216,7 +1297,11 @@ static av_cold int vtenc_init(AVCodecContext *avctx) vtctx->entropy = VT_ENTROPY_NOT_SET; } - if (!get_vt_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + if (!get_vt_h264_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + } else { + vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; + if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + } vtctx->session = NULL; @@ -2426,7 +2511,7 @@ static const enum AVPixelFormat pix_fmts[] = { #define OFFSET(x) offsetof(VTEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM -static const AVOption options[] = { +static const AVOption h264_options[] = { { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = H264_PROF_AUTO }, H264_PROF_AUTO, H264_PROF_COUNT, VE, "profile" }, { "baseline", "Baseline Profile", 0, AV_OPT_TYPE_CONST, { .i64 = H264_PROF_BASELINE }, INT_MIN, INT_MAX, VE, "profile" }, { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = H264_PROF_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, @@ -2469,7 +2554,7 @@ static const AVOption options[] = { static const AVClass h264_videotoolbox_class = { .class_name = "h264_videotoolbox", .item_name = av_default_item_name, - .option = options, + .option = h264_options, .version = LIBAVUTIL_VERSION_INT, }; @@ -2488,3 +2573,45 @@ AVCodec ff_h264_videotoolbox_encoder = { .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; + +static const AVOption hevc_options[] = { + { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = HEVC_PROF_AUTO }, HEVC_PROF_AUTO, HEVC_PROF_COUNT, VE, "profile" }, + { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = HEVC_PROF_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, + { "main10", "Main10 Profile", 0, AV_OPT_TYPE_CONST, { .i64 = HEVC_PROF_MAIN10 }, INT_MIN, INT_MAX, VE, "profile" }, + + { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, VE }, + + { "realtime", "Hint that encoding should happen in real-time if not faster (e.g. capturing from camera).", + OFFSET(realtime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + { "frames_before", "Other frames will come before the frames in this session. This helps smooth concatenation issues.", + OFFSET(frames_before), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "frames_after", "Other frames will come after the frames in this session. This helps smooth concatenation issues.", + OFFSET(frames_after), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + { NULL }, +}; + +static const AVClass hevc_videotoolbox_class = { + .class_name = "hevc_videotoolbox", + .item_name = av_default_item_name, + .option = hevc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_hevc_videotoolbox_encoder = { + .name = "hevc_videotoolbox", + .long_name = NULL_IF_CONFIG_SMALL("VideoToolbox H.265 Encoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .priv_data_size = sizeof(VTEncContext), + .pix_fmts = pix_fmts, + .init = vtenc_init, + .encode2 = vtenc_frame, + .close = vtenc_close, + .capabilities = AV_CODEC_CAP_DELAY, + .priv_class = &hevc_videotoolbox_class, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +};