2013-12-12 18:13:55 +03:00
/*
* OpenH264 video encoder
* Copyright ( C ) 2014 Martin Storsjo
*
2015-01-07 01:48:23 +02:00
* This file is part of FFmpeg .
2013-12-12 18:13:55 +03:00
*
2015-01-07 01:48:23 +02:00
* FFmpeg is free software ; you can redistribute it and / or
2013-12-12 18:13:55 +03:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
2015-01-07 01:48:23 +02:00
* FFmpeg is distributed in the hope that it will be useful ,
2013-12-12 18:13:55 +03:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
2015-01-07 01:48:23 +02:00
* License along with FFmpeg ; if not , write to the Free Software
2013-12-12 18:13:55 +03:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <wels/codec_api.h>
# include <wels/codec_ver.h>
# include "libavutil/attributes.h"
# include "libavutil/common.h"
2024-03-25 02:30:37 +02:00
# include "libavutil/mem.h"
2013-12-12 18:13:55 +03:00
# include "libavutil/opt.h"
2015-12-08 19:12:33 +02:00
# include "libavutil/internal.h"
2013-12-12 18:13:55 +03:00
# include "libavutil/intreadwrite.h"
# include "libavutil/mathematics.h"
# include "avcodec.h"
2022-03-16 19:18:28 +02:00
# include "codec_internal.h"
2021-04-25 01:43:26 +02:00
# include "encode.h"
2016-06-23 23:58:17 +02:00
# include "libopenh264.h"
2013-12-12 18:13:55 +03:00
2016-07-08 22:21:41 +02:00
# if !OPENH264_VER_AT_LEAST(1, 6)
# define SM_SIZELIMITED_SLICE SM_DYN_SLICE
# endif
2020-04-29 05:00:47 +02:00
# define TARGET_BITRATE_DEFAULT 2*1000*1000
2013-12-12 18:13:55 +03:00
typedef struct SVCContext {
const AVClass * av_class ;
ISVCEncoder * encoder ;
int slice_mode ;
int loopfilter ;
2020-05-06 15:47:50 +02:00
int profile ;
2015-10-08 19:28:55 +02:00
int max_nal_size ;
2015-10-28 11:06:36 +02:00
int skip_frames ;
2015-10-28 11:12:42 +02:00
int skipped ;
2020-05-06 15:47:52 +02:00
int coder ;
2020-04-29 05:00:48 +02:00
// rate control mode
int rc_mode ;
2013-12-12 18:13:55 +03:00
} SVCContext ;
# define OFFSET(x) offsetof(SVCContext, x)
# define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
2020-04-29 05:00:50 +02:00
# define DEPRECATED AV_OPT_FLAG_DEPRECATED
2013-12-12 18:13:55 +03:00
static const AVOption options [ ] = {
2015-09-08 15:53:42 +02:00
{ " loopfilter " , " enable loop filter " , OFFSET ( loopfilter ) , AV_OPT_TYPE_INT , { . i64 = 1 } , 0 , 1 , VE } ,
2024-02-11 16:41:05 +02:00
{ " profile " , " set profile restrictions " , OFFSET ( profile ) , AV_OPT_TYPE_INT , { . i64 = AV_PROFILE_UNKNOWN } , AV_PROFILE_UNKNOWN , 0xffff , VE , . unit = " profile " } ,
# define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, { .i64 = value }, 0, 0, VE, .unit = "profile"
2023-09-02 14:57:41 +02:00
{ PROFILE ( " constrained_baseline " , AV_PROFILE_H264_CONSTRAINED_BASELINE ) } ,
{ PROFILE ( " main " , AV_PROFILE_H264_MAIN ) } ,
{ PROFILE ( " high " , AV_PROFILE_H264_HIGH ) } ,
2020-05-06 15:47:50 +02:00
# undef PROFILE
2015-12-14 20:08:53 +02:00
{ " max_nal_size " , " set maximum NAL size in bytes " , OFFSET ( max_nal_size ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , VE } ,
{ " allow_skip_frames " , " allow skipping frames to hit the target bitrate " , OFFSET ( skip_frames ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , VE } ,
2024-02-11 16:41:05 +02:00
{ " coder " , " Coder type " , OFFSET ( coder ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 1 , VE , . unit = " coder " } ,
{ " default " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = - 1 } , INT_MIN , INT_MAX , VE , . unit = " coder " } ,
{ " cavlc " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , INT_MIN , INT_MAX , VE , . unit = " coder " } ,
{ " cabac " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , INT_MIN , INT_MAX , VE , . unit = " coder " } ,
{ " vlc " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , INT_MIN , INT_MAX , VE , . unit = " coder " } ,
{ " ac " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , INT_MIN , INT_MAX , VE , . unit = " coder " } ,
2020-04-29 05:00:48 +02:00
2024-02-11 16:41:05 +02:00
{ " rc_mode " , " Select rate control mode " , OFFSET ( rc_mode ) , AV_OPT_TYPE_INT , { . i64 = RC_QUALITY_MODE } , RC_OFF_MODE , RC_TIMESTAMP_MODE , VE , . unit = " rc_mode " } ,
{ " off " , " bit rate control off " , 0 , AV_OPT_TYPE_CONST , { . i64 = RC_OFF_MODE } , 0 , 0 , VE , . unit = " rc_mode " } ,
{ " quality " , " quality mode " , 0 , AV_OPT_TYPE_CONST , { . i64 = RC_QUALITY_MODE } , 0 , 0 , VE , . unit = " rc_mode " } ,
{ " bitrate " , " bitrate mode " , 0 , AV_OPT_TYPE_CONST , { . i64 = RC_BITRATE_MODE } , 0 , 0 , VE , . unit = " rc_mode " } ,
{ " buffer " , " using buffer status to adjust the video quality (no bitrate control) " , 0 , AV_OPT_TYPE_CONST , { . i64 = RC_BUFFERBASED_MODE } , 0 , 0 , VE , . unit = " rc_mode " } ,
2020-04-29 05:00:48 +02:00
# if OPENH264_VER_AT_LEAST(1, 4)
2024-02-11 16:41:05 +02:00
{ " timestamp " , " bit rate control based on timestamp " , 0 , AV_OPT_TYPE_CONST , { . i64 = RC_TIMESTAMP_MODE } , 0 , 0 , VE , . unit = " rc_mode " } ,
2020-04-29 05:00:48 +02:00
# endif
2013-12-12 18:13:55 +03:00
{ NULL }
} ;
static const AVClass class = {
2018-11-12 18:04:43 +02:00
. class_name = " libopenh264enc " ,
2024-01-19 14:33:28 +02:00
. item_name = av_default_item_name ,
2017-06-10 16:45:06 +02:00
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
2013-12-12 18:13:55 +03:00
} ;
static av_cold int svc_encode_close ( AVCodecContext * avctx )
{
SVCContext * s = avctx - > priv_data ;
if ( s - > encoder )
WelsDestroySVCEncoder ( s - > encoder ) ;
2015-10-28 11:12:42 +02:00
if ( s - > skipped > 0 )
av_log ( avctx , AV_LOG_WARNING , " %d frames skipped \n " , s - > skipped ) ;
2013-12-12 18:13:55 +03:00
return 0 ;
}
static av_cold int svc_encode_init ( AVCodecContext * avctx )
{
SVCContext * s = avctx - > priv_data ;
SEncParamExt param = { 0 } ;
2015-09-09 21:32:42 +02:00
int log_level ;
2015-09-09 21:32:42 +02:00
WelsTraceCallback callback_function ;
2015-10-03 15:19:10 +02:00
AVCPBProperties * props ;
2013-12-12 18:13:55 +03:00
if ( WelsCreateSVCEncoder ( & s - > encoder ) ) {
av_log ( avctx , AV_LOG_ERROR , " Unable to create encoder \n " ) ;
return AVERROR_UNKNOWN ;
}
2015-09-09 21:32:42 +02:00
// Pass all libopenh264 messages to our callback, to allow ourselves to filter them.
log_level = WELS_LOG_DETAIL ;
( * s - > encoder ) - > SetOption ( s - > encoder , ENCODER_OPTION_TRACE_LEVEL , & log_level ) ;
2015-09-09 21:32:42 +02:00
// Set the logging callback function to one that uses av_log() (see implementation above).
2016-06-23 23:58:17 +02:00
callback_function = ( WelsTraceCallback ) ff_libopenh264_trace_callback ;
2015-10-30 16:26:25 +02:00
( * s - > encoder ) - > SetOption ( s - > encoder , ENCODER_OPTION_TRACE_CALLBACK , & callback_function ) ;
2015-09-09 21:32:42 +02:00
// Set the AVCodecContext as the libopenh264 callback context so that it can be passed to av_log().
2015-10-30 16:26:25 +02:00
( * s - > encoder ) - > SetOption ( s - > encoder , ENCODER_OPTION_TRACE_CALLBACK_CONTEXT , & avctx ) ;
2015-09-09 21:32:42 +02:00
2013-12-12 18:13:55 +03:00
( * s - > encoder ) - > GetDefaultParams ( s - > encoder , & param ) ;
2020-07-26 13:16:43 +02:00
if ( avctx - > framerate . num > 0 & & avctx - > framerate . den > 0 ) {
param . fMaxFrameRate = av_q2d ( avctx - > framerate ) ;
} else {
2023-05-04 11:50:48 +02:00
FF_DISABLE_DEPRECATION_WARNINGS
param . fMaxFrameRate = 1.0 / av_q2d ( avctx - > time_base )
# if FF_API_TICKS_PER_FRAME
/ FFMAX ( avctx - > ticks_per_frame , 1 )
# endif
;
FF_ENABLE_DEPRECATION_WARNINGS
2020-07-26 13:16:43 +02:00
}
2013-12-12 18:13:55 +03:00
param . iPicWidth = avctx - > width ;
param . iPicHeight = avctx - > height ;
2020-04-29 05:00:47 +02:00
param . iTargetBitrate = avctx - > bit_rate > 0 ? avctx - > bit_rate : TARGET_BITRATE_DEFAULT ;
2013-12-12 18:13:55 +03:00
param . iMaxBitrate = FFMAX ( avctx - > rc_max_rate , avctx - > bit_rate ) ;
2020-04-29 05:00:48 +02:00
param . iRCMode = s - > rc_mode ;
2020-04-29 05:00:46 +02:00
if ( avctx - > qmax > = 0 )
param . iMaxQp = av_clip ( avctx - > qmax , 1 , 51 ) ;
if ( avctx - > qmin > = 0 )
param . iMinQp = av_clip ( avctx - > qmin , 1 , param . iMaxQp ) ;
2013-12-12 18:13:55 +03:00
param . iTemporalLayerNum = 1 ;
param . iSpatialLayerNum = 1 ;
param . bEnableDenoise = 0 ;
param . bEnableBackgroundDetection = 1 ;
param . bEnableAdaptiveQuant = 1 ;
2015-10-28 11:06:36 +02:00
param . bEnableFrameSkip = s - > skip_frames ;
2013-12-12 18:13:55 +03:00
param . bEnableLongTermReference = 0 ;
param . iLtrMarkPeriod = 30 ;
2020-04-29 05:00:47 +02:00
if ( avctx - > gop_size > = 0 )
param . uiIntraPeriod = avctx - > gop_size ;
2015-03-05 13:57:44 +02:00
# if OPENH264_VER_AT_LEAST(1, 4)
param . eSpsPpsIdStrategy = CONSTANT_ID ;
# else
2013-12-12 18:13:55 +03:00
param . bEnableSpsPpsIdAddition = 0 ;
2015-03-05 13:57:44 +02:00
# endif
2013-12-12 18:13:55 +03:00
param . bPrefixNalAddingCtrl = 0 ;
param . iLoopFilterDisableIdc = ! s - > loopfilter ;
2022-01-14 11:48:54 +02:00
param . iEntropyCodingModeFlag = s - > coder > = 0 ? s - > coder : 1 ;
2013-12-12 18:13:55 +03:00
param . iMultipleThreadIdc = avctx - > thread_count ;
2020-05-06 15:47:50 +02:00
2020-05-06 15:47:51 +02:00
/* Allow specifying the libopenh264 profile through AVCodecContext. */
2023-09-02 14:57:41 +02:00
if ( AV_PROFILE_UNKNOWN = = s - > profile & &
AV_PROFILE_UNKNOWN ! = avctx - > profile )
2020-05-06 15:47:51 +02:00
switch ( avctx - > profile ) {
2023-09-02 14:57:41 +02:00
case AV_PROFILE_H264_HIGH :
case AV_PROFILE_H264_MAIN :
case AV_PROFILE_H264_CONSTRAINED_BASELINE :
2020-05-06 15:47:51 +02:00
s - > profile = avctx - > profile ;
break ;
default :
av_log ( avctx , AV_LOG_WARNING ,
" Unsupported avctx->profile: %d. \n " , avctx - > profile ) ;
break ;
}
2023-09-02 14:57:41 +02:00
if ( s - > profile = = AV_PROFILE_UNKNOWN & & s - > coder > = 0 )
s - > profile = s - > coder = = 0 ? AV_PROFILE_H264_CONSTRAINED_BASELINE :
2020-05-06 15:47:50 +02:00
# if OPENH264_VER_AT_LEAST(1, 8)
2023-09-02 14:57:41 +02:00
AV_PROFILE_H264_HIGH ;
2020-05-06 15:47:50 +02:00
# else
2023-09-02 14:57:41 +02:00
AV_PROFILE_H264_MAIN ;
2020-05-06 15:47:50 +02:00
# endif
switch ( s - > profile ) {
2023-09-02 14:57:41 +02:00
case AV_PROFILE_H264_HIGH :
2022-01-14 11:48:54 +02:00
av_log ( avctx , AV_LOG_VERBOSE , " Using %s, "
" select EProfileIdc PRO_HIGH in libopenh264. \n " ,
param . iEntropyCodingModeFlag ? " CABAC " : " CAVLC " ) ;
2020-05-06 15:47:50 +02:00
break ;
2023-09-02 14:57:41 +02:00
case AV_PROFILE_H264_MAIN :
2022-01-14 11:48:54 +02:00
av_log ( avctx , AV_LOG_VERBOSE , " Using %s, "
" select EProfileIdc PRO_MAIN in libopenh264. \n " ,
param . iEntropyCodingModeFlag ? " CABAC " : " CAVLC " ) ;
2020-05-06 15:47:50 +02:00
break ;
2023-09-02 14:57:41 +02:00
case AV_PROFILE_H264_CONSTRAINED_BASELINE :
case AV_PROFILE_UNKNOWN :
s - > profile = AV_PROFILE_H264_CONSTRAINED_BASELINE ;
2020-05-06 15:47:50 +02:00
param . iEntropyCodingModeFlag = 0 ;
av_log ( avctx , AV_LOG_VERBOSE , " Using CAVLC, "
" select EProfileIdc PRO_BASELINE in libopenh264. \n " ) ;
break ;
default :
2023-09-02 14:57:41 +02:00
s - > profile = AV_PROFILE_H264_CONSTRAINED_BASELINE ;
2020-05-06 15:47:50 +02:00
param . iEntropyCodingModeFlag = 0 ;
av_log ( avctx , AV_LOG_WARNING , " Unsupported profile, "
" select EProfileIdc PRO_BASELINE in libopenh264. \n " ) ;
break ;
}
2013-12-12 18:13:55 +03:00
param . sSpatialLayers [ 0 ] . iVideoWidth = param . iPicWidth ;
param . sSpatialLayers [ 0 ] . iVideoHeight = param . iPicHeight ;
param . sSpatialLayers [ 0 ] . fFrameRate = param . fMaxFrameRate ;
param . sSpatialLayers [ 0 ] . iSpatialBitrate = param . iTargetBitrate ;
param . sSpatialLayers [ 0 ] . iMaxSpatialBitrate = param . iMaxBitrate ;
2022-01-14 11:48:10 +02:00
param . sSpatialLayers [ 0 ] . uiProfileIdc = s - > profile ;
2013-12-12 18:13:55 +03:00
2018-11-01 15:15:11 +02:00
# if OPENH264_VER_AT_LEAST(1, 7)
if ( avctx - > sample_aspect_ratio . num & & avctx - > sample_aspect_ratio . den ) {
// Table E-1.
static const AVRational sar_idc [ ] = {
{ 0 , 0 } , // Unspecified (never written here).
{ 1 , 1 } , { 12 , 11 } , { 10 , 11 } , { 16 , 11 } ,
{ 40 , 33 } , { 24 , 11 } , { 20 , 11 } , { 32 , 11 } ,
{ 80 , 33 } , { 18 , 11 } , { 15 , 11 } , { 64 , 33 } ,
{ 160 , 99 } , // Last 3 are unknown to openh264: { 4, 3 }, { 3, 2 }, { 2, 1 },
} ;
static const ESampleAspectRatio asp_idc [ ] = {
ASP_UNSPECIFIED ,
ASP_1x1 , ASP_12x11 , ASP_10x11 , ASP_16x11 ,
ASP_40x33 , ASP_24x11 , ASP_20x11 , ASP_32x11 ,
ASP_80x33 , ASP_18x11 , ASP_15x11 , ASP_64x33 ,
ASP_160x99 ,
} ;
int num , den , i ;
av_reduce ( & num , & den , avctx - > sample_aspect_ratio . num ,
avctx - > sample_aspect_ratio . den , 65535 ) ;
for ( i = 1 ; i < FF_ARRAY_ELEMS ( sar_idc ) ; i + + ) {
if ( num = = sar_idc [ i ] . num & &
den = = sar_idc [ i ] . den )
break ;
}
if ( i = = FF_ARRAY_ELEMS ( sar_idc ) ) {
param . sSpatialLayers [ 0 ] . eAspectRatio = ASP_EXT_SAR ;
param . sSpatialLayers [ 0 ] . sAspectRatioExtWidth = num ;
param . sSpatialLayers [ 0 ] . sAspectRatioExtHeight = den ;
} else {
param . sSpatialLayers [ 0 ] . eAspectRatio = asp_idc [ i ] ;
}
param . sSpatialLayers [ 0 ] . bAspectRatioPresent = true ;
2020-04-06 13:14:45 +02:00
} else {
2018-11-01 15:15:11 +02:00
param . sSpatialLayers [ 0 ] . bAspectRatioPresent = false ;
}
# endif
2016-06-24 00:06:12 +02:00
if ( ( avctx - > slices > 1 ) & & ( s - > max_nal_size ) ) {
av_log ( avctx , AV_LOG_ERROR ,
" Invalid combination -slices %d and -max_nal_size %d. \n " ,
avctx - > slices , s - > max_nal_size ) ;
2016-07-14 21:24:55 +02:00
return AVERROR ( EINVAL ) ;
2015-10-08 19:28:55 +02:00
}
2013-12-12 18:13:55 +03:00
if ( avctx - > slices > 1 )
s - > slice_mode = SM_FIXEDSLCNUM_SLICE ;
2015-10-08 19:28:55 +02:00
if ( s - > max_nal_size )
2016-07-08 22:21:41 +02:00
s - > slice_mode = SM_SIZELIMITED_SLICE ;
2015-10-08 19:28:55 +02:00
2016-07-08 22:21:41 +02:00
# if OPENH264_VER_AT_LEAST(1, 6)
param . sSpatialLayers [ 0 ] . sSliceArgument . uiSliceMode = s - > slice_mode ;
param . sSpatialLayers [ 0 ] . sSliceArgument . uiSliceNum = avctx - > slices ;
# else
2013-12-12 18:13:55 +03:00
param . sSpatialLayers [ 0 ] . sSliceCfg . uiSliceMode = s - > slice_mode ;
param . sSpatialLayers [ 0 ] . sSliceCfg . sSliceArgument . uiSliceNum = avctx - > slices ;
2016-07-08 22:21:41 +02:00
# endif
2020-04-29 05:00:49 +02:00
if ( avctx - > slices = = 0 & & s - > slice_mode = = SM_FIXEDSLCNUM_SLICE )
av_log ( avctx , AV_LOG_WARNING , " Slice count will be set automatically \n " ) ;
2013-12-12 18:13:55 +03:00
2016-07-08 22:21:41 +02:00
if ( s - > slice_mode = = SM_SIZELIMITED_SLICE ) {
2020-04-06 13:14:45 +02:00
if ( s - > max_nal_size ) {
2015-10-08 19:28:55 +02:00
param . uiMaxNalSize = s - > max_nal_size ;
2016-07-08 22:21:41 +02:00
# if OPENH264_VER_AT_LEAST(1, 6)
param . sSpatialLayers [ 0 ] . sSliceArgument . uiSliceSizeConstraint = s - > max_nal_size ;
# else
2015-10-08 19:28:55 +02:00
param . sSpatialLayers [ 0 ] . sSliceCfg . sSliceArgument . uiSliceSizeConstraint = s - > max_nal_size ;
2016-07-08 22:21:41 +02:00
# endif
2015-10-08 19:28:55 +02:00
} else {
2015-09-13 23:45:24 +02:00
av_log ( avctx , AV_LOG_ERROR , " Invalid -max_nal_size, "
" specify a valid max_nal_size to use -slice_mode dyn \n " ) ;
2016-07-14 21:24:55 +02:00
return AVERROR ( EINVAL ) ;
2015-10-08 19:28:55 +02:00
}
}
2022-01-14 07:53:19 +02:00
# if OPENH264_VER_AT_LEAST(1, 6)
param . sSpatialLayers [ 0 ] . uiVideoFormat = VF_UNDEF ;
2023-04-18 11:08:52 +02:00
2022-01-14 07:53:19 +02:00
if ( avctx - > color_range ! = AVCOL_RANGE_UNSPECIFIED ) {
param . sSpatialLayers [ 0 ] . bFullRange = ( avctx - > color_range = = AVCOL_RANGE_JPEG ) ;
2023-04-18 11:08:52 +02:00
} else if ( avctx - > pix_fmt = = AV_PIX_FMT_YUVJ420P )
param . sSpatialLayers [ 0 ] . bFullRange = 1 ;
2022-01-14 07:53:19 +02:00
if ( avctx - > colorspace ! = AVCOL_SPC_UNSPECIFIED | |
avctx - > color_primaries ! = AVCOL_PRI_UNSPECIFIED | |
avctx - > color_trc ! = AVCOL_TRC_UNSPECIFIED ) {
param . sSpatialLayers [ 0 ] . bColorDescriptionPresent = true ;
}
if ( avctx - > colorspace ! = AVCOL_SPC_UNSPECIFIED )
param . sSpatialLayers [ 0 ] . uiColorMatrix = avctx - > colorspace ;
if ( avctx - > color_primaries ! = AVCOL_PRI_UNSPECIFIED )
param . sSpatialLayers [ 0 ] . uiColorPrimaries = avctx - > color_primaries ;
if ( avctx - > color_trc ! = AVCOL_TRC_UNSPECIFIED )
param . sSpatialLayers [ 0 ] . uiTransferCharacteristics = avctx - > color_trc ;
2023-04-18 17:19:18 +02:00
param . sSpatialLayers [ 0 ] . bVideoSignalTypePresent =
( param . sSpatialLayers [ 0 ] . bFullRange | | param . sSpatialLayers [ 0 ] . bColorDescriptionPresent ) ;
2022-01-14 07:53:19 +02:00
# endif
2013-12-12 18:13:55 +03:00
if ( ( * s - > encoder ) - > InitializeExt ( s - > encoder , & param ) ! = cmResultSuccess ) {
av_log ( avctx , AV_LOG_ERROR , " Initialize failed \n " ) ;
2016-07-14 21:24:55 +02:00
return AVERROR_UNKNOWN ;
2013-12-12 18:13:55 +03:00
}
2015-06-29 21:59:37 +02:00
if ( avctx - > flags & AV_CODEC_FLAG_GLOBAL_HEADER ) {
2013-12-12 18:13:55 +03:00
SFrameBSInfo fbi = { 0 } ;
int i , size = 0 ;
( * s - > encoder ) - > EncodeParameterSets ( s - > encoder , & fbi ) ;
for ( i = 0 ; i < fbi . sLayerInfo [ 0 ] . iNalCount ; i + + )
size + = fbi . sLayerInfo [ 0 ] . pNalLengthInByte [ i ] ;
2015-06-29 23:48:34 +02:00
avctx - > extradata = av_mallocz ( size + AV_INPUT_BUFFER_PADDING_SIZE ) ;
2016-07-14 21:24:55 +02:00
if ( ! avctx - > extradata )
return AVERROR ( ENOMEM ) ;
2013-12-12 18:13:55 +03:00
avctx - > extradata_size = size ;
memcpy ( avctx - > extradata , fbi . sLayerInfo [ 0 ] . pBsBuf , size ) ;
}
2023-09-04 14:39:07 +02:00
props = ff_encode_add_cpb_side_data ( avctx ) ;
2016-07-14 21:24:55 +02:00
if ( ! props )
return AVERROR ( ENOMEM ) ;
2015-10-03 15:19:10 +02:00
props - > max_bitrate = param . iMaxBitrate ;
props - > avg_bitrate = param . iTargetBitrate ;
2013-12-12 18:13:55 +03:00
return 0 ;
}
static int svc_encode_frame ( AVCodecContext * avctx , AVPacket * avpkt ,
const AVFrame * frame , int * got_packet )
{
SVCContext * s = avctx - > priv_data ;
SFrameBSInfo fbi = { 0 } ;
int i , ret ;
int encoded ;
SSourcePicture sp = { 0 } ;
int size = 0 , layer , first_layer = 0 ;
int layer_size [ MAX_LAYER_NUM_OF_FRAME ] = { 0 } ;
sp . iColorFormat = videoFormatI420 ;
for ( i = 0 ; i < 3 ; i + + ) {
sp . iStride [ i ] = frame - > linesize [ i ] ;
sp . pData [ i ] = frame - > data [ i ] ;
}
sp . iPicWidth = avctx - > width ;
sp . iPicHeight = avctx - > height ;
2018-03-16 15:50:34 +02:00
if ( frame - > pict_type = = AV_PICTURE_TYPE_I ) {
( * s - > encoder ) - > ForceIntraFrame ( s - > encoder , true ) ;
}
2013-12-12 18:13:55 +03:00
encoded = ( * s - > encoder ) - > EncodeFrame ( s - > encoder , & sp , & fbi ) ;
if ( encoded ! = cmResultSuccess ) {
av_log ( avctx , AV_LOG_ERROR , " EncodeFrame failed \n " ) ;
return AVERROR_UNKNOWN ;
}
if ( fbi . eFrameType = = videoFrameTypeSkip ) {
2015-10-28 11:12:42 +02:00
s - > skipped + + ;
2013-12-12 18:13:55 +03:00
av_log ( avctx , AV_LOG_DEBUG , " frame skipped \n " ) ;
return 0 ;
}
first_layer = 0 ;
2015-01-08 00:03:09 +02:00
// Normal frames are returned with one single layer, while IDR
2013-12-12 18:13:55 +03:00
// frames have two layers, where the first layer contains the SPS/PPS.
// If using global headers, don't include the SPS/PPS in the returned
// packet - thus, only return one layer.
2015-06-29 21:59:37 +02:00
if ( avctx - > flags & AV_CODEC_FLAG_GLOBAL_HEADER )
2013-12-12 18:13:55 +03:00
first_layer = fbi . iLayerNum - 1 ;
for ( layer = first_layer ; layer < fbi . iLayerNum ; layer + + ) {
for ( i = 0 ; i < fbi . sLayerInfo [ layer ] . iNalCount ; i + + )
layer_size [ layer ] + = fbi . sLayerInfo [ layer ] . pNalLengthInByte [ i ] ;
size + = layer_size [ layer ] ;
}
2015-01-28 22:17:29 +02:00
av_log ( avctx , AV_LOG_DEBUG , " %d slices \n " , fbi . sLayerInfo [ fbi . iLayerNum - 1 ] . iNalCount ) ;
2013-12-12 18:13:55 +03:00
2021-04-25 01:43:26 +02:00
if ( ( ret = ff_get_encode_buffer ( avctx , avpkt , size , 0 ) ) )
2013-12-12 18:13:55 +03:00
return ret ;
2021-04-25 01:43:26 +02:00
2013-12-12 18:13:55 +03:00
size = 0 ;
for ( layer = first_layer ; layer < fbi . iLayerNum ; layer + + ) {
memcpy ( avpkt - > data + size , fbi . sLayerInfo [ layer ] . pBsBuf , layer_size [ layer ] ) ;
size + = layer_size [ layer ] ;
}
avpkt - > pts = frame - > pts ;
if ( fbi . eFrameType = = videoFrameTypeIDR )
avpkt - > flags | = AV_PKT_FLAG_KEY ;
* got_packet = 1 ;
return 0 ;
}
2022-03-16 22:26:11 +02:00
static const FFCodecDefault svc_enc_defaults [ ] = {
2020-04-29 05:00:47 +02:00
{ " b " , " 0 " } ,
{ " g " , " -1 " } ,
2020-04-29 05:00:46 +02:00
{ " qmin " , " -1 " } ,
{ " qmax " , " -1 " } ,
{ NULL } ,
} ;
2022-03-16 22:09:54 +02:00
const FFCodec ff_libopenh264_encoder = {
. p . name = " libopenh264 " ,
2022-08-29 13:38:02 +02:00
CODEC_LONG_NAME ( " OpenH264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 " ) ,
2022-03-16 22:09:54 +02:00
. p . type = AVMEDIA_TYPE_VIDEO ,
. p . id = AV_CODEC_ID_H264 ,
2022-11-27 14:37:10 +02:00
. p . capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_OTHER_THREADS |
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE ,
2013-12-12 18:13:55 +03:00
. priv_data_size = sizeof ( SVCContext ) ,
. init = svc_encode_init ,
2022-03-30 23:28:24 +02:00
FF_CODEC_ENCODE_CB ( svc_encode_frame ) ,
2013-12-12 18:13:55 +03:00
. close = svc_encode_close ,
2022-07-10 00:05:45 +02:00
. caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
2021-03-09 19:00:44 +02:00
FF_CODEC_CAP_AUTO_THREADS ,
2022-03-16 22:09:54 +02:00
. p . pix_fmts = ( const enum AVPixelFormat [ ] ) { AV_PIX_FMT_YUV420P ,
2023-04-18 11:08:52 +02:00
AV_PIX_FMT_YUVJ420P ,
2015-03-17 14:40:40 +02:00
AV_PIX_FMT_NONE } ,
2020-04-29 05:00:46 +02:00
. defaults = svc_enc_defaults ,
2022-03-16 22:09:54 +02:00
. p . priv_class = & class ,
. p . wrapper_name = " libopenh264 " ,
2013-12-12 18:13:55 +03:00
} ;