mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Simplify tx3g support.
This commit is contained in:
parent
254bc5a8cc
commit
01affbb93e
8 changed files with 156 additions and 295 deletions
|
|
@ -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.Extractor;
|
||||||
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
||||||
import com.google.android.exoplayer.text.TextTrackRenderer;
|
import com.google.android.exoplayer.text.TextTrackRenderer;
|
||||||
import com.google.android.exoplayer.text.tx3g.TextParser;
|
import com.google.android.exoplayer.text.tx3g.Tx3gParser;
|
||||||
import com.google.android.exoplayer.upstream.DataSource;
|
import com.google.android.exoplayer.upstream.DataSource;
|
||||||
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
|
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
|
||||||
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
|
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
|
||||||
|
|
@ -64,8 +64,8 @@ public class ExtractorRendererBuilder implements RendererBuilder {
|
||||||
player, 50);
|
player, 50);
|
||||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,
|
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,
|
||||||
null, true, player.getMainHandler(), player);
|
null, true, player.getMainHandler(), player);
|
||||||
|
TrackRenderer textRenderer = new TextTrackRenderer(sampleSource, player,
|
||||||
TrackRenderer textRenderer = new TextTrackRenderer(sampleSource, player, player.getMainHandler().getLooper(), new TextParser());
|
player.getMainHandler().getLooper(), new Tx3gParser());
|
||||||
|
|
||||||
// Invoke the callback.
|
// Invoke the callback.
|
||||||
TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];
|
TrackRenderer[] renderers = new TrackRenderer[DemoPlayer.RENDERER_COUNT];
|
||||||
|
|
|
||||||
|
|
@ -225,8 +225,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd));
|
Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd));
|
||||||
if (track == null || (track.type != Track.TYPE_AUDIO && track.type != Track.TYPE_VIDEO &&
|
if (track == null || track.mediaFormat == null || (track.type != Track.TYPE_AUDIO
|
||||||
track.type != Track.TYPE_TEXT)) {
|
&& track.type != Track.TYPE_VIDEO && track.type != Track.TYPE_TEXT)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,10 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||||
private boolean inputStreamEnded;
|
private boolean inputStreamEnded;
|
||||||
|
|
||||||
private Subtitle subtitle;
|
private Subtitle subtitle;
|
||||||
|
private Subtitle nextSubtitle;
|
||||||
private SubtitleParserHelper parserHelper;
|
private SubtitleParserHelper parserHelper;
|
||||||
private HandlerThread parserThread;
|
private HandlerThread parserThread;
|
||||||
private int nextSubtitleEventIndex;
|
private int nextSubtitleEventIndex;
|
||||||
private boolean textRendererNeedsUpdate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param source A source from which samples containing subtitle data can be read.
|
* @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;
|
inputStreamEnded = false;
|
||||||
currentPositionUs = positionUs;
|
currentPositionUs = positionUs;
|
||||||
source.seekToUs(positionUs);
|
source.seekToUs(positionUs);
|
||||||
if (subtitle != null && (positionUs < subtitle.getStartTime()
|
subtitle = null;
|
||||||
|| subtitle.getLastEventTime() <= positionUs)) {
|
nextSubtitle = null;
|
||||||
subtitle = null;
|
|
||||||
}
|
|
||||||
parserHelper.flush();
|
parserHelper.flush();
|
||||||
clearTextRenderer();
|
clearTextRenderer();
|
||||||
syncNextEventIndex(positionUs);
|
|
||||||
textRendererNeedsUpdate = subtitle != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -141,49 +137,49 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||||
throw new ExoPlaybackException(e);
|
throw new ExoPlaybackException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parserHelper.isParsing()) {
|
if (nextSubtitle == null) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Subtitle dequeuedSubtitle = null;
|
|
||||||
if (subtitle == null) {
|
|
||||||
try {
|
try {
|
||||||
dequeuedSubtitle = parserHelper.getAndClearResult();
|
nextSubtitle = parserHelper.getAndClearResult();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ExoPlaybackException(e);
|
throw new ExoPlaybackException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subtitle == null && dequeuedSubtitle != null) {
|
boolean textRendererNeedsUpdate = false;
|
||||||
// We've dequeued a new subtitle. Sync the event index and update the subtitle.
|
long subtitleNextEventTimeUs = Long.MAX_VALUE;
|
||||||
subtitle = dequeuedSubtitle;
|
if (subtitle != null) {
|
||||||
syncNextEventIndex(positionUs);
|
|
||||||
textRendererNeedsUpdate = true;
|
|
||||||
} else if (subtitle != null) {
|
|
||||||
// We're iterating through the events in a subtitle. Set textRendererNeedsUpdate if we
|
// We're iterating through the events in a subtitle. Set textRendererNeedsUpdate if we
|
||||||
// advance to the next event.
|
// advance to the next event.
|
||||||
long nextEventTimeUs = getNextEventTime();
|
subtitleNextEventTimeUs = getNextEventTime();
|
||||||
while (nextEventTimeUs <= positionUs) {
|
while (subtitleNextEventTimeUs <= positionUs) {
|
||||||
nextSubtitleEventIndex++;
|
nextSubtitleEventIndex++;
|
||||||
nextEventTimeUs = getNextEventTime();
|
subtitleNextEventTimeUs = getNextEventTime();
|
||||||
textRendererNeedsUpdate = true;
|
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
|
if (subtitleNextEventTimeUs == Long.MAX_VALUE && nextSubtitle != null
|
||||||
// sync and set textRendererNeedsUpdate.
|
&& nextSubtitle.getStartTime() <= positionUs) {
|
||||||
if (!inputStreamEnded && subtitle == null) {
|
// 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 {
|
try {
|
||||||
SampleHolder sampleHolder = parserHelper.getSampleHolder();
|
SampleHolder sampleHolder = parserHelper.getSampleHolder();
|
||||||
sampleHolder.clearData();
|
sampleHolder.clearData();
|
||||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||||
if (result == SampleSource.SAMPLE_READ) {
|
if (result == SampleSource.SAMPLE_READ) {
|
||||||
parserHelper.startParseOperation();
|
parserHelper.startParseOperation();
|
||||||
textRendererNeedsUpdate = false;
|
|
||||||
} else if (result == SampleSource.END_OF_STREAM) {
|
} else if (result == SampleSource.END_OF_STREAM) {
|
||||||
inputStreamEnded = true;
|
inputStreamEnded = true;
|
||||||
}
|
}
|
||||||
|
|
@ -191,21 +187,12 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||||
throw new ExoPlaybackException(e);
|
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
|
@Override
|
||||||
protected void onDisabled() {
|
protected void onDisabled() {
|
||||||
subtitle = null;
|
subtitle = null;
|
||||||
|
nextSubtitle = null;
|
||||||
parserThread.quit();
|
parserThread.quit();
|
||||||
parserThread = null;
|
parserThread = null;
|
||||||
parserHelper = null;
|
parserHelper = null;
|
||||||
|
|
@ -236,7 +223,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnded() {
|
protected boolean isEnded() {
|
||||||
return inputStreamEnded && subtitle == null;
|
return inputStreamEnded && (subtitle == null || getNextEventTime() == Long.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -246,18 +233,13 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncNextEventIndex(long positionUs) {
|
|
||||||
nextSubtitleEventIndex = subtitle == null ? -1 : subtitle.getNextEventTimeIndex(positionUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getNextEventTime() {
|
private long getNextEventTime() {
|
||||||
return ((nextSubtitleEventIndex == -1)
|
return ((nextSubtitleEventIndex == -1)
|
||||||
|| (nextSubtitleEventIndex >= subtitle.getEventTimeCount())) ? Long.MAX_VALUE
|
|| (nextSubtitleEventIndex >= subtitle.getEventTimeCount())) ? Long.MAX_VALUE
|
||||||
: (subtitle.getEventTime(nextSubtitleEventIndex));
|
: (subtitle.getEventTime(nextSubtitleEventIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTextRenderer(long positionUs) {
|
private void updateTextRenderer(List<Cue> cues) {
|
||||||
List<Cue> cues = subtitle.getCues(positionUs);
|
|
||||||
if (textRendererHandler != null) {
|
if (textRendererHandler != null) {
|
||||||
textRendererHandler.obtainMessage(MSG_UPDATE_OVERLAY, cues).sendToTarget();
|
textRendererHandler.obtainMessage(MSG_UPDATE_OVERLAY, cues).sendToTarget();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -266,12 +248,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearTextRenderer() {
|
private void clearTextRenderer() {
|
||||||
if (textRendererHandler != null) {
|
updateTextRenderer(Collections.<Cue>emptyList());
|
||||||
textRendererHandler.obtainMessage(MSG_UPDATE_OVERLAY, Collections.<Cue>emptyList())
|
|
||||||
.sendToTarget();
|
|
||||||
} else {
|
|
||||||
invokeRendererInternalCues(Collections.<Cue>emptyList());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 com.google.android.exoplayer.text.Subtitle;
|
|
||||||
import com.google.android.exoplayer.text.SubtitleParser;
|
|
||||||
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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
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>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.text.Cue;
|
|
||||||
import com.google.android.exoplayer.text.Subtitle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A representation of a tx3g subtitle.
|
|
||||||
*/
|
|
||||||
public final class TextSubtitle implements Subtitle {
|
|
||||||
static String TAG = "TextSubtitle";
|
|
||||||
private final List<SubtitleData> text;
|
|
||||||
|
|
||||||
public TextSubtitle(List<SubtitleData> text) {
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getStartTime() {
|
|
||||||
return text.get(0).startTimePosUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getNextEventTimeIndex(long timeUs) {
|
|
||||||
|
|
||||||
int index = findTheClosed(timeUs);
|
|
||||||
int next = (index ) < text.size() ? (index ) : -1;
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getEventTimeCount() {
|
|
||||||
return text.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getEventTime(int index) {
|
|
||||||
if (index > text.size() - 1) return -1;
|
|
||||||
|
|
||||||
return text.get(index).startTimePosUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getLastEventTime() {
|
|
||||||
return text.get(0).startTimePosUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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 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;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SubtitleParser} for tx3g.
|
||||||
|
* <p>
|
||||||
|
* Currently only supports parsing of a single text track
|
||||||
|
*/
|
||||||
|
public final class Tx3gParser implements SubtitleParser {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
|
||||||
|
throws IOException {
|
||||||
|
DataInputStream dataInputStream = new DataInputStream(inputStream);
|
||||||
|
try {
|
||||||
|
String cueText = dataInputStream.readUTF();
|
||||||
|
return new Tx3gSubtitle(startTimeUs, new Cue(cueText));
|
||||||
|
} finally {
|
||||||
|
dataInputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canParse(String mimeType) {
|
||||||
|
return MimeTypes.APPLICATION_TX3G.equals(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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 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.
|
||||||
|
*/
|
||||||
|
/* package */ final class Tx3gSubtitle implements Subtitle {
|
||||||
|
|
||||||
|
private final long startTimeUs;
|
||||||
|
private final List<Cue> cues;
|
||||||
|
|
||||||
|
public Tx3gSubtitle(long startTimeUs, Cue cue) {
|
||||||
|
this.startTimeUs = startTimeUs;
|
||||||
|
this.cues = Collections.singletonList(cue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getStartTime() {
|
||||||
|
return startTimeUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNextEventTimeIndex(long timeUs) {
|
||||||
|
return timeUs < startTimeUs ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEventTimeCount() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEventTime(int index) {
|
||||||
|
Assertions.checkArgument(index == 0);
|
||||||
|
return startTimeUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLastEventTime() {
|
||||||
|
return startTimeUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Cue> getCues(long timeUs) {
|
||||||
|
return timeUs >= startTimeUs ? cues : Collections.<Cue>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue