Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
51d1c0b8
authored
Nov 28, 2022
by
claincly
Committed by
Rohit Singh
Nov 29, 2022
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Fix VideoEncoderSetting.bitrate is ignored when set
PiperOrigin-RevId: 491377695
parent
3a7f940f
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
169 additions
and
37 deletions
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java
library/transformer/src/test/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactoryTest.java
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactory.java
View file @
51d1c0b8
...
...
@@ -204,6 +204,25 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
/* outputSurface= */
null
);
}
/**
* Returns a {@link DefaultCodec} for video encoding.
*
* <p>Use {@link Builder#setRequestedVideoEncoderSettings} with {@link
* VideoEncoderSettings#bitrate} set to request for a specific encoding bitrate. Bitrate settings
* in {@link Format} are ignored when {@link VideoEncoderSettings#bitrate} or {@link
* VideoEncoderSettings#enableHighQualityTargeting} is set.
*
* @param format The {@link Format} (of the output data) used to determine the underlying encoder
* and its configuration values. {@link Format#sampleMimeType}, {@link Format#width} and
* {@link Format#height} are set to those of the desired output video format. {@link
* Format#rotationDegrees} is 0 and {@link Format#width} {@code >=} {@link Format#height},
* therefore the video is always in landscape orientation. {@link Format#frameRate} is set to
* the output video's frame rate, if available.
* @param allowedMimeTypes The non-empty list of allowed output sample {@linkplain MimeTypes MIME
* types}.
* @return A {@link DefaultCodec} for video encoding.
* @throws TransformationException If no suitable {@link DefaultCodec} can be created.
*/
@Override
public
Codec
createForVideoEncoding
(
Format
format
,
List
<
String
>
allowedMimeTypes
)
throws
TransformationException
{
...
...
@@ -244,26 +263,35 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
mimeType
,
encoderSupportedFormat
.
width
,
encoderSupportedFormat
.
height
);
mediaFormat
.
setInteger
(
MediaFormat
.
KEY_FRAME_RATE
,
round
(
encoderSupportedFormat
.
frameRate
));
if
(
supportedVideoEncoderSettings
.
enableHighQualityTargeting
)
{
int
bitrate
=
new
DeviceMappedEncoderBitrateProvider
()
.
getBitrate
(
encoderInfo
.
getName
(),
encoderSupportedFormat
.
width
,
encoderSupportedFormat
.
height
,
encoderSupportedFormat
.
frameRate
);
encoderSupportedFormat
=
encoderSupportedFormat
.
buildUpon
().
setAverageBitrate
(
bitrate
).
build
();
}
else
if
(
encoderSupportedFormat
.
bitrate
==
Format
.
NO_VALUE
)
{
int
bitrate
=
getSuggestedBitrate
(
encoderSupportedFormat
.
width
,
encoderSupportedFormat
.
height
,
encoderSupportedFormat
.
frameRate
);
encoderSupportedFormat
=
encoderSupportedFormat
.
buildUpon
().
setAverageBitrate
(
bitrate
).
build
();
int
finalBitrate
;
if
(
enableFallback
)
{
finalBitrate
=
supportedVideoEncoderSettings
.
bitrate
;
}
else
{
// supportedVideoEncoderSettings is identical to requestedVideoEncoderSettings.
if
(
supportedVideoEncoderSettings
.
bitrate
!=
VideoEncoderSettings
.
NO_VALUE
)
{
finalBitrate
=
supportedVideoEncoderSettings
.
bitrate
;
}
else
if
(
supportedVideoEncoderSettings
.
enableHighQualityTargeting
)
{
finalBitrate
=
new
DeviceMappedEncoderBitrateProvider
()
.
getBitrate
(
encoderInfo
.
getName
(),
encoderSupportedFormat
.
width
,
encoderSupportedFormat
.
height
,
encoderSupportedFormat
.
frameRate
);
}
else
if
(
encoderSupportedFormat
.
averageBitrate
!=
Format
.
NO_VALUE
)
{
finalBitrate
=
encoderSupportedFormat
.
averageBitrate
;
}
else
{
finalBitrate
=
getSuggestedBitrate
(
encoderSupportedFormat
.
width
,
encoderSupportedFormat
.
height
,
encoderSupportedFormat
.
frameRate
);
}
}
encoderSupportedFormat
=
encoderSupportedFormat
.
buildUpon
().
setAverageBitrate
(
finalBitrate
).
build
();
mediaFormat
.
setInteger
(
MediaFormat
.
KEY_BIT_RATE
,
encoderSupportedFormat
.
averageBitrate
);
mediaFormat
.
setInteger
(
MediaFormat
.
KEY_BITRATE_MODE
,
supportedVideoEncoderSettings
.
bitrateMode
);
...
...
@@ -387,16 +415,23 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
requestedFormat
.
width
,
requestedFormat
.
height
));
int
requestedBitrate
=
videoEncoderSettings
.
bitrate
!=
VideoEncoderSettings
.
NO_VALUE
?
videoEncoderSettings
.
bitrate
:
getSuggestedBitrate
(
finalResolution
.
getWidth
(),
finalResolution
.
getHeight
(),
requestedFormat
.
frameRate
);
filteredEncoderInfos
=
filterEncodersByBitrate
(
filteredEncoderInfos
,
mimeType
,
requestedBitrate
);
if
(
filteredEncoderInfos
.
isEmpty
())
{
return
null
;
int
requestedBitrate
=
Format
.
NO_VALUE
;
// Encoders are not filtered by bitrate if high quality targeting is enabled.
if
(!
videoEncoderSettings
.
enableHighQualityTargeting
)
{
requestedBitrate
=
videoEncoderSettings
.
bitrate
!=
VideoEncoderSettings
.
NO_VALUE
?
videoEncoderSettings
.
bitrate
:
requestedFormat
.
averageBitrate
!=
Format
.
NO_VALUE
?
requestedFormat
.
averageBitrate
:
getSuggestedBitrate
(
finalResolution
.
getWidth
(),
finalResolution
.
getHeight
(),
requestedFormat
.
frameRate
);
filteredEncoderInfos
=
filterEncodersByBitrate
(
filteredEncoderInfos
,
mimeType
,
requestedBitrate
);
if
(
filteredEncoderInfos
.
isEmpty
())
{
return
null
;
}
}
filteredEncoderInfos
=
...
...
@@ -406,11 +441,6 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
return
null
;
}
// TODO(b/238094555): Check encoder supports bitrate targeted by high quality.
MediaCodecInfo
pickedEncoderInfo
=
filteredEncoderInfos
.
get
(
0
);
int
closestSupportedBitrate
=
EncoderUtil
.
getSupportedBitrateRange
(
pickedEncoderInfo
,
mimeType
).
clamp
(
requestedBitrate
);
VideoEncoderSettings
.
Builder
supportedEncodingSettingBuilder
=
videoEncoderSettings
.
buildUpon
();
Format
.
Builder
encoderSupportedFormatBuilder
=
requestedFormat
...
...
@@ -418,11 +448,23 @@ public final class DefaultEncoderFactory implements Codec.EncoderFactory {
.
setSampleMimeType
(
mimeType
)
.
setWidth
(
finalResolution
.
getWidth
())
.
setHeight
(
finalResolution
.
getHeight
());
if
(!
videoEncoderSettings
.
enableHighQualityTargeting
)
{
supportedEncodingSettingBuilder
.
setBitrate
(
closestSupportedBitrate
);
encoderSupportedFormatBuilder
.
setAverageBitrate
(
closestSupportedBitrate
);
MediaCodecInfo
pickedEncoderInfo
=
filteredEncoderInfos
.
get
(
0
);
if
(
videoEncoderSettings
.
enableHighQualityTargeting
)
{
requestedBitrate
=
new
DeviceMappedEncoderBitrateProvider
()
.
getBitrate
(
pickedEncoderInfo
.
getName
(),
finalResolution
.
getWidth
(),
finalResolution
.
getHeight
(),
requestedFormat
.
frameRate
);
// Resets the flag after getting a targeted bitrate, so that supportedEncodingSetting can have
// bitrate set.
supportedEncodingSettingBuilder
.
setEnableHighQualityTargeting
(
false
);
}
int
closestSupportedBitrate
=
EncoderUtil
.
getSupportedBitrateRange
(
pickedEncoderInfo
,
mimeType
).
clamp
(
requestedBitrate
);
supportedEncodingSettingBuilder
.
setBitrate
(
closestSupportedBitrate
);
encoderSupportedFormatBuilder
.
setAverageBitrate
(
closestSupportedBitrate
);
if
(
videoEncoderSettings
.
profile
==
VideoEncoderSettings
.
NO_VALUE
||
videoEncoderSettings
.
level
==
VideoEncoderSettings
.
NO_VALUE
...
...
library/transformer/src/test/java/com/google/android/exoplayer2/transformer/DefaultEncoderFactoryTest.java
View file @
51d1c0b8
...
...
@@ -131,6 +131,96 @@ public class DefaultEncoderFactoryTest {
assertThat
(
actualVideoFormat
.
height
).
isEqualTo
(
1080
);
}
@Test
public
void
createForVideoEncoding_setFormatAverageBitrateUnsetVideoEncoderSettings_configuresEncoderUsingFormatAverageBitrate
()
throws
Exception
{
Format
requestedVideoFormat
=
createVideoFormat
(
MimeTypes
.
VIDEO_H264
,
1920
,
1080
,
30
);
requestedVideoFormat
=
requestedVideoFormat
.
buildUpon
().
setAverageBitrate
(
5_000_000
).
build
();
Format
actualVideoFormat
=
new
DefaultEncoderFactory
.
Builder
(
context
)
.
setRequestedVideoEncoderSettings
(
VideoEncoderSettings
.
DEFAULT
)
.
build
()
.
createForVideoEncoding
(
requestedVideoFormat
,
/* allowedMimeTypes= */
ImmutableList
.
of
(
MimeTypes
.
VIDEO_H264
))
.
getConfigurationFormat
();
assertThat
(
actualVideoFormat
.
sampleMimeType
).
isEqualTo
(
MimeTypes
.
VIDEO_H264
);
assertThat
(
actualVideoFormat
.
width
).
isEqualTo
(
1920
);
assertThat
(
actualVideoFormat
.
height
).
isEqualTo
(
1080
);
assertThat
(
actualVideoFormat
.
averageBitrate
).
isEqualTo
(
5_000_000
);
}
@Test
public
void
createForVideoEncoding_unsetFormatAverageBitrateAndUnsetVideoEncoderSettingsBitrate_configuresEncoderUsingDefaultBitrateMapping
()
throws
Exception
{
Format
requestedVideoFormat
=
createVideoFormat
(
MimeTypes
.
VIDEO_H264
,
1920
,
1080
,
30
);
Format
actualVideoFormat
=
new
DefaultEncoderFactory
.
Builder
(
context
)
.
build
()
.
createForVideoEncoding
(
requestedVideoFormat
,
/* allowedMimeTypes= */
ImmutableList
.
of
(
MimeTypes
.
VIDEO_H264
))
.
getConfigurationFormat
();
assertThat
(
actualVideoFormat
.
sampleMimeType
).
isEqualTo
(
MimeTypes
.
VIDEO_H264
);
assertThat
(
actualVideoFormat
.
width
).
isEqualTo
(
1920
);
assertThat
(
actualVideoFormat
.
height
).
isEqualTo
(
1080
);
// The default behavior is to use DefaultEncoderFactory#getSuggestedBitrate.
// 1920 * 1080 * 30 * 0.07 * 2.
assertThat
(
actualVideoFormat
.
averageBitrate
).
isEqualTo
(
8_709_120
);
}
@Test
public
void
createForVideoEncoding_setFormatAverageBitrateAndSetVideoEncoderSettingHighQualityTargeting_configuresEncoderUsingHighQualityTargeting
()
throws
Exception
{
Format
requestedVideoFormat
=
createVideoFormat
(
MimeTypes
.
VIDEO_H264
,
1920
,
1080
,
30
);
requestedVideoFormat
=
requestedVideoFormat
.
buildUpon
().
setAverageBitrate
(
5_000_000
).
build
();
Format
actualVideoFormat
=
new
DefaultEncoderFactory
.
Builder
(
context
)
.
setRequestedVideoEncoderSettings
(
new
VideoEncoderSettings
.
Builder
().
setEnableHighQualityTargeting
(
true
).
build
())
.
build
()
.
createForVideoEncoding
(
requestedVideoFormat
,
/* allowedMimeTypes= */
ImmutableList
.
of
(
MimeTypes
.
VIDEO_H264
))
.
getConfigurationFormat
();
assertThat
(
actualVideoFormat
.
sampleMimeType
).
isEqualTo
(
MimeTypes
.
VIDEO_H264
);
assertThat
(
actualVideoFormat
.
width
).
isEqualTo
(
1920
);
assertThat
(
actualVideoFormat
.
height
).
isEqualTo
(
1080
);
// DeviceMappedEncoderBitrateProvider will produce 1920 * 1080 * 30 * 1.4, but the value is
// clampped down to the encoder's maximum, 25_000_000.
assertThat
(
actualVideoFormat
.
averageBitrate
).
isEqualTo
(
25_000_000
);
}
@Test
public
void
createForVideoEncoding_setFormatAverageBitrateAndVideoEncoderSettingsBitrate_configuresEncoderUsingVideoEncoderSettingsBitrate
()
throws
Exception
{
Format
requestedVideoFormat
=
createVideoFormat
(
MimeTypes
.
VIDEO_H264
,
1920
,
1080
,
30
);
requestedVideoFormat
=
requestedVideoFormat
.
buildUpon
().
setAverageBitrate
(
5_000_000
).
build
();
Format
actualVideoFormat
=
new
DefaultEncoderFactory
.
Builder
(
context
)
.
setRequestedVideoEncoderSettings
(
new
VideoEncoderSettings
.
Builder
().
setBitrate
(
10_000_000
).
build
())
.
build
()
.
createForVideoEncoding
(
requestedVideoFormat
,
/* allowedMimeTypes= */
ImmutableList
.
of
(
MimeTypes
.
VIDEO_H264
))
.
getConfigurationFormat
();
assertThat
(
actualVideoFormat
.
sampleMimeType
).
isEqualTo
(
MimeTypes
.
VIDEO_H264
);
assertThat
(
actualVideoFormat
.
width
).
isEqualTo
(
1920
);
assertThat
(
actualVideoFormat
.
height
).
isEqualTo
(
1080
);
assertThat
(
actualVideoFormat
.
averageBitrate
).
isEqualTo
(
10_000_000
);
}
@Config
(
sdk
=
29
)
@Test
public
void
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment