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
535e14cb
authored
May 06, 2020
by
krocard
Committed by
Oliver Woodman
May 06, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Implement format to encoding for AAC
PiperOrigin-RevId: 310199693
parent
a2ce75d8
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
110 additions
and
13 deletions
library/common/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java
library/common/src/test/java/com/google/android/exoplayer2/util/MimeTypesTest.java
library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
library/common/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java
View file @
535e14cb
...
...
@@ -18,13 +18,29 @@ package com.google.android.exoplayer2.util;
import
android.text.TextUtils
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.audio.AacUtil
;
import
java.util.ArrayList
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* Defines common MIME types and helper methods.
*/
public
final
class
MimeTypes
{
/** An mp4a Object Type Indication (OTI) and its optional audio OTI is defined by RFC 6381. */
public
static
final
class
Mp4aObjectType
{
/** The Object Type Indication of the mp4a codec. */
public
final
int
objectTypeIndication
;
/** The Audio Object Type Indication of the mp4a codec, or 0 if it is absent. */
@AacUtil
.
AacAudioObjectType
public
final
int
audioObjectTypeIndication
;
private
Mp4aObjectType
(
int
objectTypeIndication
,
int
audioObjectTypeIndication
)
{
this
.
objectTypeIndication
=
objectTypeIndication
;
this
.
audioObjectTypeIndication
=
audioObjectTypeIndication
;
}
}
public
static
final
String
BASE_TYPE_VIDEO
=
"video"
;
public
static
final
String
BASE_TYPE_AUDIO
=
"audio"
;
public
static
final
String
BASE_TYPE_TEXT
=
"text"
;
...
...
@@ -106,6 +122,9 @@ public final class MimeTypes {
private
static
final
ArrayList
<
CustomMimeType
>
customMimeTypes
=
new
ArrayList
<>();
private
static
final
Pattern
MP4A_RFC_6381_CODEC_PATTERN
=
Pattern
.
compile
(
"^mp4a\\.([a-zA-Z0-9]{2})(?:\\.([0-9]{1,2}))?$"
);
/**
* Registers a custom MIME type. Most applications do not need to call this method, as handling of
* standard MIME types is built in. These built-in MIME types take precedence over any registered
...
...
@@ -275,15 +294,9 @@ public final class MimeTypes {
}
else
if
(
codec
.
startsWith
(
"mp4a"
))
{
@Nullable
String
mimeType
=
null
;
if
(
codec
.
startsWith
(
"mp4a."
))
{
String
objectTypeString
=
codec
.
substring
(
5
);
// remove the 'mp4a.' prefix
if
(
objectTypeString
.
length
()
>=
2
)
{
try
{
String
objectTypeHexString
=
Util
.
toUpperInvariant
(
objectTypeString
.
substring
(
0
,
2
));
int
objectTypeInt
=
Integer
.
parseInt
(
objectTypeHexString
,
16
);
mimeType
=
getMimeTypeFromMp4ObjectType
(
objectTypeInt
);
}
catch
(
NumberFormatException
ignored
)
{
// Ignored.
}
@Nullable
Mp4aObjectType
objectType
=
getObjectTypeFromMp4aRFC6381CodecString
(
codec
);
if
(
objectType
!=
null
)
{
mimeType
=
getMimeTypeFromMp4ObjectType
(
objectType
.
objectTypeIndication
);
}
}
return
mimeType
==
null
?
MimeTypes
.
AUDIO_AAC
:
mimeType
;
...
...
@@ -407,13 +420,25 @@ public final class MimeTypes {
* it is an encoded (non-PCM) audio format, or {@link C#ENCODING_INVALID} otherwise.
*
* @param mimeType The MIME type.
* @return The {@link C}{@code .ENCODING_*} constant that corresponds to a specified MIME type, or
* @param codecs Codecs of the format as described in RFC 6381, or null if unknown or not
* applicable.
* @return One of {@link C.Encoding} constants that corresponds to a specified MIME type, or
* {@link C#ENCODING_INVALID}.
*/
public
static
@C
.
Encoding
int
getEncoding
(
String
mimeType
)
{
@C
.
Encoding
public
static
int
getEncoding
(
String
mimeType
,
@Nullable
String
codecs
)
{
switch
(
mimeType
)
{
case
MimeTypes
.
AUDIO_MPEG
:
return
C
.
ENCODING_MP3
;
case
MimeTypes
.
AUDIO_AAC
:
if
(
codecs
==
null
)
{
return
C
.
ENCODING_INVALID
;
}
@Nullable
Mp4aObjectType
objectType
=
getObjectTypeFromMp4aRFC6381CodecString
(
codecs
);
if
(
objectType
==
null
)
{
return
C
.
ENCODING_INVALID
;
}
return
AacUtil
.
getEncodingForAudioObjectType
(
objectType
.
audioObjectTypeIndication
);
case
MimeTypes
.
AUDIO_AC3
:
return
C
.
ENCODING_AC3
;
case
MimeTypes
.
AUDIO_E_AC3
:
...
...
@@ -444,6 +469,40 @@ public final class MimeTypes {
}
/**
* Retrieves the object type of an mp4 audio codec from its string as defined in RFC 6381.
*
* <p>Per https://mp4ra.org/#/object_types and https://tools.ietf.org/html/rfc6381#section-3.3, an
* mp4 codec string has the form: <code>
* ~~~~~~~~~~~~~~ Object Type Indication (OTI) byte in hex
* mp4a.[a-zA-Z0-9]{2}(.[0-9]{1,2})?
* ~~~~~~~~~~ audio OTI, decimal. Only for certain OTI.
* </code> For example: mp4a.40.2, has an OTI of 0x40 and an audio OTI of 2.
*
* @param codec The string as defined in RFC 6381 describing an mp4 audio codec.
* @return The {@link Mp4aObjectType} or {@code null} if the input is invalid.
*/
@Nullable
public
static
Mp4aObjectType
getObjectTypeFromMp4aRFC6381CodecString
(
String
codec
)
{
Matcher
matcher
=
MP4A_RFC_6381_CODEC_PATTERN
.
matcher
(
codec
);
if
(!
matcher
.
matches
())
{
return
null
;
}
String
objectTypeIndicationHex
=
Assertions
.
checkNotNull
(
matcher
.
group
(
1
));
@Nullable
String
audioObjectTypeIndicationDec
=
matcher
.
group
(
2
);
int
objectTypeIndication
;
int
audioObjectTypeIndication
=
0
;
try
{
objectTypeIndication
=
Integer
.
parseInt
(
objectTypeIndicationHex
,
16
);
if
(
audioObjectTypeIndicationDec
!=
null
)
{
audioObjectTypeIndication
=
Integer
.
parseInt
(
audioObjectTypeIndicationDec
);
}
}
catch
(
NumberFormatException
e
)
{
return
null
;
}
return
new
Mp4aObjectType
(
objectTypeIndication
,
audioObjectTypeIndication
);
}
/**
* Returns the top-level type of {@code mimeType}, or null if {@code mimeType} is null or does not
* contain a forward slash character ({@code '/'}).
*/
...
...
library/common/src/test/java/com/google/android/exoplayer2/util/MimeTypesTest.java
View file @
535e14cb
...
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.util;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
androidx.annotation.Nullable
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
...
...
@@ -133,4 +134,41 @@ public final class MimeTypesTest {
assertThat
(
MimeTypes
.
getMimeTypeFromMp4ObjectType
(
0x01
)).
isNull
();
assertThat
(
MimeTypes
.
getMimeTypeFromMp4ObjectType
(-
1
)).
isNull
();
}
@Test
public
void
getObjectTypeFromMp4aRFC6381CodecString_onInvalidInput_returnsNull
()
{
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
""
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"abc"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a."
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.1"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.a"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.1g"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4v.20.9"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.100.1"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.10."
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.a.1"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.10,01"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.1f.f1"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.1a.a"
)).
isNull
();
assertThat
(
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
"mp4a.01.110"
)).
isNull
();
}
@Test
public
void
getObjectTypeFromMp4aRFC6381CodecString_onValidInput_returnsCorrectObjectType
()
{
assert_getObjectTypeFromMp4aRFC6381CodecString_for_returns
(
"mp4a.00.0"
,
0x00
,
0
);
assert_getObjectTypeFromMp4aRFC6381CodecString_for_returns
(
"mp4a.01.01"
,
0x01
,
1
);
assert_getObjectTypeFromMp4aRFC6381CodecString_for_returns
(
"mp4a.10.10"
,
0x10
,
10
);
assert_getObjectTypeFromMp4aRFC6381CodecString_for_returns
(
"mp4a.a0.90"
,
0xa0
,
90
);
assert_getObjectTypeFromMp4aRFC6381CodecString_for_returns
(
"mp4a.Ff.99"
,
0xff
,
99
);
assert_getObjectTypeFromMp4aRFC6381CodecString_for_returns
(
"mp4a.D0.9"
,
0xd0
,
9
);
}
private
static
void
assert_getObjectTypeFromMp4aRFC6381CodecString_for_returns
(
String
codec
,
int
expectedObjectTypeIndicator
,
int
expectedAudioObjectTypeIndicator
)
{
@Nullable
MimeTypes
.
Mp4aObjectType
objectType
=
MimeTypes
.
getObjectTypeFromMp4aRFC6381CodecString
(
codec
);
assertThat
(
objectType
).
isNotNull
();
assertThat
(
objectType
.
objectTypeIndication
).
isEqualTo
(
expectedObjectTypeIndicator
);
assertThat
(
objectType
.
audioObjectTypeIndication
).
isEqualTo
(
expectedAudioObjectTypeIndicator
);
}
}
library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
View file @
535e14cb
...
...
@@ -463,13 +463,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
// E-AC3 JOC is object-based so the output channel count is arbitrary.
if
(
audioSink
.
supportsOutput
(
/* channelCount= */
Format
.
NO_VALUE
,
format
.
sampleRate
,
C
.
ENCODING_E_AC3_JOC
))
{
return
MimeTypes
.
getEncoding
(
MimeTypes
.
AUDIO_E_AC3_JOC
);
return
MimeTypes
.
getEncoding
(
MimeTypes
.
AUDIO_E_AC3_JOC
,
format
.
codecs
);
}
// E-AC3 receivers can decode JOC streams, but in 2-D rather than 3-D, so try to fall back.
mimeType
=
MimeTypes
.
AUDIO_E_AC3
;
}
@C
.
Encoding
int
encoding
=
MimeTypes
.
getEncoding
(
mimeType
);
@C
.
Encoding
int
encoding
=
MimeTypes
.
getEncoding
(
mimeType
,
format
.
codecs
);
if
(
audioSink
.
supportsOutput
(
format
.
channelCount
,
format
.
sampleRate
,
encoding
))
{
return
encoding
;
}
else
{
...
...
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