mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add encoder setting to set frame repeat interval
This can be used for screen recording to produce files without large gaps between frames. PiperOrigin-RevId: 726451010
This commit is contained in:
parent
2a91d47ea9
commit
04d9a751c6
@ -385,6 +385,13 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
|
||||
}
|
||||
}
|
||||
|
||||
long repeatPreviousFrameIntervalUs =
|
||||
supportedVideoEncoderSettings.repeatPreviousFrameIntervalUs;
|
||||
if (repeatPreviousFrameIntervalUs != VideoEncoderSettings.NO_VALUE) {
|
||||
mediaFormat.setLong(
|
||||
MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, repeatPreviousFrameIntervalUs);
|
||||
}
|
||||
|
||||
if (Util.SDK_INT >= 35) {
|
||||
mediaFormat.setInteger(MediaFormat.KEY_IMPORTANCE, max(0, -codecPriority));
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ public final class VideoEncoderSettings {
|
||||
private float iFrameIntervalSeconds;
|
||||
private int operatingRate;
|
||||
private int priority;
|
||||
private long repeatPreviousFrameIntervalUs;
|
||||
private boolean enableHighQualityTargeting;
|
||||
|
||||
/** Creates a new instance. */
|
||||
@ -93,6 +94,7 @@ public final class VideoEncoderSettings {
|
||||
this.iFrameIntervalSeconds = DEFAULT_I_FRAME_INTERVAL_SECONDS;
|
||||
this.operatingRate = NO_VALUE;
|
||||
this.priority = NO_VALUE;
|
||||
this.repeatPreviousFrameIntervalUs = NO_VALUE;
|
||||
}
|
||||
|
||||
private Builder(VideoEncoderSettings videoEncoderSettings) {
|
||||
@ -103,6 +105,7 @@ public final class VideoEncoderSettings {
|
||||
this.iFrameIntervalSeconds = videoEncoderSettings.iFrameIntervalSeconds;
|
||||
this.operatingRate = videoEncoderSettings.operatingRate;
|
||||
this.priority = videoEncoderSettings.priority;
|
||||
this.repeatPreviousFrameIntervalUs = videoEncoderSettings.repeatPreviousFrameIntervalUs;
|
||||
this.enableHighQualityTargeting = videoEncoderSettings.enableHighQualityTargeting;
|
||||
}
|
||||
|
||||
@ -190,6 +193,21 @@ public final class VideoEncoderSettings {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the threshold duration between input frames beyond which to repeat the previous frame if
|
||||
* no new frame has been received, in microseconds. The default value is {@link #NO_VALUE},
|
||||
* which means that frames are not automatically repeated.
|
||||
*
|
||||
* @param repeatPreviousFrameIntervalUs The {@linkplain
|
||||
* MediaFormat#KEY_REPEAT_PREVIOUS_FRAME_AFTER frame repeat interval}, in microseconds.
|
||||
* @return This builder.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setRepeatPreviousFrameIntervalUs(long repeatPreviousFrameIntervalUs) {
|
||||
this.repeatPreviousFrameIntervalUs = repeatPreviousFrameIntervalUs;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to enable automatic adjustment of the bitrate to target a high quality encoding.
|
||||
*
|
||||
@ -223,6 +241,7 @@ public final class VideoEncoderSettings {
|
||||
iFrameIntervalSeconds,
|
||||
operatingRate,
|
||||
priority,
|
||||
repeatPreviousFrameIntervalUs,
|
||||
enableHighQualityTargeting);
|
||||
}
|
||||
}
|
||||
@ -248,6 +267,12 @@ public final class VideoEncoderSettings {
|
||||
/** The encoder {@link MediaFormat#KEY_PRIORITY priority}. */
|
||||
public final int priority;
|
||||
|
||||
/**
|
||||
* The {@linkplain MediaFormat#KEY_REPEAT_PREVIOUS_FRAME_AFTER frame repeat interval}, in
|
||||
* microseconds.
|
||||
*/
|
||||
public final long repeatPreviousFrameIntervalUs;
|
||||
|
||||
/** Whether the encoder should automatically set the bitrate to target a high quality encoding. */
|
||||
public final boolean enableHighQualityTargeting;
|
||||
|
||||
@ -259,6 +284,7 @@ public final class VideoEncoderSettings {
|
||||
float iFrameIntervalSeconds,
|
||||
int operatingRate,
|
||||
int priority,
|
||||
long repeatPreviousFrameIntervalUs,
|
||||
boolean enableHighQualityTargeting) {
|
||||
this.bitrate = bitrate;
|
||||
this.bitrateMode = bitrateMode;
|
||||
@ -267,6 +293,7 @@ public final class VideoEncoderSettings {
|
||||
this.iFrameIntervalSeconds = iFrameIntervalSeconds;
|
||||
this.operatingRate = operatingRate;
|
||||
this.priority = priority;
|
||||
this.repeatPreviousFrameIntervalUs = repeatPreviousFrameIntervalUs;
|
||||
this.enableHighQualityTargeting = enableHighQualityTargeting;
|
||||
}
|
||||
|
||||
@ -293,6 +320,7 @@ public final class VideoEncoderSettings {
|
||||
&& iFrameIntervalSeconds == that.iFrameIntervalSeconds
|
||||
&& operatingRate == that.operatingRate
|
||||
&& priority == that.priority
|
||||
&& repeatPreviousFrameIntervalUs == that.repeatPreviousFrameIntervalUs
|
||||
&& enableHighQualityTargeting == that.enableHighQualityTargeting;
|
||||
}
|
||||
|
||||
@ -306,6 +334,9 @@ public final class VideoEncoderSettings {
|
||||
result = 31 * result + Float.floatToIntBits(iFrameIntervalSeconds);
|
||||
result = 31 * result + operatingRate;
|
||||
result = 31 * result + priority;
|
||||
result =
|
||||
31 * result
|
||||
+ (int) (repeatPreviousFrameIntervalUs ^ (repeatPreviousFrameIntervalUs >>> 32));
|
||||
result = 31 * result + (enableHighQualityTargeting ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
@ -323,6 +323,42 @@ public class DefaultEncoderFactoryTest {
|
||||
assertThat(configurationMediaFormat.containsKey(MediaFormat.KEY_OPERATING_RATE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
createForVideoEncoding_withRepeatPreviousFrameIntervalUs_configuresEncoderWithRepeatPreviousFrameIntervalUs()
|
||||
throws Exception {
|
||||
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||
DefaultCodec videoEncoder =
|
||||
new DefaultEncoderFactory.Builder(context)
|
||||
.setRequestedVideoEncoderSettings(
|
||||
new VideoEncoderSettings.Builder().setRepeatPreviousFrameIntervalUs(33_333).build())
|
||||
.build()
|
||||
.createForVideoEncoding(requestedVideoFormat);
|
||||
|
||||
assertThat(
|
||||
videoEncoder
|
||||
.getConfigurationMediaFormat()
|
||||
.getLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER))
|
||||
.isEqualTo(33_333);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
createForVideoEncoding_withDefaultEncoderSettings_doesNotConfigureRepeatPreviousFrameIntervalUs()
|
||||
throws Exception {
|
||||
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||
DefaultCodec videoEncoder =
|
||||
new DefaultEncoderFactory.Builder(context)
|
||||
.build()
|
||||
.createForVideoEncoding(requestedVideoFormat);
|
||||
|
||||
assertThat(
|
||||
videoEncoder
|
||||
.getConfigurationMediaFormat()
|
||||
.containsKey(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createForVideoEncoding_withNoAvailableEncoderFromEncoderSelector_throws() {
|
||||
Format requestedVideoFormat = createVideoFormat(MimeTypes.VIDEO_H264, 1920, 1080, 30);
|
||||
|
Loading…
x
Reference in New Issue
Block a user