/*
 * Copyright 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.camera.video.internal.workaround;

import android.media.MediaCodecList;
import android.media.MediaFormat;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.video.internal.compat.quirk.DeviceQuirks;
import androidx.camera.video.internal.compat.quirk.ExcludeKeyFrameRateInFindEncoderQuirk;

/**
 * Workaround to fix the selection of video encoder by MediaFormat on API 21.
 *
 * @see ExcludeKeyFrameRateInFindEncoderQuirk
 */
public class EncoderFinder {
    private final boolean mShouldRemoveKeyFrameRate;

    public EncoderFinder() {
        final ExcludeKeyFrameRateInFindEncoderQuirk quirk =
                DeviceQuirks.get(ExcludeKeyFrameRateInFindEncoderQuirk.class);

        mShouldRemoveKeyFrameRate = (quirk != null);
    }

    /**
     * Selects an encoder by a given MediaFormat.
     *
     * <p>There is one particular case when get a video encoder on API 21.
     */
    @Nullable
    public String findEncoderForFormat(@NonNull MediaFormat mediaFormat,
            @NonNull MediaCodecList mediaCodecList) {
        // If the frame rate value is assigned, keep it and restore it later.
        String encoderName;

        if (mShouldRemoveKeyFrameRate && mediaFormat.containsKey(MediaFormat.KEY_FRAME_RATE)) {
            int tempFrameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
            // Reset frame rate value in API 21.
            mediaFormat.setString(MediaFormat.KEY_FRAME_RATE, null);
            encoderName = mediaCodecList.findEncoderForFormat(mediaFormat);
            // Restore the frame rate value.
            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, tempFrameRate);
        } else {
            encoderName = mediaCodecList.findEncoderForFormat(mediaFormat);
        }

        return encoderName;
    }

}

@@ -732,16 +732,41 @@
 aFormat;
+%0Aimport android.os.Build;
 %0A%0Aimport
@@ -1517,68 +1517,177 @@
 %3EThe
-re is one particular case when get a video encoder on API 21
+ encoder finder might temporarily alter the media format for better compatibility%0A     * based on OS version. It is not thread safe to use the same media format instance
 .%0A  
@@ -1829,24 +1829,119 @@
 odecList) %7B%0A
+        Integer tempFrameRate = null;%0A        Integer tempAacProfile = null;%0A        try %7B%0A    
         // I
@@ -2014,33 +2014,8 @@
     
-    String encoderName;%0A%0A
     
@@ -2118,19 +2118,19 @@
         
-int
+   
  tempFra
@@ -2134,24 +2134,40 @@
 FrameRate = 
+Integer.valueOf(
 mediaFormat.
@@ -2204,16 +2204,17 @@
 ME_RATE)
+)
 ;%0A      
@@ -2215,24 +2215,28 @@
             
+   
+ 
 // Reset fra
@@ -2260,16 +2260,20 @@
 API 21.%0A
+    
         
@@ -2341,37 +2341,729 @@
             
-encoderName =
+%7D%0A%0A            // TODO(b/192129356): Remove KEY_AAC_PROFILE when API %3C= 23 in order to find an encoder%0A            //  name or it will get null. This is currently needed for not blocking e2e/MH test.%0A            //  After the bug has been clarified, the workaround should be removed or a quirk should%0A            //  be added.%0A            if (Build.VERSION.SDK_INT %3C= Build.VERSION_CODES.M && mediaFormat.containsKey(%0A                    MediaFormat.KEY_AAC_PROFILE)) %7B%0A                tempAacProfile = Integer.valueOf(%0A                        mediaFormat.getInteger(MediaFormat.KEY_AAC_PROFILE));%0A                mediaFormat.setString(MediaFormat.KEY_AAC_PROFILE, null);%0A            %7D%0A%0A            return
  mediaCodecL
@@ -3100,24 +3100,41 @@
 Format);%0A   
+     %7D finally %7B%0A
          // 
@@ -3126,24 +3126,27 @@
  %7B%0A         
+   
 // Restore t
@@ -3166,16 +3166,61 @@
  value.%0A
+            if (tempFrameRate != null) %7B%0A    
         
@@ -3287,16 +3287,27 @@
 rameRate
+.intValue()
 );%0A     
@@ -3313,90 +3313,196 @@
     
+ 
-%7D else %7B%0A            encoderNam
+   %7D%0A%0A            // Restore the aac profile value.%0A            if (tempAacProfil
 e 
+!
 = 
-mediaCodecList.findEncoderForFormat(mediaFormat
+null) %7B%0A                mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, tempAacProfile.intValue()
 );%0A 
@@ -3500,34 +3500,37 @@
 lue());%0A        
+  
+  
 %7D
-%0A
 %0A        return 
@@ -3526,33 +3526,14 @@
     
-return encoderName;
+%7D
 %0A    %7D%0A
-%0A
 %7D%0A

Fix failure of e2e CameraCoreAppVideoCaptureAspectRatioTest on Samsung J2, J1 mini