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
da97e30e
authored
Sep 18, 2015
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Support mp3 media segments in HLS.
Issue #804
parent
c960636d
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
61 additions
and
30 deletions
library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java
library/src/main/java/com/google/android/exoplayer/hls/HlsChunkSource.java
library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java
library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java
View file @
da97e30e
...
...
@@ -48,6 +48,7 @@ public final class Mp3Extractor implements Extractor {
private
static
final
int
INFO_HEADER
=
Util
.
getIntegerCodeForString
(
"Info"
);
private
static
final
int
VBRI_HEADER
=
Util
.
getIntegerCodeForString
(
"VBRI"
);
private
final
long
forcedFirstSampleTimestampUs
;
private
final
BufferingInput
inputBuffer
;
private
final
ParsableByteArray
scratch
;
private
final
MpegAudioHeader
synchronizedHeader
;
...
...
@@ -63,11 +64,25 @@ public final class Mp3Extractor implements Extractor {
private
int
samplesRead
;
private
int
sampleBytesRemaining
;
/** Constructs a new {@link Mp3Extractor}. */
/**
* Constructs a new {@link Mp3Extractor}.
*/
public
Mp3Extractor
()
{
this
(-
1
);
}
/**
* Constructs a new {@link Mp3Extractor}.
*
* @param forcedFirstSampleTimestampUs A timestamp to force for the first sample, or -1 if forcing
* is not required.
*/
public
Mp3Extractor
(
long
forcedFirstSampleTimestampUs
)
{
this
.
forcedFirstSampleTimestampUs
=
forcedFirstSampleTimestampUs
;
inputBuffer
=
new
BufferingInput
(
MpegAudioHeader
.
MAX_FRAME_SIZE_BYTES
*
3
);
scratch
=
new
ParsableByteArray
(
4
);
synchronizedHeader
=
new
MpegAudioHeader
();
basisTimeUs
=
-
1
;
}
@Override
...
...
@@ -164,6 +179,10 @@ public final class Mp3Extractor implements Extractor {
}
if
(
basisTimeUs
==
-
1
)
{
basisTimeUs
=
seeker
.
getTimeUs
(
getPosition
(
extractorInput
,
inputBuffer
));
if
(
forcedFirstSampleTimestampUs
!=
-
1
)
{
long
embeddedFirstSampleTimestampUs
=
seeker
.
getTimeUs
(
0
);
basisTimeUs
+=
forcedFirstSampleTimestampUs
-
embeddedFirstSampleTimestampUs
;
}
}
sampleBytesRemaining
=
synchronizedHeader
.
frameSize
;
}
...
...
library/src/main/java/com/google/android/exoplayer/hls/HlsChunkSource.java
View file @
da97e30e
...
...
@@ -23,6 +23,7 @@ import com.google.android.exoplayer.chunk.ChunkOperationHolder;
import
com.google.android.exoplayer.chunk.DataChunk
;
import
com.google.android.exoplayer.chunk.Format
;
import
com.google.android.exoplayer.extractor.Extractor
;
import
com.google.android.exoplayer.extractor.mp3.Mp3Extractor
;
import
com.google.android.exoplayer.extractor.ts.AdtsExtractor
;
import
com.google.android.exoplayer.extractor.ts.PtsTimestampAdjuster
;
import
com.google.android.exoplayer.extractor.ts.TsExtractor
;
...
...
@@ -114,6 +115,7 @@ public class HlsChunkSource {
private
static
final
String
TAG
=
"HlsChunkSource"
;
private
static
final
String
AAC_FILE_EXTENSION
=
".aac"
;
private
static
final
String
MP3_FILE_EXTENSION
=
".mp3"
;
private
static
final
float
BANDWIDTH_FRACTION
=
0.8f
;
private
final
DataSource
dataSource
;
...
...
@@ -354,24 +356,28 @@ public class HlsChunkSource {
// Configure the extractor that will read the chunk.
HlsExtractorWrapper
extractorWrapper
;
if
(
previousTsChunk
==
null
||
segment
.
discontinuity
||
liveDiscontinuity
if
(
chunkUri
.
getLastPathSegment
().
endsWith
(
AAC_FILE_EXTENSION
))
{
Extractor
extractor
=
new
AdtsExtractor
(
startTimeUs
);
extractorWrapper
=
new
HlsExtractorWrapper
(
trigger
,
format
,
startTimeUs
,
extractor
,
switchingVariantSpliced
,
adaptiveMaxWidth
,
adaptiveMaxHeight
);
}
else
if
(
chunkUri
.
getLastPathSegment
().
endsWith
(
MP3_FILE_EXTENSION
))
{
Extractor
extractor
=
new
Mp3Extractor
(
startTimeUs
);
extractorWrapper
=
new
HlsExtractorWrapper
(
trigger
,
format
,
startTimeUs
,
extractor
,
switchingVariantSpliced
,
adaptiveMaxWidth
,
adaptiveMaxHeight
);
}
else
if
(
previousTsChunk
==
null
||
segment
.
discontinuity
||
liveDiscontinuity
||
!
format
.
equals
(
previousTsChunk
.
format
))
{
Extractor
extractor
;
if
(
chunkUri
.
getLastPathSegment
().
endsWith
(
AAC_FILE_EXTENSION
))
{
extractor
=
new
AdtsExtractor
(
startTimeUs
);
}
else
{
if
(
previousTsChunk
==
null
||
segment
.
discontinuity
||
liveDiscontinuity
||
ptsTimestampAdjuster
==
null
)
{
// TODO: Use this for AAC as well, along with the ID3 PRIV priv tag values with owner
// identifier com.apple.streaming.transportStreamTimestamp.
ptsTimestampAdjuster
=
new
PtsTimestampAdjuster
(
startTimeUs
);
}
extractor
=
new
TsExtractor
(
ptsTimestampAdjuster
);
// MPEG-2 TS segments, but we need a new extractor.
if
(
previousTsChunk
==
null
||
segment
.
discontinuity
||
liveDiscontinuity
||
ptsTimestampAdjuster
==
null
)
{
// TODO: Use this for AAC as well, along with the ID3 PRIV priv tag values with owner
// identifier com.apple.streaming.transportStreamTimestamp.
ptsTimestampAdjuster
=
new
PtsTimestampAdjuster
(
startTimeUs
);
}
Extractor
extractor
=
new
TsExtractor
(
ptsTimestampAdjuster
);
extractorWrapper
=
new
HlsExtractorWrapper
(
trigger
,
format
,
startTimeUs
,
extractor
,
switchingVariantSpliced
,
adaptiveMaxWidth
,
adaptiveMaxHeight
);
}
else
{
// MPEG-2 TS segments, and we need to continue using the same extractor.
extractorWrapper
=
previousTsChunk
.
extractorWrapper
;
}
...
...
library/src/main/java/com/google/android/exoplayer/hls/HlsSampleSource.java
View file @
da97e30e
...
...
@@ -131,24 +131,30 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
return
true
;
}
if
(!
extractors
.
isEmpty
())
{
// We're not prepared, but we might have loaded what we need.
HlsExtractorWrapper
extractor
=
getCurrentExtractor
();
if
(
extractor
.
isPrepared
())
{
trackCount
=
extractor
.
getTrackCount
();
trackEnabledStates
=
new
boolean
[
trackCount
];
pendingDiscontinuities
=
new
boolean
[
trackCount
];
downstreamMediaFormats
=
new
MediaFormat
[
trackCount
];
trackFormat
=
new
MediaFormat
[
trackCount
];
long
durationUs
=
chunkSource
.
getDurationUs
();
for
(
int
i
=
0
;
i
<
trackCount
;
i
++)
{
MediaFormat
format
=
extractor
.
getMediaFormat
(
i
).
copyWithDurationUs
(
durationUs
);
if
(
MimeTypes
.
isVideo
(
format
.
mimeType
))
{
format
=
format
.
copyAsAdaptive
();
while
(
true
)
{
// We're not prepared, but we might have loaded what we need.
HlsExtractorWrapper
extractor
=
extractors
.
getFirst
();
if
(
extractor
.
isPrepared
())
{
trackCount
=
extractor
.
getTrackCount
();
trackEnabledStates
=
new
boolean
[
trackCount
];
pendingDiscontinuities
=
new
boolean
[
trackCount
];
downstreamMediaFormats
=
new
MediaFormat
[
trackCount
];
trackFormat
=
new
MediaFormat
[
trackCount
];
long
durationUs
=
chunkSource
.
getDurationUs
();
for
(
int
i
=
0
;
i
<
trackCount
;
i
++)
{
MediaFormat
format
=
extractor
.
getMediaFormat
(
i
).
copyWithDurationUs
(
durationUs
);
if
(
MimeTypes
.
isVideo
(
format
.
mimeType
))
{
format
=
format
.
copyAsAdaptive
();
}
trackFormat
[
i
]
=
format
;
}
trackFormat
[
i
]
=
format
;
prepared
=
true
;
return
true
;
}
else
if
(
extractors
.
size
()
>
1
)
{
extractors
.
removeFirst
().
clear
();
}
else
{
break
;
}
prepared
=
true
;
return
true
;
}
}
// We're not prepared and we haven't loaded what we need.
...
...
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