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
0b8b03e4
authored
Feb 07, 2021
by
aquilescanta
Committed by
Oliver Woodman
Feb 09, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add method to create a MediaFormat based on an ExoPlayer Format
PiperOrigin-RevId: 356157035
parent
01b6061b
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
284 additions
and
5 deletions
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtil.java
library/core/src/test/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtilTest.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtil.java
View file @
0b8b03e4
...
...
@@ -15,27 +15,94 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
mediacodec
;
import
android.annotation.SuppressLint
;
import
android.media.AudioFormat
;
import
android.media.MediaFormat
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.video.ColorInfo
;
import
java.nio.ByteBuffer
;
import
java.util.List
;
/** Helper class
for configur
ing {@link MediaFormat} instances. */
/** Helper class
containing utility methods for manag
ing {@link MediaFormat} instances. */
public
final
class
MediaFormatUtil
{
private
MediaFormatUtil
()
{}
/**
* Custom {@link MediaFormat} key associated with a float representing the ratio between a pixel's
* width and height.
*/
public
static
final
String
KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT
=
"exo-pixel-width-height-ratio-float"
;
/**
* Custom {@link MediaFormat} key associated with an integer representing the PCM encoding.
*
* <p>Equivalent to {@link MediaFormat#KEY_PCM_ENCODING}, except it allows additional
* ExoPlayer-specific values including {@link C#ENCODING_PCM_16BIT_BIG_ENDIAN}, {@link
* C#ENCODING_PCM_24BIT}, and {@link C#ENCODING_PCM_32BIT}.
*/
public
static
final
String
KEY_EXO_PCM_ENCODING
=
"exo-pcm-encoding-int"
;
private
static
final
int
MAX_POWER_OF_TWO_INT
=
1
<<
30
;
/**
* Returns a {@link MediaFormat} representing the given ExoPlayer {@link Format}.
*
* <p>May include the following custom keys:
*
* <ul>
* <li>{@link #KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT}.
* <li>{@link #KEY_EXO_PCM_ENCODING}.
* </ul>
*/
@SuppressLint
(
"InlinedApi"
)
// Inlined MediaFormat keys.
public
static
MediaFormat
createMediaFormatFromFormat
(
Format
format
)
{
MediaFormat
result
=
new
MediaFormat
();
maybeSetInteger
(
result
,
MediaFormat
.
KEY_BIT_RATE
,
format
.
bitrate
);
maybeSetInteger
(
result
,
MediaFormat
.
KEY_CHANNEL_COUNT
,
format
.
channelCount
);
maybeSetColorInfo
(
result
,
format
.
colorInfo
);
maybeSetString
(
result
,
MediaFormat
.
KEY_MIME
,
format
.
sampleMimeType
);
maybeSetString
(
result
,
MediaFormat
.
KEY_CODECS_STRING
,
format
.
codecs
);
maybeSetFloat
(
result
,
MediaFormat
.
KEY_FRAME_RATE
,
format
.
frameRate
);
maybeSetInteger
(
result
,
MediaFormat
.
KEY_WIDTH
,
format
.
width
);
maybeSetInteger
(
result
,
MediaFormat
.
KEY_HEIGHT
,
format
.
height
);
setCsdBuffers
(
result
,
format
.
initializationData
);
maybeSetPcmEncoding
(
result
,
format
.
pcmEncoding
);
maybeSetString
(
result
,
MediaFormat
.
KEY_LANGUAGE
,
format
.
language
);
maybeSetInteger
(
result
,
MediaFormat
.
KEY_MAX_INPUT_SIZE
,
format
.
maxInputSize
);
maybeSetInteger
(
result
,
MediaFormat
.
KEY_SAMPLE_RATE
,
format
.
sampleRate
);
maybeSetInteger
(
result
,
MediaFormat
.
KEY_CAPTION_SERVICE_NUMBER
,
format
.
accessibilityChannel
);
result
.
setInteger
(
MediaFormat
.
KEY_ROTATION
,
format
.
rotationDegrees
);
int
selectionFlags
=
format
.
selectionFlags
;
setBooleanAsInt
(
result
,
MediaFormat
.
KEY_IS_AUTOSELECT
,
selectionFlags
&
C
.
SELECTION_FLAG_AUTOSELECT
);
setBooleanAsInt
(
result
,
MediaFormat
.
KEY_IS_DEFAULT
,
selectionFlags
&
C
.
SELECTION_FLAG_DEFAULT
);
setBooleanAsInt
(
result
,
MediaFormat
.
KEY_IS_FORCED_SUBTITLE
,
selectionFlags
&
C
.
SELECTION_FLAG_FORCED
);
result
.
setInteger
(
MediaFormat
.
KEY_ENCODER_DELAY
,
format
.
encoderDelay
);
result
.
setInteger
(
MediaFormat
.
KEY_ENCODER_PADDING
,
format
.
encoderPadding
);
maybeSetPixelAspectRatio
(
result
,
format
.
pixelWidthHeightRatio
);
return
result
;
}
/**
* Sets a {@link MediaFormat} {@link String} value.
* Sets a {@link MediaFormat} {@link String} value.
Does nothing if {@code value} is null.
*
* @param format The {@link MediaFormat} being configured.
* @param key The key to set.
* @param value The value to set.
*/
public
static
void
setString
(
MediaFormat
format
,
String
key
,
String
value
)
{
format
.
setString
(
key
,
value
);
public
static
void
maybeSetString
(
MediaFormat
format
,
String
key
,
@Nullable
String
value
)
{
if
(
value
!=
null
)
{
format
.
setString
(
key
,
value
);
}
}
/**
...
...
@@ -106,4 +173,57 @@ public final class MediaFormatUtil {
maybeSetByteBuffer
(
format
,
MediaFormat
.
KEY_HDR_STATIC_INFO
,
colorInfo
.
hdrStaticInfo
);
}
}
// Internal methods.
private
static
void
setBooleanAsInt
(
MediaFormat
format
,
String
key
,
int
value
)
{
format
.
setInteger
(
key
,
value
!=
0
?
1
:
0
);
}
// Inlined MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH and MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT.
@SuppressLint
(
"InlinedApi"
)
private
static
void
maybeSetPixelAspectRatio
(
MediaFormat
mediaFormat
,
float
pixelWidthHeightRatio
)
{
mediaFormat
.
setFloat
(
KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT
,
pixelWidthHeightRatio
);
int
pixelAspectRatioWidth
=
1
;
int
pixelAspectRatioHeight
=
1
;
// ExoPlayer extractors output the pixel aspect ratio as a float. Do our best to recreate the
// pixel aspect ratio width and height by using a large power of two factor.
if
(
pixelWidthHeightRatio
<
1.0f
)
{
pixelAspectRatioHeight
=
MAX_POWER_OF_TWO_INT
;
pixelAspectRatioWidth
=
(
int
)
(
pixelWidthHeightRatio
*
pixelAspectRatioHeight
);
}
else
if
(
pixelWidthHeightRatio
>
1.0f
)
{
pixelAspectRatioWidth
=
MAX_POWER_OF_TWO_INT
;
pixelAspectRatioHeight
=
(
int
)
(
pixelAspectRatioWidth
/
pixelWidthHeightRatio
);
}
mediaFormat
.
setInteger
(
MediaFormat
.
KEY_PIXEL_ASPECT_RATIO_WIDTH
,
pixelAspectRatioWidth
);
mediaFormat
.
setInteger
(
MediaFormat
.
KEY_PIXEL_ASPECT_RATIO_HEIGHT
,
pixelAspectRatioHeight
);
}
@SuppressLint
(
"InlinedApi"
)
// Inlined KEY_PCM_ENCODING.
private
static
void
maybeSetPcmEncoding
(
MediaFormat
mediaFormat
,
@C
.
PcmEncoding
int
exoPcmEncoding
)
{
if
(
exoPcmEncoding
==
Format
.
NO_VALUE
)
{
return
;
}
int
mediaFormatPcmEncoding
;
maybeSetInteger
(
mediaFormat
,
KEY_EXO_PCM_ENCODING
,
exoPcmEncoding
);
switch
(
exoPcmEncoding
)
{
case
C
.
ENCODING_PCM_8BIT
:
mediaFormatPcmEncoding
=
AudioFormat
.
ENCODING_PCM_8BIT
;
break
;
case
C
.
ENCODING_PCM_16BIT
:
mediaFormatPcmEncoding
=
AudioFormat
.
ENCODING_PCM_16BIT
;
break
;
case
C
.
ENCODING_PCM_FLOAT
:
mediaFormatPcmEncoding
=
AudioFormat
.
ENCODING_PCM_FLOAT
;
break
;
default
:
// No matching value. Do nothing.
return
;
}
mediaFormat
.
setInteger
(
MediaFormat
.
KEY_PCM_ENCODING
,
mediaFormatPcmEncoding
);
}
private
MediaFormatUtil
()
{}
}
library/core/src/test/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtilTest.java
0 → 100644
View file @
0b8b03e4
/*
* Copyright (C) 2021 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
com
.
google
.
android
.
exoplayer2
.
mediacodec
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.media.MediaFormat
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.video.ColorInfo
;
import
com.google.common.collect.ImmutableList
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.robolectric.annotation.Config
;
/** Unit tests for {@link MediaFormatUtil}. */
@RunWith
(
AndroidJUnit4
.
class
)
@Config
(
sdk
=
29
)
// Allows using MediaFormat.getKeys() to make assertions over the expected keys.
public
class
MediaFormatUtilTest
{
@Test
public
void
createMediaFormatFromEmptyExoPlayerFormat_generatesExpectedEntries
()
{
MediaFormat
mediaFormat
=
MediaFormatUtil
.
createMediaFormatFromFormat
(
new
Format
.
Builder
().
build
());
// Assert that no invalid keys are accidentally being populated.
assertThat
(
mediaFormat
.
getKeys
())
.
containsExactly
(
MediaFormatUtil
.
KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT
,
MediaFormat
.
KEY_ENCODER_DELAY
,
MediaFormat
.
KEY_ENCODER_PADDING
,
MediaFormat
.
KEY_PIXEL_ASPECT_RATIO_WIDTH
,
MediaFormat
.
KEY_PIXEL_ASPECT_RATIO_HEIGHT
,
MediaFormat
.
KEY_IS_DEFAULT
,
MediaFormat
.
KEY_IS_FORCED_SUBTITLE
,
MediaFormat
.
KEY_IS_AUTOSELECT
,
MediaFormat
.
KEY_ROTATION
);
assertThat
(
mediaFormat
.
getFloat
(
MediaFormatUtil
.
KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT
))
.
isEqualTo
(
1
.
f
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_ENCODER_DELAY
)).
isEqualTo
(
0
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_ENCODER_PADDING
)).
isEqualTo
(
0
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_PIXEL_ASPECT_RATIO_WIDTH
)).
isEqualTo
(
1
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_PIXEL_ASPECT_RATIO_HEIGHT
)).
isEqualTo
(
1
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_IS_DEFAULT
)).
isEqualTo
(
0
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_IS_FORCED_SUBTITLE
)).
isEqualTo
(
0
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_IS_AUTOSELECT
)).
isEqualTo
(
0
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_ROTATION
)).
isEqualTo
(
0
);
}
@Test
public
void
createMediaFormatFromPopulatedExoPlayerFormat_generatesExpectedMediaFormatEntries
()
{
Format
format
=
new
Format
.
Builder
()
.
setAverageBitrate
(
1
)
.
setChannelCount
(
2
)
.
setColorInfo
(
new
ColorInfo
(
/* colorSpace= */
C
.
COLOR_SPACE_BT601
,
/* colorRange= */
C
.
COLOR_RANGE_FULL
,
/* colorTransfer= */
C
.
COLOR_TRANSFER_HLG
,
new
byte
[]
{
3
}))
.
setSampleMimeType
(
MimeTypes
.
VIDEO_H264
)
.
setCodecs
(
"avc.123"
)
.
setFrameRate
(
4
)
.
setWidth
(
5
)
.
setHeight
(
6
)
.
setInitializationData
(
ImmutableList
.
of
(
new
byte
[]
{
7
},
new
byte
[]
{
8
}))
.
setPcmEncoding
(
C
.
ENCODING_PCM_8BIT
)
.
setLanguage
(
"en"
)
.
setMaxInputSize
(
9
)
.
setRotationDegrees
(
10
)
.
setSampleRate
(
11
)
.
setAccessibilityChannel
(
12
)
.
setSelectionFlags
(
C
.
SELECTION_FLAG_AUTOSELECT
|
C
.
SELECTION_FLAG_DEFAULT
|
C
.
SELECTION_FLAG_FORCED
)
.
setEncoderDelay
(
13
)
.
setEncoderPadding
(
14
)
.
setPixelWidthHeightRatio
(.
5
f
)
.
build
();
MediaFormat
mediaFormat
=
MediaFormatUtil
.
createMediaFormatFromFormat
(
format
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_BIT_RATE
)).
isEqualTo
(
format
.
bitrate
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_CHANNEL_COUNT
))
.
isEqualTo
(
format
.
channelCount
);
ColorInfo
colorInfo
=
Assertions
.
checkNotNull
(
format
.
colorInfo
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_COLOR_TRANSFER
))
.
isEqualTo
(
colorInfo
.
colorTransfer
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_COLOR_RANGE
)).
isEqualTo
(
colorInfo
.
colorRange
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_COLOR_STANDARD
))
.
isEqualTo
(
colorInfo
.
colorSpace
);
assertThat
(
mediaFormat
.
getByteBuffer
(
MediaFormat
.
KEY_HDR_STATIC_INFO
).
array
())
.
isEqualTo
(
colorInfo
.
hdrStaticInfo
);
assertThat
(
mediaFormat
.
getString
(
MediaFormat
.
KEY_MIME
)).
isEqualTo
(
format
.
sampleMimeType
);
assertThat
(
mediaFormat
.
getString
(
MediaFormat
.
KEY_CODECS_STRING
)).
isEqualTo
(
format
.
codecs
);
assertThat
(
mediaFormat
.
getFloat
(
MediaFormat
.
KEY_FRAME_RATE
)).
isEqualTo
(
format
.
frameRate
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_WIDTH
)).
isEqualTo
(
format
.
width
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_HEIGHT
)).
isEqualTo
(
format
.
height
);
assertThat
(
mediaFormat
.
getByteBuffer
(
"csd-0"
).
array
())
.
isEqualTo
(
format
.
initializationData
.
get
(
0
));
assertThat
(
mediaFormat
.
getByteBuffer
(
"csd-1"
).
array
())
.
isEqualTo
(
format
.
initializationData
.
get
(
1
));
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_PCM_ENCODING
)).
isEqualTo
(
format
.
pcmEncoding
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormatUtil
.
KEY_EXO_PCM_ENCODING
))
.
isEqualTo
(
format
.
pcmEncoding
);
assertThat
(
mediaFormat
.
getString
(
MediaFormat
.
KEY_LANGUAGE
)).
isEqualTo
(
format
.
language
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_MAX_INPUT_SIZE
))
.
isEqualTo
(
format
.
maxInputSize
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_ROTATION
)).
isEqualTo
(
format
.
rotationDegrees
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_SAMPLE_RATE
)).
isEqualTo
(
format
.
sampleRate
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_CAPTION_SERVICE_NUMBER
))
.
isEqualTo
(
format
.
accessibilityChannel
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_IS_AUTOSELECT
)).
isNotEqualTo
(
0
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_IS_DEFAULT
)).
isNotEqualTo
(
0
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_IS_FORCED_SUBTITLE
)).
isNotEqualTo
(
0
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_ENCODER_DELAY
))
.
isEqualTo
(
format
.
encoderDelay
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_ENCODER_PADDING
))
.
isEqualTo
(
format
.
encoderPadding
);
float
calculatedPixelAspectRatio
=
(
float
)
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_PIXEL_ASPECT_RATIO_WIDTH
)
/
mediaFormat
.
getInteger
(
MediaFormat
.
KEY_PIXEL_ASPECT_RATIO_HEIGHT
);
assertThat
(
calculatedPixelAspectRatio
).
isWithin
(.
0001
f
).
of
(
format
.
pixelWidthHeightRatio
);
assertThat
(
mediaFormat
.
getFloat
(
MediaFormatUtil
.
KEY_EXO_PIXEL_WIDTH_HEIGHT_RATIO_FLOAT
))
.
isEqualTo
(
format
.
pixelWidthHeightRatio
);
}
@Test
public
void
createMediaFormatWithExoPlayerPcmEncoding_containsExoPlayerSpecificEncoding
()
{
Format
format
=
new
Format
.
Builder
().
setPcmEncoding
(
C
.
ENCODING_PCM_32BIT
).
build
();
MediaFormat
mediaFormat
=
MediaFormatUtil
.
createMediaFormatFromFormat
(
format
);
assertThat
(
mediaFormat
.
getInteger
(
MediaFormatUtil
.
KEY_EXO_PCM_ENCODING
))
.
isEqualTo
(
C
.
ENCODING_PCM_32BIT
);
assertThat
(
mediaFormat
.
containsKey
(
MediaFormat
.
KEY_PCM_ENCODING
)).
isFalse
();
}
}
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