mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add AudioEncoderSettings to Transformer
It allows clients to specify the audio encoding profile and bitrate. This is similar to VideoEncoderSettings. PiperOrigin-RevId: 679131963
This commit is contained in:
parent
f4eef88089
commit
b6192f7a39
@ -34,6 +34,7 @@ import android.content.Context;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Bitmap.Config;
|
import android.graphics.Bitmap.Config;
|
||||||
import android.media.Image;
|
import android.media.Image;
|
||||||
|
import android.media.MediaCodecInfo;
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import android.opengl.EGLContext;
|
import android.opengl.EGLContext;
|
||||||
import android.opengl.EGLDisplay;
|
import android.opengl.EGLDisplay;
|
||||||
@ -1215,6 +1216,28 @@ public final class AndroidTestUtil {
|
|||||||
throw new AssumptionViolatedException(skipReason);
|
throw new AssumptionViolatedException(skipReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assumes that the device supports encoding with the given MIME type and profile.
|
||||||
|
*
|
||||||
|
* @param mimeType The {@linkplain MimeTypes MIME type}.
|
||||||
|
* @param profile The {@linkplain MediaCodecInfo.CodecProfileLevel codec profile}.
|
||||||
|
* @throws AssumptionViolatedException If the device does have required encoder or profile.
|
||||||
|
*/
|
||||||
|
public static void assumeCanEncodeWithProfile(String mimeType, int profile) {
|
||||||
|
ImmutableList<MediaCodecInfo> supportedEncoders = EncoderUtil.getSupportedEncoders(mimeType);
|
||||||
|
if (supportedEncoders.isEmpty()) {
|
||||||
|
throw new AssumptionViolatedException("No supported encoders");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < supportedEncoders.size(); i++) {
|
||||||
|
if (EncoderUtil.findSupportedEncodingProfiles(supportedEncoders.get(i), mimeType)
|
||||||
|
.contains(profile)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new AssumptionViolatedException("Profile not supported");
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a {@link Muxer.Factory} depending upon the API level. */
|
/** Returns a {@link Muxer.Factory} depending upon the API level. */
|
||||||
public static Muxer.Factory getMuxerFactoryBasedOnApi() {
|
public static Muxer.Factory getMuxerFactoryBasedOnApi() {
|
||||||
// MediaMuxer supports B-frame from API > 24.
|
// MediaMuxer supports B-frame from API > 24.
|
||||||
|
@ -15,7 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.transformer;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
|
import static android.media.MediaCodecInfo.CodecProfileLevel.AACObjectHE;
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
|
import static androidx.media3.common.util.MediaFormatUtil.createFormatFromMediaFormat;
|
||||||
import static androidx.media3.common.util.Util.isRunningOnEmulator;
|
import static androidx.media3.common.util.Util.isRunningOnEmulator;
|
||||||
import static androidx.media3.test.utils.TestUtil.retrieveTrackFormat;
|
import static androidx.media3.test.utils.TestUtil.retrieveTrackFormat;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.JPG_ASSET;
|
import static androidx.media3.transformer.AndroidTestUtil.JPG_ASSET;
|
||||||
@ -31,6 +34,7 @@ import static androidx.media3.transformer.AndroidTestUtil.MP4_TRIM_OPTIMIZATION_
|
|||||||
import static androidx.media3.transformer.AndroidTestUtil.PNG_ASSET;
|
import static androidx.media3.transformer.AndroidTestUtil.PNG_ASSET;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.WAV_ASSET;
|
import static androidx.media3.transformer.AndroidTestUtil.WAV_ASSET;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.WEBP_LARGE;
|
import static androidx.media3.transformer.AndroidTestUtil.WEBP_LARGE;
|
||||||
|
import static androidx.media3.transformer.AndroidTestUtil.assumeCanEncodeWithProfile;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.assumeFormatsSupported;
|
import static androidx.media3.transformer.AndroidTestUtil.assumeFormatsSupported;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.createFrameCountingEffect;
|
import static androidx.media3.transformer.AndroidTestUtil.createFrameCountingEffect;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.createOpenGlObjects;
|
import static androidx.media3.transformer.AndroidTestUtil.createOpenGlObjects;
|
||||||
@ -47,10 +51,12 @@ import static androidx.media3.transformer.ExportResult.OPTIMIZATION_FAILED_FORMA
|
|||||||
import static androidx.media3.transformer.ExportResult.OPTIMIZATION_SUCCEEDED;
|
import static androidx.media3.transformer.ExportResult.OPTIMIZATION_SUCCEEDED;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assume.assumeFalse;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.media.MediaFormat;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.opengl.EGLContext;
|
import android.opengl.EGLContext;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@ -71,6 +77,7 @@ import androidx.media3.common.audio.ChannelMixingAudioProcessor;
|
|||||||
import androidx.media3.common.audio.ChannelMixingMatrix;
|
import androidx.media3.common.audio.ChannelMixingMatrix;
|
||||||
import androidx.media3.common.audio.SonicAudioProcessor;
|
import androidx.media3.common.audio.SonicAudioProcessor;
|
||||||
import androidx.media3.common.audio.SpeedProvider;
|
import androidx.media3.common.audio.SpeedProvider;
|
||||||
|
import androidx.media3.common.util.CodecSpecificDataUtil;
|
||||||
import androidx.media3.common.util.GlUtil;
|
import androidx.media3.common.util.GlUtil;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.datasource.DataSourceBitmapLoader;
|
import androidx.media3.datasource.DataSourceBitmapLoader;
|
||||||
@ -85,6 +92,7 @@ import androidx.media3.effect.RgbFilter;
|
|||||||
import androidx.media3.effect.ScaleAndRotateTransformation;
|
import androidx.media3.effect.ScaleAndRotateTransformation;
|
||||||
import androidx.media3.effect.SpeedChangeEffect;
|
import androidx.media3.effect.SpeedChangeEffect;
|
||||||
import androidx.media3.effect.TimestampWrapper;
|
import androidx.media3.effect.TimestampWrapper;
|
||||||
|
import androidx.media3.exoplayer.MediaExtractorCompat;
|
||||||
import androidx.media3.exoplayer.audio.TeeAudioProcessor;
|
import androidx.media3.exoplayer.audio.TeeAudioProcessor;
|
||||||
import androidx.media3.extractor.mp4.Mp4Extractor;
|
import androidx.media3.extractor.mp4.Mp4Extractor;
|
||||||
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||||
@ -96,6 +104,7 @@ import androidx.media3.transformer.AndroidTestUtil.FrameCountingByteBufferProces
|
|||||||
import androidx.media3.transformer.AssetLoader.CompositionSettings;
|
import androidx.media3.transformer.AssetLoader.CompositionSettings;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.common.base.Ascii;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -2167,6 +2176,80 @@ public class TransformerEndToEndTest {
|
|||||||
assertThat(new File(result.filePath).length()).isGreaterThan(0);
|
assertThat(new File(result.filePath).length()).isGreaterThan(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void export_setAudioEncodingProfile_changesProfile() throws Exception {
|
||||||
|
assumeFalse(shouldSkipDeviceForAacObjectHeProfileEncoding());
|
||||||
|
assumeCanEncodeWithProfile(MimeTypes.AUDIO_AAC, AACObjectHE);
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
Transformer transformer =
|
||||||
|
new Transformer.Builder(context)
|
||||||
|
.setEncoderFactory(
|
||||||
|
new AndroidTestUtil.ForceEncodeEncoderFactory(
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.setRequestedAudioEncoderSettings(
|
||||||
|
new AudioEncoderSettings.Builder().setProfile(AACObjectHE).build())
|
||||||
|
.build()))
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = new MediaItem.Builder().setUri(MP4_ASSET.uri).build();
|
||||||
|
EditedMediaItem editedMediaItem =
|
||||||
|
new EditedMediaItem.Builder(mediaItem).setRemoveVideo(true).build();
|
||||||
|
|
||||||
|
ExportTestResult result =
|
||||||
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
|
.build()
|
||||||
|
.run(testId, editedMediaItem);
|
||||||
|
|
||||||
|
MediaExtractorCompat mediaExtractor = new MediaExtractorCompat(context);
|
||||||
|
mediaExtractor.setDataSource(Uri.parse(result.filePath), /* offset= */ 0);
|
||||||
|
checkState(mediaExtractor.getTrackCount() == 1);
|
||||||
|
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(/* trackIndex= */ 0);
|
||||||
|
Format format = createFormatFromMediaFormat(mediaFormat);
|
||||||
|
Pair<Integer, Integer> profileAndLevel = CodecSpecificDataUtil.getCodecProfileAndLevel(format);
|
||||||
|
assertThat(profileAndLevel.first).isEqualTo(AACObjectHE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void export_setAudioEncodingBitrate_configuresEncoderWithRequestedBitrate()
|
||||||
|
throws Exception {
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
int requestedBitrate = 60_000;
|
||||||
|
// The MediaMuxer is not writing the bitrate hence use the InAppMuxer.
|
||||||
|
Transformer transformer =
|
||||||
|
new Transformer.Builder(context)
|
||||||
|
.setMuxerFactory(new InAppMuxer.Factory.Builder().build())
|
||||||
|
.setEncoderFactory(
|
||||||
|
new AndroidTestUtil.ForceEncodeEncoderFactory(
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.setRequestedAudioEncoderSettings(
|
||||||
|
new AudioEncoderSettings.Builder().setBitrate(requestedBitrate).build())
|
||||||
|
.build()))
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = new MediaItem.Builder().setUri(MP4_ASSET.uri).build();
|
||||||
|
EditedMediaItem editedMediaItem =
|
||||||
|
new EditedMediaItem.Builder(mediaItem).setRemoveVideo(true).build();
|
||||||
|
|
||||||
|
ExportTestResult result =
|
||||||
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
|
.build()
|
||||||
|
.run(testId, editedMediaItem);
|
||||||
|
|
||||||
|
MediaExtractorCompat mediaExtractor = new MediaExtractorCompat(context);
|
||||||
|
mediaExtractor.setDataSource(Uri.parse(result.filePath), /* offset= */ 0);
|
||||||
|
checkState(mediaExtractor.getTrackCount() == 1);
|
||||||
|
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(/* trackIndex= */ 0);
|
||||||
|
Format format = createFormatFromMediaFormat(mediaFormat);
|
||||||
|
// The format contains the requested bitrate but the actual bitrate is generally different.
|
||||||
|
assertThat(format.bitrate).isEqualTo(requestedBitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldSkipDeviceForAacObjectHeProfileEncoding() {
|
||||||
|
// These devices claims to have the AACObjectHE profile but the profile never gets applied.
|
||||||
|
return (Util.SDK_INT == 27 && Ascii.equalsIgnoreCase(Util.MODEL, "cph1803"))
|
||||||
|
|| (Util.SDK_INT == 27 && Ascii.equalsIgnoreCase(Util.MODEL, "cph1909"))
|
||||||
|
|| (Util.SDK_INT == 27 && Ascii.equalsIgnoreCase(Util.MODEL, "redmi note 5"))
|
||||||
|
|| (Util.SDK_INT == 26 && isRunningOnEmulator());
|
||||||
|
}
|
||||||
|
|
||||||
private static AudioProcessor createSonic(float pitch) {
|
private static AudioProcessor createSonic(float pitch) {
|
||||||
SonicAudioProcessor sonic = new SonicAudioProcessor();
|
SonicAudioProcessor sonic = new SonicAudioProcessor();
|
||||||
sonic.setPitch(pitch);
|
sonic.setPitch(pitch);
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 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.media3.transformer;
|
||||||
|
|
||||||
|
import android.media.MediaCodecInfo;
|
||||||
|
import androidx.media3.common.Format;
|
||||||
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
|
|
||||||
|
/** Represents the audio encoder settings. */
|
||||||
|
@UnstableApi
|
||||||
|
public final class AudioEncoderSettings {
|
||||||
|
/** Builds {@link AudioEncoderSettings} instances. */
|
||||||
|
public static final class Builder {
|
||||||
|
private int profile;
|
||||||
|
private int bitrate;
|
||||||
|
|
||||||
|
/** Creates a new instance. */
|
||||||
|
public Builder() {
|
||||||
|
profile = NO_VALUE;
|
||||||
|
bitrate = NO_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link AudioEncoderSettings#profile}.
|
||||||
|
*
|
||||||
|
* <p>The default value is {@link #NO_VALUE} and the appropriate profile will be used
|
||||||
|
* automatically.
|
||||||
|
*
|
||||||
|
* <p>The requested profile must be one of the values defined in {@link
|
||||||
|
* MediaCodecInfo.CodecProfileLevel} and must be compatible with the requested {@linkplain
|
||||||
|
* Transformer.Builder#setAudioMimeType(String) audio MIME type}. When using the {@link
|
||||||
|
* DefaultEncoderFactory}, if the encoder does not support the requested profile, then it will
|
||||||
|
* be ignored to avoid any encoder configuration failures.
|
||||||
|
*
|
||||||
|
* @param profile The profile.
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setProfile(int profile) {
|
||||||
|
this.profile = profile;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link AudioEncoderSettings#bitrate}.
|
||||||
|
*
|
||||||
|
* <p>The default value is {@link #NO_VALUE}.
|
||||||
|
*
|
||||||
|
* <p>The encoder may ignore the requested bitrate to improve the encoding quality.
|
||||||
|
*
|
||||||
|
* @param bitrate The bitrate in bits per second.
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setBitrate(int bitrate) {
|
||||||
|
this.bitrate = bitrate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds the instance. */
|
||||||
|
public AudioEncoderSettings build() {
|
||||||
|
return new AudioEncoderSettings(profile, bitrate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A value for various fields to indicate that the field's value is unknown or not applicable. */
|
||||||
|
public static final int NO_VALUE = Format.NO_VALUE;
|
||||||
|
|
||||||
|
/** A default {@link AudioEncoderSettings}. */
|
||||||
|
public static final AudioEncoderSettings DEFAULT = new Builder().build();
|
||||||
|
|
||||||
|
/** The encoding profile. */
|
||||||
|
public final int profile;
|
||||||
|
|
||||||
|
/** The encoding bitrate in bits per second. */
|
||||||
|
public final int bitrate;
|
||||||
|
|
||||||
|
private AudioEncoderSettings(int profile, int bitrate) {
|
||||||
|
this.profile = profile;
|
||||||
|
this.bitrate = bitrate;
|
||||||
|
}
|
||||||
|
}
|
@ -64,6 +64,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
|||||||
|
|
||||||
private EncoderSelector videoEncoderSelector;
|
private EncoderSelector videoEncoderSelector;
|
||||||
private VideoEncoderSettings requestedVideoEncoderSettings;
|
private VideoEncoderSettings requestedVideoEncoderSettings;
|
||||||
|
private AudioEncoderSettings requestedAudioEncoderSettings;
|
||||||
private boolean enableFallback;
|
private boolean enableFallback;
|
||||||
private @C.Priority int codecPriority;
|
private @C.Priority int codecPriority;
|
||||||
|
|
||||||
@ -72,6 +73,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
|||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
videoEncoderSelector = EncoderSelector.DEFAULT;
|
videoEncoderSelector = EncoderSelector.DEFAULT;
|
||||||
requestedVideoEncoderSettings = VideoEncoderSettings.DEFAULT;
|
requestedVideoEncoderSettings = VideoEncoderSettings.DEFAULT;
|
||||||
|
requestedAudioEncoderSettings = AudioEncoderSettings.DEFAULT;
|
||||||
enableFallback = true;
|
enableFallback = true;
|
||||||
codecPriority = C.PRIORITY_PROCESSING_FOREGROUND;
|
codecPriority = C.PRIORITY_PROCESSING_FOREGROUND;
|
||||||
}
|
}
|
||||||
@ -111,6 +113,20 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the requested {@link AudioEncoderSettings}.
|
||||||
|
*
|
||||||
|
* <p>The default value is {@link AudioEncoderSettings#DEFAULT}.
|
||||||
|
*
|
||||||
|
* <p>Values in {@code requestedAudioEncoderSettings} may be ignored to reduce failures.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setRequestedAudioEncoderSettings(
|
||||||
|
AudioEncoderSettings requestedAudioEncoderSettings) {
|
||||||
|
this.requestedAudioEncoderSettings = requestedAudioEncoderSettings;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether the encoder can fallback.
|
* Sets whether the encoder can fallback.
|
||||||
*
|
*
|
||||||
@ -160,6 +176,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
|||||||
private final Context context;
|
private final Context context;
|
||||||
private final EncoderSelector videoEncoderSelector;
|
private final EncoderSelector videoEncoderSelector;
|
||||||
private final VideoEncoderSettings requestedVideoEncoderSettings;
|
private final VideoEncoderSettings requestedVideoEncoderSettings;
|
||||||
|
private final AudioEncoderSettings requestedAudioEncoderSettings;
|
||||||
private final boolean enableFallback;
|
private final boolean enableFallback;
|
||||||
private final @C.Priority int codecPriority;
|
private final @C.Priority int codecPriority;
|
||||||
|
|
||||||
@ -203,6 +220,7 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
|||||||
this.context = builder.context;
|
this.context = builder.context;
|
||||||
this.videoEncoderSelector = builder.videoEncoderSelector;
|
this.videoEncoderSelector = builder.videoEncoderSelector;
|
||||||
this.requestedVideoEncoderSettings = builder.requestedVideoEncoderSettings;
|
this.requestedVideoEncoderSettings = builder.requestedVideoEncoderSettings;
|
||||||
|
this.requestedAudioEncoderSettings = builder.requestedAudioEncoderSettings;
|
||||||
this.enableFallback = builder.enableFallback;
|
this.enableFallback = builder.enableFallback;
|
||||||
this.codecPriority = builder.codecPriority;
|
this.codecPriority = builder.codecPriority;
|
||||||
}
|
}
|
||||||
@ -221,11 +239,35 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
|||||||
if (mediaCodecInfos.isEmpty()) {
|
if (mediaCodecInfos.isEmpty()) {
|
||||||
throw createExportException(format, "No audio media codec found");
|
throw createExportException(format, "No audio media codec found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaCodecInfo selectedEncoder = mediaCodecInfos.get(0);
|
||||||
|
|
||||||
|
if (requestedAudioEncoderSettings.profile != AudioEncoderSettings.NO_VALUE) {
|
||||||
|
for (int i = 0; i < mediaCodecInfos.size(); i++) {
|
||||||
|
MediaCodecInfo encoderInfo = mediaCodecInfos.get(i);
|
||||||
|
if (EncoderUtil.findSupportedEncodingProfiles(encoderInfo, format.sampleMimeType)
|
||||||
|
.contains(requestedAudioEncoderSettings.profile)) {
|
||||||
|
selectedEncoder = encoderInfo;
|
||||||
|
if (format.sampleMimeType.equals(MimeTypes.AUDIO_AAC)) {
|
||||||
|
mediaFormat.setInteger(
|
||||||
|
MediaFormat.KEY_AAC_PROFILE, requestedAudioEncoderSettings.profile);
|
||||||
|
}
|
||||||
|
// On some devices setting only KEY_AAC_PROFILE for AAC does not work.
|
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_PROFILE, requestedAudioEncoderSettings.profile);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestedAudioEncoderSettings.bitrate != AudioEncoderSettings.NO_VALUE) {
|
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, requestedAudioEncoderSettings.bitrate);
|
||||||
|
}
|
||||||
|
|
||||||
return new DefaultCodec(
|
return new DefaultCodec(
|
||||||
context,
|
context,
|
||||||
format,
|
format,
|
||||||
mediaFormat,
|
mediaFormat,
|
||||||
mediaCodecInfos.get(0).getName(),
|
selectedEncoder.getName(),
|
||||||
/* isDecoder= */ false,
|
/* isDecoder= */ false,
|
||||||
/* outputSurface= */ null);
|
/* outputSurface= */ null);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user