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
01affbb9
authored
Jun 04, 2015
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Simplify tx3g support.
parent
254bc5a8
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
67 additions
and
206 deletions
demo/src/main/java/com/google/android/exoplayer/demo/player/ExtractorRendererBuilder.java
library/src/main/java/com/google/android/exoplayer/extractor/mp4/Mp4Extractor.java
library/src/main/java/com/google/android/exoplayer/text/TextTrackRenderer.java
library/src/main/java/com/google/android/exoplayer/text/tx3g/SubtitleData.java
library/src/main/java/com/google/android/exoplayer/text/tx3g/TextParser.java → library/src/main/java/com/google/android/exoplayer/text/tx3g/Tx3gParser.java
library/src/main/java/com/google/android/exoplayer/text/tx3g/TextSubtitle.java → library/src/main/java/com/google/android/exoplayer/text/tx3g/Tx3gSubtitle.java
demo/src/main/java/com/google/android/exoplayer/demo/player/ExtractorRendererBuilder.java
View file @
01affbb9
...
...
@@ -23,7 +23,7 @@ import com.google.android.exoplayer.demo.player.DemoPlayer.RendererBuilderCallba
import
com.google.android.exoplayer.extractor.Extractor
;
import
com.google.android.exoplayer.extractor.ExtractorSampleSource
;
import
com.google.android.exoplayer.text.TextTrackRenderer
;
import
com.google.android.exoplayer.text.tx3g.T
ext
Parser
;
import
com.google.android.exoplayer.text.tx3g.T
x3g
Parser
;
import
com.google.android.exoplayer.upstream.DataSource
;
import
com.google.android.exoplayer.upstream.DefaultBandwidthMeter
;
import
com.google.android.exoplayer.upstream.DefaultUriDataSource
;
...
...
@@ -64,8 +64,8 @@ public class ExtractorRendererBuilder implements RendererBuilder {
player
,
50
);
MediaCodecAudioTrackRenderer
audioRenderer
=
new
MediaCodecAudioTrackRenderer
(
sampleSource
,
null
,
true
,
player
.
getMainHandler
(),
player
);
TrackRenderer
textRenderer
=
new
TextTrackRenderer
(
sampleSource
,
player
,
player
.
getMainHandler
().
getLooper
(),
new
Text
Parser
());
TrackRenderer
textRenderer
=
new
TextTrackRenderer
(
sampleSource
,
player
,
player
.
getMainHandler
().
getLooper
(),
new
Tx3g
Parser
());
// Invoke the callback.
TrackRenderer
[]
renderers
=
new
TrackRenderer
[
DemoPlayer
.
RENDERER_COUNT
];
...
...
library/src/main/java/com/google/android/exoplayer/extractor/mp4/Mp4Extractor.java
View file @
01affbb9
...
...
@@ -225,8 +225,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
}
Track
track
=
AtomParsers
.
parseTrak
(
atom
,
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_mvhd
));
if
(
track
==
null
||
(
track
.
type
!=
Track
.
TYPE_AUDIO
&&
track
.
type
!=
Track
.
TYPE_VIDEO
&&
track
.
type
!=
Track
.
TYPE_TEXT
))
{
if
(
track
==
null
||
track
.
mediaFormat
==
null
||
(
track
.
type
!=
Track
.
TYPE_AUDIO
&&
track
.
type
!=
Track
.
TYPE_VIDEO
&&
track
.
type
!=
Track
.
TYPE_TEXT
))
{
continue
;
}
...
...
library/src/main/java/com/google/android/exoplayer/text/TextTrackRenderer.java
View file @
01affbb9
...
...
@@ -55,10 +55,10 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
private
boolean
inputStreamEnded
;
private
Subtitle
subtitle
;
private
Subtitle
nextSubtitle
;
private
SubtitleParserHelper
parserHelper
;
private
HandlerThread
parserThread
;
private
int
nextSubtitleEventIndex
;
private
boolean
textRendererNeedsUpdate
;
/**
* @param source A source from which samples containing subtitle data can be read.
...
...
@@ -122,14 +122,10 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
inputStreamEnded
=
false
;
currentPositionUs
=
positionUs
;
source
.
seekToUs
(
positionUs
);
if
(
subtitle
!=
null
&&
(
positionUs
<
subtitle
.
getStartTime
()
||
subtitle
.
getLastEventTime
()
<=
positionUs
))
{
subtitle
=
null
;
}
subtitle
=
null
;
nextSubtitle
=
null
;
parserHelper
.
flush
();
clearTextRenderer
();
syncNextEventIndex
(
positionUs
);
textRendererNeedsUpdate
=
subtitle
!=
null
;
}
@Override
...
...
@@ -141,49 +137,49 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
throw
new
ExoPlaybackException
(
e
);
}
if
(
parserHelper
.
isParsing
())
{
return
;
}
Subtitle
dequeuedSubtitle
=
null
;
if
(
subtitle
==
null
)
{
if
(
nextSubtitle
==
null
)
{
try
{
dequeued
Subtitle
=
parserHelper
.
getAndClearResult
();
next
Subtitle
=
parserHelper
.
getAndClearResult
();
}
catch
(
IOException
e
)
{
throw
new
ExoPlaybackException
(
e
);
}
}
if
(
subtitle
==
null
&&
dequeuedSubtitle
!=
null
)
{
// We've dequeued a new subtitle. Sync the event index and update the subtitle.
subtitle
=
dequeuedSubtitle
;
syncNextEventIndex
(
positionUs
);
textRendererNeedsUpdate
=
true
;
}
else
if
(
subtitle
!=
null
)
{
boolean
textRendererNeedsUpdate
=
false
;
long
subtitleNextEventTimeUs
=
Long
.
MAX_VALUE
;
if
(
subtitle
!=
null
)
{
// We're iterating through the events in a subtitle. Set textRendererNeedsUpdate if we
// advance to the next event.
long
n
extEventTimeUs
=
getNextEventTime
();
while
(
n
extEventTimeUs
<=
positionUs
)
{
subtitleN
extEventTimeUs
=
getNextEventTime
();
while
(
subtitleN
extEventTimeUs
<=
positionUs
)
{
nextSubtitleEventIndex
++;
n
extEventTimeUs
=
getNextEventTime
();
subtitleN
extEventTimeUs
=
getNextEventTime
();
textRendererNeedsUpdate
=
true
;
}
if
(
nextEventTimeUs
==
Long
.
MAX_VALUE
)
{
// We've finished processing the subtitle.
subtitle
=
null
;
}
}
// We don't have a subtitle. Try and read the next one from the source, and if we succeed then
// sync and set textRendererNeedsUpdate.
if
(!
inputStreamEnded
&&
subtitle
==
null
)
{
if
(
subtitleNextEventTimeUs
==
Long
.
MAX_VALUE
&&
nextSubtitle
!=
null
&&
nextSubtitle
.
getStartTime
()
<=
positionUs
)
{
// Advance to the next subtitle. Sync the next event index and trigger an update.
subtitle
=
nextSubtitle
;
nextSubtitle
=
null
;
nextSubtitleEventIndex
=
subtitle
.
getNextEventTimeIndex
(
positionUs
);
textRendererNeedsUpdate
=
true
;
}
if
(
textRendererNeedsUpdate
&&
getState
()
==
TrackRenderer
.
STATE_STARTED
)
{
// textRendererNeedsUpdate is set and we're playing. Update the renderer.
updateTextRenderer
(
subtitle
.
getCues
(
positionUs
));
}
if
(!
inputStreamEnded
&&
nextSubtitle
==
null
&&
!
parserHelper
.
isParsing
())
{
// Try and read the next subtitle from the source.
try
{
SampleHolder
sampleHolder
=
parserHelper
.
getSampleHolder
();
sampleHolder
.
clearData
();
int
result
=
source
.
readData
(
trackIndex
,
positionUs
,
formatHolder
,
sampleHolder
,
false
);
if
(
result
==
SampleSource
.
SAMPLE_READ
)
{
parserHelper
.
startParseOperation
();
textRendererNeedsUpdate
=
false
;
}
else
if
(
result
==
SampleSource
.
END_OF_STREAM
)
{
inputStreamEnded
=
true
;
}
...
...
@@ -191,21 +187,12 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
throw
new
ExoPlaybackException
(
e
);
}
}
// Update the text renderer if we're both playing and textRendererNeedsUpdate is set.
if
(
textRendererNeedsUpdate
&&
getState
()
==
TrackRenderer
.
STATE_STARTED
)
{
textRendererNeedsUpdate
=
false
;
if
(
subtitle
==
null
)
{
clearTextRenderer
();
}
else
{
updateTextRenderer
(
positionUs
);
}
}
}
@Override
protected
void
onDisabled
()
{
subtitle
=
null
;
nextSubtitle
=
null
;
parserThread
.
quit
();
parserThread
=
null
;
parserHelper
=
null
;
...
...
@@ -236,7 +223,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
@Override
protected
boolean
isEnded
()
{
return
inputStreamEnded
&&
subtitle
==
null
;
return
inputStreamEnded
&&
(
subtitle
==
null
||
getNextEventTime
()
==
Long
.
MAX_VALUE
)
;
}
@Override
...
...
@@ -246,18 +233,13 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
return
true
;
}
private
void
syncNextEventIndex
(
long
positionUs
)
{
nextSubtitleEventIndex
=
subtitle
==
null
?
-
1
:
subtitle
.
getNextEventTimeIndex
(
positionUs
);
}
private
long
getNextEventTime
()
{
return
((
nextSubtitleEventIndex
==
-
1
)
||
(
nextSubtitleEventIndex
>=
subtitle
.
getEventTimeCount
()))
?
Long
.
MAX_VALUE
:
(
subtitle
.
getEventTime
(
nextSubtitleEventIndex
));
}
private
void
updateTextRenderer
(
long
positionUs
)
{
List
<
Cue
>
cues
=
subtitle
.
getCues
(
positionUs
);
private
void
updateTextRenderer
(
List
<
Cue
>
cues
)
{
if
(
textRendererHandler
!=
null
)
{
textRendererHandler
.
obtainMessage
(
MSG_UPDATE_OVERLAY
,
cues
).
sendToTarget
();
}
else
{
...
...
@@ -266,12 +248,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
}
private
void
clearTextRenderer
()
{
if
(
textRendererHandler
!=
null
)
{
textRendererHandler
.
obtainMessage
(
MSG_UPDATE_OVERLAY
,
Collections
.<
Cue
>
emptyList
())
.
sendToTarget
();
}
else
{
invokeRendererInternalCues
(
Collections
.<
Cue
>
emptyList
());
}
updateTextRenderer
(
Collections
.<
Cue
>
emptyList
());
}
@SuppressWarnings
(
"unchecked"
)
...
...
library/src/main/java/com/google/android/exoplayer/text/tx3g/SubtitleData.java
deleted
100644 → 0
View file @
254bc5a8
/*
* 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
.
text
.
tx3g
;
import
java.util.Comparator
;
/**
* A representation of a single tx3g.
*/
class
SubtitleData
implements
Comparable
<
SubtitleData
>,
Comparator
<
SubtitleData
>
{
public
final
long
startTimePosUs
;
public
final
String
subtitle
;
SubtitleData
(
long
startTimePosUs
,
String
subtitle
)
{
this
.
startTimePosUs
=
startTimePosUs
;
this
.
subtitle
=
subtitle
;
}
@Override
public
int
compare
(
SubtitleData
o1
,
SubtitleData
o2
)
{
if
(
o1
.
startTimePosUs
<
o2
.
startTimePosUs
)
return
-
1
;
if
(
o1
.
startTimePosUs
>
o2
.
startTimePosUs
)
return
1
;
return
0
;
}
@Override
public
int
compareTo
(
SubtitleData
another
)
{
if
(
startTimePosUs
<
another
.
startTimePosUs
)
return
-
1
;
if
(
startTimePosUs
>
another
.
startTimePosUs
)
return
1
;
return
0
;
}
}
library/src/main/java/com/google/android/exoplayer/text/tx3g/T
ext
Parser.java
→
library/src/main/java/com/google/android/exoplayer/text/tx3g/T
x3g
Parser.java
View file @
01affbb9
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer
.
text
.
tx3g
;
import
com.google.android.exoplayer.text.Cue
;
import
com.google.android.exoplayer.text.Subtitle
;
import
com.google.android.exoplayer.text.SubtitleParser
;
import
com.google.android.exoplayer.util.MimeTypes
;
...
...
@@ -22,67 +23,29 @@ import com.google.android.exoplayer.util.MimeTypes;
import
java.io.DataInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.LinkedList
;
import
java.util.List
;
/**
* A simple Text parser that supports tx3g atom.
*
* Only support to parse a single text track at this version ,
* since ExtractorSampleSource does not handle multiple audio/video tracks.
*
* A {@link SubtitleParser} for tx3g.
* <p>
* Currently only supports parsing of a single text track
*/
public
class
TextParser
implements
SubtitleParser
{
private
static
final
String
TAG
=
"TextParser"
;
private
final
List
<
SubtitleData
>
subtitleList
;
private
static
final
int
MAX_SUBTITLE_COUNT
=
4
;
public
TextParser
()
{
subtitleList
=
new
LinkedList
<
SubtitleData
>();
}
public
final
class
Tx3gParser
implements
SubtitleParser
{
@Override
public
Subtitle
parse
(
InputStream
inputStream
,
String
inputEncoding
,
long
startTimeUs
)
throws
IOException
{
DataInputStream
in
=
new
DataInputStream
(
inputStream
);
String
text
=
in
.
readUTF
();
text
=
(
text
==
null
)
?
""
:
text
;
SubtitleData
cue
=
new
SubtitleData
(
startTimeUs
,
text
);
//try to resize the list.
if
(
subtitleList
.
size
()
>
0
)
{
long
lastTimeUs
=
subtitleList
.
get
(
subtitleList
.
size
()
-
1
).
startTimePosUs
;
if
(
startTimeUs
<
lastTimeUs
)
{
//when forward seek
subtitleList
.
clear
();
}
while
(
subtitleList
.
size
()
>
MAX_SUBTITLE_COUNT
)
{
subtitleList
.
remove
(
0
);
}
throws
IOException
{
DataInputStream
dataInputStream
=
new
DataInputStream
(
inputStream
);
try
{
String
cueText
=
dataInputStream
.
readUTF
();
return
new
Tx3gSubtitle
(
startTimeUs
,
new
Cue
(
cueText
));
}
finally
{
dataInputStream
.
close
();
}
subtitleList
.
add
(
cue
);
Collections
.
sort
(
subtitleList
,
new
Comparator
<
SubtitleData
>()
{
@Override
public
int
compare
(
SubtitleData
o1
,
SubtitleData
o2
)
{
if
(
o1
.
startTimePosUs
<
o2
.
startTimePosUs
)
return
-
1
;
if
(
o1
.
startTimePosUs
>
o2
.
startTimePosUs
)
return
1
;
return
0
;
}
});
return
new
TextSubtitle
(
subtitleList
);
}
@Override
public
boolean
canParse
(
String
mimeType
)
{
return
MimeTypes
.
APPLICATION_TX3G
.
equals
(
mimeType
);
}
}
library/src/main/java/com/google/android/exoplayer/text/tx3g/T
ext
Subtitle.java
→
library/src/main/java/com/google/android/exoplayer/text/tx3g/T
x3g
Subtitle.java
View file @
01affbb9
...
...
@@ -15,82 +15,55 @@
*/
package
com
.
google
.
android
.
exoplayer
.
text
.
tx3g
;
import
java.util.ArrayList
;
import
java.util.List
;
import
com.google.android.exoplayer.text.Cue
;
import
com.google.android.exoplayer.text.Subtitle
;
import
com.google.android.exoplayer.util.Assertions
;
import
java.util.Collections
;
import
java.util.List
;
/**
* A representation of a tx3g subtitle.
*/
public
final
class
TextSubtitle
implements
Subtitle
{
static
String
TAG
=
"TextSubtitle"
;
private
final
List
<
SubtitleData
>
text
;
/* package */
final
class
Tx3gSubtitle
implements
Subtitle
{
private
final
long
startTimeUs
;
private
final
List
<
Cue
>
cues
;
public
TextSubtitle
(
List
<
SubtitleData
>
text
)
{
this
.
text
=
text
;
public
Tx3gSubtitle
(
long
startTimeUs
,
Cue
cue
)
{
this
.
startTimeUs
=
startTimeUs
;
this
.
cues
=
Collections
.
singletonList
(
cue
);
}
@Override
public
long
getStartTime
()
{
return
text
.
get
(
0
).
startTimePos
Us
;
return
startTime
Us
;
}
@Override
public
int
getNextEventTimeIndex
(
long
timeUs
)
{
int
index
=
findTheClosed
(
timeUs
);
int
next
=
(
index
)
<
text
.
size
()
?
(
index
)
:
-
1
;
return
next
;
return
timeUs
<
startTimeUs
?
0
:
-
1
;
}
@Override
public
int
getEventTimeCount
()
{
return
text
.
size
()
;
return
1
;
}
@Override
public
long
getEventTime
(
int
index
)
{
if
(
index
>
text
.
size
()
-
1
)
return
-
1
;
return
text
.
get
(
index
).
startTimePosUs
;
Assertions
.
checkArgument
(
index
==
0
);
return
startTimeUs
;
}
@Override
public
long
getLastEventTime
()
{
return
text
.
get
(
0
).
startTimePos
Us
;
return
startTime
Us
;
}
@Override
public
List
<
Cue
>
getCues
(
long
timeUs
)
{
int
index
=
findTheClosed
(
timeUs
);
List
<
Cue
>
list
=
new
ArrayList
<>();
if
(
index
==
-
1
)
return
null
;
String
str
=
text
.
get
(
index
).
subtitle
;
list
.
add
(
new
Cue
(
str
));
return
list
;
return
timeUs
>=
startTimeUs
?
cues
:
Collections
.<
Cue
>
emptyList
();
}
private
int
findTheClosed
(
long
timeUs
)
{
//TODO : Time complexity is O(n),not good solution.
int
length
=
text
.
size
();
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
SubtitleData
data
=
text
.
get
(
i
);
boolean
bCheckFront
=
data
.
startTimePosUs
<=
timeUs
;
boolean
bCheckEnd
=
false
;
if
(
i
+
1
<
length
)
{
bCheckEnd
=
text
.
get
(
i
+
1
).
startTimePosUs
>
timeUs
;
}
else
if
(
i
+
1
==
length
)
{
bCheckEnd
=
true
;
}
if
(
bCheckFront
&&
bCheckEnd
)
return
i
;
}
return
-
1
;
}
}
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