Skip to content

Instantly share code, notes, and snippets.

@anotherhale
Created November 14, 2014 19:18
Show Gist options
  • Save anotherhale/878c2d87e6347973ef31 to your computer and use it in GitHub Desktop.
Save anotherhale/878c2d87e6347973ef31 to your computer and use it in GitHub Desktop.
ByteArraySampleSource used in ExoPlayer TextRenderer for renderering local subtitle (TTML) files.
import android.annotation.TargetApi;
import android.content.Context;
import android.os.AsyncTask;
import com.google.android.exoplayer.FormatHolder;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackInfo;
import com.google.android.exoplayer.TrackRenderer;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.UUID;
/**
* Simple ByteArray SampleSource implementation that loads entire TTML file into ByteArray.
*/
public class ByteArraySampleSource extends AsyncTask<Void, Void, Void> implements SampleSource {
private static final int TRACK_STATE_DISABLED = 0;
private static final int TRACK_STATE_ENABLED = 1;
private static final int TRACK_STATE_FORMAT_SENT = 2;
private long seekTimeUs;
private final byte[] bytes;
public ByteArraySampleSource(byte[] bytes) {
this.bytes = bytes;
}
@Override
public boolean prepare() throws IOException {
return true;
}
@Override
public int getTrackCount() {
return 1;
}
@Override
public TrackInfo getTrackInfo(int track) {
return null;
}
@Override
public void enable(int track, long timeUs) {
seekToUs(timeUs);
}
@Override
public boolean continueBuffering(long playbackPositionUs) {
return true;
}
@Override
public int readData(int track, long playbackPositionUs, FormatHolder formatHolder,
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
if (sampleHolder.data != null) {
sampleHolder.size = bytes.length;
sampleHolder.data = ByteBuffer.wrap(new byte[bytes.length]);
}
seekTimeUs = -1;
return SAMPLE_READ;
}
@TargetApi(18)
private Map<UUID, byte[]> getPsshInfoV18() {
return null;
}
@Override
public void disable(int track) {
//Not implemented
}
@Override
public void seekToUs(long timeUs) {
if (seekTimeUs != timeUs) {
seekTimeUs = timeUs;
}
}
@Override
public long getBufferedPositionUs() {
return TrackRenderer.UNKNOWN_TIME_US;
}
@Override
public void release() {
}
@Override
protected Void doInBackground(Void... params) {
return null;
}
}
@triwav
Copy link

triwav commented Mar 3, 2015

@anotherhale thanks for this code. It's the only thing I could find to point me on the right track. I did need to do some modifications to it though to get it work. I mentioned it here: google/ExoPlayer#39
posting it here as well:

Thought I would post this here since trying to find documentation on adding an external caption file is very hard:
https://gist.github.com/triwav/ba72e99e5181427f4645

And to use it I'm doing:
try
{
URL url = new URL(video.getClosedCaptionUrl());
HttpSampleSource subtitleSource = new HttpSampleSource(url, "text/vtt");
textRenderer = new TextTrackRenderer(subtitleSource, new WebvttParser(), this, getContext().getApplicationContext().getMainLooper());
player.prepare(videoRenderer, audioRenderer, textRenderer);
} catch (MalformedURLException e)
{
player.prepare(videoRenderer, audioRenderer);
}

Note that I am having to pass in the mime type which is less than ideal but getTrackInfo could get called before the load has completed resulting in my case the webvtt file getting ignored by the subtitle parser. One bug is that when it gets to the end of the video it will just hang there. I'm currently dealing with this with this code in my onText method:
// Bug manually dealing with for now
int playerPosition = player.getCurrentPosition();
if (previousOnTextTime == playerPosition)
{
player.setRendererEnabled(TYPE_TEXT, false);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment