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
37d12ff1
authored
Apr 11, 2015
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Steps toward generalizing the Extractor interface for all extractors.
parent
3a551c73
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
402 additions
and
264 deletions
library/src/main/java/com/google/android/exoplayer/extractor/ts/DataSourceExtractorInput.java → library/src/main/java/com/google/android/exoplayer/extractor/DefaultExtractorInput.java
library/src/main/java/com/google/android/exoplayer/extractor/SampleQueue.java → library/src/main/java/com/google/android/exoplayer/extractor/DefaultTrackOutput.java
library/src/main/java/com/google/android/exoplayer/extractor/Extractor.java
library/src/main/java/com/google/android/exoplayer/extractor/ExtractorInput.java
library/src/main/java/com/google/android/exoplayer/extractor/ExtractorOutput.java
library/src/main/java/com/google/android/exoplayer/extractor/RollingSampleBuffer.java
library/src/main/java/com/google/android/exoplayer/extractor/TrackOutput.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsExtractor.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsReader.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/ElementaryStreamReader.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/Id3Reader.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/SeiReader.java
library/src/main/java/com/google/android/exoplayer/extractor/ts/TsExtractor.java
library/src/main/java/com/google/android/exoplayer/hls/HlsExtractorWrapper.java
library/src/main/java/com/google/android/exoplayer/hls/TsChunk.java
library/src/main/java/com/google/android/exoplayer/extractor/
ts/DataSource
ExtractorInput.java
→
library/src/main/java/com/google/android/exoplayer/extractor/
Default
ExtractorInput.java
View file @
37d12ff1
...
...
@@ -13,32 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer
.
extractor
.
ts
;
package
com
.
google
.
android
.
exoplayer
.
extractor
;
import
com.google.android.exoplayer.
extractor.Extractor.ExtractorInput
;
import
com.google.android.exoplayer.
C
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
java.io.EOFException
;
import
java.io.IOException
;
/**
* An {@link ExtractorInput} that wraps a {@link DataSource}.
*/
public
final
class
D
ataSource
ExtractorInput
implements
ExtractorInput
{
public
final
class
D
efault
ExtractorInput
implements
ExtractorInput
{
private
static
final
byte
[]
SCRATCH_SPACE
=
new
byte
[
4096
];
private
final
DataSource
dataSource
;
private
long
position
;
private
boolean
isEnded
;
private
long
length
;
/**
* @param dataSource The wrapped {@link DataSource}.
* @param position The initial position in the stream.
* @param length The length of the stream, or {@link C#LENGTH_UNBOUNDED} if it is unknown.
*/
public
D
ataSourceExtractorInput
(
DataSource
dataSource
,
long
position
)
{
public
D
efaultExtractorInput
(
DataSource
dataSource
,
long
position
,
long
length
)
{
this
.
dataSource
=
dataSource
;
this
.
position
=
position
;
this
.
length
=
length
;
}
@Override
...
...
@@ -47,16 +50,15 @@ public final class DataSourceExtractorInput implements ExtractorInput {
throw
new
InterruptedException
();
}
int
bytesRead
=
dataSource
.
read
(
target
,
offset
,
length
);
if
(
bytesRead
==
-
1
)
{
isEnded
=
true
;
return
-
1
;
if
(
bytesRead
==
C
.
RESULT_END_OF_INPUT
)
{
return
C
.
RESULT_END_OF_INPUT
;
}
position
+=
bytesRead
;
return
bytesRead
;
}
@Override
public
boolean
readFully
(
byte
[]
target
,
int
offset
,
int
length
)
public
boolean
readFully
(
byte
[]
target
,
int
offset
,
int
length
,
boolean
allowEndOfInput
)
throws
IOException
,
InterruptedException
{
int
remaining
=
length
;
while
(
remaining
>
0
)
{
...
...
@@ -64,9 +66,11 @@ public final class DataSourceExtractorInput implements ExtractorInput {
throw
new
InterruptedException
();
}
int
bytesRead
=
dataSource
.
read
(
target
,
offset
,
remaining
);
if
(
bytesRead
==
-
1
)
{
isEnded
=
true
;
return
false
;
if
(
bytesRead
==
C
.
RESULT_END_OF_INPUT
)
{
if
(
allowEndOfInput
&&
remaining
==
length
)
{
return
false
;
}
throw
new
EOFException
();
}
offset
+=
bytesRead
;
remaining
-=
bytesRead
;
...
...
@@ -76,21 +80,25 @@ public final class DataSourceExtractorInput implements ExtractorInput {
}
@Override
public
boolean
skipFully
(
int
length
)
throws
IOException
,
InterruptedException
{
public
void
readFully
(
byte
[]
target
,
int
offset
,
int
length
)
throws
IOException
,
InterruptedException
{
readFully
(
target
,
offset
,
length
,
false
);
}
@Override
public
void
skipFully
(
int
length
)
throws
IOException
,
InterruptedException
{
int
remaining
=
length
;
while
(
remaining
>
0
)
{
if
(
Thread
.
interrupted
())
{
throw
new
InterruptedException
();
}
int
bytesRead
=
dataSource
.
read
(
SCRATCH_SPACE
,
0
,
Math
.
min
(
SCRATCH_SPACE
.
length
,
remaining
));
if
(
bytesRead
==
-
1
)
{
isEnded
=
true
;
return
false
;
if
(
bytesRead
==
C
.
RESULT_END_OF_INPUT
)
{
throw
new
EOFException
();
}
remaining
-=
bytesRead
;
}
position
+=
length
;
return
true
;
}
@Override
...
...
@@ -99,8 +107,8 @@ public final class DataSourceExtractorInput implements ExtractorInput {
}
@Override
public
boolean
isEnded
()
{
return
isEnded
;
public
long
getLength
()
{
return
length
;
}
}
library/src/main/java/com/google/android/exoplayer/extractor/
SampleQueue
.java
→
library/src/main/java/com/google/android/exoplayer/extractor/
DefaultTrackOutput
.java
View file @
37d12ff1
...
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer.extractor;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.SampleHolder
;
import
com.google.android.exoplayer.extractor.Extractor.TrackOutput
;
import
com.google.android.exoplayer.upstream.BufferPool
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
...
...
@@ -29,7 +28,7 @@ import java.io.IOException;
* the first sample returned from the queue is a keyframe, allowing splicing to another queue, and
* so on.
*/
public
final
class
SampleQueue
implements
TrackOutput
{
public
final
class
DefaultTrackOutput
implements
TrackOutput
{
private
final
RollingSampleBuffer
rollingBuffer
;
private
final
SampleHolder
sampleInfoHolder
;
...
...
@@ -39,14 +38,11 @@ public final class SampleQueue implements TrackOutput {
private
long
lastReadTimeUs
;
private
long
spliceOutTimeUs
;
// Accessed only by the loading thread.
private
boolean
writingSample
;
// Accessed by both the loading and consuming threads.
private
volatile
long
largestParsedTimestampUs
;
private
volatile
MediaFormat
format
;
public
SampleQueue
(
BufferPool
bufferPool
)
{
public
DefaultTrackOutput
(
BufferPool
bufferPool
)
{
rollingBuffer
=
new
RollingSampleBuffer
(
bufferPool
);
sampleInfoHolder
=
new
SampleHolder
(
SampleHolder
.
BUFFER_REPLACEMENT_MODE_DISABLED
);
needKeyframe
=
true
;
...
...
@@ -61,6 +57,13 @@ public final class SampleQueue implements TrackOutput {
// Called by the consuming thread.
/**
* True if the output has received a format. False otherwise.
*/
public
boolean
hasFormat
()
{
return
format
!=
null
;
}
public
MediaFormat
getFormat
()
{
return
format
;
}
...
...
@@ -114,7 +117,7 @@ public final class SampleQueue implements TrackOutput {
* @param nextQueue The queue being spliced to.
* @return Whether the splice was configured successfully.
*/
public
boolean
configureSpliceTo
(
SampleQueue
nextQueue
)
{
public
boolean
configureSpliceTo
(
DefaultTrackOutput
nextQueue
)
{
if
(
spliceOutTimeUs
!=
Long
.
MIN_VALUE
)
{
// We've already configured the splice.
return
true
;
...
...
@@ -164,44 +167,29 @@ public final class SampleQueue implements TrackOutput {
return
true
;
}
// TrackOutput implementation. Called by the loading thread.
@Override
public
boolean
hasFormat
()
{
return
format
!=
null
;
}
@Override
public
void
setFormat
(
MediaFormat
format
)
{
this
.
format
=
format
;
}
// Called by the loading thread.
@Override
public
int
appendData
(
DataSource
dataSource
,
int
length
)
throws
IOException
{
public
int
sampleData
(
DataSource
dataSource
,
int
length
)
throws
IOException
{
return
rollingBuffer
.
appendData
(
dataSource
,
length
);
}
@Override
public
void
appendData
(
ParsableByteArray
buffer
,
int
length
)
{
rollingBuffer
.
appendData
(
buffer
,
length
);
}
// TrackOutput implementation. Called by the loading thread.
@Override
public
void
startSample
(
long
sampleTimeUs
,
int
offset
)
{
writingSample
=
true
;
largestParsedTimestampUs
=
Math
.
max
(
largestParsedTimestampUs
,
sampleTimeUs
);
rollingBuffer
.
startSample
(
sampleTimeUs
,
offset
);
public
void
format
(
MediaFormat
format
)
{
this
.
format
=
format
;
}
@Override
public
void
commitSample
(
int
flags
,
int
offset
,
byte
[]
encryptionKey
)
{
rollingBuffer
.
commitSample
(
flags
,
offset
,
encryptionKey
);
writingSample
=
false
;
public
void
sampleData
(
ParsableByteArray
buffer
,
int
length
)
{
rollingBuffer
.
appendData
(
buffer
,
length
);
}
@Override
public
boolean
isWritingSample
()
{
return
writingSample
;
public
void
sampleMetadata
(
long
timeUs
,
int
flags
,
int
size
,
int
offset
,
byte
[]
encryptionKey
)
{
largestParsedTimestampUs
=
Math
.
max
(
largestParsedTimestampUs
,
timeUs
);
rollingBuffer
.
commitSample
(
timeUs
,
flags
,
rollingBuffer
.
getWritePosition
()
-
size
-
offset
,
size
,
encryptionKey
);
}
}
library/src/main/java/com/google/android/exoplayer/extractor/Extractor.java
View file @
37d12ff1
...
...
@@ -15,139 +15,44 @@
*/
package
com
.
google
.
android
.
exoplayer
.
extractor
;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
import
com.google.android.exoplayer.C
;
import
java.io.IOException
;
/**
* Facilitates extraction of
media samples for HLS playbacks
.
* Facilitates extraction of
data from a container format
.
*/
public
interface
Extractor
{
/**
* An object from which source data can be read.
* Returned by {@link #read(ExtractorInput)} if the {@link ExtractorInput} passed to the next
* {@link #read(ExtractorInput)} is required to provide data continuing from the position in the
* stream reached by the returning call.
*/
public
interface
ExtractorInput
{
/**
* Reads up to {@code length} bytes from the input.
* <p>
* This method blocks until at least one byte of data can be read, the end of the input is
* detected, or an exception is thrown.
*
* @param target A target array into which data should be written.
* @param offset The offset into the target array at which to write.
* @param length The maximum number of bytes to read from the input.
* @return The number of bytes read, or -1 if the input has ended.
* @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread has been interrupted.
*/
int
read
(
byte
[]
target
,
int
offset
,
int
length
)
throws
IOException
,
InterruptedException
;
/**
* Like {@link #read(byte[], int, int)}, but guaranteed to read request {@code length} in full
* unless the end of the input is detected, or an exception is thrown.
*
* TODO: Firm up behavior of this method if (a) zero bytes are read before EOS, (b) the read
* is partially satisfied before EOS.
*
* @param target A target array into which data should be written.
* @param offset The offset into the target array at which to write.
* @param length The number of bytes to read from the input.
* @return True if the read was successful. False if the end of the input was reached.
* @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread has been interrupted.
*/
boolean
readFully
(
byte
[]
target
,
int
offset
,
int
length
)
throws
IOException
,
InterruptedException
;
/**
* Like {@link #readFully(byte[], int, int)}, except the data is skipped instead of read.
*
* TODO: Firm up behavior of this method if (a) zero bytes are skipped before EOS, (b) the skip
* is partially satisfied before EOS.
*
* @param length The number of bytes to skip from the input.
* @return True if the read was successful. False if the end of the input was reached.
* @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread is interrupted.
*/
boolean
skipFully
(
int
length
)
throws
IOException
,
InterruptedException
;
/**
* The current position in the stream.
*
* @return The position in the stream.
*/
long
getPosition
();
/**
* Whether or not the input has ended.
*
* @return True if the input has ended. False otherwise.
*/
boolean
isEnded
();
}
public
static
final
int
RESULT_CONTINUE
=
0
;
/**
* An object to which extracted data should be output.
* Returned by {@link #read(ExtractorInput)} if the end of the {@link ExtractorInput} was reached.
* Equal to {@link C#RESULT_END_OF_INPUT}.
*/
public
interface
TrackOutputBuilder
{
/**
* Invoked to build a {@link TrackOutput} to which data should be output for a given track.
*
* @param trackId A stable track id.
* @return The corresponding {@link TrackOutput}.
*/
TrackOutput
buildOutput
(
int
trackId
);
/**
* Invoked when all {@link TrackOutput}s have been built, meaning {@link #buildOutput(int)}
* will not be invoked again.
*/
void
allOutputsBuilt
();
}
/**
* An object to which extracted data belonging to a given track should be output.
*/
public
interface
TrackOutput
{
boolean
hasFormat
();
void
setFormat
(
MediaFormat
format
);
boolean
isWritingSample
();
int
appendData
(
DataSource
dataSource
,
int
length
)
throws
IOException
;
void
appendData
(
ParsableByteArray
data
,
int
length
);
void
startSample
(
long
timeUs
,
int
offset
);
void
commitSample
(
int
flags
,
int
offset
,
byte
[]
encryptionKey
);
}
public
static
final
int
RESULT_END_OF_INPUT
=
C
.
RESULT_END_OF_INPUT
;
/**
* Initializes the extractor.
* Initializes the extractor
with an {@link ExtractorOutput}
.
*
* @param output A
{@link TrackOutputBuilder} to which extracted data should be output
.
* @param output A
n {@link ExtractorOutput} to receive extracted data
.
*/
void
init
(
TrackOutputBuilder
output
);
void
init
(
ExtractorOutput
output
);
/**
* Reads from the provided {@link ExtractorInput}.
* Extracts data read from a provided {@link ExtractorInput}.
* <p>
* Each read will extract at most one sample from the stream before returning.
*
* @param input The {@link ExtractorInput} from which to read.
* @throws IOException If an error occurred reading from the source.
* @param input The {@link ExtractorInput} from which data should be read.
* @return One of the {@code RESULT_} values defined in this interface.
* @throws IOException If an error occurred reading from the input.
* @throws InterruptedException If the thread was interrupted.
*/
void
read
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
;
int
read
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
;
}
library/src/main/java/com/google/android/exoplayer/extractor/ExtractorInput.java
0 → 100644
View file @
37d12ff1
/*
* Copyright (C) 2014 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
.
exoplayer
.
extractor
;
import
com.google.android.exoplayer.C
;
import
java.io.EOFException
;
import
java.io.IOException
;
/**
* Provides data to be consumed by an {@link Extractor}.
*/
public
interface
ExtractorInput
{
/**
* Reads up to {@code length} bytes from the input.
* <p>
* This method blocks until at least one byte of data can be read, the end of the input is
* detected, or an exception is thrown.
*
* @param target A target array into which data should be written.
* @param offset The offset into the target array at which to write.
* @param length The maximum number of bytes to read from the input.
* @return The number of bytes read, or {@link C#RESULT_END_OF_INPUT} if the input has ended.
* @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread has been interrupted.
*/
int
read
(
byte
[]
target
,
int
offset
,
int
length
)
throws
IOException
,
InterruptedException
;
/**
* Like {@link #read(byte[], int, int)}, but reads the requested {@code length} in full.
* <p>
* If the end of the input is found having read no data, then behavior is dependent on
* {@code allowEndOfInput}. If {@code allowEndOfInput == true} then {@code false} is returned.
* Otherwise an {@link EOFException} is thrown.
* <p>
* Encountering the end of input having partially satisfied the read is always considered an
* error, and will result in an {@link EOFException} being thrown.
*
* @param target A target array into which data should be written.
* @param offset The offset into the target array at which to write.
* @param length The number of bytes to read from the input.
* @param allowEndOfInput True if encountering the end of the input having read no data is
* allowed, and should result in {@code false} being returned. False if it should be
* considered an error, causing an {@link EOFException} to be thrown.
* @return True if the read was successful. False if the end of the input was encountered having
* read no data.
* @throws EOFException If the end of input was encountered having partially satisfied the read
* (i.e. having read at least one byte, but fewer than {@code length}), or if no bytes were
* read and {@code allowEndOfInput} is false.
* @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread has been interrupted.
*/
boolean
readFully
(
byte
[]
target
,
int
offset
,
int
length
,
boolean
allowEndOfInput
)
throws
IOException
,
InterruptedException
;
/**
* Equivalent to {@code readFully(target, offset, length, false)}.
*
* @param target A target array into which data should be written.
* @param offset The offset into the target array at which to write.
* @param length The number of bytes to read from the input.
* @throws EOFException If the end of input was encountered.
* @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread is interrupted.
*/
void
readFully
(
byte
[]
target
,
int
offset
,
int
length
)
throws
IOException
,
InterruptedException
;
/**
* Like {@link #readFully(byte[], int, int)}, except the data is skipped instead of read.
* <p>
* Encountering the end of input is always considered an error, and will result in an
* {@link EOFException} being thrown.
*
* @param length The number of bytes to skip from the input.
* @throws EOFException If the end of input was encountered.
* @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread is interrupted.
*/
void
skipFully
(
int
length
)
throws
IOException
,
InterruptedException
;
/**
* The current position (byte offset) in the stream.
*
* @return The position (byte offset) in the stream.
*/
long
getPosition
();
/**
* Returns the length of the source stream, or {@link C#LENGTH_UNBOUNDED} if it is unknown.
*
* @return The length of the source stream, or {@link C#LENGTH_UNBOUNDED}.
*/
long
getLength
();
}
library/src/main/java/com/google/android/exoplayer/extractor/ExtractorOutput.java
0 → 100644
View file @
37d12ff1
/*
* Copyright (C) 2014 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
.
exoplayer
.
extractor
;
/**
* Receives stream level data extracted by an {@link Extractor}.
*/
public
interface
ExtractorOutput
{
/**
* Invoked when the {@link Extractor} identifies the existence of a track in the stream.
* <p>
* Returns a {@link TrackOutput} that will receive track level data belonging to the track.
*
* @param trackId A track identifier.
* @return The {@link TrackOutput} that should receive track level data belonging to the track.
*/
TrackOutput
track
(
int
trackId
);
/**
* Invoked when all tracks have been identified, meaning that {@link #track(int)} will not be
* invoked again.
*/
void
endTracks
();
}
library/src/main/java/com/google/android/exoplayer/extractor/RollingSampleBuffer.java
View file @
37d12ff1
...
...
@@ -19,7 +19,6 @@ import com.google.android.exoplayer.C;
import
com.google.android.exoplayer.SampleHolder
;
import
com.google.android.exoplayer.upstream.BufferPool
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
com.google.android.exoplayer.util.Assertions
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
import
java.io.IOException
;
...
...
@@ -48,8 +47,6 @@ import java.util.concurrent.ConcurrentLinkedQueue;
private
long
totalBytesWritten
;
private
byte
[]
lastFragment
;
private
int
lastFragmentOffset
;
private
long
pendingSampleTimeUs
;
private
long
pendingSampleOffset
;
public
RollingSampleBuffer
(
BufferPool
bufferPool
)
{
this
.
fragmentPool
=
bufferPool
;
...
...
@@ -71,7 +68,8 @@ import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Fills {@code holder} with information about the current sample, but does not write its data.
* <p>
* The fields set are {SampleHolder#size}, {SampleHolder#timeUs} and {SampleHolder#flags}.
* The fields set are {@link SampleHolder#size}, {@link SampleHolder#timeUs} and
* {@link SampleHolder#flags}.
*
* @param holder The holder into which the current sample information should be written.
* @return True if the holder was filled. False if there is no current sample.
...
...
@@ -92,10 +90,15 @@ import java.util.concurrent.ConcurrentLinkedQueue;
* Reads the current sample, advancing the read index to the next sample.
*
* @param sampleHolder The holder into which the current sample should be written.
* @return True if a sample was read. False if there is no current sample.
*/
public
void
readSample
(
SampleHolder
sampleHolder
)
{
public
boolean
readSample
(
SampleHolder
sampleHolder
)
{
// Write the sample information into the holder and extrasHolder.
infoQueue
.
peekSample
(
sampleHolder
,
extrasHolder
);
boolean
haveSample
=
infoQueue
.
peekSample
(
sampleHolder
,
extrasHolder
);
if
(!
haveSample
)
{
return
false
;
}
// Read encryption data if the sample is encrypted.
if
(
sampleHolder
.
isEncrypted
())
{
readEncryptionData
(
sampleHolder
,
extrasHolder
);
...
...
@@ -110,6 +113,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
// Advance the read head.
long
nextOffset
=
infoQueue
.
moveToNextSample
();
dropFragmentsTo
(
nextOffset
);
return
true
;
}
/**
...
...
@@ -250,16 +254,12 @@ import java.util.concurrent.ConcurrentLinkedQueue;
// Called by the loading thread.
/**
*
Indicates the start point for the next sample
.
*
Returns the current write position in the rolling buffer
.
*
* @param sampleTimeUs The sample timestamp.
* @param offset The offset of the sample's data, relative to the total number of bytes written
* to the buffer. Must be negative or zero.
* @return The current write position.
*/
public
void
startSample
(
long
sampleTimeUs
,
int
offset
)
{
Assertions
.
checkState
(
offset
<=
0
);
pendingSampleTimeUs
=
sampleTimeUs
;
pendingSampleOffset
=
totalBytesWritten
+
offset
;
public
long
getWritePosition
()
{
return
totalBytesWritten
;
}
/**
...
...
@@ -314,16 +314,15 @@ import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Indicates the end point for the current sample, making it available for consumption.
*
* @param sampleTimeUs The sample timestamp.
* @param flags Flags that accompany the sample. See {@link SampleHolder#flags}.
* @param
offset The offset of the first byte after the end of the sample's data, relative to
*
the total number of bytes written to the buffer. Must be negative or zero
.
* @param
position The position of the sample data in the rolling buffer.
*
@param size The size of the sample, in bytes
.
* @param encryptionKey The encryption key associated with the sample, or null.
*/
public
void
commitSample
(
int
flags
,
int
offset
,
byte
[]
encryptionKey
)
{
Assertions
.
checkState
(
offset
<=
0
);
int
sampleSize
=
(
int
)
(
totalBytesWritten
+
offset
-
pendingSampleOffset
);
infoQueue
.
commitSample
(
pendingSampleTimeUs
,
pendingSampleOffset
,
sampleSize
,
flags
,
encryptionKey
);
public
void
commitSample
(
long
sampleTimeUs
,
int
flags
,
long
position
,
int
size
,
byte
[]
encryptionKey
)
{
infoQueue
.
commitSample
(
sampleTimeUs
,
flags
,
position
,
size
,
encryptionKey
);
}
/**
...
...
@@ -398,7 +397,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
// Called by the loading thread.
public
synchronized
void
commitSample
(
long
timeUs
,
long
offset
,
int
size
,
int
sampleFlags
,
public
synchronized
void
commitSample
(
long
timeUs
,
int
sampleFlags
,
long
offset
,
int
size
,
byte
[]
encryptionKey
)
{
timesUs
[
writeIndex
]
=
timeUs
;
offsets
[
writeIndex
]
=
offset
;
...
...
library/src/main/java/com/google/android/exoplayer/extractor/TrackOutput.java
0 → 100644
View file @
37d12ff1
/*
* Copyright (C) 2014 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
.
exoplayer
.
extractor
;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.SampleHolder
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
/**
* Receives track level data extracted by an {@link Extractor}.
*/
public
interface
TrackOutput
{
/**
* Invoked when the {@link MediaFormat} of the track has been extracted from the stream.
*
* @param format The extracted {@link MediaFormat}.
*/
void
format
(
MediaFormat
format
);
/**
* Invoked to write sample data to the output.
*
* @param data A {@link ParsableByteArray} from which to read the sample data.
* @param length The number of bytes to read.
*/
void
sampleData
(
ParsableByteArray
data
,
int
length
);
/**
* Invoked when metadata associated with a sample has been extracted from the stream.
* <p>
* The corresponding sample data will have already been passed to the output via calls to
* {@link #sampleData(ParsableByteArray, int)}.
*
* @param timeUs The media timestamp associated with the sample, in microseconds.
* @param flags Flags associated with the sample. See {@link SampleHolder#flags}.
* @param size The size of the sample data, in bytes.
* @param offset The number of bytes that have been passed to
* {@link #sampleData(ParsableByteArray, int)} since the last byte belonging to the sample
* whose metadata is being passed.
* @param encryptionKey The encryption key associated with the sample. May be null.
*/
void
sampleMetadata
(
long
timeUs
,
int
flags
,
int
size
,
int
offset
,
byte
[]
encryptionKey
);
}
library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsExtractor.java
View file @
37d12ff1
...
...
@@ -16,6 +16,8 @@
package
com
.
google
.
android
.
exoplayer
.
extractor
.
ts
;
import
com.google.android.exoplayer.extractor.Extractor
;
import
com.google.android.exoplayer.extractor.ExtractorInput
;
import
com.google.android.exoplayer.extractor.ExtractorOutput
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
import
java.io.IOException
;
...
...
@@ -42,16 +44,17 @@ public class AdtsExtractor implements Extractor {
}
@Override
public
void
init
(
TrackOutputBuilder
output
)
{
adtsReader
=
new
AdtsReader
(
output
.
buildOutput
(
0
));
output
.
allOutputsBuilt
();
public
void
init
(
ExtractorOutput
output
)
{
adtsReader
=
new
AdtsReader
(
output
.
track
(
0
));
output
.
endTracks
();
}
@Override
public
void
read
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
public
int
read
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
int
bytesRead
=
input
.
read
(
packetBuffer
.
data
,
0
,
MAX_PACKET_SIZE
);
if
(
bytesRead
==
-
1
)
{
return
;
return
RESULT_END_OF_INPUT
;
}
// Feed whatever data we have to the reader, regardless of whether the read finished or not.
...
...
@@ -62,6 +65,7 @@ public class AdtsExtractor implements Extractor {
// unnecessary to copy the data through packetBuffer.
adtsReader
.
consume
(
packetBuffer
,
firstSampleTimestamp
,
firstPacket
);
firstPacket
=
false
;
return
RESULT_CONTINUE
;
}
}
library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsReader.java
View file @
37d12ff1
...
...
@@ -17,7 +17,7 @@ package com.google.android.exoplayer.extractor.ts;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.extractor.
Extractor.
TrackOutput
;
import
com.google.android.exoplayer.extractor.TrackOutput
;
import
com.google.android.exoplayer.util.CodecSpecificDataUtil
;
import
com.google.android.exoplayer.util.MimeTypes
;
import
com.google.android.exoplayer.util.ParsableBitArray
;
...
...
@@ -48,7 +48,8 @@ import java.util.Collections;
private
boolean
lastByteWasFF
;
private
boolean
hasCrc
;
// Parsed from the header.
// Used when parsing the header.
private
boolean
hasOutputFormat
;
private
long
frameDurationUs
;
private
int
sampleSize
;
...
...
@@ -78,17 +79,16 @@ import java.util.Collections;
int
targetLength
=
hasCrc
?
HEADER_SIZE
+
CRC_SIZE
:
HEADER_SIZE
;
if
(
continueRead
(
data
,
adtsScratch
.
getData
(),
targetLength
))
{
parseHeader
();
output
.
startSample
(
timeUs
,
0
);
bytesRead
=
0
;
state
=
STATE_READING_SAMPLE
;
}
break
;
case
STATE_READING_SAMPLE:
int
bytesToRead
=
Math
.
min
(
data
.
bytesLeft
(),
sampleSize
-
bytesRead
);
output
.
append
Data
(
data
,
bytesToRead
);
output
.
sample
Data
(
data
,
bytesToRead
);
bytesRead
+=
bytesToRead
;
if
(
bytesRead
==
sampleSize
)
{
output
.
commitSample
(
C
.
SAMPLE_FLAG_SYNC
,
0
,
null
);
output
.
sampleMetadata
(
timeUs
,
C
.
SAMPLE_FLAG_SYNC
,
sampleSize
,
0
,
null
);
timeUs
+=
frameDurationUs
;
bytesRead
=
0
;
state
=
STATE_FINDING_SYNC
;
...
...
@@ -152,7 +152,7 @@ import java.util.Collections;
private
void
parseHeader
()
{
adtsScratch
.
setPosition
(
0
);
if
(!
output
.
hasFormat
()
)
{
if
(!
hasOutputFormat
)
{
int
audioObjectType
=
adtsScratch
.
readBits
(
2
)
+
1
;
int
sampleRateIndex
=
adtsScratch
.
readBits
(
4
);
adtsScratch
.
skipBits
(
1
);
...
...
@@ -167,7 +167,8 @@ import java.util.Collections;
MediaFormat
.
NO_VALUE
,
audioParams
.
second
,
audioParams
.
first
,
Collections
.
singletonList
(
audioSpecificConfig
));
frameDurationUs
=
(
C
.
MICROS_PER_SECOND
*
1024L
)
/
mediaFormat
.
sampleRate
;
output
.
setFormat
(
mediaFormat
);
output
.
format
(
mediaFormat
);
hasOutputFormat
=
true
;
}
else
{
adtsScratch
.
skipBits
(
10
);
}
...
...
library/src/main/java/com/google/android/exoplayer/extractor/ts/ElementaryStreamReader.java
View file @
37d12ff1
...
...
@@ -15,7 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
.
extractor
.
ts
;
import
com.google.android.exoplayer.extractor.
Extractor.
TrackOutput
;
import
com.google.android.exoplayer.extractor.TrackOutput
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
/**
...
...
library/src/main/java/com/google/android/exoplayer/extractor/ts/H264Reader.java
View file @
37d12ff1
...
...
@@ -17,7 +17,7 @@ package com.google.android.exoplayer.extractor.ts;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.extractor.
Extractor.
TrackOutput
;
import
com.google.android.exoplayer.extractor.TrackOutput
;
import
com.google.android.exoplayer.util.Assertions
;
import
com.google.android.exoplayer.util.H264Util
;
import
com.google.android.exoplayer.util.MimeTypes
;
...
...
@@ -46,9 +46,15 @@ import java.util.List;
private
final
NalUnitTargetBuffer
sei
;
private
final
ParsableByteArray
seiWrapper
;
private
boolean
hasOutputFormat
;
private
int
scratchEscapeCount
;
private
int
[]
scratchEscapePositions
;
private
boolean
writingSample
;
private
boolean
isKeyframe
;
private
long
samplePosition
;
private
long
sampleTimeUs
;
private
long
totalBytesWritten
;
public
H264Reader
(
TrackOutput
output
,
SeiReader
seiReader
)
{
super
(
output
);
...
...
@@ -69,7 +75,8 @@ import java.util.List;
byte
[]
dataArray
=
data
.
data
;
// Append the data to the buffer.
output
.
appendData
(
data
,
data
.
bytesLeft
());
totalBytesWritten
+=
data
.
bytesLeft
();
output
.
sampleData
(
data
,
data
.
bytesLeft
());
// Scan the appended data, processing NAL units as they are encountered
while
(
offset
<
limit
)
{
...
...
@@ -85,15 +92,20 @@ import java.util.List;
}
int
nalUnitType
=
H264Util
.
getNalUnitType
(
dataArray
,
nextNalUnitOffset
);
int
nalUnitOffsetInData
=
nextNalUnitOffset
-
limi
t
;
int
bytesWrittenPastNalUnit
=
limit
-
nextNalUnitOffse
t
;
if
(
nalUnitType
==
NAL_UNIT_TYPE_AUD
)
{
if
(
output
.
isWritingSample
()
)
{
if
(
isKeyframe
&&
!
output
.
hasFormat
()
&&
sps
.
isCompleted
()
&&
pps
.
isCompleted
())
{
if
(
writingSample
)
{
if
(
isKeyframe
&&
!
hasOutputFormat
&&
sps
.
isCompleted
()
&&
pps
.
isCompleted
())
{
parseMediaFormat
(
sps
,
pps
);
}
output
.
commitSample
(
isKeyframe
?
C
.
SAMPLE_FLAG_SYNC
:
0
,
nalUnitOffsetInData
,
null
);
int
flags
=
isKeyframe
?
C
.
SAMPLE_FLAG_SYNC
:
0
;
int
size
=
(
int
)
(
totalBytesWritten
-
samplePosition
)
-
bytesWrittenPastNalUnit
;
output
.
sampleMetadata
(
sampleTimeUs
,
flags
,
size
,
bytesWrittenPastNalUnit
,
null
);
writingSample
=
false
;
}
output
.
startSample
(
pesTimeUs
,
nalUnitOffsetInData
);
writingSample
=
true
;
samplePosition
=
totalBytesWritten
-
bytesWrittenPastNalUnit
;
sampleTimeUs
=
pesTimeUs
;
isKeyframe
=
false
;
}
else
if
(
nalUnitType
==
NAL_UNIT_TYPE_IDR
)
{
isKeyframe
=
true
;
...
...
@@ -120,7 +132,7 @@ import java.util.List;
}
private
void
feedNalUnitTargetBuffersStart
(
int
nalUnitType
)
{
if
(!
output
.
hasFormat
()
)
{
if
(!
hasOutputFormat
)
{
sps
.
startNalUnit
(
nalUnitType
);
pps
.
startNalUnit
(
nalUnitType
);
}
...
...
@@ -128,7 +140,7 @@ import java.util.List;
}
private
void
feedNalUnitTargetBuffersData
(
byte
[]
dataArray
,
int
offset
,
int
limit
)
{
if
(!
output
.
hasFormat
()
)
{
if
(!
hasOutputFormat
)
{
sps
.
appendToNalUnit
(
dataArray
,
offset
,
limit
);
pps
.
appendToNalUnit
(
dataArray
,
offset
,
limit
);
}
...
...
@@ -232,9 +244,9 @@ import java.util.List;
frameHeight
-=
(
frameCropTopOffset
+
frameCropBottomOffset
)
*
cropUnitY
;
}
// Set the format.
output
.
setFormat
(
MediaFormat
.
createVideoFormat
(
MimeTypes
.
VIDEO_H264
,
MediaFormat
.
NO_VALUE
,
frameWidth
,
frameHeight
,
initializationData
))
;
output
.
format
(
MediaFormat
.
createVideoFormat
(
MimeTypes
.
VIDEO_H264
,
MediaFormat
.
NO_VALUE
,
C
.
UNKNOWN_TIME_US
,
frameWidth
,
frameHeight
,
initializationData
));
hasOutputFormat
=
true
;
}
private
void
skipScalingList
(
ParsableBitArray
bitArray
,
int
size
)
{
...
...
library/src/main/java/com/google/android/exoplayer/extractor/ts/Id3Reader.java
View file @
37d12ff1
...
...
@@ -17,7 +17,7 @@ package com.google.android.exoplayer.extractor.ts;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.extractor.
Extractor.
TrackOutput
;
import
com.google.android.exoplayer.extractor.TrackOutput
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
/**
...
...
@@ -25,24 +25,32 @@ import com.google.android.exoplayer.util.ParsableByteArray;
*/
/* package */
class
Id3Reader
extends
ElementaryStreamReader
{
private
boolean
writingSample
;
private
long
sampleTimeUs
;
private
int
sampleSize
;
public
Id3Reader
(
TrackOutput
output
)
{
super
(
output
);
output
.
setF
ormat
(
MediaFormat
.
createId3Format
());
output
.
f
ormat
(
MediaFormat
.
createId3Format
());
}
@Override
public
void
consume
(
ParsableByteArray
data
,
long
pesTimeUs
,
boolean
startOfPacket
)
{
if
(
startOfPacket
)
{
output
.
startSample
(
pesTimeUs
,
0
);
writingSample
=
true
;
sampleTimeUs
=
pesTimeUs
;
sampleSize
=
0
;
}
if
(
output
.
isWritingSample
())
{
output
.
appendData
(
data
,
data
.
bytesLeft
());
if
(
writingSample
)
{
sampleSize
+=
data
.
bytesLeft
();
output
.
sampleData
(
data
,
data
.
bytesLeft
());
}
}
@Override
public
void
packetFinished
()
{
output
.
commitSample
(
C
.
SAMPLE_FLAG_SYNC
,
0
,
null
);
output
.
sampleMetadata
(
sampleTimeUs
,
C
.
SAMPLE_FLAG_SYNC
,
sampleSize
,
0
,
null
);
writingSample
=
false
;
}
}
library/src/main/java/com/google/android/exoplayer/extractor/ts/SeiReader.java
View file @
37d12ff1
...
...
@@ -17,7 +17,7 @@ package com.google.android.exoplayer.extractor.ts;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.extractor.
Extractor.
TrackOutput
;
import
com.google.android.exoplayer.extractor.TrackOutput
;
import
com.google.android.exoplayer.text.eia608.Eia608Parser
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
...
...
@@ -31,7 +31,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
public
SeiReader
(
TrackOutput
output
)
{
super
(
output
);
output
.
setF
ormat
(
MediaFormat
.
createEia608Format
());
output
.
f
ormat
(
MediaFormat
.
createEia608Format
());
}
@Override
...
...
@@ -55,9 +55,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
}
while
(
b
==
0xFF
);
// Process the payload. We only support EIA-608 payloads currently.
if
(
Eia608Parser
.
isSeiMessageEia608
(
payloadType
,
payloadSize
,
seiBuffer
))
{
output
.
startSample
(
pesTimeUs
,
0
);
output
.
appendData
(
seiBuffer
,
payloadSize
);
output
.
commitSample
(
C
.
SAMPLE_FLAG_SYNC
,
0
,
null
);
output
.
sampleData
(
seiBuffer
,
payloadSize
);
output
.
sampleMetadata
(
pesTimeUs
,
C
.
SAMPLE_FLAG_SYNC
,
payloadSize
,
0
,
null
);
}
else
{
seiBuffer
.
skip
(
payloadSize
);
}
...
...
library/src/main/java/com/google/android/exoplayer/extractor/ts/TsExtractor.java
View file @
37d12ff1
...
...
@@ -17,6 +17,8 @@ package com.google.android.exoplayer.extractor.ts;
import
com.google.android.exoplayer.C
;
import
com.google.android.exoplayer.extractor.Extractor
;
import
com.google.android.exoplayer.extractor.ExtractorInput
;
import
com.google.android.exoplayer.extractor.ExtractorOutput
;
import
com.google.android.exoplayer.util.ParsableBitArray
;
import
com.google.android.exoplayer.util.ParsableByteArray
;
...
...
@@ -50,7 +52,7 @@ public final class TsExtractor implements Extractor {
private
final
ParsableBitArray
tsScratch
;
// Accessed only by the loading thread.
private
TrackOutputBuilder
output
;
private
ExtractorOutput
output
;
private
long
timestampOffsetUs
;
private
long
lastPts
;
...
...
@@ -65,21 +67,22 @@ public final class TsExtractor implements Extractor {
}
@Override
public
void
init
(
TrackOutputBuilder
output
)
{
public
void
init
(
ExtractorOutput
output
)
{
this
.
output
=
output
;
}
@Override
public
void
read
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
if
(!
input
.
readFully
(
tsPacketBuffer
.
data
,
0
,
TS_PACKET_SIZE
))
{
return
;
public
int
read
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
if
(!
input
.
readFully
(
tsPacketBuffer
.
data
,
0
,
TS_PACKET_SIZE
,
true
))
{
return
RESULT_END_OF_INPUT
;
}
tsPacketBuffer
.
setPosition
(
0
);
tsPacketBuffer
.
setLimit
(
TS_PACKET_SIZE
);
int
syncByte
=
tsPacketBuffer
.
readUnsignedByte
();
if
(
syncByte
!=
TS_SYNC_BYTE
)
{
return
;
return
RESULT_CONTINUE
;
}
tsPacketBuffer
.
readBytes
(
tsScratch
,
3
);
...
...
@@ -105,6 +108,8 @@ public final class TsExtractor implements Extractor {
payloadReader
.
consume
(
tsPacketBuffer
,
payloadUnitStartIndicator
,
output
);
}
}
return
RESULT_CONTINUE
;
}
/**
...
...
@@ -140,7 +145,7 @@ public final class TsExtractor implements Extractor {
private
abstract
static
class
TsPayloadReader
{
public
abstract
void
consume
(
ParsableByteArray
data
,
boolean
payloadUnitStartIndicator
,
TrackOutputBuilder
output
);
ExtractorOutput
output
);
}
...
...
@@ -157,7 +162,7 @@ public final class TsExtractor implements Extractor {
@Override
public
void
consume
(
ParsableByteArray
data
,
boolean
payloadUnitStartIndicator
,
TrackOutputBuilder
output
)
{
ExtractorOutput
output
)
{
// Skip pointer.
if
(
payloadUnitStartIndicator
)
{
int
pointerField
=
data
.
readUnsignedByte
();
...
...
@@ -197,7 +202,7 @@ public final class TsExtractor implements Extractor {
@Override
public
void
consume
(
ParsableByteArray
data
,
boolean
payloadUnitStartIndicator
,
TrackOutputBuilder
output
)
{
ExtractorOutput
output
)
{
// Skip pointer.
if
(
payloadUnitStartIndicator
)
{
int
pointerField
=
data
.
readUnsignedByte
();
...
...
@@ -241,16 +246,16 @@ public final class TsExtractor implements Extractor {
ElementaryStreamReader
pesPayloadReader
=
null
;
switch
(
streamType
)
{
case
TS_STREAM_TYPE_AAC:
pesPayloadReader
=
new
AdtsReader
(
output
.
buildOutput
(
TS_STREAM_TYPE_AAC
));
pesPayloadReader
=
new
AdtsReader
(
output
.
track
(
TS_STREAM_TYPE_AAC
));
break
;
case
TS_STREAM_TYPE_H264:
SeiReader
seiReader
=
new
SeiReader
(
output
.
buildOutput
(
TS_STREAM_TYPE_EIA608
));
SeiReader
seiReader
=
new
SeiReader
(
output
.
track
(
TS_STREAM_TYPE_EIA608
));
streamReaders
.
put
(
TS_STREAM_TYPE_EIA608
,
seiReader
);
pesPayloadReader
=
new
H264Reader
(
output
.
buildOutput
(
TS_STREAM_TYPE_H264
),
pesPayloadReader
=
new
H264Reader
(
output
.
track
(
TS_STREAM_TYPE_H264
),
seiReader
);
break
;
case
TS_STREAM_TYPE_ID3:
pesPayloadReader
=
new
Id3Reader
(
output
.
buildOutput
(
TS_STREAM_TYPE_ID3
));
pesPayloadReader
=
new
Id3Reader
(
output
.
track
(
TS_STREAM_TYPE_ID3
));
break
;
}
...
...
@@ -260,7 +265,7 @@ public final class TsExtractor implements Extractor {
}
}
output
.
allOutputsBuilt
();
output
.
endTracks
();
}
}
...
...
@@ -300,7 +305,7 @@ public final class TsExtractor implements Extractor {
@Override
public
void
consume
(
ParsableByteArray
data
,
boolean
payloadUnitStartIndicator
,
TrackOutputBuilder
output
)
{
ExtractorOutput
output
)
{
if
(
payloadUnitStartIndicator
)
{
switch
(
state
)
{
case
STATE_FINDING_HEADER:
...
...
library/src/main/java/com/google/android/exoplayer/hls/HlsExtractorWrapper.java
View file @
37d12ff1
...
...
@@ -17,10 +17,11 @@ package com.google.android.exoplayer.hls;
import
com.google.android.exoplayer.MediaFormat
;
import
com.google.android.exoplayer.SampleHolder
;
import
com.google.android.exoplayer.extractor.DefaultTrackOutput
;
import
com.google.android.exoplayer.extractor.Extractor
;
import
com.google.android.exoplayer.extractor.
SampleQueue
;
import
com.google.android.exoplayer.extractor.Extractor
.ExtractorIn
put
;
import
com.google.android.exoplayer.extractor.
Extractor.
TrackOutput
;
import
com.google.android.exoplayer.extractor.
ExtractorInput
;
import
com.google.android.exoplayer.extractor.Extractor
Out
put
;
import
com.google.android.exoplayer.extractor.TrackOutput
;
import
com.google.android.exoplayer.upstream.BufferPool
;
import
com.google.android.exoplayer.util.Assertions
;
...
...
@@ -31,25 +32,24 @@ import java.io.IOException;
/**
* Wraps a {@link Extractor}, adding functionality to enable reading of the extracted samples.
*/
public
final
class
HlsExtractorWrapper
implements
Extractor
.
TrackOutputBuilder
{
public
final
class
HlsExtractorWrapper
implements
Extractor
Output
{
private
final
BufferPool
bufferPool
;
private
final
Extractor
extractor
;
private
final
SparseArray
<
SampleQueue
>
sampleQueues
;
private
final
SparseArray
<
DefaultTrackOutput
>
sampleQueues
;
private
final
boolean
shouldSpliceIn
;
private
volatile
boolean
output
sBuilt
;
private
volatile
boolean
track
sBuilt
;
// Accessed only by the consuming thread.
private
boolean
prepared
;
private
boolean
spliceConfigured
;
public
HlsExtractorWrapper
(
BufferPool
bufferPool
,
Extractor
extractor
,
boolean
shouldSpliceIn
)
{
public
HlsExtractorWrapper
(
BufferPool
bufferPool
,
Extractor
extractor
,
boolean
shouldSpliceIn
)
{
this
.
bufferPool
=
bufferPool
;
this
.
extractor
=
extractor
;
this
.
shouldSpliceIn
=
shouldSpliceIn
;
sampleQueues
=
new
SparseArray
<
SampleQueue
>();
sampleQueues
=
new
SparseArray
<
DefaultTrackOutput
>();
extractor
.
init
(
this
);
}
...
...
@@ -76,8 +76,8 @@ public final class HlsExtractorWrapper implements Extractor.TrackOutputBuilder {
boolean
spliceConfigured
=
true
;
int
trackCount
=
getTrackCount
();
for
(
int
i
=
0
;
i
<
trackCount
;
i
++)
{
SampleQueue
currentSampleQueue
=
sampleQueues
.
valueAt
(
i
);
SampleQueue
nextSampleQueue
=
nextExtractor
.
sampleQueues
.
valueAt
(
i
);
DefaultTrackOutput
currentSampleQueue
=
sampleQueues
.
valueAt
(
i
);
DefaultTrackOutput
nextSampleQueue
=
nextExtractor
.
sampleQueues
.
valueAt
(
i
);
spliceConfigured
&=
currentSampleQueue
.
configureSpliceTo
(
nextSampleQueue
);
}
this
.
spliceConfigured
=
spliceConfigured
;
...
...
@@ -113,7 +113,7 @@ public final class HlsExtractorWrapper implements Extractor.TrackOutputBuilder {
* @return True if the extractor is prepared. False otherwise.
*/
public
boolean
isPrepared
()
{
if
(!
prepared
&&
output
sBuilt
)
{
if
(!
prepared
&&
track
sBuilt
)
{
for
(
int
i
=
0
;
i
<
sampleQueues
.
size
();
i
++)
{
if
(!
sampleQueues
.
valueAt
(
i
).
hasFormat
())
{
return
false
;
...
...
@@ -188,25 +188,27 @@ public final class HlsExtractorWrapper implements Extractor.TrackOutputBuilder {
* Reads from the provided {@link ExtractorInput}.
*
* @param input The {@link ExtractorInput} from which to read.
* @return One of {@link Extractor#RESULT_CONTINUE} and {@link Extractor#RESULT_END_OF_INPUT}.
* @throws IOException If an error occurred reading from the source.
* @throws InterruptedException If the thread was interrupted.
*/
public
void
read
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
extractor
.
read
(
input
);
public
int
read
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
int
result
=
extractor
.
read
(
input
);
return
result
;
}
// ExtractorOutput implementation.
@Override
public
TrackOutput
buildOutput
(
int
id
)
{
SampleQueue
sampleQueue
=
new
SampleQueue
(
bufferPool
);
public
TrackOutput
track
(
int
id
)
{
DefaultTrackOutput
sampleQueue
=
new
DefaultTrackOutput
(
bufferPool
);
sampleQueues
.
put
(
id
,
sampleQueue
);
return
sampleQueue
;
}
@Override
public
void
allOutputsBuilt
()
{
this
.
output
sBuilt
=
true
;
public
void
endTracks
()
{
this
.
track
sBuilt
=
true
;
}
}
library/src/main/java/com/google/android/exoplayer/hls/TsChunk.java
View file @
37d12ff1
...
...
@@ -15,8 +15,9 @@
*/
package
com
.
google
.
android
.
exoplayer
.
hls
;
import
com.google.android.exoplayer.extractor.Extractor.ExtractorInput
;
import
com.google.android.exoplayer.extractor.ts.DataSourceExtractorInput
;
import
com.google.android.exoplayer.extractor.DefaultExtractorInput
;
import
com.google.android.exoplayer.extractor.Extractor
;
import
com.google.android.exoplayer.extractor.ExtractorInput
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
com.google.android.exoplayer.upstream.DataSpec
;
...
...
@@ -101,9 +102,9 @@ public final class TsChunk extends HlsChunk {
@Override
public
void
load
()
throws
IOException
,
InterruptedException
{
ExtractorInput
input
=
new
DataSourceExtractorInput
(
dataSource
,
0
)
;
ExtractorInput
input
;
try
{
dataSource
.
open
(
dataSpec
);
input
=
new
DefaultExtractorInput
(
dataSource
,
0
,
dataSource
.
open
(
dataSpec
)
);
// If we previously fed part of this chunk to the extractor, skip it this time.
// TODO: Ideally we'd construct a dataSpec that only loads the remainder of the data here,
// rather than loading the whole chunk again and then skipping data we previously loaded. To
...
...
@@ -111,12 +112,12 @@ public final class TsChunk extends HlsChunk {
// encrypted with AES, for which we'll need to modify the way that decryption is performed.
input
.
skipFully
(
loadPosition
);
try
{
while
(!
input
.
isEnded
()
&&
!
loadCanceled
)
{
extractor
.
read
(
input
);
int
result
=
Extractor
.
RESULT_CONTINUE
;
while
(
result
==
Extractor
.
RESULT_CONTINUE
&&
!
loadCanceled
)
{
result
=
extractor
.
read
(
input
);
}
}
finally
{
loadPosition
=
(
int
)
input
.
getPosition
();
loadFinished
=
!
loadCanceled
;
}
}
finally
{
dataSource
.
close
();
...
...
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