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
ad7237b5
authored
Nov 25, 2015
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Handle E-AC-3 audio in HLS.
parent
9fd575e1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
154 additions
and
109 deletions
library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java
library/src/main/java/com/google/android/exoplayer/extractor/mp4/AtomParsers.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/Ac3Reader.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsReader.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/TsExtractor.java
library/src/main/java/com/google/android/exoplayer/util/Ac3Util.java
library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java
View file @
ad7237b5
...
...
@@ -941,9 +941,9 @@ public final class AudioTrack {
|
((
buffer
.
get
(
buffer
.
position
()
+
5
)
&
0xFC
)
>>
2
);
return
(
nblks
+
1
)
*
32
;
}
else
if
(
encoding
==
C
.
ENCODING_AC3
)
{
return
Ac3Util
.
getAc3S
amplesPerSyncframe
();
return
Ac3Util
.
getAc3S
yncframeAudioSampleCount
();
}
else
if
(
encoding
==
C
.
ENCODING_E_AC3
)
{
return
Ac3Util
.
parseE
ac3SamplesPerSyncframe
(
buffer
);
return
Ac3Util
.
parseE
Ac3SyncframeAudioSampleCount
(
buffer
);
}
else
{
throw
new
IllegalStateException
(
"Unexpected audio encoding: "
+
encoding
);
}
...
...
library/src/main/java/com/google/android/exoplayer/extractor/mp4/AtomParsers.java
View file @
ad7237b5
...
...
@@ -774,12 +774,12 @@ import java.util.List;
// TODO: Choose the right AC-3 track based on the contents of dac3/dec3.
// TODO: Add support for encryption (by setting out.trackEncryptionBoxes).
parent
.
setPosition
(
Atom
.
HEADER_SIZE
+
childAtomPosition
);
out
.
mediaFormat
=
Ac3Util
.
parseA
nnexFAc3
Format
(
parent
,
Integer
.
toString
(
trackId
),
out
.
mediaFormat
=
Ac3Util
.
parseA
c3AnnexF
Format
(
parent
,
Integer
.
toString
(
trackId
),
durationUs
,
language
);
return
;
}
else
if
(
atomType
==
Atom
.
TYPE_ec_3
&&
childAtomType
==
Atom
.
TYPE_dec3
)
{
parent
.
setPosition
(
Atom
.
HEADER_SIZE
+
childAtomPosition
);
out
.
mediaFormat
=
Ac3Util
.
parse
AnnexFEAc3
Format
(
parent
,
Integer
.
toString
(
trackId
),
out
.
mediaFormat
=
Ac3Util
.
parse
EAc3AnnexF
Format
(
parent
,
Integer
.
toString
(
trackId
),
durationUs
,
language
);
return
;
}
else
if
((
atomType
==
Atom
.
TYPE_dtsc
||
atomType
==
Atom
.
TYPE_dtse
...
...
library/src/main/java/com/google/android/exoplayer/extractor/ts/Ac3Reader.java
View file @
ad7237b5
...
...
@@ -23,7 +23,7 @@ import com.google.android.exoplayer.util.ParsableBitArray;
import
com.google.android.exoplayer.util.ParsableByteArray
;
/**
* Parses a continuous AC-3 byte stream and extracts individual samples.
* Parses a continuous
(E-)
AC-3 byte stream and extracts individual samples.
*/
/* package */
final
class
Ac3Reader
extends
ElementaryStreamReader
{
...
...
@@ -33,6 +33,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
private
static
final
int
HEADER_SIZE
=
8
;
private
final
boolean
isEac3
;
private
final
ParsableBitArray
headerScratchBits
;
private
final
ParsableByteArray
headerScratchBytes
;
...
...
@@ -43,16 +44,23 @@ import com.google.android.exoplayer.util.ParsableByteArray;
private
boolean
lastByteWas0B
;
// Used when parsing the header.
private
long
fram
eDurationUs
;
private
long
sampl
eDurationUs
;
private
MediaFormat
mediaFormat
;
private
int
sampleSize
;
private
int
bitrate
;
// Used when reading the samples.
private
long
timeUs
;
public
Ac3Reader
(
TrackOutput
output
)
{
/**
* Constructs a new reader for (E-)AC-3 elementary streams.
*
* @param output Track output for extracted samples.
* @param isEac3 Whether the stream is E-AC-3 (ETSI TS 102 366 Annex E). Specify {@code false} to
* parse sample headers as AC-3.
*/
public
Ac3Reader
(
TrackOutput
output
,
boolean
isEac3
)
{
super
(
output
);
this
.
isEac3
=
isEac3
;
headerScratchBits
=
new
ParsableBitArray
(
new
byte
[
HEADER_SIZE
]);
headerScratchBytes
=
new
ParsableByteArray
(
headerScratchBits
.
data
);
state
=
STATE_FINDING_SYNC
;
...
...
@@ -94,7 +102,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
bytesRead
+=
bytesToRead
;
if
(
bytesRead
==
sampleSize
)
{
output
.
sampleMetadata
(
timeUs
,
C
.
SAMPLE_FLAG_SYNC
,
sampleSize
,
0
,
null
);
timeUs
+=
fram
eDurationUs
;
timeUs
+=
sampl
eDurationUs
;
state
=
STATE_FINDING_SYNC
;
}
break
;
...
...
@@ -124,11 +132,11 @@ import com.google.android.exoplayer.util.ParsableByteArray;
}
/**
* Locates the next sync
word, advancing the position to the byte that immediately follows it.
*
If a sync
word was not located, the position is advanced to the limit.
* Locates the next sync
word, advancing the position to the byte that immediately follows it. If a
*
sync
word was not located, the position is advanced to the limit.
*
* @param pesBuffer The buffer whose position should be advanced.
* @return True if a sync
word position was found. False otherwise.
* @return True if a syncword position was found. False otherwise.
*/
private
boolean
skipToNextSync
(
ParsableByteArray
pesBuffer
)
{
while
(
pesBuffer
.
bytesLeft
()
>
0
)
{
...
...
@@ -151,15 +159,21 @@ import com.google.android.exoplayer.util.ParsableByteArray;
* Parses the sample header.
*/
private
void
parseHeader
()
{
headerScratchBits
.
setPosition
(
0
);
sampleSize
=
Ac3Util
.
parseFrameSize
(
headerScratchBits
);
if
(
mediaFormat
==
null
)
{
headerScratchBits
.
setPosition
(
0
);
mediaFormat
=
Ac3Util
.
parseFrameAc3Format
(
headerScratchBits
,
null
,
C
.
UNKNOWN_TIME_US
,
null
);
mediaFormat
=
isEac3
?
Ac3Util
.
parseEac3SyncframeFormat
(
headerScratchBits
,
null
,
C
.
UNKNOWN_TIME_US
,
null
)
:
Ac3Util
.
parseAc3SyncframeFormat
(
headerScratchBits
,
null
,
C
.
UNKNOWN_TIME_US
,
null
);
output
.
format
(
mediaFormat
);
bitrate
=
Ac3Util
.
getBitrate
(
sampleSize
,
mediaFormat
.
sampleRate
);
}
frameDurationUs
=
(
int
)
(
1000L
*
8
*
sampleSize
/
bitrate
);
sampleSize
=
isEac3
?
Ac3Util
.
parseEAc3SyncframeSize
(
headerScratchBits
.
data
)
:
Ac3Util
.
parseAc3SyncframeSize
(
headerScratchBits
.
data
);
int
audioSamplesPerSyncframe
=
isEac3
?
Ac3Util
.
parseEAc3SyncframeAudioSampleCount
(
headerScratchBits
.
data
)
:
Ac3Util
.
getAc3SyncframeAudioSampleCount
();
// In this class a sample is an access unit (syncframe in AC-3), but the MediaFormat sample rate
// specifies the number of PCM audio samples per second.
sampleDurationUs
=
(
int
)
(
C
.
MICROS_PER_SECOND
*
audioSamplesPerSyncframe
/
mediaFormat
.
sampleRate
);
}
}
library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsReader.java
View file @
ad7237b5
...
...
@@ -50,7 +50,7 @@ import java.util.Collections;
// Used when parsing the header.
private
boolean
hasOutputFormat
;
private
long
fram
eDurationUs
;
private
long
sampl
eDurationUs
;
private
int
sampleSize
;
// Used when reading the samples.
...
...
@@ -96,7 +96,7 @@ import java.util.Collections;
bytesRead
+=
bytesToRead
;
if
(
bytesRead
==
sampleSize
)
{
output
.
sampleMetadata
(
timeUs
,
C
.
SAMPLE_FLAG_SYNC
,
sampleSize
,
0
,
null
);
timeUs
+=
fram
eDurationUs
;
timeUs
+=
sampl
eDurationUs
;
bytesRead
=
0
;
state
=
STATE_FINDING_SYNC
;
}
...
...
@@ -173,7 +173,9 @@ import java.util.Collections;
MediaFormat
mediaFormat
=
MediaFormat
.
createAudioFormat
(
null
,
MimeTypes
.
AUDIO_AAC
,
MediaFormat
.
NO_VALUE
,
MediaFormat
.
NO_VALUE
,
C
.
UNKNOWN_TIME_US
,
audioParams
.
second
,
audioParams
.
first
,
Collections
.
singletonList
(
audioSpecificConfig
),
null
);
frameDurationUs
=
(
C
.
MICROS_PER_SECOND
*
1024L
)
/
mediaFormat
.
sampleRate
;
// In this class a sample is an access unit, but the MediaFormat sample rate specifies the
// number of PCM audio samples per second.
sampleDurationUs
=
(
C
.
MICROS_PER_SECOND
*
1024
)
/
mediaFormat
.
sampleRate
;
output
.
format
(
mediaFormat
);
hasOutputFormat
=
true
;
}
else
{
...
...
library/src/main/java/com/google/android/exoplayer/extractor/ts/TsExtractor.java
View file @
ad7237b5
...
...
@@ -310,9 +310,11 @@ public final class TsExtractor implements Extractor {
case
TS_STREAM_TYPE_AAC:
pesPayloadReader
=
new
AdtsReader
(
output
.
track
(
TS_STREAM_TYPE_AAC
));
break
;
case
TS_STREAM_TYPE_E_AC3:
case
TS_STREAM_TYPE_AC3:
pesPayloadReader
=
new
Ac3Reader
(
output
.
track
(
streamType
));
pesPayloadReader
=
new
Ac3Reader
(
output
.
track
(
TS_STREAM_TYPE_AC3
),
false
);
break
;
case
TS_STREAM_TYPE_E_AC3:
pesPayloadReader
=
new
Ac3Reader
(
output
.
track
(
TS_STREAM_TYPE_E_AC3
),
true
);
break
;
case
TS_STREAM_TYPE_H262:
pesPayloadReader
=
new
H262Reader
(
output
.
track
(
TS_STREAM_TYPE_H262
));
...
...
library/src/main/java/com/google/android/exoplayer/util/Ac3Util.java
View file @
ad7237b5
...
...
@@ -20,61 +20,62 @@ import com.google.android.exoplayer.MediaFormat;
import
java.nio.ByteBuffer
;
/**
* Utility methods for parsing
AC-3 header
s.
* Utility methods for parsing
(E-)AC-3 syncframes, which are access units in (E-)AC-3 bitstream
s.
*/
public
final
class
Ac3Util
{
/**
* The number of new samples per (E-)AC-3 audio block.
*/
private
static
final
int
SAMPLES_PER_AUDIO_BLOCK
=
256
;
private
static
final
int
AUDIO_
SAMPLES_PER_AUDIO_BLOCK
=
256
;
/**
* Each syncframe has 6 blocks that provide 256 new
samples. See ETSI TS 102 366 subsection
4.1.
* Each syncframe has 6 blocks that provide 256 new
audio samples. See ETSI TS 102 366
4.1.
*/
private
static
final
int
AC3_S
AMPLES_PER_SYNCFRAME
=
6
*
SAMPLES_PER_AUDIO_BLOCK
;
private
static
final
int
AC3_S
YNCFRAME_AUDIO_SAMPLE_COUNT
=
6
*
AUDIO_
SAMPLES_PER_AUDIO_BLOCK
;
/**
* Number of audio blocks per E-AC-3 sync
frame, indexed by numblkscod.
* Number of audio blocks per E-AC-3 syncframe, indexed by numblkscod.
*/
private
static
final
int
[]
AUDIO_
BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD
=
new
int
[]
{
1
,
2
,
3
,
6
};
private
static
final
int
[]
BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD
=
new
int
[]
{
1
,
2
,
3
,
6
};
/**
* Sample rates, indexed by fscod.
*/
private
static
final
int
[]
SAMPLE_RATES
=
new
int
[]
{
48000
,
44100
,
32000
};
private
static
final
int
[]
SAMPLE_RATE_BY_FSCOD
=
new
int
[]
{
48000
,
44100
,
32000
};
/**
* Sample rates, indexed by fscod2 (E-AC-3).
*/
private
static
final
int
[]
SAMPLE_RATE_BY_FSCOD2
=
new
int
[]
{
24000
,
22050
,
16000
};
/**
* Channel counts, indexed by acmod.
*/
private
static
final
int
[]
CHANNEL_COUNT
S
=
new
int
[]
{
2
,
1
,
2
,
3
,
3
,
4
,
4
,
5
};
private
static
final
int
[]
CHANNEL_COUNT
_BY_ACMOD
=
new
int
[]
{
2
,
1
,
2
,
3
,
3
,
4
,
4
,
5
};
/**
* Nominal bitrates in kbps, indexed by
bit_rate_code.
* Nominal bitrates in kbps, indexed by
frmsizecod / 2. (See ETSI TS 102 366 table 4.13.)
*/
private
static
final
int
[]
BITRATE
S
=
new
int
[]
{
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
,
384
,
448
,
512
,
576
,
640
};
private
static
final
int
[]
BITRATE
_BY_HALF_FRMSIZECOD
=
new
int
[]
{
32
,
40
,
48
,
56
,
64
,
80
,
96
,
112
,
128
,
160
,
192
,
224
,
256
,
320
,
384
,
448
,
512
,
576
,
640
};
/**
* 16-bit words per sync
frame, indexed by frmsizecod / 2. (See ETSI TS 102 366 table 4.13.)
* 16-bit words per syncframe, indexed by frmsizecod / 2. (See ETSI TS 102 366 table 4.13.)
*/
private
static
final
int
[]
FRMSIZECOD_TO_FRAME_SIZE_44_1
=
new
int
[]
{
69
,
87
,
104
,
121
,
139
,
17
4
,
208
,
243
,
278
,
348
,
417
,
487
,
557
,
696
,
835
,
975
,
1114
,
1253
,
1393
};
private
static
final
int
[]
SYNCFRAME_SIZE_WORDS_BY_HALF_FRMSIZECOD_44_1
=
new
int
[]
{
69
,
87
,
10
4
,
121
,
139
,
174
,
208
,
243
,
278
,
348
,
417
,
487
,
557
,
696
,
835
,
975
,
1114
,
1253
,
1393
};
/**
* Returns the AC-3 format given {@code data} containing the AC3SpecificBox according to
* ETSI TS 102 366 Annex F.
* ETSI TS 102 366 Annex F.
The reading position of {@code data} will be modified.
*
* @param data The AC3SpecificBox.
* @param data The AC3SpecificBox
to parse
.
* @param trackId The track identifier to set on the format, or null.
* @param durationUs The duration to set on the format, in microseconds.
* @param language The language to set on the format.
* @return The AC-3 format parsed from data in the header.
*/
public
static
MediaFormat
parseA
nnexFAc3
Format
(
ParsableByteArray
data
,
String
trackId
,
public
static
MediaFormat
parseA
c3AnnexF
Format
(
ParsableByteArray
data
,
String
trackId
,
long
durationUs
,
String
language
)
{
// fscod (sample rate code)
int
fscod
=
(
data
.
readUnsignedByte
()
&
0xC0
)
>>
6
;
int
sampleRate
=
SAMPLE_RATE
S
[
fscod
];
int
sampleRate
=
SAMPLE_RATE
_BY_FSCOD
[
fscod
];
int
nextByte
=
data
.
readUnsignedByte
();
// Map acmod (audio coding mode) onto a channel count.
int
channelCount
=
CHANNEL_COUNTS
[(
nextByte
&
0x38
)
>>
3
];
// lfeon (low frequency effects on)
if
((
nextByte
&
0x04
)
!=
0
)
{
int
channelCount
=
CHANNEL_COUNT_BY_ACMOD
[(
nextByte
&
0x38
)
>>
3
];
if
((
nextByte
&
0x04
)
!=
0
)
{
// lfeon
channelCount
++;
}
return
MediaFormat
.
createAudioFormat
(
trackId
,
MimeTypes
.
AUDIO_AC3
,
MediaFormat
.
NO_VALUE
,
...
...
@@ -83,28 +84,25 @@ public final class Ac3Util {
/**
* Returns the E-AC-3 format given {@code data} containing the EC3SpecificBox according to
* ETSI TS 102 366 Annex F.
* ETSI TS 102 366 Annex F.
The reading position of {@code data} will be modified.
*
* @param data The EC3SpecificBox.
* @param data The EC3SpecificBox
to parse
.
* @param trackId The track identifier to set on the format, or null.
* @param durationUs The duration to set on the format, in microseconds.
* @param language The language to set on the format.
* @return The E-AC-3 format parsed from data in the header.
*/
public
static
MediaFormat
parse
AnnexFEAc3
Format
(
ParsableByteArray
data
,
String
trackId
,
public
static
MediaFormat
parse
EAc3AnnexF
Format
(
ParsableByteArray
data
,
String
trackId
,
long
durationUs
,
String
language
)
{
data
.
skipBytes
(
2
);
//
Skip data_rate and num_ind_sub.
data
.
skipBytes
(
2
);
//
data_rate, num_ind_sub
// Read only the first substream.
// TODO: Read later substreams?
// fscod (sample rate code)
int
fscod
=
(
data
.
readUnsignedByte
()
&
0xC0
)
>>
6
;
int
sampleRate
=
SAMPLE_RATE
S
[
fscod
];
int
sampleRate
=
SAMPLE_RATE
_BY_FSCOD
[
fscod
];
int
nextByte
=
data
.
readUnsignedByte
();
// Map acmod (audio coding mode) onto a channel count.
int
channelCount
=
CHANNEL_COUNTS
[(
nextByte
&
0x0E
)
>>
1
];
// lfeon (low frequency effects on)
if
((
nextByte
&
0x01
)
!=
0
)
{
int
channelCount
=
CHANNEL_COUNT_BY_ACMOD
[(
nextByte
&
0x0E
)
>>
1
];
if
((
nextByte
&
0x01
)
!=
0
)
{
// lfeon
channelCount
++;
}
return
MediaFormat
.
createAudioFormat
(
trackId
,
MimeTypes
.
AUDIO_E_AC3
,
MediaFormat
.
NO_VALUE
,
...
...
@@ -112,22 +110,20 @@ public final class Ac3Util {
}
/**
* Returns the AC-3 format given {@code data} containing
the frame header starting from the sync
*
wor
d.
* Returns the AC-3 format given {@code data} containing
a syncframe. The reading position of
*
{@code data} will be modifie
d.
*
* @param data
Data to parse, positioned at the start of the syncword
.
* @param data
The data to parse, positioned at the start of the syncframe
.
* @param trackId The track identifier to set on the format, or null.
* @param durationUs The duration to set on the format, in microseconds.
* @param language The language to set on the format.
* @return The AC-3 format parsed from data in the header.
*/
public
static
MediaFormat
parse
FrameAc3
Format
(
ParsableBitArray
data
,
String
trackId
,
public
static
MediaFormat
parse
Ac3Syncframe
Format
(
ParsableBitArray
data
,
String
trackId
,
long
durationUs
,
String
language
)
{
// Skip syncword and crc1.
data
.
skipBits
(
4
*
8
);
data
.
skipBits
(
16
+
16
);
// syncword, crc1
int
fscod
=
data
.
readBits
(
2
);
data
.
skipBits
(
14
);
// frmsizecod(6) + bsid (5 bits) + bsmod (3 bits)
data
.
skipBits
(
6
+
5
+
3
);
// frmsizecod, bsid, bsmod
int
acmod
=
data
.
readBits
(
3
);
if
((
acmod
&
0x01
)
!=
0
&&
acmod
!=
1
)
{
data
.
skipBits
(
2
);
// cmixlev
...
...
@@ -135,77 +131,108 @@ public final class Ac3Util {
if
((
acmod
&
0x04
)
!=
0
)
{
data
.
skipBits
(
2
);
// surmixlev
}
if
(
acmod
==
0x0
2
)
{
if
(
acmod
==
2
)
{
data
.
skipBits
(
2
);
// dsurmod
}
boolean
lfeon
=
data
.
readBit
();
return
MediaFormat
.
createAudioFormat
(
trackId
,
MimeTypes
.
AUDIO_AC3
,
MediaFormat
.
NO_VALUE
,
MediaFormat
.
NO_VALUE
,
durationUs
,
CHANNEL_COUNT
S
[
acmod
]
+
(
lfeon
?
1
:
0
),
SAMPLE_RATE
S
[
fscod
],
null
,
language
);
MediaFormat
.
NO_VALUE
,
durationUs
,
CHANNEL_COUNT
_BY_ACMOD
[
acmod
]
+
(
lfeon
?
1
:
0
),
SAMPLE_RATE
_BY_FSCOD
[
fscod
],
null
,
language
);
}
/**
* Returns the
AC-3 frame size in bytes given {@code data} containing the frame header starting
*
from the sync wor
d.
* Returns the
E-AC-3 format given {@code data} containing a syncframe. The reading position of
*
{@code data} will be modifie
d.
*
* @param data Data to parse, positioned at the start of the syncword.
* @return The frame size parsed from data in the header.
* @param data The data to parse, positioned at the start of the syncframe.
* @param trackId The track identifier to set on the format, or null.
* @param durationUs The duration to set on the format, in microseconds.
* @param language The language to set on the format.
* @return The E-AC-3 format parsed from data in the header.
*/
public
static
int
parseFrameSize
(
ParsableBitArray
data
)
{
// Skip syncword and crc1.
data
.
skipBits
(
4
*
8
);
public
static
MediaFormat
parseEac3SyncframeFormat
(
ParsableBitArray
data
,
String
trackId
,
long
durationUs
,
String
language
)
{
data
.
skipBits
(
16
+
2
+
11
);
// syncword, strmtype, frmsiz
int
sampleRate
;
int
fscod
=
data
.
readBits
(
2
);
int
frmsizecod
=
data
.
readBits
(
6
);
int
sampleRate
=
SAMPLE_RATES
[
fscod
];
int
bitrate
=
BITRATES
[
frmsizecod
/
2
];
if
(
sampleRate
==
32000
)
{
return
6
*
bitrate
;
}
else
if
(
sampleRate
==
44100
)
{
return
2
*
(
FRMSIZECOD_TO_FRAME_SIZE_44_1
[
frmsizecod
/
2
]
+
(
frmsizecod
%
2
));
}
else
{
// sampleRate == 48000
return
4
*
bitrate
;
if
(
fscod
==
3
)
{
sampleRate
=
SAMPLE_RATE_BY_FSCOD2
[
data
.
readBits
(
2
)];
}
else
{
data
.
skipBits
(
2
);
// numblkscod
sampleRate
=
SAMPLE_RATE_BY_FSCOD
[
fscod
];
}
int
acmod
=
data
.
readBits
(
3
);
boolean
lfeon
=
data
.
readBit
();
return
MediaFormat
.
createAudioFormat
(
trackId
,
MimeTypes
.
AUDIO_E_AC3
,
MediaFormat
.
NO_VALUE
,
MediaFormat
.
NO_VALUE
,
durationUs
,
CHANNEL_COUNT_BY_ACMOD
[
acmod
]
+
(
lfeon
?
1
:
0
),
sampleRate
,
null
,
language
);
}
/**
* Returns the
bitrate of AC-3 audio given the size of a buffer and the sample rat
e.
* Returns the
size in bytes of the given AC-3 syncfram
e.
*
* @param bufferSize Size in bytes of a full buffer of samples.
* @param sampleRate Sample rate in hz.
* @return Bitrate of the audio stream in kbit/s.
*/
public
static
int
getBitrate
(
int
bufferSize
,
int
sampleRate
)
{
// Each AC-3 buffer contains 1536 frames of audio, so the AudioTrack playback position
// advances by 1536 per buffer (32 ms at 48 kHz).
int
unscaledBitrate
=
bufferSize
*
8
*
sampleRate
;
int
divisor
=
1000
*
1536
;
return
(
unscaledBitrate
+
divisor
/
2
)
/
divisor
;
* @param data The syncframe to parse.
* @return The syncframe size in bytes.
*/
public
static
int
parseAc3SyncframeSize
(
byte
[]
data
)
{
int
fscod
=
(
data
[
4
]
&
0xC0
)
>>
6
;
int
frmsizecod
=
data
[
4
]
&
0x3F
;
return
getAc3SyncframeSize
(
fscod
,
frmsizecod
);
}
/**
* Returns the number of samples per AC-3 syncframe.
* Returns the size in bytes of the given E-AC-3 syncframe.
*
* @param data The syncframe to parse.
* @return The syncframe size in bytes.
*/
public
static
int
getAc3SamplesPerSyncframe
(
)
{
return
AC3_SAMPLES_PER_SYNCFRAME
;
public
static
int
parseEAc3SyncframeSize
(
byte
[]
data
)
{
return
2
*
(((
data
[
2
]
&
0x07
)
<<
8
)
+
(
data
[
3
]
&
0xFF
)
+
1
);
// frmsiz
}
/**
* Returns the number of samples per syncframe for the E-AC-3 frame in {@code buffer}.
* Returns the number of audio samples in an AC-3 syncframe.
*/
public
static
int
getAc3SyncframeAudioSampleCount
()
{
return
AC3_SYNCFRAME_AUDIO_SAMPLE_COUNT
;
}
/**
* Returns the number of audio samples represented by the given E-AC-3 syncframe.
*
* @param
buffer The
frame to parse.
* @return The number of
samples per
syncframe.
* @param
data The sync
frame to parse.
* @return The number of
audio samples represented by the
syncframe.
*/
public
static
int
parseE
ac3SamplesPerSyncframe
(
ByteBuffer
buffer
)
{
public
static
int
parseE
Ac3SyncframeAudioSampleCount
(
byte
[]
data
)
{
// See ETSI TS 102 366 subsection E.1.2.2.
int
audioBlocks
;
if
(((
buffer
.
get
(
buffer
.
position
()
+
4
)
&
0xC0
)
>>
6
)
==
0x03
)
{
// fscod
audioBlocks
=
6
;
}
else
{
int
numblkscod
=
(
buffer
.
get
(
buffer
.
position
()
+
4
)
&
0x30
)
>>
4
;
audioBlocks
=
AUDIO_BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD
[
numblkscod
]
*
256
;
return
AUDIO_SAMPLES_PER_AUDIO_BLOCK
*
(((
data
[
4
]
&
0xC0
)
>>
6
)
==
0x03
?
6
// fscod
:
BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD
[(
data
[
4
]
&
0x30
)
>>
4
]);
}
/**
* Like {@link #parseEAc3SyncframeAudioSampleCount(byte[])} but reads from a byte buffer. The
* buffer position is not modified.
*
* @see #parseEAc3SyncframeAudioSampleCount(byte[])
*/
public
static
int
parseEAc3SyncframeAudioSampleCount
(
ByteBuffer
buffer
)
{
// See ETSI TS 102 366 subsection E.1.2.2.
int
fscod
=
(
buffer
.
get
(
buffer
.
position
()
+
4
)
&
0xC0
)
>>
6
;
return
AUDIO_SAMPLES_PER_AUDIO_BLOCK
*
(
fscod
==
0x03
?
6
:
BLOCKS_PER_SYNCFRAME_BY_NUMBLKSCOD
[(
buffer
.
get
(
buffer
.
position
()
+
4
)
&
0x30
)
>>
4
]);
}
private
static
int
getAc3SyncframeSize
(
int
fscod
,
int
frmsizecod
)
{
int
sampleRate
=
SAMPLE_RATE_BY_FSCOD
[
fscod
];
if
(
sampleRate
==
44100
)
{
return
2
*
(
SYNCFRAME_SIZE_WORDS_BY_HALF_FRMSIZECOD_44_1
[
frmsizecod
/
2
]
+
(
frmsizecod
%
2
));
}
int
bitrate
=
BITRATE_BY_HALF_FRMSIZECOD
[
frmsizecod
/
2
];
if
(
sampleRate
==
32000
)
{
return
6
*
bitrate
;
}
else
{
// sampleRate == 48000
return
4
*
bitrate
;
}
return
audioBlocks
*
SAMPLES_PER_AUDIO_BLOCK
;
}
private
Ac3Util
()
{
...
...
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