13cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihpackage android.media; 23cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 33cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport android.content.Context; 43cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport android.media.SubtitleController.Renderer; 53cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport android.os.Handler; 63cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport android.os.Message; 73cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport android.os.Parcel; 83cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport android.util.Log; 93cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 103cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.io.BufferedReader; 113cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.io.ByteArrayInputStream; 123cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.io.IOException; 133cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.io.InputStreamReader; 143cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.io.Reader; 153cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.io.UnsupportedEncodingException; 163cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.util.ArrayList; 173cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.util.List; 183cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihimport java.util.Vector; 193cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 203cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih/** @hide */ 213cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihpublic class SRTRenderer extends Renderer { 223cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private final Context mContext; 233cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private final boolean mRender; 243cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private final Handler mEventHandler; 253cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 263cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private WebVttRenderingWidget mRenderingWidget; 273cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 283cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih public SRTRenderer(Context context) { 293cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih this(context, null); 303cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 313cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 323cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih SRTRenderer(Context mContext, Handler mEventHandler) { 333cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih this.mContext = mContext; 343cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih this.mRender = (mEventHandler == null); 353cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih this.mEventHandler = mEventHandler; 363cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 373cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 383cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih @Override 393cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih public boolean supports(MediaFormat format) { 403cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (format.containsKey(MediaFormat.KEY_MIME)) { 413cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (!format.getString(MediaFormat.KEY_MIME) 423cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih .equals(MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP)) { 433cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih return false; 443cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih }; 453cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih return mRender == (format.getInteger(MediaFormat.KEY_IS_TIMED_TEXT, 0) == 0); 463cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 473cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih return false; 483cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 493cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 503cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih @Override 513cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih public SubtitleTrack createTrack(MediaFormat format) { 523cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (mRender && mRenderingWidget == null) { 533cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih mRenderingWidget = new WebVttRenderingWidget(mContext); 543cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 553cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 563cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (mRender) { 573cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih return new SRTTrack(mRenderingWidget, format); 583cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } else { 593cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih return new SRTTrack(mEventHandler, format); 603cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 613cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 623cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih} 633cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 643cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shihclass SRTTrack extends WebVttTrack { 653cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private static final int MEDIA_TIMED_TEXT = 99; // MediaPlayer.MEDIA_TIMED_TEXT 663cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private static final int KEY_STRUCT_TEXT = 16; // TimedText.KEY_STRUCT_TEXT 673cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private static final int KEY_START_TIME = 7; // TimedText.KEY_START_TIME 683cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private static final int KEY_LOCAL_SETTING = 102; // TimedText.KEY_START_TIME 693cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 703cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private static final String TAG = "SRTTrack"; 713cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private final Handler mEventHandler; 723cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 733cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih SRTTrack(WebVttRenderingWidget renderingWidget, MediaFormat format) { 743cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih super(renderingWidget, format); 753cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih mEventHandler = null; 763cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 773cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 783cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih SRTTrack(Handler eventHandler, MediaFormat format) { 793cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih super(null, format); 803cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih mEventHandler = eventHandler; 813cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 823cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 833cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih @Override 843cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih protected void onData(SubtitleData data) { 853cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih try { 863cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih TextTrackCue cue = new TextTrackCue(); 873cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mStartTimeMs = data.getStartTimeUs() / 1000; 883cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mEndTimeMs = (data.getStartTimeUs() + data.getDurationUs()) / 1000; 893cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 903cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih String paragraph; 913cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih paragraph = new String(data.getData(), "UTF-8"); 923cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih String[] lines = paragraph.split("\\r?\\n"); 933cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mLines = new TextTrackCueSpan[lines.length][]; 943cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 953cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih int i = 0; 963cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih for (String line : lines) { 973cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih TextTrackCueSpan[] span = new TextTrackCueSpan[] { 983cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih new TextTrackCueSpan(line, -1) 993cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih }; 1003cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mLines[i++] = span; 1013cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1023cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1033cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih addCue(cue); 1043cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } catch (UnsupportedEncodingException e) { 1053cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e); 1063cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1073cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1083cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1093cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih @Override 1103cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih public void onData(byte[] data, boolean eos, long runID) { 1113cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih // TODO make reentrant 1123cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih try { 1133cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih Reader r = new InputStreamReader(new ByteArrayInputStream(data), "UTF-8"); 1143cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih BufferedReader br = new BufferedReader(r); 1153cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1163cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih String header; 1173cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih while ((header = br.readLine()) != null) { 1183cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih // discard subtitle number 1193cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih header = br.readLine(); 1203cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (header == null) { 1213cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih break; 1223cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1233cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1243cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih TextTrackCue cue = new TextTrackCue(); 1253cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih String[] startEnd = header.split("-->"); 1263cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mStartTimeMs = parseMs(startEnd[0]); 1273cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mEndTimeMs = parseMs(startEnd[1]); 1283cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1293cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih String s; 1303cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih List<String> paragraph = new ArrayList<String>(); 1313cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih while (!((s = br.readLine()) == null || s.trim().equals(""))) { 1323cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih paragraph.add(s); 1333cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1343cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1353cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih int i = 0; 1363cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mLines = new TextTrackCueSpan[paragraph.size()][]; 1373cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mStrings = paragraph.toArray(new String[0]); 1383cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih for (String line : paragraph) { 1393cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih TextTrackCueSpan[] span = new TextTrackCueSpan[] { 1403cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih new TextTrackCueSpan(line, -1) 1413cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih }; 1423cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mStrings[i] = line; 1433cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih cue.mLines[i++] = span; 1443cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1453cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1463cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih addCue(cue); 1473cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1483cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1493cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } catch (UnsupportedEncodingException e) { 1503cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e); 1513cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } catch (IOException ioe) { 1523cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih // shouldn't happen 1533cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih Log.e(TAG, ioe.getMessage(), ioe); 1543cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1553cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1563cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1573cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih @Override 1583cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih public void updateView(Vector<Cue> activeCues) { 1593cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (getRenderingWidget() != null) { 1603cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih super.updateView(activeCues); 1613cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih return; 1623cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1633cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1643cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih if (mEventHandler == null) { 1653cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih return; 1663cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1673cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1683cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih final int _ = 0; 1693cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih for (Cue cue : activeCues) { 1703cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih TextTrackCue ttc = (TextTrackCue) cue; 1713cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1723cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih Parcel parcel = Parcel.obtain(); 1733cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih parcel.writeInt(KEY_LOCAL_SETTING); 1743cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih parcel.writeInt(KEY_START_TIME); 1753cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih parcel.writeInt((int) cue.mStartTimeMs); 1763cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1773cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih parcel.writeInt(KEY_STRUCT_TEXT); 1783cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih StringBuilder sb = new StringBuilder(); 1793cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih for (String line : ttc.mStrings) { 1803cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih sb.append(line).append('\n'); 1813cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1823cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1833cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih byte[] buf = sb.toString().getBytes(); 1843cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih parcel.writeInt(buf.length); 1853cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih parcel.writeByteArray(buf); 1863cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1873cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, _, _, parcel); 1883cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih mEventHandler.sendMessage(msg); 1893cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1903cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih activeCues.clear(); 1913cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 1923cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1933cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih private static long parseMs(String in) { 1943cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih long hours = Long.parseLong(in.split(":")[0].trim()); 1953cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih long minutes = Long.parseLong(in.split(":")[1].trim()); 1963cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih long seconds = Long.parseLong(in.split(":")[2].split(",")[0].trim()); 1973cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih long millies = Long.parseLong(in.split(":")[2].split(",")[1].trim()); 1983cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 1993cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih return hours * 60 * 60 * 1000 + minutes * 60 * 1000 + seconds * 1000 + millies; 2003cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih 2013cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih } 2023cdf7c5b622a8fbb20410736bdab5888d0e1873cRobert Shih} 203