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
989bbef2
authored
Oct 09, 2014
by
ojw28
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #74 from google/dev
Merge dev -> dev-l
parents
be721943
75943104
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
198 additions
and
143 deletions
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DebugTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/DefaultLoadControl.java
library/src/main/java/com/google/android/exoplayer/DummyTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java
library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java
library/src/main/java/com/google/android/exoplayer/LoadControl.java
library/src/main/java/com/google/android/exoplayer/MediaClock.java
library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/ParserException.java
library/src/main/java/com/google/android/exoplayer/SampleSource.java
library/src/main/java/com/google/android/exoplayer/TrackRenderer.java
library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java
library/src/main/java/com/google/android/exoplayer/text/TextTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/text/ttml/TtmlParser.java
demo/src/main/java/com/google/android/exoplayer/demo/full/player/DebugTrackRenderer.java
View file @
989bbef2
...
...
@@ -68,10 +68,10 @@ import android.widget.TextView;
}
@Override
protected
void
doSomeWork
(
long
timeUs
)
throws
ExoPlaybackException
{
protected
void
doSomeWork
(
long
positionUs
,
long
elapsedReal
timeUs
)
throws
ExoPlaybackException
{
maybeFail
();
if
(
timeUs
<
currentPositionUs
||
time
Us
>
currentPositionUs
+
1000000
)
{
currentPositionUs
=
time
Us
;
if
(
positionUs
<
currentPositionUs
||
position
Us
>
currentPositionUs
+
1000000
)
{
currentPositionUs
=
position
Us
;
textView
.
post
(
this
);
}
}
...
...
library/src/main/java/com/google/android/exoplayer/DefaultLoadControl.java
View file @
989bbef2
...
...
@@ -166,9 +166,9 @@ public class DefaultLoadControl implements LoadControl {
// Update the loader state.
int
loaderBufferState
=
getLoaderBufferState
(
playbackPositionUs
,
nextLoadPositionUs
);
LoaderState
loaderState
=
loaderStates
.
get
(
loader
);
boolean
loaderStateChanged
=
loaderState
.
bufferState
!=
loaderBufferState
||
loaderState
.
nextLoadPositionUs
!=
nextLoadPositionUs
||
loaderState
.
loading
!=
loading
||
loaderState
.
failed
!=
failed
;
boolean
loaderStateChanged
=
loaderState
.
bufferState
!=
loaderBufferState
||
loaderState
.
nextLoadPositionUs
!=
nextLoadPositionUs
||
loaderState
.
loading
!=
loading
||
loaderState
.
failed
!=
failed
;
if
(
loaderStateChanged
)
{
loaderState
.
bufferState
=
loaderBufferState
;
loaderState
.
nextLoadPositionUs
=
nextLoadPositionUs
;
...
...
@@ -214,17 +214,17 @@ public class DefaultLoadControl implements LoadControl {
private
void
updateControlState
()
{
boolean
loading
=
false
;
boolean
failed
=
false
;
boolean
finished
=
tru
e
;
boolean
haveNextLoadPosition
=
fals
e
;
int
highestState
=
bufferPoolState
;
for
(
int
i
=
0
;
i
<
loaders
.
size
();
i
++)
{
LoaderState
loaderState
=
loaderStates
.
get
(
loaders
.
get
(
i
));
loading
|=
loaderState
.
loading
;
failed
|=
loaderState
.
failed
;
finished
&=
loaderState
.
nextLoadPositionUs
=
=
-
1
;
haveNextLoadPosition
|=
loaderState
.
nextLoadPositionUs
!
=
-
1
;
highestState
=
Math
.
max
(
highestState
,
loaderState
.
bufferState
);
}
fillingBuffers
=
!
loaders
.
isEmpty
()
&&
!
f
inished
&&
!
failed
fillingBuffers
=
!
loaders
.
isEmpty
()
&&
!
f
ailed
&&
(
loading
||
haveNextLoadPosition
)
&&
(
highestState
==
BELOW_LOW_WATERMARK
||
(
highestState
==
BETWEEN_WATERMARKS
&&
fillingBuffers
));
if
(
fillingBuffers
&&
!
streamingPrioritySet
)
{
...
...
library/src/main/java/com/google/android/exoplayer/DummyTrackRenderer.java
View file @
989bbef2
...
...
@@ -40,12 +40,12 @@ public class DummyTrackRenderer extends TrackRenderer {
}
@Override
protected
void
seekTo
(
long
time
Us
)
{
protected
void
seekTo
(
long
position
Us
)
{
throw
new
IllegalStateException
();
}
@Override
protected
void
doSomeWork
(
long
timeUs
)
{
protected
void
doSomeWork
(
long
positionUs
,
long
elapsedReal
timeUs
)
{
throw
new
IllegalStateException
();
}
...
...
library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java
View file @
989bbef2
...
...
@@ -77,6 +77,7 @@ import java.util.List;
private
int
state
;
private
int
customMessagesSent
=
0
;
private
int
customMessagesProcessed
=
0
;
private
long
elapsedRealtimeUs
;
private
volatile
long
durationUs
;
private
volatile
long
positionUs
;
...
...
@@ -383,7 +384,8 @@ import java.util.List;
positionUs
=
timeSourceTrackRenderer
!=
null
&&
enabledRenderers
.
contains
(
timeSourceTrackRenderer
)
?
timeSourceTrackRenderer
.
getCurrentPositionUs
()
:
mediaClock
.
getTimeUs
();
mediaClock
.
getPositionUs
();
elapsedRealtimeUs
=
SystemClock
.
elapsedRealtime
()
*
1000
;
}
private
void
doSomeWork
()
throws
ExoPlaybackException
{
...
...
@@ -399,7 +401,7 @@ import java.util.List;
// TODO: Each renderer should return the maximum delay before which it wishes to be
// invoked again. The minimum of these values should then be used as the delay before the next
// invocation of this method.
renderer
.
doSomeWork
(
positionUs
);
renderer
.
doSomeWork
(
positionUs
,
elapsedRealtimeUs
);
isEnded
=
isEnded
&&
renderer
.
isEnded
();
allRenderersReadyOrEnded
=
allRenderersReadyOrEnded
&&
rendererReadyOrEnded
(
renderer
);
...
...
@@ -462,7 +464,7 @@ import java.util.List;
rebuffering
=
false
;
positionUs
=
positionMs
*
1000L
;
mediaClock
.
stop
();
mediaClock
.
set
Time
Us
(
positionUs
);
mediaClock
.
set
Position
Us
(
positionUs
);
if
(
state
==
ExoPlayer
.
STATE_IDLE
||
state
==
ExoPlayer
.
STATE_PREPARING
)
{
return
;
}
...
...
@@ -582,7 +584,7 @@ import java.util.List;
if
(
renderer
==
timeSourceTrackRenderer
)
{
// We've been using timeSourceTrackRenderer to advance the current position, but it's
// being disabled. Sync mediaClock so that it can take over timing responsibilities.
mediaClock
.
set
Time
Us
(
renderer
.
getCurrentPositionUs
());
mediaClock
.
set
Position
Us
(
renderer
.
getCurrentPositionUs
());
}
ensureStopped
(
renderer
);
enabledRenderers
.
remove
(
renderer
);
...
...
library/src/main/java/com/google/android/exoplayer/FrameworkSampleSource.java
View file @
989bbef2
...
...
@@ -50,7 +50,7 @@ public final class FrameworkSampleSource implements SampleSource {
private
int
[]
trackStates
;
private
boolean
[]
pendingDiscontinuities
;
private
long
seek
Time
Us
;
private
long
seek
Position
Us
;
public
FrameworkSampleSource
(
Context
context
,
Uri
uri
,
Map
<
String
,
String
>
headers
,
int
downstreamRendererCount
)
{
...
...
@@ -94,16 +94,16 @@ public final class FrameworkSampleSource implements SampleSource {
}
@Override
public
void
enable
(
int
track
,
long
time
Us
)
{
public
void
enable
(
int
track
,
long
position
Us
)
{
Assertions
.
checkState
(
prepared
);
Assertions
.
checkState
(
trackStates
[
track
]
==
TRACK_STATE_DISABLED
);
trackStates
[
track
]
=
TRACK_STATE_ENABLED
;
extractor
.
selectTrack
(
track
);
seekToUs
(
time
Us
);
seekToUs
(
position
Us
);
}
@Override
public
boolean
continueBuffering
(
long
p
laybackP
ositionUs
)
{
public
boolean
continueBuffering
(
long
positionUs
)
{
// MediaExtractor takes care of buffering and blocks until it has samples, so we can always
// return true here. Although note that the blocking behavior is itself as bug, as per the
// TODO further up this file. This method will need to return something else as part of fixing
...
...
@@ -112,7 +112,7 @@ public final class FrameworkSampleSource implements SampleSource {
}
@Override
public
int
readData
(
int
track
,
long
p
laybackP
ositionUs
,
MediaFormatHolder
formatHolder
,
public
int
readData
(
int
track
,
long
positionUs
,
MediaFormatHolder
formatHolder
,
SampleHolder
sampleHolder
,
boolean
onlyReadDiscontinuity
)
{
Assertions
.
checkState
(
prepared
);
Assertions
.
checkState
(
trackStates
[
track
]
!=
TRACK_STATE_DISABLED
);
...
...
@@ -144,7 +144,7 @@ public final class FrameworkSampleSource implements SampleSource {
if
((
sampleHolder
.
flags
&
MediaExtractor
.
SAMPLE_FLAG_ENCRYPTED
)
!=
0
)
{
sampleHolder
.
cryptoInfo
.
setFromExtractorV16
(
extractor
);
}
seek
Time
Us
=
-
1
;
seek
Position
Us
=
-
1
;
extractor
.
advance
();
return
SAMPLE_READ
;
}
else
{
...
...
@@ -168,13 +168,13 @@ public final class FrameworkSampleSource implements SampleSource {
}
@Override
public
void
seekToUs
(
long
time
Us
)
{
public
void
seekToUs
(
long
position
Us
)
{
Assertions
.
checkState
(
prepared
);
if
(
seek
TimeUs
!=
time
Us
)
{
if
(
seek
PositionUs
!=
position
Us
)
{
// Avoid duplicate calls to the underlying extractor's seek method in the case that there
// have been no interleaving calls to advance.
seek
TimeUs
=
time
Us
;
extractor
.
seekTo
(
time
Us
,
MediaExtractor
.
SEEK_TO_PREVIOUS_SYNC
);
seek
PositionUs
=
position
Us
;
extractor
.
seekTo
(
position
Us
,
MediaExtractor
.
SEEK_TO_PREVIOUS_SYNC
);
for
(
int
i
=
0
;
i
<
trackStates
.
length
;
++
i
)
{
if
(
trackStates
[
i
]
!=
TRACK_STATE_DISABLED
)
{
pendingDiscontinuities
[
i
]
=
true
;
...
...
library/src/main/java/com/google/android/exoplayer/LoadControl.java
View file @
989bbef2
...
...
@@ -65,9 +65,10 @@ public interface LoadControl {
*
* @param loader The loader invoking the update.
* @param playbackPositionUs The loader's playback position.
* @param nextLoadPositionUs The loader's next load position, or -1 if finished.
* @param nextLoadPositionUs The loader's next load position. -1 if finished, failed, or if the
* next load position is not yet known.
* @param loading Whether the loader is currently loading data.
* @param failed Whether the loader has failed
, meaning it does not wish to load more data
.
* @param failed Whether the loader has failed.
* @return True if the loader is allowed to start its next load. False otherwise.
*/
boolean
update
(
Object
loader
,
long
playbackPositionUs
,
long
nextLoadPositionUs
,
...
...
library/src/main/java/com/google/android/exoplayer/MediaClock.java
View file @
989bbef2
...
...
@@ -29,10 +29,10 @@ import android.os.SystemClock;
/**
* The media time when the clock was last set or stopped.
*/
private
long
time
Us
;
private
long
position
Us
;
/**
* The difference between {@link SystemClock#elapsedRealtime()} and {@link #
time
Us}
* The difference between {@link SystemClock#elapsedRealtime()} and {@link #
position
Us}
* when the clock was last set or started.
*/
private
long
deltaUs
;
...
...
@@ -43,7 +43,7 @@ import android.os.SystemClock;
public
void
start
()
{
if
(!
started
)
{
started
=
true
;
deltaUs
=
elapsedRealtimeMinus
(
time
Us
);
deltaUs
=
elapsedRealtimeMinus
(
position
Us
);
}
}
...
...
@@ -52,28 +52,28 @@ import android.os.SystemClock;
*/
public
void
stop
()
{
if
(
started
)
{
time
Us
=
elapsedRealtimeMinus
(
deltaUs
);
position
Us
=
elapsedRealtimeMinus
(
deltaUs
);
started
=
false
;
}
}
/**
* @param timeUs The
time
to set in microseconds.
* @param timeUs The
position
to set in microseconds.
*/
public
void
set
Time
Us
(
long
timeUs
)
{
this
.
time
Us
=
timeUs
;
public
void
set
Position
Us
(
long
timeUs
)
{
this
.
position
Us
=
timeUs
;
deltaUs
=
elapsedRealtimeMinus
(
timeUs
);
}
/**
* @return The current
time
in microseconds.
* @return The current
position
in microseconds.
*/
public
long
get
Time
Us
()
{
return
started
?
elapsedRealtimeMinus
(
deltaUs
)
:
time
Us
;
public
long
get
Position
Us
()
{
return
started
?
elapsedRealtimeMinus
(
deltaUs
)
:
position
Us
;
}
private
long
elapsedRealtimeMinus
(
long
microSecond
s
)
{
return
SystemClock
.
elapsedRealtime
()
*
1000
-
microSecond
s
;
private
long
elapsedRealtimeMinus
(
long
toSubtractU
s
)
{
return
SystemClock
.
elapsedRealtime
()
*
1000
-
toSubtractU
s
;
}
}
library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java
View file @
989bbef2
...
...
@@ -94,10 +94,18 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
/**
* AudioTrack timestamps are deemed spurious if they are offset from the system clock by more
* than this amount. This is a fail safe that should not be required on correctly functioning
* devices.
* than this amount.
* <p>
* This is a fail safe that should not be required on correctly functioning devices.
*/
private
static
final
long
MAX_AUDIO_TIMESTAMP_OFFSET_US
=
10
*
MICROS_PER_SECOND
;
/**
* AudioTrack latencies are deemed impossibly large if they are greater than this amount.
* <p>
* This is a fail safe that should not be required on correctly functioning devices.
*/
private
static
final
long
MAX_AUDIO_T
IMSTAMP_OFFSET
_US
=
10
*
MICROS_PER_SECOND
;
private
static
final
long
MAX_AUDIO_T
RACK_LATENCY
_US
=
10
*
MICROS_PER_SECOND
;
private
static
final
int
MAX_PLAYHEAD_OFFSET_COUNT
=
10
;
private
static
final
int
MIN_PLAYHEAD_OFFSET_SAMPLE_INTERVAL_US
=
30000
;
...
...
@@ -261,14 +269,14 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
protected
void
onEnabled
(
long
time
Us
,
boolean
joining
)
{
super
.
onEnabled
(
time
Us
,
joining
);
protected
void
onEnabled
(
long
position
Us
,
boolean
joining
)
{
super
.
onEnabled
(
position
Us
,
joining
);
lastReportedCurrentPositionUs
=
Long
.
MIN_VALUE
;
}
@Override
protected
void
doSomeWork
(
long
timeUs
)
throws
ExoPlaybackException
{
super
.
doSomeWork
(
timeUs
);
protected
void
doSomeWork
(
long
positionUs
,
long
elapsedReal
timeUs
)
throws
ExoPlaybackException
{
super
.
doSomeWork
(
positionUs
,
elapsedReal
timeUs
);
maybeSampleSyncParams
();
}
...
...
@@ -515,7 +523,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
if
(
audioTimestampUs
<
audioTrackResumeSystemTimeUs
)
{
// The timestamp corresponds to a time before the track was most recently resumed.
audioTimestampSet
=
false
;
}
else
if
(
Math
.
abs
(
audioTimestampUs
-
systemClockUs
)
>
MAX_AUDIO_TIMSTAMP_OFFSET_US
)
{
}
else
if
(
Math
.
abs
(
audioTimestampUs
-
systemClockUs
)
>
MAX_AUDIO_TIM
E
STAMP_OFFSET_US
)
{
// The timestamp time base is probably wrong.
audioTimestampSet
=
false
;
Log
.
w
(
TAG
,
"Spurious audio timestamp: "
+
audioTimestampCompat
.
getFramePosition
()
+
", "
...
...
@@ -531,6 +539,11 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
framesToDurationUs
(
bufferSize
/
frameSize
);
// Sanity check that the latency is non-negative.
audioTrackLatencyUs
=
Math
.
max
(
audioTrackLatencyUs
,
0
);
// Sanity check that the latency isn't too large.
if
(
audioTrackLatencyUs
>
MAX_AUDIO_TRACK_LATENCY_US
)
{
Log
.
w
(
TAG
,
"Ignoring impossibly large audio latency: "
+
audioTrackLatencyUs
);
audioTrackLatencyUs
=
0
;
}
}
catch
(
Exception
e
)
{
// The method existed, but doesn't work. Don't try again.
audioTrackGetLatencyMethod
=
null
;
...
...
@@ -569,16 +582,16 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
protected
void
seekTo
(
long
time
Us
)
throws
ExoPlaybackException
{
super
.
seekTo
(
time
Us
);
protected
void
seekTo
(
long
position
Us
)
throws
ExoPlaybackException
{
super
.
seekTo
(
position
Us
);
// TODO: Try and re-use the same AudioTrack instance once [redacted] is fixed.
releaseAudioTrack
();
lastReportedCurrentPositionUs
=
Long
.
MIN_VALUE
;
}
@Override
protected
boolean
processOutputBuffer
(
long
timeUs
,
MediaCodec
codec
,
ByteBuffer
buffer
,
MediaCodec
.
BufferInfo
bufferInfo
,
int
bufferIndex
,
boolean
shouldSkip
)
protected
boolean
processOutputBuffer
(
long
positionUs
,
long
elapsedRealtimeUs
,
MediaCodec
codec
,
ByteBuffer
buffer
,
MediaCodec
.
BufferInfo
bufferInfo
,
int
bufferIndex
,
boolean
shouldSkip
)
throws
ExoPlaybackException
{
if
(
shouldSkip
)
{
codec
.
releaseOutputBuffer
(
bufferIndex
,
false
);
...
...
@@ -613,6 +626,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer {
// time and the number of bytes submitted. Also reset lastReportedCurrentPositionUs to
// allow time to jump backwards if it really wants to.
audioTrackStartMediaTimeUs
+=
(
bufferStartTime
-
expectedBufferStartTime
);
audioTrackStartMediaTimeState
=
START_IN_SYNC
;
lastReportedCurrentPositionUs
=
Long
.
MIN_VALUE
;
}
}
...
...
library/src/main/java/com/google/android/exoplayer/MediaCodecTrackRenderer.java
View file @
989bbef2
...
...
@@ -217,13 +217,13 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
@Override
protected
void
onEnabled
(
long
time
Us
,
boolean
joining
)
{
source
.
enable
(
trackIndex
,
time
Us
);
protected
void
onEnabled
(
long
position
Us
,
boolean
joining
)
{
source
.
enable
(
trackIndex
,
position
Us
);
sourceState
=
SOURCE_STATE_NOT_READY
;
inputStreamEnded
=
false
;
outputStreamEnded
=
false
;
waitingForKeys
=
false
;
currentPositionUs
=
time
Us
;
currentPositionUs
=
position
Us
;
}
/**
...
...
@@ -367,9 +367,9 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
@Override
protected
void
seekTo
(
long
time
Us
)
throws
ExoPlaybackException
{
currentPositionUs
=
time
Us
;
source
.
seekToUs
(
time
Us
);
protected
void
seekTo
(
long
position
Us
)
throws
ExoPlaybackException
{
currentPositionUs
=
position
Us
;
source
.
seekToUs
(
position
Us
);
sourceState
=
SOURCE_STATE_NOT_READY
;
inputStreamEnded
=
false
;
outputStreamEnded
=
false
;
...
...
@@ -387,22 +387,22 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
@Override
protected
void
doSomeWork
(
long
timeUs
)
throws
ExoPlaybackException
{
protected
void
doSomeWork
(
long
positionUs
,
long
elapsedReal
timeUs
)
throws
ExoPlaybackException
{
try
{
sourceState
=
source
.
continueBuffering
(
time
Us
)
sourceState
=
source
.
continueBuffering
(
position
Us
)
?
(
sourceState
==
SOURCE_STATE_NOT_READY
?
SOURCE_STATE_READY
:
sourceState
)
:
SOURCE_STATE_NOT_READY
;
checkForDiscontinuity
();
if
(
format
==
null
)
{
readFormat
();
}
else
if
(
codec
==
null
&&
!
shouldInitCodec
()
&&
getState
()
==
TrackRenderer
.
STATE_STARTED
)
{
discardSamples
(
time
Us
);
discardSamples
(
position
Us
);
}
else
{
if
(
codec
==
null
&&
shouldInitCodec
())
{
maybeInitCodec
();
}
if
(
codec
!=
null
)
{
while
(
drainOutputBuffer
(
timeUs
))
{}
while
(
drainOutputBuffer
(
positionUs
,
elapsedReal
timeUs
))
{}
if
(
feedInputBuffer
(
true
))
{
while
(
feedInputBuffer
(
false
))
{}
}
...
...
@@ -421,10 +421,10 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
}
private
void
discardSamples
(
long
time
Us
)
throws
IOException
,
ExoPlaybackException
{
private
void
discardSamples
(
long
position
Us
)
throws
IOException
,
ExoPlaybackException
{
sampleHolder
.
data
=
null
;
int
result
=
SampleSource
.
SAMPLE_READ
;
while
(
result
==
SampleSource
.
SAMPLE_READ
&&
currentPositionUs
<=
time
Us
)
{
while
(
result
==
SampleSource
.
SAMPLE_READ
&&
currentPositionUs
<=
position
Us
)
{
result
=
source
.
readData
(
trackIndex
,
currentPositionUs
,
formatHolder
,
sampleHolder
,
false
);
if
(
result
==
SampleSource
.
SAMPLE_READ
)
{
if
(!
sampleHolder
.
decodeOnly
)
{
...
...
@@ -469,7 +469,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
/**
* @param firstFeed True if this is the first call to this method from the current invocation of
* {@link #doSomeWork(long)}. False otherwise.
* {@link #doSomeWork(long
, long
)}. False otherwise.
* @return True if it may be possible to feed more input data. False otherwise.
* @throws IOException If an error occurs reading data from the upstream source.
* @throws ExoPlaybackException If an error occurs feeding the input buffer.
...
...
@@ -694,7 +694,8 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
* @return True if it may be possible to drain more output data. False otherwise.
* @throws ExoPlaybackException If an error occurs draining the output buffer.
*/
private
boolean
drainOutputBuffer
(
long
timeUs
)
throws
ExoPlaybackException
{
private
boolean
drainOutputBuffer
(
long
positionUs
,
long
elapsedRealtimeUs
)
throws
ExoPlaybackException
{
if
(
outputStreamEnded
)
{
return
false
;
}
...
...
@@ -722,8 +723,8 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
boolean
decodeOnly
=
decodeOnlyPresentationTimestamps
.
contains
(
outputBufferInfo
.
presentationTimeUs
);
if
(
processOutputBuffer
(
timeUs
,
codec
,
outputBuffers
[
outputIndex
],
outputBufferInfo
,
outputIndex
,
decodeOnly
))
{
if
(
processOutputBuffer
(
positionUs
,
elapsedRealtimeUs
,
codec
,
outputBuffers
[
outputIndex
]
,
output
BufferInfo
,
output
Index
,
decodeOnly
))
{
if
(
decodeOnly
)
{
decodeOnlyPresentationTimestamps
.
remove
(
outputBufferInfo
.
presentationTimeUs
);
}
else
{
...
...
@@ -743,9 +744,9 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
* longer required. False otherwise.
* @throws ExoPlaybackException If an error occurs processing the output buffer.
*/
protected
abstract
boolean
processOutputBuffer
(
long
timeUs
,
MediaCodec
codec
,
ByteBuffer
buffer
,
MediaCodec
.
BufferInfo
bufferInfo
,
int
bufferIndex
,
boolean
shouldSkip
)
throws
ExoPlaybackException
;
protected
abstract
boolean
processOutputBuffer
(
long
positionUs
,
long
elapsedRealtimeUs
,
MediaCodec
codec
,
ByteBuffer
buffer
,
MediaCodec
.
BufferInfo
bufferInfo
,
int
bufferIndex
,
boolean
shouldSkip
)
throws
ExoPlaybackException
;
/**
* Returns the name of the secure variant of a given decoder.
...
...
library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java
View file @
989bbef2
...
...
@@ -226,8 +226,8 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
protected
void
onEnabled
(
long
startTime
Us
,
boolean
joining
)
{
super
.
onEnabled
(
startTime
Us
,
joining
);
protected
void
onEnabled
(
long
position
Us
,
boolean
joining
)
{
super
.
onEnabled
(
position
Us
,
joining
);
renderedFirstFrame
=
false
;
if
(
joining
&&
allowedJoiningTimeUs
>
0
)
{
joiningDeadlineUs
=
SystemClock
.
elapsedRealtime
()
*
1000L
+
allowedJoiningTimeUs
;
...
...
@@ -235,8 +235,8 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
protected
void
seekTo
(
long
time
Us
)
throws
ExoPlaybackException
{
super
.
seekTo
(
time
Us
);
protected
void
seekTo
(
long
position
Us
)
throws
ExoPlaybackException
{
super
.
seekTo
(
position
Us
);
renderedFirstFrame
=
false
;
joiningDeadlineUs
=
-
1
;
}
...
...
@@ -355,14 +355,15 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
protected
boolean
processOutputBuffer
(
long
timeUs
,
MediaCodec
codec
,
ByteBuffer
buffer
,
MediaCodec
.
BufferInfo
bufferInfo
,
int
bufferIndex
,
boolean
shouldSkip
)
{
protected
boolean
processOutputBuffer
(
long
positionUs
,
long
elapsedRealtimeUs
,
MediaCodec
codec
,
ByteBuffer
buffer
,
MediaCodec
.
BufferInfo
bufferInfo
,
int
bufferIndex
,
boolean
shouldSkip
)
{
if
(
shouldSkip
)
{
skipOutputBuffer
(
codec
,
bufferIndex
);
return
true
;
}
long
earlyUs
=
bufferInfo
.
presentationTimeUs
-
timeUs
;
long
elapsedSinceStartOfLoop
=
SystemClock
.
elapsedRealtime
()
*
1000
-
elapsedRealtimeUs
;
long
earlyUs
=
bufferInfo
.
presentationTimeUs
-
positionUs
-
elapsedSinceStartOfLoop
;
if
(
earlyUs
<
-
30000
)
{
// We're more than 30ms late rendering the frame.
dropOutputBuffer
(
codec
,
bufferIndex
);
...
...
library/src/main/java/com/google/android/exoplayer/ParserException.java
View file @
989bbef2
...
...
@@ -26,8 +26,12 @@ public class ParserException extends IOException {
super
(
message
);
}
public
ParserException
(
Exception
cause
)
{
public
ParserException
(
Throwable
cause
)
{
super
(
cause
);
}
public
ParserException
(
String
message
,
Throwable
cause
)
{
super
(
message
,
cause
);
}
}
library/src/main/java/com/google/android/exoplayer/SampleSource.java
View file @
989bbef2
...
...
@@ -85,9 +85,9 @@ public interface SampleSource {
* This method should not be called until after the source has been successfully prepared.
*
* @param track The track to enable.
* @param
time
Us The player's current playback position.
* @param
position
Us The player's current playback position.
*/
public
void
enable
(
int
track
,
long
time
Us
);
public
void
enable
(
int
track
,
long
position
Us
);
/**
* Disable the specified track.
...
...
@@ -101,12 +101,12 @@ public interface SampleSource {
/**
* Indicates to the source that it should still be buffering data.
*
* @param p
laybackP
ositionUs The current playback position.
* @param positionUs The current playback position.
* @return True if the source has available samples, or if the end of the stream has been reached.
* False if more data needs to be buffered for samples to become available.
* @throws IOException If an error occurred reading from the source.
*/
public
boolean
continueBuffering
(
long
p
laybackP
ositionUs
)
throws
IOException
;
public
boolean
continueBuffering
(
long
positionUs
)
throws
IOException
;
/**
* Attempts to read either a sample, a new format or or a discontinuity from the source.
...
...
@@ -118,7 +118,7 @@ public interface SampleSource {
* than the one for which data was requested.
*
* @param track The track from which to read.
* @param p
laybackP
ositionUs The current playback position.
* @param positionUs The current playback position.
* @param formatHolder A {@link MediaFormatHolder} object to populate in the case of a new format.
* @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample. If
* the caller requires the sample data then it must ensure that {@link SampleHolder#data}
...
...
@@ -129,7 +129,7 @@ public interface SampleSource {
* {@link #DISCONTINUITY_READ}, {@link #NOTHING_READ} or {@link #END_OF_STREAM}.
* @throws IOException If an error occurred reading from the source.
*/
public
int
readData
(
int
track
,
long
p
laybackP
ositionUs
,
MediaFormatHolder
formatHolder
,
public
int
readData
(
int
track
,
long
positionUs
,
MediaFormatHolder
formatHolder
,
SampleHolder
sampleHolder
,
boolean
onlyReadDiscontinuity
)
throws
IOException
;
/**
...
...
@@ -137,16 +137,16 @@ public interface SampleSource {
* <p>
* This method should not be called until after the source has been successfully prepared.
*
* @param
time
Us The seek position in microseconds.
* @param
position
Us The seek position in microseconds.
*/
public
void
seekToUs
(
long
time
Us
);
public
void
seekToUs
(
long
position
Us
);
/**
* Returns an estimate of the position up to which data is buffered.
* <p>
* This method should not be called until after the source has been successfully prepared.
*
* @return An estimate of the absolute position in micro
-
seconds up to which data is buffered,
* @return An estimate of the absolute position in microseconds up to which data is buffered,
* or {@link TrackRenderer#END_OF_TRACK_US} if data is buffered to the end of the stream, or
* {@link TrackRenderer#UNKNOWN_TIME_US} if no estimate is available.
*/
...
...
library/src/main/java/com/google/android/exoplayer/TrackRenderer.java
View file @
989bbef2
...
...
@@ -18,6 +18,8 @@ package com.google.android.exoplayer;
import
com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent
;
import
com.google.android.exoplayer.util.Assertions
;
import
android.os.SystemClock
;
/**
* Renders a single component of media.
*
...
...
@@ -59,7 +61,7 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
*/
protected
static
final
int
STATE_ENABLED
=
2
;
/**
* The renderer is started. Calls to {@link #doSomeWork(long)} should cause the media to be
* The renderer is started. Calls to {@link #doSomeWork(long
, long
)} should cause the media to be
* rendered.
*/
protected
static
final
int
STATE_STARTED
=
3
;
...
...
@@ -83,9 +85,9 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
/**
* A time source renderer is a renderer that, when started, advances its own playback position.
* This means that {@link #getCurrentPositionUs()} will return increasing positions independently
* to increasing values being passed to {@link #doSomeWork(long
)}. A player may have at most one
*
time source renderer. If provided, the player will use such a renderer as its source of time
* during playback.
* to increasing values being passed to {@link #doSomeWork(long
, long)}. A player may have at most
*
one time source renderer. If provided, the player will use such a renderer as its source of
*
time
during playback.
* <p>
* This method may be called when the renderer is in any state.
*
...
...
@@ -136,15 +138,15 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
/**
* Enable the renderer.
*
* @param
time
Us The player's current position.
* @param
position
Us The player's current position.
* @param joining Whether this renderer is being enabled to join an ongoing playback. If true
* then {@link #start} must be called immediately after this method returns (unless a
* {@link ExoPlaybackException} is thrown).
*/
/* package */
final
void
enable
(
long
time
Us
,
boolean
joining
)
throws
ExoPlaybackException
{
/* package */
final
void
enable
(
long
position
Us
,
boolean
joining
)
throws
ExoPlaybackException
{
Assertions
.
checkState
(
state
==
TrackRenderer
.
STATE_PREPARED
);
state
=
TrackRenderer
.
STATE_ENABLED
;
onEnabled
(
time
Us
,
joining
);
onEnabled
(
position
Us
,
joining
);
}
/**
...
...
@@ -152,18 +154,18 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
* <p>
* The default implementation is a no-op.
*
* @param
time
Us The player's current position.
* @param
position
Us The player's current position.
* @param joining Whether this renderer is being enabled to join an ongoing playback. If true
* then {@link #onStarted} is guaranteed to be called immediately after this method returns
* (unless a {@link ExoPlaybackException} is thrown).
* @throws ExoPlaybackException If an error occurs.
*/
protected
void
onEnabled
(
long
time
Us
,
boolean
joining
)
throws
ExoPlaybackException
{
protected
void
onEnabled
(
long
position
Us
,
boolean
joining
)
throws
ExoPlaybackException
{
// Do nothing.
}
/**
* Starts the renderer, meaning that calls to {@link #doSomeWork(long)} will cause the
* Starts the renderer, meaning that calls to {@link #doSomeWork(long
, long
)} will cause the
* track to be rendered.
*/
/* package */
final
void
start
()
throws
ExoPlaybackException
{
...
...
@@ -289,10 +291,14 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
* This method may be called when the renderer is in the following states:
* {@link #STATE_ENABLED}, {@link #STATE_STARTED}
*
* @param timeUs The current playback time.
* @param positionUs The current media time in microseconds, measured at the start of the
* current iteration of the rendering loop.
* @param elapsedRealtimeUs {@link SystemClock#elapsedRealtime()} in microseconds, measured at
* the start of the current iteration of the rendering loop.
* @throws ExoPlaybackException If an error occurs.
*/
protected
abstract
void
doSomeWork
(
long
timeUs
)
throws
ExoPlaybackException
;
protected
abstract
void
doSomeWork
(
long
positionUs
,
long
elapsedRealtimeUs
)
throws
ExoPlaybackException
;
/**
* Returns the duration of the media being rendered.
...
...
@@ -300,7 +306,7 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
* This method may be called when the renderer is in the following states:
* {@link #STATE_PREPARED}, {@link #STATE_ENABLED}, {@link #STATE_STARTED}
*
* @return The duration of the track in micro
-
seconds, or {@link #MATCH_LONGEST_US} if
* @return The duration of the track in microseconds, or {@link #MATCH_LONGEST_US} if
* the track's duration should match that of the longest track whose duration is known, or
* or {@link #UNKNOWN_TIME_US} if the duration is not known.
*/
...
...
@@ -312,17 +318,17 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
* This method may be called when the renderer is in the following states:
* {@link #STATE_ENABLED}, {@link #STATE_STARTED}
*
* @return The current playback position in micro
-
seconds.
* @return The current playback position in microseconds.
*/
protected
abstract
long
getCurrentPositionUs
();
/**
* Returns an estimate of the absolute position in micro
-
seconds up to which data is buffered.
* Returns an estimate of the absolute position in microseconds up to which data is buffered.
* <p>
* This method may be called when the renderer is in the following states:
* {@link #STATE_ENABLED}, {@link #STATE_STARTED}
*
* @return An estimate of the absolute position in micro
-
seconds up to which data is buffered,
* @return An estimate of the absolute position in microseconds up to which data is buffered,
* or {@link #END_OF_TRACK_US} if the track is fully buffered, or {@link #UNKNOWN_TIME_US} if
* no estimate is available.
*/
...
...
@@ -334,10 +340,10 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
* This method may be called when the renderer is in the following states:
* {@link #STATE_ENABLED}
*
* @param
timeUs The desired time in micro-
seconds.
* @param
positionUs The desired playback position in micro
seconds.
* @throws ExoPlaybackException If an error occurs.
*/
protected
abstract
void
seekTo
(
long
time
Us
)
throws
ExoPlaybackException
;
protected
abstract
void
seekTo
(
long
position
Us
)
throws
ExoPlaybackException
;
@Override
public
void
handleMessage
(
int
what
,
Object
object
)
throws
ExoPlaybackException
{
...
...
library/src/main/java/com/google/android/exoplayer/chunk/ChunkSampleSource.java
View file @
989bbef2
This diff is collapsed.
Click to expand it.
library/src/main/java/com/google/android/exoplayer/text/TextTrackRenderer.java
View file @
989bbef2
...
...
@@ -115,43 +115,43 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
}
@Override
protected
void
onEnabled
(
long
time
Us
,
boolean
joining
)
{
source
.
enable
(
trackIndex
,
time
Us
);
protected
void
onEnabled
(
long
position
Us
,
boolean
joining
)
{
source
.
enable
(
trackIndex
,
position
Us
);
parserThread
=
new
HandlerThread
(
"textParser"
);
parserThread
.
start
();
parserHelper
=
new
SubtitleParserHelper
(
parserThread
.
getLooper
(),
subtitleParser
);
seekToInternal
(
time
Us
);
seekToInternal
(
position
Us
);
}
@Override
protected
void
seekTo
(
long
time
Us
)
{
source
.
seekToUs
(
time
Us
);
seekToInternal
(
time
Us
);
protected
void
seekTo
(
long
position
Us
)
{
source
.
seekToUs
(
position
Us
);
seekToInternal
(
position
Us
);
}
private
void
seekToInternal
(
long
time
Us
)
{
private
void
seekToInternal
(
long
position
Us
)
{
inputStreamEnded
=
false
;
currentPositionUs
=
time
Us
;
source
.
seekToUs
(
time
Us
);
if
(
subtitle
!=
null
&&
(
time
Us
<
subtitle
.
getStartTime
()
||
subtitle
.
getLastEventTime
()
<=
time
Us
))
{
currentPositionUs
=
position
Us
;
source
.
seekToUs
(
position
Us
);
if
(
subtitle
!=
null
&&
(
position
Us
<
subtitle
.
getStartTime
()
||
subtitle
.
getLastEventTime
()
<=
position
Us
))
{
subtitle
=
null
;
}
parserHelper
.
flush
();
clearTextRenderer
();
syncNextEventIndex
(
time
Us
);
syncNextEventIndex
(
position
Us
);
textRendererNeedsUpdate
=
subtitle
!=
null
;
}
@Override
protected
void
doSomeWork
(
long
timeUs
)
throws
ExoPlaybackException
{
protected
void
doSomeWork
(
long
positionUs
,
long
elapsedReal
timeUs
)
throws
ExoPlaybackException
{
try
{
source
.
continueBuffering
(
time
Us
);
source
.
continueBuffering
(
position
Us
);
}
catch
(
IOException
e
)
{
throw
new
ExoPlaybackException
(
e
);
}
currentPositionUs
=
time
Us
;
currentPositionUs
=
position
Us
;
if
(
parserHelper
.
isParsing
())
{
return
;
...
...
@@ -169,13 +169,13 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
if
(
subtitle
==
null
&&
dequeuedSubtitle
!=
null
)
{
// We've dequeued a new subtitle. Sync the event index and update the subtitle.
subtitle
=
dequeuedSubtitle
;
syncNextEventIndex
(
time
Us
);
syncNextEventIndex
(
position
Us
);
textRendererNeedsUpdate
=
true
;
}
else
if
(
subtitle
!=
null
)
{
// We're iterating through the events in a subtitle. Set textRendererNeedsUpdate if we
// advance to the next event.
long
nextEventTimeUs
=
getNextEventTime
();
while
(
nextEventTimeUs
<=
time
Us
)
{
while
(
nextEventTimeUs
<=
position
Us
)
{
nextSubtitleEventIndex
++;
nextEventTimeUs
=
getNextEventTime
();
textRendererNeedsUpdate
=
true
;
...
...
@@ -191,7 +191,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
if
(
subtitle
==
null
)
{
try
{
SampleHolder
sampleHolder
=
parserHelper
.
getSampleHolder
();
int
result
=
source
.
readData
(
trackIndex
,
time
Us
,
formatHolder
,
sampleHolder
,
false
);
int
result
=
source
.
readData
(
trackIndex
,
position
Us
,
formatHolder
,
sampleHolder
,
false
);
if
(
result
==
SampleSource
.
SAMPLE_READ
)
{
parserHelper
.
startParseOperation
();
}
else
if
(
result
==
SampleSource
.
END_OF_STREAM
)
{
...
...
@@ -208,7 +208,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
if
(
subtitle
==
null
)
{
clearTextRenderer
();
}
else
{
updateTextRenderer
(
time
Us
);
updateTextRenderer
(
position
Us
);
}
}
}
...
...
@@ -256,8 +256,8 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
return
true
;
}
private
void
syncNextEventIndex
(
long
time
Us
)
{
nextSubtitleEventIndex
=
subtitle
==
null
?
-
1
:
subtitle
.
getNextEventTimeIndex
(
time
Us
);
private
void
syncNextEventIndex
(
long
position
Us
)
{
nextSubtitleEventIndex
=
subtitle
==
null
?
-
1
:
subtitle
.
getNextEventTimeIndex
(
position
Us
);
}
private
long
getNextEventTime
()
{
...
...
@@ -266,8 +266,8 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
:
(
subtitle
.
getEventTime
(
nextSubtitleEventIndex
));
}
private
void
updateTextRenderer
(
long
time
Us
)
{
String
text
=
subtitle
.
getText
(
time
Us
);
private
void
updateTextRenderer
(
long
position
Us
)
{
String
text
=
subtitle
.
getText
(
position
Us
);
log
(
"updateTextRenderer; text=: "
+
text
);
if
(
textRendererHandler
!=
null
)
{
textRendererHandler
.
obtainMessage
(
MSG_UPDATE_OVERLAY
,
text
).
sendToTarget
();
...
...
library/src/main/java/com/google/android/exoplayer/text/ttml/TtmlParser.java
View file @
989bbef2
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
.
text
.
ttml
;
import
com.google.android.exoplayer.ParserException
;
import
com.google.android.exoplayer.text.Subtitle
;
import
com.google.android.exoplayer.text.SubtitleParser
;
import
com.google.android.exoplayer.util.MimeTypes
;
...
...
@@ -72,8 +73,23 @@ public class TtmlParser implements SubtitleParser {
private
static
final
int
DEFAULT_TICKRATE
=
1
;
private
final
XmlPullParserFactory
xmlParserFactory
;
private
final
boolean
strictParsing
;
/**
* Equivalent to {@code TtmlParser(true)}.
*/
public
TtmlParser
()
{
this
(
true
);
}
/**
* @param strictParsing If true, {@link #parse(InputStream, String, long)} will throw a
* {@link ParserException} if the stream contains invalid ttml. If false, the parser will
* make a best effort to ignore minor errors in the stream. Note however that a
* {@link ParserException} will still be thrown when this is not possible.
*/
public
TtmlParser
(
boolean
strictParsing
)
{
this
.
strictParsing
=
strictParsing
;
try
{
xmlParserFactory
=
XmlPullParserFactory
.
newInstance
();
}
catch
(
XmlPullParserException
e
)
{
...
...
@@ -89,21 +105,31 @@ public class TtmlParser implements SubtitleParser {
xmlParser
.
setInput
(
inputStream
,
inputEncoding
);
TtmlSubtitle
ttmlSubtitle
=
null
;
LinkedList
<
TtmlNode
>
nodeStack
=
new
LinkedList
<
TtmlNode
>();
int
unsupported
Tag
Depth
=
0
;
int
unsupported
Node
Depth
=
0
;
int
eventType
=
xmlParser
.
getEventType
();
while
(
eventType
!=
XmlPullParser
.
END_DOCUMENT
)
{
TtmlNode
parent
=
nodeStack
.
peekLast
();
if
(
unsupported
Tag
Depth
==
0
)
{
if
(
unsupported
Node
Depth
==
0
)
{
String
name
=
xmlParser
.
getName
();
if
(
eventType
==
XmlPullParser
.
START_TAG
)
{
if
(!
isSupportedTag
(
name
))
{
Log
.
w
(
TAG
,
"Ignoring unsupported tag: "
+
xmlParser
.
getName
());
unsupported
Tag
Depth
++;
Log
.
i
(
TAG
,
"Ignoring unsupported tag: "
+
xmlParser
.
getName
());
unsupported
Node
Depth
++;
}
else
{
TtmlNode
node
=
parseNode
(
xmlParser
,
parent
);
nodeStack
.
addLast
(
node
);
if
(
parent
!=
null
)
{
parent
.
addChild
(
node
);
try
{
TtmlNode
node
=
parseNode
(
xmlParser
,
parent
);
nodeStack
.
addLast
(
node
);
if
(
parent
!=
null
)
{
parent
.
addChild
(
node
);
}
}
catch
(
ParserException
e
)
{
if
(
strictParsing
)
{
throw
e
;
}
else
{
Log
.
e
(
TAG
,
"Suppressing parser error"
,
e
);
// Treat the node (and by extension, all of its children) as unsupported.
unsupportedNodeDepth
++;
}
}
}
}
else
if
(
eventType
==
XmlPullParser
.
TEXT
)
{
...
...
@@ -116,9 +142,9 @@ public class TtmlParser implements SubtitleParser {
}
}
else
{
if
(
eventType
==
XmlPullParser
.
START_TAG
)
{
unsupported
Tag
Depth
++;
unsupported
Node
Depth
++;
}
else
if
(
eventType
==
XmlPullParser
.
END_TAG
)
{
unsupported
Tag
Depth
--;
unsupported
Node
Depth
--;
}
}
xmlParser
.
next
();
...
...
@@ -126,7 +152,7 @@ public class TtmlParser implements SubtitleParser {
}
return
ttmlSubtitle
;
}
catch
(
XmlPullParserException
xppe
)
{
throw
new
IO
Exception
(
"Unable to parse source"
,
xppe
);
throw
new
Parser
Exception
(
"Unable to parse source"
,
xppe
);
}
}
...
...
@@ -135,7 +161,7 @@ public class TtmlParser implements SubtitleParser {
return
MimeTypes
.
APPLICATION_TTML
.
equals
(
mimeType
);
}
private
TtmlNode
parseNode
(
XmlPullParser
parser
,
TtmlNode
parent
)
{
private
TtmlNode
parseNode
(
XmlPullParser
parser
,
TtmlNode
parent
)
throws
ParserException
{
long
duration
=
0
;
long
startTime
=
TtmlNode
.
UNDEFINED_TIME
;
long
endTime
=
TtmlNode
.
UNDEFINED_TIME
;
...
...
@@ -209,10 +235,10 @@ public class TtmlParser implements SubtitleParser {
* @param subframeRate The sub-framerate of the stream
* @param tickRate The tick rate of the stream.
* @return The parsed timestamp in microseconds.
* @throws
NumberFormat
Exception If the given string does not contain a valid time expression.
* @throws
Parser
Exception If the given string does not contain a valid time expression.
*/
private
static
long
parseTimeExpression
(
String
time
,
int
frameRate
,
int
subframeRate
,
int
tickRate
)
{
int
tickRate
)
throws
ParserException
{
Matcher
matcher
=
CLOCK_TIME
.
matcher
(
time
);
if
(
matcher
.
matches
())
{
String
hours
=
matcher
.
group
(
1
);
...
...
@@ -250,7 +276,7 @@ public class TtmlParser implements SubtitleParser {
}
return
(
long
)
(
offsetSeconds
*
1000000
);
}
throw
new
NumberFormat
Exception
(
"Malformed time expression: "
+
time
);
throw
new
Parser
Exception
(
"Malformed time expression: "
+
time
);
}
}
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