| package android.media; |
| |
| import android.content.Context; |
| import android.media.SubtitleController.Renderer; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.os.Parcel; |
| import android.util.Log; |
| |
| import java.io.BufferedReader; |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.Reader; |
| import java.io.UnsupportedEncodingException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Vector; |
| |
| /** @hide */ |
| public class SRTRenderer extends Renderer { |
| private final Context mContext; |
| private final boolean mRender; |
| private final Handler mEventHandler; |
| |
| private WebVttRenderingWidget mRenderingWidget; |
| |
| public SRTRenderer(Context context) { |
| this(context, null); |
| } |
| |
| SRTRenderer(Context mContext, Handler mEventHandler) { |
| this.mContext = mContext; |
| this.mRender = (mEventHandler == null); |
| this.mEventHandler = mEventHandler; |
| } |
| |
| @Override |
| public boolean supports(MediaFormat format) { |
| if (format.containsKey(MediaFormat.KEY_MIME)) { |
| if (!format.getString(MediaFormat.KEY_MIME) |
| .equals(MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP)) { |
| return false; |
| }; |
| return mRender == (format.getInteger(MediaFormat.KEY_IS_TIMED_TEXT, 0) == 0); |
| } |
| return false; |
| } |
| |
| @Override |
| public SubtitleTrack createTrack(MediaFormat format) { |
| if (mRender && mRenderingWidget == null) { |
| mRenderingWidget = new WebVttRenderingWidget(mContext); |
| } |
| |
| if (mRender) { |
| return new SRTTrack(mRenderingWidget, format); |
| } else { |
| return new SRTTrack(mEventHandler, format); |
| } |
| } |
| } |
| |
| class SRTTrack extends WebVttTrack { |
| private static final int MEDIA_TIMED_TEXT = 99; // MediaPlayer.MEDIA_TIMED_TEXT |
| private static final int KEY_STRUCT_TEXT = 16; // TimedText.KEY_STRUCT_TEXT |
| private static final int KEY_START_TIME = 7; // TimedText.KEY_START_TIME |
| private static final int KEY_LOCAL_SETTING = 102; // TimedText.KEY_START_TIME |
| |
| private static final String TAG = "SRTTrack"; |
| private final Handler mEventHandler; |
| |
| SRTTrack(WebVttRenderingWidget renderingWidget, MediaFormat format) { |
| super(renderingWidget, format); |
| mEventHandler = null; |
| } |
| |
| SRTTrack(Handler eventHandler, MediaFormat format) { |
| super(null, format); |
| mEventHandler = eventHandler; |
| } |
| |
| @Override |
| protected void onData(SubtitleData data) { |
| try { |
| TextTrackCue cue = new TextTrackCue(); |
| cue.mStartTimeMs = data.getStartTimeUs() / 1000; |
| cue.mEndTimeMs = (data.getStartTimeUs() + data.getDurationUs()) / 1000; |
| |
| String paragraph; |
| paragraph = new String(data.getData(), "UTF-8"); |
| String[] lines = paragraph.split("\\r?\\n"); |
| cue.mLines = new TextTrackCueSpan[lines.length][]; |
| |
| int i = 0; |
| for (String line : lines) { |
| TextTrackCueSpan[] span = new TextTrackCueSpan[] { |
| new TextTrackCueSpan(line, -1) |
| }; |
| cue.mLines[i++] = span; |
| } |
| |
| addCue(cue); |
| } catch (UnsupportedEncodingException e) { |
| Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e); |
| } |
| } |
| |
| @Override |
| public void onData(byte[] data, boolean eos, long runID) { |
| // TODO make reentrant |
| try { |
| Reader r = new InputStreamReader(new ByteArrayInputStream(data), "UTF-8"); |
| BufferedReader br = new BufferedReader(r); |
| |
| String header; |
| while ((header = br.readLine()) != null) { |
| // discard subtitle number |
| header = br.readLine(); |
| if (header == null) { |
| break; |
| } |
| |
| TextTrackCue cue = new TextTrackCue(); |
| String[] startEnd = header.split("-->"); |
| cue.mStartTimeMs = parseMs(startEnd[0]); |
| cue.mEndTimeMs = parseMs(startEnd[1]); |
| cue.mRunID = runID; |
| |
| String s; |
| List<String> paragraph = new ArrayList<String>(); |
| while (!((s = br.readLine()) == null || s.trim().equals(""))) { |
| paragraph.add(s); |
| } |
| |
| int i = 0; |
| cue.mLines = new TextTrackCueSpan[paragraph.size()][]; |
| cue.mStrings = paragraph.toArray(new String[0]); |
| for (String line : paragraph) { |
| TextTrackCueSpan[] span = new TextTrackCueSpan[] { |
| new TextTrackCueSpan(line, -1) |
| }; |
| cue.mStrings[i] = line; |
| cue.mLines[i++] = span; |
| } |
| |
| addCue(cue); |
| } |
| |
| } catch (UnsupportedEncodingException e) { |
| Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e); |
| } catch (IOException ioe) { |
| // shouldn't happen |
| Log.e(TAG, ioe.getMessage(), ioe); |
| } |
| } |
| |
| @Override |
| public void updateView(Vector<Cue> activeCues) { |
| if (getRenderingWidget() != null) { |
| super.updateView(activeCues); |
| return; |
| } |
| |
| if (mEventHandler == null) { |
| return; |
| } |
| |
| for (Cue cue : activeCues) { |
| TextTrackCue ttc = (TextTrackCue) cue; |
| |
| Parcel parcel = Parcel.obtain(); |
| parcel.writeInt(KEY_LOCAL_SETTING); |
| parcel.writeInt(KEY_START_TIME); |
| parcel.writeInt((int) cue.mStartTimeMs); |
| |
| parcel.writeInt(KEY_STRUCT_TEXT); |
| StringBuilder sb = new StringBuilder(); |
| for (String line : ttc.mStrings) { |
| sb.append(line).append('\n'); |
| } |
| |
| byte[] buf = sb.toString().getBytes(); |
| parcel.writeInt(buf.length); |
| parcel.writeByteArray(buf); |
| |
| Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, 0 /* arg1 */, 0 /* arg2 */, |
| parcel); |
| mEventHandler.sendMessage(msg); |
| } |
| activeCues.clear(); |
| } |
| |
| private static long parseMs(String in) { |
| long hours = Long.parseLong(in.split(":")[0].trim()); |
| long minutes = Long.parseLong(in.split(":")[1].trim()); |
| long seconds = Long.parseLong(in.split(":")[2].split(",")[0].trim()); |
| long millies = Long.parseLong(in.split(":")[2].split(",")[1].trim()); |
| |
| return hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000 + millies; |
| |
| } |
| } |