@@ -527,11 +527,17 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
527527 avifEncoder * encoder ,
528528 const avifImage * image ,
529529 avifBool alpha ,
530- avifBool updateConfig ,
530+ avifEncoderConfig updatedConfig ,
531531 avifAddImageFlags addImageFlags ,
532532 avifCodecEncodeOutput * output )
533533{
534- if (!codec -> internal -> encoderInitialized || updateConfig ) {
534+ struct aom_codec_enc_cfg * cfg = & codec -> internal -> cfg ;
535+ aom_codec_iface_t * encoderInterface = NULL ;
536+ unsigned int aomUsage = AOM_USAGE_GOOD_QUALITY ;
537+ int aomCpuUsed = -1 ;
538+ avifBool lossless = AVIF_FALSE ;
539+
540+ if (!codec -> internal -> encoderInitialized ) {
535541 // Map encoder speed to AOM usage + CpuUsed:
536542 // Speed 0: GoodQuality CpuUsed 0
537543 // Speed 1: GoodQuality CpuUsed 1
@@ -544,15 +550,13 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
544550 // Speed 8: RealTime CpuUsed 8
545551 // Speed 9: RealTime CpuUsed 9
546552 // Speed 10: RealTime CpuUsed 9
547- unsigned int aomUsage = AOM_USAGE_GOOD_QUALITY ;
548553 // Use the new AOM_USAGE_ALL_INTRA (added in https://crbug.com/aomedia/2959) for still
549554 // image encoding if it is available.
550555#if defined(AOM_USAGE_ALL_INTRA )
551556 if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE ) {
552557 aomUsage = AOM_USAGE_ALL_INTRA ;
553558 }
554559#endif
555- int aomCpuUsed = -1 ;
556560 if (encoder -> speed != AVIF_SPEED_DEFAULT ) {
557561 aomCpuUsed = AVIF_CLAMP (encoder -> speed , 0 , 9 );
558562 if (aomCpuUsed >= 7 ) {
@@ -589,50 +593,19 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
589593 }
590594 }
591595
592- struct aom_codec_enc_cfg * cfg = & codec -> internal -> cfg ;
593-
594- aom_codec_iface_t * encoderInterface = NULL ;
595- if (!codec -> internal -> encoderInitialized ) {
596- codec -> internal -> aomFormat = avifImageCalcAOMFmt (image , alpha );
597- if (codec -> internal -> aomFormat == AOM_IMG_FMT_NONE ) {
598- return AVIF_RESULT_UNKNOWN_ERROR ;
599- }
600-
601- avifGetPixelFormatInfo (image -> yuvFormat , & codec -> internal -> formatInfo );
602-
603- encoderInterface = aom_codec_av1_cx ();
604- aom_codec_err_t err = aom_codec_enc_config_default (encoderInterface , cfg , aomUsage );
605- if (err != AOM_CODEC_OK ) {
606- avifDiagnosticsPrintf (codec -> diag , "aom_codec_enc_config_default() failed: %s" , aom_codec_err_to_string (err ));
607- return AVIF_RESULT_UNKNOWN_ERROR ;
608- }
609- } else {
610- // aomUsage was taken into account by aom_codec_enc_config_default() but it can only be manually updated afterwards.
611- cfg -> g_usage = aomUsage ;
596+ codec -> internal -> aomFormat = avifImageCalcAOMFmt (image , alpha );
597+ if (codec -> internal -> aomFormat == AOM_IMG_FMT_NONE ) {
598+ return AVIF_RESULT_UNKNOWN_ERROR ;
612599 }
613600
614- if (!codec -> internal -> endUsageSet ) {
615- // Set our own default cfg->rc_end_usage value, which may differ from libaom's default.
616- switch (aomUsage ) {
617- case AOM_USAGE_GOOD_QUALITY :
618- // libaom's default is AOM_VBR. Change the default to AOM_Q since we don't need to
619- // hit a certain target bit rate. It's easier to control the worst quality in Q
620- // mode.
621- cfg -> rc_end_usage = AOM_Q ;
622- break ;
623- case AOM_USAGE_REALTIME :
624- // For real-time mode we need to use CBR rate control mode. AOM_Q doesn't fit the
625- // rate control requirements for real-time mode. CBR does.
626- cfg -> rc_end_usage = AOM_CBR ;
627- break ;
628- #if defined(AOM_USAGE_ALL_INTRA )
629- case AOM_USAGE_ALL_INTRA :
630- cfg -> rc_end_usage = AOM_Q ;
631- break ;
632- #endif
633- }
634- }
601+ avifGetPixelFormatInfo (image -> yuvFormat , & codec -> internal -> formatInfo );
635602
603+ encoderInterface = aom_codec_av1_cx ();
604+ aom_codec_err_t err = aom_codec_enc_config_default (encoderInterface , cfg , aomUsage );
605+ if (err != AOM_CODEC_OK ) {
606+ avifDiagnosticsPrintf (codec -> diag , "aom_codec_enc_config_default() failed: %s" , aom_codec_err_to_string (err ));
607+ return AVIF_RESULT_UNKNOWN_ERROR ;
608+ }
636609 // Profile 0. 8-bit and 10-bit 4:2:0 and 4:0:0 only.
637610 // Profile 1. 8-bit and 10-bit 4:4:4
638611 // Profile 2. 8-bit and 10-bit 4:2:2
@@ -671,8 +644,7 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
671644 cfg -> g_profile = seqProfile ;
672645 cfg -> g_bit_depth = image -> depth ;
673646 cfg -> g_input_bit_depth = image -> depth ;
674- cfg -> g_w = image -> width ;
675- cfg -> g_h = image -> height ;
647+
676648 if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE ) {
677649 // Set the maximum number of frames to encode to 1. This instructs
678650 // libaom to set still_picture and reduced_still_picture_header to
@@ -695,16 +667,6 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
695667 cfg -> g_threads = encoder -> maxThreads ;
696668 }
697669
698- int minQuantizer = AVIF_CLAMP (encoder -> minQuantizer , 0 , 63 );
699- int maxQuantizer = AVIF_CLAMP (encoder -> maxQuantizer , 0 , 63 );
700- if (alpha ) {
701- minQuantizer = AVIF_CLAMP (encoder -> minQuantizerAlpha , 0 , 63 );
702- maxQuantizer = AVIF_CLAMP (encoder -> maxQuantizerAlpha , 0 , 63 );
703- }
704- avifBool lossless = ((minQuantizer == AVIF_QUANTIZER_LOSSLESS ) && (maxQuantizer == AVIF_QUANTIZER_LOSSLESS ));
705- cfg -> rc_min_quantizer = minQuantizer ;
706- cfg -> rc_max_quantizer = maxQuantizer ;
707-
708670 codec -> internal -> monochromeEnabled = AVIF_FALSE ;
709671 if (aomVersion > aomVersion_2_0_0 ) {
710672 // There exists a bug in libaom's chroma_check() function where it will attempt to
@@ -720,60 +682,95 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
720682 cfg -> monochrome = 1 ;
721683 }
722684 }
685+ }
686+
687+ avifBool dimensionChanged = AVIF_FALSE ;
688+ if ((cfg -> g_w != image -> width ) || (cfg -> g_h != image -> height )) {
689+ cfg -> g_w = image -> width ;
690+ cfg -> g_h = image -> height ;
691+ if (codec -> internal -> encoderInitialized ) {
692+ // We are not ready for dimension change for now.
693+ return AVIF_RESULT_NOT_IMPLEMENTED ;
694+ }
695+ }
696+
697+ if (!codec -> internal -> encoderInitialized || updatedConfig ) {
698+ int minQuantizer = AVIF_CLAMP (encoder -> minQuantizer , 0 , 63 );
699+ int maxQuantizer = AVIF_CLAMP (encoder -> maxQuantizer , 0 , 63 );
700+ if (alpha ) {
701+ minQuantizer = AVIF_CLAMP (encoder -> minQuantizerAlpha , 0 , 63 );
702+ maxQuantizer = AVIF_CLAMP (encoder -> maxQuantizerAlpha , 0 , 63 );
703+ }
704+ lossless = ((minQuantizer == AVIF_QUANTIZER_LOSSLESS ) && (maxQuantizer == AVIF_QUANTIZER_LOSSLESS ));
705+ cfg -> rc_min_quantizer = minQuantizer ;
706+ cfg -> rc_max_quantizer = maxQuantizer ;
723707
724708 if (!avifProcessAOMOptionsPreInit (codec , alpha , cfg )) {
725709 return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION ;
726710 }
711+ }
727712
728- avifBool initPhase = AVIF_FALSE ;
729- if (!codec -> internal -> encoderInitialized ) {
730- aom_codec_flags_t encoderFlags = 0 ;
731- if (image -> depth > 8 ) {
732- encoderFlags |= AOM_CODEC_USE_HIGHBITDEPTH ;
733- }
734-
735- if (aom_codec_enc_init (& codec -> internal -> encoder , encoderInterface , cfg , encoderFlags ) != AOM_CODEC_OK ) {
736- avifDiagnosticsPrintf (codec -> diag ,
737- "aom_codec_enc_init() failed: %s: %s" ,
738- aom_codec_error (& codec -> internal -> encoder ),
739- aom_codec_error_detail (& codec -> internal -> encoder ));
740- return AVIF_RESULT_UNKNOWN_ERROR ;
741- }
742- codec -> internal -> encoderInitialized = AVIF_TRUE ;
743- initPhase = AVIF_TRUE ;
744- } else {
745- if (aom_codec_enc_config_set (& codec -> internal -> encoder , cfg ) != AOM_CODEC_OK ) {
746- avifDiagnosticsPrintf (codec -> diag ,
747- "aom_codec_enc_config_set() failed: %s: %s" ,
748- aom_codec_error (& codec -> internal -> encoder ),
749- aom_codec_error_detail (& codec -> internal -> encoder ));
750- return AVIF_RESULT_UNKNOWN_ERROR ;
713+ if (!codec -> internal -> encoderInitialized ) {
714+ if (!codec -> internal -> endUsageSet ) {
715+ // Set our own default cfg->rc_end_usage value, which may differ from libaom's default.
716+ switch (aomUsage ) {
717+ case AOM_USAGE_GOOD_QUALITY :
718+ // libaom's default is AOM_VBR. Change the default to AOM_Q since we don't need to
719+ // hit a certain target bit rate. It's easier to control the worst quality in Q
720+ // mode.
721+ cfg -> rc_end_usage = AOM_Q ;
722+ break ;
723+ case AOM_USAGE_REALTIME :
724+ // For real-time mode we need to use CBR rate control mode. AOM_Q doesn't fit the
725+ // rate control requirements for real-time mode. CBR does.
726+ cfg -> rc_end_usage = AOM_CBR ;
727+ break ;
728+ #if defined(AOM_USAGE_ALL_INTRA )
729+ case AOM_USAGE_ALL_INTRA :
730+ cfg -> rc_end_usage = AOM_Q ;
731+ break ;
732+ #endif
751733 }
752734 }
753735
754- if (!initPhase || lossless ) {
755- aom_codec_control (& codec -> internal -> encoder , AV1E_SET_LOSSLESS , lossless );
756- }
757- int rowMT = encoder -> maxThreads > 1 ;
758- if (!initPhase || rowMT ) {
759- aom_codec_control (& codec -> internal -> encoder , AV1E_SET_ROW_MT , rowMT );
736+ aom_codec_flags_t encoderFlags = 0 ;
737+ if (image -> depth > 8 ) {
738+ encoderFlags |= AOM_CODEC_USE_HIGHBITDEPTH ;
760739 }
761- int tileRowsLog2 = AVIF_CLAMP (encoder -> tileRowsLog2 , 0 , 6 );
762- if (!initPhase || (tileRowsLog2 > 0 )) {
763- aom_codec_control (& codec -> internal -> encoder , AV1E_SET_TILE_ROWS , tileRowsLog2 );
740+
741+ if (aom_codec_enc_init (& codec -> internal -> encoder , encoderInterface , cfg , encoderFlags ) != AOM_CODEC_OK ) {
742+ avifDiagnosticsPrintf (codec -> diag ,
743+ "aom_codec_enc_init() failed: %s: %s" ,
744+ aom_codec_error (& codec -> internal -> encoder ),
745+ aom_codec_error_detail (& codec -> internal -> encoder ));
746+ return AVIF_RESULT_UNKNOWN_ERROR ;
764747 }
765- int tileColsLog2 = AVIF_CLAMP ( encoder -> tileColsLog2 , 0 , 6 );
766- if (! initPhase || ( tileColsLog2 > 0 ) ) {
767- aom_codec_control (& codec -> internal -> encoder , AV1E_SET_TILE_COLUMNS , tileColsLog2 );
748+
749+ if (encoder -> maxThreads > 1 ) {
750+ aom_codec_control (& codec -> internal -> encoder , AV1E_SET_ROW_MT , 1 );
768751 }
769752 if (aomCpuUsed != -1 ) {
770753 if (aom_codec_control (& codec -> internal -> encoder , AOME_SET_CPUUSED , aomCpuUsed ) != AOM_CODEC_OK ) {
771754 return AVIF_RESULT_UNKNOWN_ERROR ;
772755 }
773756 }
757+ } else if ((updatedConfig & ~ AVIF_ENCODER_CONFIG_CODEC_SPECIFIC ) || dimensionChanged ) {
758+ // Codec specific options does not change cfg, so no need to update it.
759+ aom_codec_err_t err = aom_codec_enc_config_set (& codec -> internal -> encoder , cfg );
760+ if (err != AOM_CODEC_OK ) {
761+ avifDiagnosticsPrintf (codec -> diag ,
762+ "aom_codec_enc_config_set() failed: %s: %s" ,
763+ aom_codec_error (& codec -> internal -> encoder ),
764+ aom_codec_error_detail (& codec -> internal -> encoder ));
765+ return AVIF_RESULT_UNKNOWN_ERROR ;
766+ }
767+ }
768+
769+ if (!codec -> internal -> encoderInitialized || (updatedConfig & AVIF_ENCODER_CONFIG_CODEC_SPECIFIC )) {
774770 if (!avifProcessAOMOptionsPostInit (codec , alpha )) {
775771 return AVIF_RESULT_INVALID_CODEC_SPECIFIC_OPTION ;
776772 }
773+
777774#if defined(AOM_USAGE_ALL_INTRA )
778775 if (aomUsage == AOM_USAGE_ALL_INTRA && !codec -> internal -> endUsageSet && !codec -> internal -> cqLevelSet ) {
779776 // The default rc_end_usage in all intra mode is AOM_Q, which requires cq-level to
@@ -786,14 +783,39 @@ static avifResult aomCodecEncodeImage(avifCodec * codec,
786783 aom_codec_control (& codec -> internal -> encoder , AOME_SET_CQ_LEVEL , cqLevel );
787784 }
788785#endif
786+ }
787+
788+ if (!codec -> internal -> encoderInitialized ) {
789+ if (lossless ) {
790+ aom_codec_control (& codec -> internal -> encoder , AV1E_SET_LOSSLESS , lossless );
791+ }
792+ int tileRowsLog2 = AVIF_CLAMP (encoder -> tileRowsLog2 , 0 , 6 );
793+ if (tileRowsLog2 > 0 ) {
794+ aom_codec_control (& codec -> internal -> encoder , AV1E_SET_TILE_ROWS , tileRowsLog2 );
795+ }
796+ int tileColsLog2 = AVIF_CLAMP (encoder -> tileColsLog2 , 0 , 6 );
797+ if (tileColsLog2 > 0 ) {
798+ aom_codec_control (& codec -> internal -> encoder , AV1E_SET_TILE_COLUMNS , tileColsLog2 );
799+ }
800+
789801 if (!codec -> internal -> tuningSet ) {
790802 if (aom_codec_control (& codec -> internal -> encoder , AOME_SET_TUNING , AOM_TUNE_SSIM ) != AOM_CODEC_OK ) {
791803 return AVIF_RESULT_UNKNOWN_ERROR ;
792804 }
793805 }
794-
795- // Sync our copy with updated config in AOM encoder.
796- * cfg = * codec -> internal -> encoder .config .enc ;
806+ codec -> internal -> encoderInitialized = AVIF_TRUE ;
807+ } else if (updatedConfig ) {
808+ if (((!alpha ) && ((updatedConfig & AVIF_ENCODER_CONFIG_MIN_QUANTIZER ) || (updatedConfig & AVIF_ENCODER_CONFIG_MAX_QUANTIZER ))) ||
809+ (alpha && ((updatedConfig & AVIF_ENCODER_CONFIG_MIN_QUANTIZER_ALPHA ) ||
810+ (updatedConfig & AVIF_ENCODER_CONFIG_MAX_QUANTIZER_ALPHA )))) {
811+ aom_codec_control (& codec -> internal -> encoder , AV1E_SET_LOSSLESS , lossless );
812+ }
813+ if (updatedConfig & AVIF_ENCODER_CONFIG_TILE_ROWS_LOG_2 ) {
814+ aom_codec_control (& codec -> internal -> encoder , AV1E_SET_TILE_ROWS , AVIF_CLAMP (encoder -> tileRowsLog2 , 0 , 6 ));
815+ }
816+ if (updatedConfig & AVIF_ENCODER_CONFIG_TILE_COLS_LOG_2 ) {
817+ aom_codec_control (& codec -> internal -> encoder , AV1E_SET_TILE_COLUMNS , AVIF_CLAMP (encoder -> tileColsLog2 , 0 , 6 ));
818+ }
797819 }
798820
799821 aom_image_t aomImage ;
0 commit comments