mirror of
https://github.com/androidx/media.git
synced 2025-04-29 22:36:54 +08:00
Update DefaultEncoderFactory to set GOP parameters
If set on the requested VideoEncoderSettings, then these parameters are passed into the MediaFormat used by the DefaultEncoderFactory to configure the underlying codec. PiperOrigin-RevId: 751059914
This commit is contained in:
parent
910b6ab884
commit
dae5ebb820
@ -46,6 +46,7 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||||
|
|
||||||
/** A default implementation of {@link Codec.EncoderFactory}. */
|
/** A default implementation of {@link Codec.EncoderFactory}. */
|
||||||
@ -395,6 +396,33 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int maxBFrames = supportedVideoEncoderSettings.maxBFrames;
|
||||||
|
if (SDK_INT >= 29 && maxBFrames != VideoEncoderSettings.NO_VALUE) {
|
||||||
|
mediaFormat.setInteger(MediaFormat.KEY_MAX_B_FRAMES, maxBFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
int numNonBidirectionalTemporalLayers =
|
||||||
|
supportedVideoEncoderSettings.numNonBidirectionalTemporalLayers;
|
||||||
|
int numBidirectionalTemporalLayers =
|
||||||
|
supportedVideoEncoderSettings.numBidirectionalTemporalLayers;
|
||||||
|
if (SDK_INT >= 25 && numNonBidirectionalTemporalLayers >= 0) {
|
||||||
|
String temporalSchema;
|
||||||
|
if (numNonBidirectionalTemporalLayers == 0) {
|
||||||
|
temporalSchema = "none";
|
||||||
|
} else if (numBidirectionalTemporalLayers > 0) {
|
||||||
|
temporalSchema =
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"android.generic.%d+%d",
|
||||||
|
numNonBidirectionalTemporalLayers,
|
||||||
|
numBidirectionalTemporalLayers);
|
||||||
|
} else {
|
||||||
|
temporalSchema =
|
||||||
|
String.format(Locale.ROOT, "android.generic.%d", numNonBidirectionalTemporalLayers);
|
||||||
|
}
|
||||||
|
mediaFormat.setString(MediaFormat.KEY_TEMPORAL_LAYERING, temporalSchema);
|
||||||
|
}
|
||||||
|
|
||||||
return new DefaultCodec(
|
return new DefaultCodec(
|
||||||
context,
|
context,
|
||||||
encoderSupportedFormat,
|
encoderSupportedFormat,
|
||||||
|
@ -337,6 +337,164 @@ public class DefaultEncoderFactoryTest {
|
|||||||
.isFalse();
|
.isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(sdk = 29)
|
||||||
|
public void createForVideoEncoding_withMaxBFrames_configuresEncoderWithMaxBFrames()
|
||||||
|
throws Exception {
|
||||||
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
|
||||||
|
DefaultCodec videoEncoder =
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.setRequestedVideoEncoderSettings(
|
||||||
|
new VideoEncoderSettings.Builder().setMaxBFrames(3).build())
|
||||||
|
.build()
|
||||||
|
.createForVideoEncoding(requestedVideoFormat, /* logSessionId= */ null);
|
||||||
|
|
||||||
|
assertThat(videoEncoder.getConfigurationMediaFormat().getInteger(MediaFormat.KEY_MAX_B_FRAMES))
|
||||||
|
.isEqualTo(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(sdk = 23)
|
||||||
|
public void createForVideoEncoding_withMaxBFramesOnApi23_doesNotConfigureMaxBFrames()
|
||||||
|
throws Exception {
|
||||||
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
|
||||||
|
DefaultCodec videoEncoder =
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.setRequestedVideoEncoderSettings(
|
||||||
|
new VideoEncoderSettings.Builder().setMaxBFrames(3).build())
|
||||||
|
.build()
|
||||||
|
.createForVideoEncoding(requestedVideoFormat, /* logSessionId= */ null);
|
||||||
|
|
||||||
|
assertThat(videoEncoder.getConfigurationMediaFormat().containsKey(MediaFormat.KEY_MAX_B_FRAMES))
|
||||||
|
.isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(sdk = 29)
|
||||||
|
public void createForVideoEncoding_withDefaultEncoderSettings_doesNotConfigureMaxBFrames()
|
||||||
|
throws Exception {
|
||||||
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
|
||||||
|
DefaultCodec videoEncoder =
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.build()
|
||||||
|
.createForVideoEncoding(requestedVideoFormat, /* logSessionId= */ null);
|
||||||
|
|
||||||
|
assertThat(videoEncoder.getConfigurationMediaFormat().containsKey(MediaFormat.KEY_MAX_B_FRAMES))
|
||||||
|
.isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config(sdk = 29)
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createForVideoEncoding_withTemporalLayeringSchemaWithZeroLayers_configuresEncoderWithTemporalLayeringSchema()
|
||||||
|
throws Exception {
|
||||||
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
|
||||||
|
DefaultCodec videoEncoder =
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.setRequestedVideoEncoderSettings(
|
||||||
|
new VideoEncoderSettings.Builder()
|
||||||
|
.setTemporalLayers(
|
||||||
|
/* numNonBidirectionalLayers= */ 0, /* numBidirectionalLayers= */ 0)
|
||||||
|
.build())
|
||||||
|
.build()
|
||||||
|
.createForVideoEncoding(requestedVideoFormat, /* logSessionId= */ null);
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
videoEncoder.getConfigurationMediaFormat().getString(MediaFormat.KEY_TEMPORAL_LAYERING))
|
||||||
|
.isEqualTo("none");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config(sdk = 29)
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createForVideoEncoding_withTemporalLayeringSchemaWithoutBidirectionalLayers_configuresEncoderWithTemporalLayeringSchema()
|
||||||
|
throws Exception {
|
||||||
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
|
||||||
|
DefaultCodec videoEncoder =
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.setRequestedVideoEncoderSettings(
|
||||||
|
new VideoEncoderSettings.Builder()
|
||||||
|
.setTemporalLayers(
|
||||||
|
/* numNonBidirectionalLayers= */ 1, /* numBidirectionalLayers= */ 0)
|
||||||
|
.build())
|
||||||
|
.build()
|
||||||
|
.createForVideoEncoding(requestedVideoFormat, /* logSessionId= */ null);
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
videoEncoder.getConfigurationMediaFormat().getString(MediaFormat.KEY_TEMPORAL_LAYERING))
|
||||||
|
.isEqualTo("android.generic.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config(sdk = 29)
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createForVideoEncoding_withTemporalLayeringSchemaWithBidirectionalLayers_configuresEncoderWithTemporalLayeringSchema()
|
||||||
|
throws Exception {
|
||||||
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
|
||||||
|
DefaultCodec videoEncoder =
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.setRequestedVideoEncoderSettings(
|
||||||
|
new VideoEncoderSettings.Builder()
|
||||||
|
.setTemporalLayers(
|
||||||
|
/* numNonBidirectionalLayers= */ 1, /* numBidirectionalLayers= */ 2)
|
||||||
|
.build())
|
||||||
|
.build()
|
||||||
|
.createForVideoEncoding(requestedVideoFormat, /* logSessionId= */ null);
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
videoEncoder.getConfigurationMediaFormat().getString(MediaFormat.KEY_TEMPORAL_LAYERING))
|
||||||
|
.isEqualTo("android.generic.1+2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config(sdk = 23)
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createForVideoEncoding_withTemporalLayeringSchemaOnApi23_doesNotConfigureTemporalLayeringSchema()
|
||||||
|
throws Exception {
|
||||||
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
|
||||||
|
DefaultCodec videoEncoder =
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.setRequestedVideoEncoderSettings(
|
||||||
|
new VideoEncoderSettings.Builder()
|
||||||
|
.setTemporalLayers(
|
||||||
|
/* numNonBidirectionalLayers= */ 1, /* numBidirectionalLayers= */ 2)
|
||||||
|
.build())
|
||||||
|
.build()
|
||||||
|
.createForVideoEncoding(requestedVideoFormat, /* logSessionId= */ null);
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
videoEncoder
|
||||||
|
.getConfigurationMediaFormat()
|
||||||
|
.containsKey(MediaFormat.KEY_TEMPORAL_LAYERING))
|
||||||
|
.isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config(sdk = 29)
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createForVideoEncoding_withDefaultEncoderSettings_doesNotConfigureTemporalLayeringSchema()
|
||||||
|
throws Exception {
|
||||||
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
|
||||||
|
DefaultCodec videoEncoder =
|
||||||
|
new DefaultEncoderFactory.Builder(context)
|
||||||
|
.build()
|
||||||
|
.createForVideoEncoding(requestedVideoFormat, /* logSessionId= */ null);
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
videoEncoder
|
||||||
|
.getConfigurationMediaFormat()
|
||||||
|
.containsKey(MediaFormat.KEY_TEMPORAL_LAYERING))
|
||||||
|
.isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createForVideoEncoding_withNoAvailableEncoderFromEncoderSelector_throws() {
|
public void createForVideoEncoding_withNoAvailableEncoderFromEncoderSelector_throws() {
|
||||||
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user