├── .classpath ├── .gitignore ├── .project ├── AndroidManifest.xml ├── README.md ├── gen └── com │ └── example │ └── media │ └── timedtexttest │ ├── BuildConfig.java │ └── R.java ├── ic_launcher-web.png ├── libs └── android-support-v4.jar ├── proguard-project.txt ├── project.properties ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── layout │ └── activity_main.xml ├── menu │ └── activity_main.xml ├── raw │ ├── sub.srt │ └── video.mp4 ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml └── values │ ├── strings.xml │ └── styles.xml └── src └── com └── example └── media └── timedtexttest └── MainActivity.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | TimedTextTest 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TimedTextTest 2 | ============= 3 | 4 | An example project of using TimedText in android 4.0+ to add subtitles to a video. 5 | 6 | 7 | It is related to the below StackOverflow question: 8 | 9 | http://stackoverflow.com/questions/13422673/looking-for-a-working-example-of-addtimedtextsource-for-adding-subtitle-to-a-vid/14929323?noredirect=1#comment22672683_14929323 10 | -------------------------------------------------------------------------------- /gen/com/example/media/timedtexttest/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** Automatically generated file. DO NOT MODIFY */ 2 | package com.example.media.timedtexttest; 3 | 4 | public final class BuildConfig { 5 | public final static boolean DEBUG = true; 6 | } -------------------------------------------------------------------------------- /gen/com/example/media/timedtexttest/R.java: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED FILE. DO NOT MODIFY. 2 | * 3 | * This class was automatically generated by the 4 | * aapt tool from the resource data it found. It 5 | * should not be modified by hand. 6 | */ 7 | 8 | package com.example.media.timedtexttest; 9 | 10 | public final class R { 11 | public static final class attr { 12 | } 13 | public static final class drawable { 14 | public static final int ic_launcher=0x7f020000; 15 | } 16 | public static final class id { 17 | public static final int menu_settings=0x7f080001; 18 | public static final int txtDisplay=0x7f080000; 19 | } 20 | public static final class layout { 21 | public static final int activity_main=0x7f030000; 22 | } 23 | public static final class menu { 24 | public static final int activity_main=0x7f070000; 25 | } 26 | public static final class raw { 27 | public static final int sub=0x7f040000; 28 | public static final int video=0x7f040001; 29 | } 30 | public static final class string { 31 | public static final int app_name=0x7f050000; 32 | public static final int hello_world=0x7f050001; 33 | public static final int menu_settings=0x7f050002; 34 | } 35 | public static final class style { 36 | /** 37 | Base application theme, dependent on API level. This theme is replaced 38 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 39 | 40 | 41 | Theme customizations available in newer API levels can go in 42 | res/values-vXX/styles.xml, while customizations related to 43 | backward-compatibility can go here. 44 | 45 | 46 | Base application theme for API 11+. This theme completely replaces 47 | AppBaseTheme from res/values/styles.xml on API 11+ devices. 48 | 49 | API 11 theme customizations can go here. 50 | 51 | Base application theme for API 14+. This theme completely replaces 52 | AppBaseTheme from BOTH res/values/styles.xml and 53 | res/values-v11/styles.xml on API 14+ devices. 54 | 55 | API 14 theme customizations can go here. 56 | */ 57 | public static final int AppBaseTheme=0x7f060000; 58 | /** Application theme. 59 | All customizations that are NOT specific to a particular API-level can go here. 60 | */ 61 | public static final int AppTheme=0x7f060001; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTech-Developer/TimedTextTest/79ea1006d572a244d9ea163291ac3a4e36ddc677/ic_launcher-web.png -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTech-Developer/TimedTextTest/79ea1006d572a244d9ea163291ac3a4e36ddc677/libs/android-support-v4.jar -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-16 15 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTech-Developer/TimedTextTest/79ea1006d572a244d9ea163291ac3a4e36ddc677/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTech-Developer/TimedTextTest/79ea1006d572a244d9ea163291ac3a4e36ddc677/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTech-Developer/TimedTextTest/79ea1006d572a244d9ea163291ac3a4e36ddc677/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTech-Developer/TimedTextTest/79ea1006d572a244d9ea163291ac3a4e36ddc677/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /res/menu/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /res/raw/sub.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,220 --> 00:00:01,215 3 | First Text Example 4 | 5 | 2 6 | 00:00:03,148 --> 00:00:05,053 7 | Second Text Example 8 | 9 | 3 10 | 00:00:08,004 --> 00:00:09,884 11 | Third Text Example 12 | 13 | 4 14 | 00:00:11,300 --> 00:00:12,900 15 | Fourth Text Example 16 | 17 | 5 18 | 00:00:15,500 --> 00:00:16,700 19 | Fifth Text Example 20 | 21 | 6 22 | 00:00:18,434 --> 00:00:20,434 23 | Sixth Text Example 24 | 25 | 7 26 | 00:00:22,600 --> 00:00:23,700 27 | Last Text Example 28 | -------------------------------------------------------------------------------- /res/raw/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTech-Developer/TimedTextTest/79ea1006d572a244d9ea163291ac3a4e36ddc677/res/raw/video.mp4 -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TimedTextTest 5 | Hello world! 6 | Settings 7 | 8 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /src/com/example/media/timedtexttest/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.media.timedtexttest; 2 | 3 | import java.io.Closeable; 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.OutputStream; 9 | import java.util.Locale; 10 | 11 | import android.app.Activity; 12 | import android.media.MediaPlayer; 13 | import android.media.MediaPlayer.OnTimedTextListener; 14 | import android.media.MediaPlayer.TrackInfo; 15 | import android.media.TimedText; 16 | import android.os.Bundle; 17 | import android.os.Handler; 18 | import android.util.Log; 19 | import android.widget.TextView; 20 | 21 | public class MainActivity extends Activity implements OnTimedTextListener { 22 | private static final String TAG = "TimedTextTest"; 23 | private TextView txtDisplay; 24 | private static Handler handler = new Handler(); 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_main); 30 | txtDisplay = (TextView) findViewById(R.id.txtDisplay); 31 | MediaPlayer player = MediaPlayer.create(this, R.raw.video); 32 | try { 33 | player.addTimedTextSource(getSubtitleFile(R.raw.sub), 34 | MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP); 35 | int textTrackIndex = findTrackIndexFor( 36 | TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT, player.getTrackInfo()); 37 | if (textTrackIndex >= 0) { 38 | player.selectTrack(textTrackIndex); 39 | } else { 40 | Log.w(TAG, "Cannot find text track!"); 41 | } 42 | player.setOnTimedTextListener(this); 43 | player.start(); 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | } 47 | } 48 | 49 | private int findTrackIndexFor(int mediaTrackType, TrackInfo[] trackInfo) { 50 | int index = -1; 51 | for (int i = 0; i < trackInfo.length; i++) { 52 | if (trackInfo[i].getTrackType() == mediaTrackType) { 53 | return i; 54 | } 55 | } 56 | return index; 57 | } 58 | 59 | private String getSubtitleFile(int resId) { 60 | String fileName = getResources().getResourceEntryName(resId); 61 | File subtitleFile = getFileStreamPath(fileName); 62 | if (subtitleFile.exists()) { 63 | Log.d(TAG, "Subtitle already exists"); 64 | return subtitleFile.getAbsolutePath(); 65 | } 66 | Log.d(TAG, "Subtitle does not exists, copy it from res/raw"); 67 | 68 | // Copy the file from the res/raw folder to your app folder on the 69 | // device 70 | InputStream inputStream = null; 71 | OutputStream outputStream = null; 72 | try { 73 | inputStream = getResources().openRawResource(resId); 74 | outputStream = new FileOutputStream(subtitleFile, false); 75 | copyFile(inputStream, outputStream); 76 | return subtitleFile.getAbsolutePath(); 77 | } catch (Exception e) { 78 | e.printStackTrace(); 79 | } finally { 80 | closeStreams(inputStream, outputStream); 81 | } 82 | return ""; 83 | } 84 | 85 | private void copyFile(InputStream inputStream, OutputStream outputStream) 86 | throws IOException { 87 | final int BUFFER_SIZE = 1024; 88 | byte[] buffer = new byte[BUFFER_SIZE]; 89 | int length = -1; 90 | while ((length = inputStream.read(buffer)) != -1) { 91 | outputStream.write(buffer, 0, length); 92 | } 93 | } 94 | 95 | // A handy method I use to close all the streams 96 | private void closeStreams(Closeable... closeables) { 97 | if (closeables != null) { 98 | for (Closeable stream : closeables) { 99 | if (stream != null) { 100 | try { 101 | stream.close(); 102 | } catch (IOException e) { 103 | e.printStackTrace(); 104 | } 105 | } 106 | } 107 | } 108 | } 109 | 110 | @Override 111 | public void onTimedText(final MediaPlayer mp, final TimedText text) { 112 | if (text != null) { 113 | handler.post(new Runnable() { 114 | @Override 115 | public void run() { 116 | int seconds = mp.getCurrentPosition() / 1000; 117 | 118 | txtDisplay.setText("[" + secondsToDuration(seconds) + "] " 119 | + text.getText()); 120 | } 121 | }); 122 | } 123 | } 124 | 125 | // To display the seconds in the duration format 00:00:00 126 | public String secondsToDuration(int seconds) { 127 | return String.format("%02d:%02d:%02d", seconds / 3600, 128 | (seconds % 3600) / 60, (seconds % 60), Locale.US); 129 | } 130 | } 131 | --------------------------------------------------------------------------------