├── .gitattributes
├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── shirlman
│ │ └── yiplayer
│ │ ├── MyApplication.java
│ │ ├── core
│ │ └── OnlineQueryService.java
│ │ ├── events
│ │ ├── DictionaryEvent.java
│ │ └── VideoEvents.java
│ │ ├── jobs
│ │ ├── GetLocalVideoListJob.java
│ │ └── JobPriority.java
│ │ ├── models
│ │ ├── ICibaResponse.java
│ │ ├── ShooterSubtitleDetailResponse.java
│ │ ├── ShooterSubtitleResponse.java
│ │ ├── VideoGroup.java
│ │ ├── VideoInfo.java
│ │ └── YoudaoResponse.java
│ │ ├── ui
│ │ ├── activities
│ │ │ ├── MainActivity.java
│ │ │ └── VideoActivity.java
│ │ ├── adapters
│ │ │ ├── LocalVideoAdapter.java
│ │ │ ├── LocalVideoGroupAdapter.java
│ │ │ └── OnlineSubtitleAdapter.java
│ │ ├── fragments
│ │ │ ├── LocalVideoFragment.java
│ │ │ └── LocalVideoGroupFragment.java
│ │ └── widgets
│ │ │ └── VideoController.java
│ │ └── util
│ │ ├── FileUtils.java
│ │ └── StringUtils.java
│ └── res
│ ├── drawable-v21
│ ├── ic_menu_camera.xml
│ ├── ic_menu_gallery.xml
│ ├── ic_menu_manage.xml
│ ├── ic_menu_send.xml
│ ├── ic_menu_share.xml
│ ├── ic_menu_slideshow.xml
│ ├── video_controller_lock.png
│ ├── video_controller_next.png
│ ├── video_controller_pause.png
│ ├── video_controller_play.png
│ └── video_controller_settings.png
│ ├── drawable
│ ├── local_video_info_bg.xml
│ ├── seek_bar_background_fill.xml
│ ├── seek_bar_bg.xml
│ ├── seek_bar_progress_fill.xml
│ ├── side_nav_bar.xml
│ ├── video_controller_bg.xml
│ └── video_lock_bg.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── app_bar_main.xml
│ ├── content_main.xml
│ ├── local_video_fragment.xml
│ ├── local_video_item.xml
│ ├── nav_header_main.xml
│ ├── online_subtitle.xml
│ ├── online_subtitle_item.xml
│ ├── video_controller.xml
│ └── video_view.xml
│ ├── menu
│ ├── activity_main_drawer.xml
│ └── main.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-v21
│ └── styles.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── drawables.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── com.shirlman.yiplayer_main_activity.png
├── com.shirlman.yiplayer_video_controller.png
└── 微信图片_20170522195813.png
├── settings.gradle
└── vlc
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── org
│ └── videolan
│ └── libvlc
│ ├── AWindow.java
│ ├── AWindowNativeHandler.java
│ ├── Dialog.java
│ ├── IVLCVout.java
│ ├── LibVLC.java
│ ├── Media.java
│ ├── MediaDiscoverer.java
│ ├── MediaList.java
│ ├── MediaPlayer.java
│ ├── VLCEvent.java
│ ├── VLCObject.java
│ ├── media
│ ├── MediaPlayer.java
│ └── VideoView.java
│ ├── subtitle
│ ├── Caption.java
│ ├── FatalParsingException.java
│ ├── FormatASS.java
│ ├── FormatSCC.java
│ ├── FormatSRT.java
│ ├── FormatSTL.java
│ ├── FormatTTML.java
│ ├── Region.java
│ ├── Style.java
│ ├── SubtitleFormat.java
│ ├── Time.java
│ ├── TimedTextFileFormat.java
│ ├── TimedTextObject.java
│ └── TimedTextProcessor.java
│ └── util
│ ├── AndroidUtil.java
│ ├── Dumper.java
│ ├── Extensions.java
│ ├── HWDecoderUtil.java
│ ├── MediaBrowser.java
│ └── VLCUtil.java
├── jniLibs
└── armeabi-v7a
│ ├── libanw.10.so
│ ├── libanw.13.so
│ ├── libanw.14.so
│ ├── libanw.18.so
│ ├── libanw.21.so
│ ├── libcompat.7.so
│ ├── libiomx.10.so
│ ├── libiomx.13.so
│ ├── libiomx.14.so
│ ├── libvlc.so
│ └── libvlcjni.so
└── res
└── values
└── strings.xml
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | YiPlayer
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 1.8
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # YiPlayer
2 | A video player which can help users to learn English through videos.
3 | > **Current Feature:**
4 |
5 | > - Play local videos
6 | > - Basic video control, like play, pause, resume, lock
7 | > - Support local subtitle
8 | > - Implement setOnTimedTextListener
9 | > - Query word from iCiba
10 | > - Query subtitle from shooter.cn
11 |
12 | If you want to use VideoView library(Based on VLC Android SDK 2.0.2), you can copy the VLC library to your project, it's totally independent.
13 |
14 | 
15 | 
16 | 
17 | ------ | ----- | -----
18 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "24.0.0"
6 |
7 | defaultConfig {
8 | applicationId "com.shirlman.yiplayer"
9 | minSdkVersion 15
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:24.0.0'
25 | compile 'com.android.support:design:24.0.0'
26 | compile 'com.squareup.retrofit2:retrofit:2.1.0'
27 | compile 'com.squareup.retrofit2:converter-gson:2.1.0'
28 | compile ('com.squareup.retrofit2:converter-simplexml:2.1.0') {
29 | // if not exclude will cause build error
30 | exclude module: 'stax-api'
31 | exclude module: 'stax'
32 | exclude module: 'xpp3'
33 | }
34 | compile 'com.birbit:android-priority-jobqueue:2.0.0-alpha5'
35 | compile 'org.greenrobot:eventbus:3.0.0'
36 | compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
37 | compile 'com.android.support:recyclerview-v7:24.0.0'
38 | compile project(path: ':vlc')
39 | }
40 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
16 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/MyApplication.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer;
2 |
3 | import android.app.Application;
4 |
5 | import com.birbit.android.jobqueue.JobManager;
6 | import com.birbit.android.jobqueue.config.Configuration;
7 | import com.nostra13.universalimageloader.core.DisplayImageOptions;
8 | import com.nostra13.universalimageloader.core.ImageLoader;
9 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
10 |
11 | /**
12 | * Created by KB-Server on 2016/6/24.
13 | */
14 | public class MyApplication extends Application {
15 | private static MyApplication mMyApplication;
16 | private static JobManager mJobManager;
17 |
18 | @Override
19 | public void onCreate() {
20 | super.onCreate();
21 | mMyApplication = this;
22 |
23 | initImageLoader();
24 | }
25 |
26 | public static MyApplication getInstance() {
27 | return mMyApplication;
28 | }
29 |
30 | public static JobManager getJobManager() {
31 | if(mJobManager == null) {
32 | Configuration jobConfiguration = new Configuration.Builder(mMyApplication.getApplicationContext())
33 | .minConsumerCount(5)//always keep at least one consumer alive
34 | .maxConsumerCount(10)//up to 5 consumers at a time
35 | .loadFactor(5)//5 jobs per consumer
36 | //.consumerKeepAlive(120)//wait 2 minute
37 | .build();
38 |
39 | mJobManager = new JobManager(jobConfiguration);
40 | }
41 |
42 | return mJobManager;
43 | }
44 |
45 | private void initImageLoader() {
46 | DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
47 | // .cacheInMemory(true)
48 | // .cacheOnDisk(true)
49 | .build();
50 |
51 | ImageLoaderConfiguration imageLoaderConfiguration =
52 | new ImageLoaderConfiguration.Builder(getApplicationContext())
53 | .defaultDisplayImageOptions(defaultOptions)
54 | .build();
55 |
56 | ImageLoader.getInstance().init(imageLoaderConfiguration);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/core/OnlineQueryService.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.core;
2 |
3 | import com.shirlman.yiplayer.models.ICibaResponse;
4 | import com.shirlman.yiplayer.models.ShooterSubtitleDetailResponse;
5 | import com.shirlman.yiplayer.models.ShooterSubtitleResponse;
6 | import com.shirlman.yiplayer.models.YoudaoResponse;
7 |
8 | import java.util.Map;
9 |
10 | import retrofit2.Call;
11 | import retrofit2.http.Body;
12 | import retrofit2.http.GET;
13 | import retrofit2.http.Headers;
14 | import retrofit2.http.Path;
15 | import retrofit2.http.Query;
16 | import retrofit2.http.QueryMap;
17 |
18 | /**
19 | * Created by KB-Server on 2016/7/24.
20 | */
21 | public interface OnlineQueryService {
22 | @GET("http://fanyi.youdao.com/openapi.do")
23 | Call queryWordFromYoudao(@QueryMap Map filters);
24 |
25 | @GET("http://dict-co.iciba.com/api/dictionary.php")
26 | Call queryWordFromICiba(@QueryMap Map filters);
27 |
28 | @GET("http://api.assrt.net/v1/sub/search")
29 | Call querySubtitleFromShooter(@QueryMap Map filters);
30 |
31 | @GET("http://api.assrt.net/v1/sub/detail")
32 | Call getSubtitleDetailFromShooter(@QueryMap Map filters);
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/events/DictionaryEvent.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.events;
2 |
3 | /**
4 | * Created by KB-Server on 2016/7/24.
5 | */
6 | public class DictionaryEvent {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/events/VideoEvents.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.events;
2 |
3 | import com.shirlman.yiplayer.models.VideoGroup;
4 | import com.shirlman.yiplayer.models.VideoInfo;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by KB-Server on 2016/6/24.
10 | */
11 | public class VideoEvents {
12 | public static class OnLocalVideoListGot {
13 | private List videoGroupList;
14 |
15 | public OnLocalVideoListGot(List videoGroupList) {
16 | this.videoGroupList = videoGroupList;
17 | }
18 |
19 | public List getVideoGroupList() {
20 | return videoGroupList;
21 | }
22 | }
23 |
24 | public static class OpenVideoGroup {
25 | private VideoGroup videoGroup;
26 |
27 | public OpenVideoGroup(VideoGroup videoGroup) {
28 | this.videoGroup = videoGroup;
29 | }
30 |
31 | public VideoGroup getVideoGroup() {
32 | return videoGroup;
33 | }
34 | }
35 |
36 | public static class PlayLocalVideo {
37 | private VideoInfo videoInfo;
38 |
39 | public PlayLocalVideo(VideoInfo videoInfo) {
40 | this.videoInfo = videoInfo;
41 | }
42 |
43 | public VideoInfo getVideoInfo() {
44 | return videoInfo;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/jobs/GetLocalVideoListJob.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.jobs;
2 |
3 | import android.database.Cursor;
4 | import android.provider.MediaStore;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 |
8 | import com.birbit.android.jobqueue.Job;
9 | import com.birbit.android.jobqueue.Params;
10 | import com.birbit.android.jobqueue.RetryConstraint;
11 | import com.shirlman.yiplayer.MyApplication;
12 | import com.shirlman.yiplayer.events.VideoEvents;
13 | import com.shirlman.yiplayer.models.VideoGroup;
14 | import com.shirlman.yiplayer.models.VideoInfo;
15 |
16 | import org.greenrobot.eventbus.EventBus;
17 |
18 | import java.util.ArrayList;
19 | import java.util.HashMap;
20 | import java.util.List;
21 |
22 | /**
23 | * Created by KB-Server on 2016/6/24.
24 | */
25 | public class GetLocalVideoListJob extends Job {
26 | public GetLocalVideoListJob() {
27 | super(new Params(JobPriority.HIGH).requireNetwork());
28 | }
29 |
30 | @Override
31 | public void onAdded() {
32 |
33 | }
34 |
35 | @Override
36 | public void onRun() throws Throwable {
37 | HashMap videoGroupHashMap = new HashMap<>();
38 |
39 | String[] thumbColumns = {
40 | MediaStore.Video.Thumbnails.DATA,
41 | MediaStore.Video.Thumbnails.VIDEO_ID
42 | };
43 |
44 | String[] mediaColumns = {
45 | MediaStore.Video.Media._ID,
46 | MediaStore.Video.Media.DATA,
47 | MediaStore.Video.Media.TITLE,
48 | MediaStore.Video.Media.MIME_TYPE,
49 | MediaStore.Video.Media.DISPLAY_NAME,
50 | MediaStore.Video.Media.DURATION,
51 | MediaStore.Video.Media.SIZE,
52 | };
53 |
54 | Cursor cursor = MyApplication.getInstance().getContentResolver().query(
55 | MediaStore.Video.Media.EXTERNAL_CONTENT_URI, mediaColumns, null, null, null);
56 |
57 | if (cursor != null && cursor.moveToFirst()) {
58 | do {
59 | VideoInfo videoInfo = new VideoInfo();
60 |
61 | int mediaId = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media._ID));
62 |
63 | Cursor thumbCursor = MyApplication.getInstance().getContentResolver().query(
64 | MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI, thumbColumns,
65 | MediaStore.Video.Thumbnails.VIDEO_ID+ "=" + mediaId,
66 | null,
67 | null);
68 |
69 | if (thumbCursor != null && thumbCursor.moveToFirst()) {
70 | videoInfo.setThumbPath(thumbCursor.getString(thumbCursor.getColumnIndex(MediaStore.Video.Thumbnails.DATA)));
71 | }
72 |
73 | videoInfo.setTitle(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE)));
74 | videoInfo.setDisplayName(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)));
75 |
76 | int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION));
77 | videoInfo.setDuration(duration);
78 |
79 | videoInfo.setSize(cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)));
80 |
81 | String videoPath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
82 | videoInfo.setPath(videoPath);
83 |
84 | String videoFolderPath = videoPath.substring(0, videoPath.lastIndexOf("/"));
85 | videoInfo.setFolderPath(videoFolderPath);
86 |
87 | String videoGroupName = videoFolderPath.substring(videoFolderPath.lastIndexOf("/") + 1);
88 |
89 | if(!videoGroupHashMap.containsKey(videoGroupName)) {
90 | VideoGroup videoGroup = new VideoGroup();
91 | videoGroup.setGroupName(videoGroupName);
92 |
93 | List videoInfoList = new ArrayList<>();
94 | videoInfoList.add(videoInfo);
95 | videoGroup.setVideoInfoList(videoInfoList);
96 |
97 | videoGroupHashMap.put(videoGroupName, videoGroup);
98 | } else {
99 | videoGroupHashMap.get(videoGroupName).getVideoInfoList().add(videoInfo);
100 | }
101 | } while (cursor.moveToNext());
102 | }
103 |
104 | EventBus.getDefault().post(new VideoEvents.OnLocalVideoListGot(new ArrayList<>(videoGroupHashMap.values())));
105 | }
106 |
107 | @Override
108 | protected void onCancel(int cancelReason, @Nullable Throwable throwable) {
109 |
110 | }
111 |
112 | @Override
113 | protected RetryConstraint shouldReRunOnThrowable(@NonNull Throwable throwable, int runCount, int maxRunCount) {
114 | return null;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/jobs/JobPriority.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.jobs;
2 |
3 | /**
4 | * Created by KB-Server on 2016/6/24.
5 | */
6 | public class JobPriority {
7 | public static int LOW = 0;
8 | public static int MID = 500;
9 | public static int HIGH = 1000;
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/models/ICibaResponse.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.models;
2 |
3 | import org.simpleframework.xml.Attribute;
4 | import org.simpleframework.xml.Element;
5 | import org.simpleframework.xml.ElementList;
6 | import org.simpleframework.xml.Root;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Created by KB-Server on 2016/7/24.
12 | */
13 | @Root(name = "dict", strict = false)
14 | public class ICibaResponse {
15 | @Attribute(name = "num", required = false)
16 | private String num;
17 | @Attribute(name = "id", required = false)
18 | private String id;
19 | @Attribute(name = "name", required = false)
20 | private String name;
21 | @Element(name = "key")
22 | private String key;
23 | @ElementList(inline = true, entry="ps", required = false)
24 | private List ps;
25 | @ElementList(inline = true, entry="pron", required = false)
26 | private List pron;
27 | @ElementList(inline = true, entry="pos", required = false)
28 | private List pos;
29 | @ElementList(inline = true, entry="acceptation", required = false)
30 | private List acceptation;
31 | /**
32 | * orig : In ` I wish you were here', ` were'is in the subjunctive.
33 | * trans : 在Iwishyou were here一 句中, were 表达的是虚拟语气.
34 | */
35 | @ElementList(inline = true, entry="sent")
36 | private List sent;
37 |
38 | public String getNum() {
39 | return num;
40 | }
41 |
42 | public void setNum(String num) {
43 | this.num = num;
44 | }
45 |
46 | public String getId() {
47 | return id;
48 | }
49 |
50 | public void setId(String id) {
51 | this.id = id;
52 | }
53 |
54 | public String getName() {
55 | return name;
56 | }
57 |
58 | public void setName(String name) {
59 | this.name = name;
60 | }
61 |
62 | public String getKey() {
63 | return key;
64 | }
65 |
66 | public void setKey(String key) {
67 | this.key = key;
68 | }
69 |
70 | public List getPs() {
71 | return ps;
72 | }
73 |
74 | public void setPs(List ps) {
75 | this.ps = ps;
76 | }
77 |
78 | public List getPron() {
79 | return pron;
80 | }
81 |
82 | public void setPron(List pron) {
83 | this.pron = pron;
84 | }
85 |
86 | public List getPos() {
87 | return pos;
88 | }
89 |
90 | public void setPos(List pos) {
91 | this.pos = pos;
92 | }
93 |
94 | public List getAcceptation() {
95 | return acceptation;
96 | }
97 |
98 | public void setAcceptation(List acceptation) {
99 | this.acceptation = acceptation;
100 | }
101 |
102 | public List getSent() {
103 | return sent;
104 | }
105 |
106 | public void setSent(List sent) {
107 | this.sent = sent;
108 | }
109 |
110 | @Element(name = "sent")
111 | public static class SentBean {
112 | @Element(name = "orig")
113 | private String orig;
114 | @Element(name = "trans")
115 | private String trans;
116 |
117 | public String getOrig() {
118 | return orig;
119 | }
120 |
121 | public void setOrig(String orig) {
122 | this.orig = orig;
123 | }
124 |
125 | public String getTrans() {
126 | return trans;
127 | }
128 |
129 | public void setTrans(String trans) {
130 | this.trans = trans;
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/models/VideoGroup.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.models;
2 |
3 | import java.io.Serializable;
4 | import java.util.List;
5 |
6 | /**
7 | * Created by KB-Server on 2016/6/25.
8 | */
9 | public class VideoGroup implements Serializable {
10 | private List videoInfoList;
11 | private String groupName;
12 |
13 | public List getVideoInfoList() {
14 | return videoInfoList;
15 | }
16 |
17 | public void setVideoInfoList(List videoInfoList) {
18 | this.videoInfoList = videoInfoList;
19 | }
20 |
21 | public String getGroupName() {
22 | return groupName;
23 | }
24 |
25 | public void setGroupName(String groupName) {
26 | this.groupName = groupName;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/models/VideoInfo.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.models;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by KB-Server on 2016/6/23.
7 | */
8 | public class VideoInfo implements Serializable {
9 | private String title;
10 | private String path;
11 | private long size;
12 | private String thumbPath;
13 | private int duration;
14 | private String folderPath;
15 | private String displayName;
16 |
17 | public String getTitle() {
18 | return title;
19 | }
20 |
21 | public void setTitle(String title) {
22 | this.title = title;
23 | }
24 |
25 | public String getPath() {
26 | return path;
27 | }
28 |
29 | public void setPath(String path) {
30 | this.path = path;
31 | }
32 |
33 | public long getSize() {
34 | return size;
35 | }
36 |
37 | public void setSize(long size) {
38 | this.size = size;
39 | }
40 |
41 | public String getThumbPath() {
42 | return thumbPath;
43 | }
44 |
45 | public void setThumbPath(String thumbPath) {
46 | this.thumbPath = thumbPath;
47 | }
48 |
49 | public int getDuration() {
50 | return duration;
51 | }
52 |
53 | public void setDuration(int duration) {
54 | this.duration = duration;
55 | }
56 |
57 | public String getFolderPath() {
58 | return folderPath;
59 | }
60 |
61 | public void setFolderPath(String folderPath) {
62 | this.folderPath = folderPath;
63 | }
64 |
65 | public String getDisplayName() {
66 | return displayName;
67 | }
68 |
69 | public void setDisplayName(String displayName) {
70 | this.displayName = displayName;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/models/YoudaoResponse.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.models;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Created by KB-Server on 2016/7/24.
9 | */
10 | public class YoudaoResponse {
11 |
12 | /**
13 | * us-phonetic : 'pɝsənl
14 | * phonetic : 'pɜːs(ə)n(ə)l
15 | * uk-phonetic : 'pɜːs(ə)n(ə)l
16 | * explains : ["n. 人事消息栏;人称代名词","adj. 个人的;身体的;亲自的"]
17 | */
18 |
19 | private BasicBean basic;
20 | /**
21 | * translation : ["个人"]
22 | * basic : {"us-phonetic":"'pɝsənl","phonetic":"'pɜːs(ə)n(ə)l","uk-phonetic":"'pɜːs(ə)n(ə)l","explains":["n. 人事消息栏;人称代名词","adj. 个人的;身体的;亲自的"]}
23 | * query : personal
24 | * errorCode : 0
25 | * web : [{"value":["个人的","私人的","人身"],"key":"personal"},{"value":["个人所得","个人收入","个人所得"],"key":"Personal income"},{"value":["个人电脑","个人计算机","人计算机"],"key":"personal computer"}]
26 | */
27 |
28 | private String query;
29 | private int errorCode;
30 | private List translation;
31 | /**
32 | * value : ["个人的","私人的","人身"]
33 | * key : personal
34 | */
35 |
36 | private List web;
37 |
38 | public BasicBean getBasic() {
39 | return basic;
40 | }
41 |
42 | public void setBasic(BasicBean basic) {
43 | this.basic = basic;
44 | }
45 |
46 | public String getQuery() {
47 | return query;
48 | }
49 |
50 | public void setQuery(String query) {
51 | this.query = query;
52 | }
53 |
54 | public int getErrorCode() {
55 | return errorCode;
56 | }
57 |
58 | public void setErrorCode(int errorCode) {
59 | this.errorCode = errorCode;
60 | }
61 |
62 | public List getTranslation() {
63 | return translation;
64 | }
65 |
66 | public void setTranslation(List translation) {
67 | this.translation = translation;
68 | }
69 |
70 | public List getWeb() {
71 | return web;
72 | }
73 |
74 | public void setWeb(List web) {
75 | this.web = web;
76 | }
77 |
78 | public static class BasicBean {
79 | private List explains;
80 | @SerializedName("us-phonetic")
81 | private String us_phonetic;
82 | private String phonetic;
83 | @SerializedName("uk-phonetic")
84 | private String uk_phonetic;
85 |
86 | public List getExplains() {
87 | return explains;
88 | }
89 |
90 | public void setExplains(List explains) {
91 | this.explains = explains;
92 | }
93 |
94 | public String getUs_phonetic() {
95 | return us_phonetic;
96 | }
97 |
98 | public void setUs_phonetic(String us_phonetic) {
99 | this.us_phonetic = us_phonetic;
100 | }
101 |
102 | public String getPhonetic() {
103 | return phonetic;
104 | }
105 |
106 | public void setPhonetic(String phonetic) {
107 | this.phonetic = phonetic;
108 | }
109 |
110 | public String getUk_phonetic() {
111 | return uk_phonetic;
112 | }
113 |
114 | public void setUk_phonetic(String uk_phonetic) {
115 | this.uk_phonetic = uk_phonetic;
116 | }
117 | }
118 |
119 | public static class WebBean {
120 | private String key;
121 | private List value;
122 |
123 | public String getKey() {
124 | return key;
125 | }
126 |
127 | public void setKey(String key) {
128 | this.key = key;
129 | }
130 |
131 | public List getValue() {
132 | return value;
133 | }
134 |
135 | public void setValue(List value) {
136 | this.value = value;
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/ui/activities/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.ui.activities;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.app.FragmentTransaction;
7 | import android.support.design.widget.NavigationView;
8 | import android.support.v4.view.GravityCompat;
9 | import android.support.v4.widget.DrawerLayout;
10 | import android.support.v7.app.ActionBarDrawerToggle;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.support.v7.widget.Toolbar;
13 | import android.view.Menu;
14 | import android.view.MenuItem;
15 |
16 | import com.shirlman.yiplayer.R;
17 | import com.shirlman.yiplayer.events.VideoEvents;
18 | import com.shirlman.yiplayer.models.VideoGroup;
19 | import com.shirlman.yiplayer.models.VideoInfo;
20 | import com.shirlman.yiplayer.ui.fragments.LocalVideoFragment;
21 | import com.shirlman.yiplayer.ui.fragments.LocalVideoGroupFragment;
22 |
23 | import org.greenrobot.eventbus.EventBus;
24 | import org.greenrobot.eventbus.Subscribe;
25 | import org.greenrobot.eventbus.ThreadMode;
26 |
27 | import java.util.List;
28 |
29 | public class MainActivity extends AppCompatActivity
30 | implements NavigationView.OnNavigationItemSelectedListener {
31 |
32 | private final String TAG = MainActivity.class.getSimpleName();
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 |
38 | EventBus.getDefault().register(this);
39 |
40 | setContentView(R.layout.activity_main);
41 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
42 | setSupportActionBar(toolbar);
43 |
44 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
45 | ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
46 | this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
47 | drawer.setDrawerListener(toggle);
48 | toggle.syncState();
49 |
50 | NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
51 | navigationView.setNavigationItemSelectedListener(this);
52 |
53 | getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new LocalVideoGroupFragment()).commit();
54 | }
55 |
56 | @Override
57 | public void onBackPressed() {
58 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
59 | if (drawer.isDrawerOpen(GravityCompat.START)) {
60 | drawer.closeDrawer(GravityCompat.START);
61 | } else {
62 | super.onBackPressed();
63 | }
64 | }
65 |
66 | @Override
67 | public boolean onCreateOptionsMenu(Menu menu) {
68 | // Inflate the menu; this adds items to the action bar if it is present.
69 | getMenuInflater().inflate(R.menu.main, menu);
70 | return true;
71 | }
72 |
73 | @Override
74 | public boolean onOptionsItemSelected(MenuItem item) {
75 | // Handle action bar item clicks here. The action bar will
76 | // automatically handle clicks on the Home/Up button, so long
77 | // as you specify a parent activity in AndroidManifest.xml.
78 | int id = item.getItemId();
79 |
80 | //noinspection SimplifiableIfStatement
81 | if (id == R.id.action_settings) {
82 | return true;
83 | }
84 |
85 | return super.onOptionsItemSelected(item);
86 | }
87 |
88 | @SuppressWarnings("StatementWithEmptyBody")
89 | @Override
90 | public boolean onNavigationItemSelected(MenuItem item) {
91 | // Handle navigation view item clicks here.
92 | int id = item.getItemId();
93 |
94 | if (id == R.id.nav_camera) {
95 | // Handle the camera action
96 | } else if (id == R.id.nav_gallery) {
97 |
98 | } else if (id == R.id.nav_slideshow) {
99 |
100 | } else if (id == R.id.nav_manage) {
101 |
102 | } else if (id == R.id.nav_share) {
103 |
104 | } else if (id == R.id.nav_send) {
105 |
106 | }
107 |
108 | DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
109 | drawer.closeDrawer(GravityCompat.START);
110 | return true;
111 | }
112 |
113 | @Override
114 | protected void onDestroy() {
115 | super.onDestroy();
116 |
117 | EventBus.getDefault().unregister(this);
118 | }
119 |
120 | private Fragment getCurrentFragment() {
121 | Fragment currentFragment = null;
122 |
123 | List fragmentList = getSupportFragmentManager().getFragments();
124 |
125 | if(fragmentList != null) {
126 | for (Fragment fragment : fragmentList) {
127 | if (fragment != null && fragment.isVisible()) {
128 | currentFragment = fragment;
129 |
130 | break;
131 | }
132 | }
133 | }
134 |
135 | return currentFragment;
136 | }
137 |
138 | @Subscribe(threadMode = ThreadMode.MAIN)
139 | public void onEventMainThread(VideoEvents.OpenVideoGroup event) {
140 | LocalVideoFragment localVideoFragment = new LocalVideoFragment();
141 | Bundle bundle = new Bundle();
142 | bundle.putSerializable(VideoGroup.class.getSimpleName(), event.getVideoGroup());
143 | localVideoFragment.setArguments(bundle);
144 | getSupportFragmentManager()
145 | .beginTransaction()
146 | .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
147 | .hide(getCurrentFragment())
148 | .add(R.id.fragment_container, localVideoFragment)
149 | .addToBackStack(null)
150 | .commit();
151 | }
152 |
153 | @Subscribe(threadMode = ThreadMode.MAIN)
154 | public void onEventMainThread(VideoEvents.PlayLocalVideo event) {
155 | Intent intent = new Intent(MainActivity.this, VideoActivity.class);
156 | intent.putExtra(VideoInfo.class.getSimpleName(), event.getVideoInfo());
157 | startActivity(intent);
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/ui/adapters/LocalVideoAdapter.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.ui.adapters;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageButton;
9 | import android.widget.TextView;
10 |
11 | import com.nostra13.universalimageloader.core.ImageLoader;
12 | import com.shirlman.yiplayer.R;
13 | import com.shirlman.yiplayer.events.VideoEvents;
14 | import com.shirlman.yiplayer.models.VideoGroup;
15 | import com.shirlman.yiplayer.models.VideoInfo;
16 | import com.shirlman.yiplayer.util.FileUtils;
17 | import com.shirlman.yiplayer.util.StringUtils;
18 |
19 | import org.greenrobot.eventbus.EventBus;
20 |
21 | /**
22 | * Created by KB-Server on 2016/6/25.
23 | */
24 | public class LocalVideoAdapter extends RecyclerView.Adapter {
25 | private VideoGroup mVideoGroup;
26 | private LayoutInflater mLayoutInflater;
27 |
28 | public LocalVideoAdapter(Context context, VideoGroup videoGroup) {
29 | mVideoGroup = videoGroup;
30 | mLayoutInflater = LayoutInflater.from(context);
31 | }
32 |
33 | @Override
34 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
35 | View rootView = mLayoutInflater.inflate(R.layout.local_video_item, parent, false);
36 |
37 | return new ViewHolder(rootView);
38 | }
39 |
40 | @Override
41 | public void onBindViewHolder(ViewHolder holder, int position) {
42 | final VideoInfo videoInfo = mVideoGroup.getVideoInfoList().get(position);
43 |
44 | ImageLoader.getInstance().displayImage("file://" + videoInfo.getThumbPath(), holder.videoThumb);
45 |
46 | holder.videoTitle.setText(videoInfo.getTitle());
47 | holder.videoDuration.setText(StringUtils.getTimeDisplayString(videoInfo.getDuration()));
48 | holder.videoSize.setText(FileUtils.showFileSize(videoInfo.getSize()));
49 |
50 | holder.videoThumb.setOnClickListener(new View.OnClickListener() {
51 | @Override
52 | public void onClick(View v) {
53 | EventBus.getDefault().post(new VideoEvents.PlayLocalVideo(videoInfo));
54 | }
55 | });
56 | }
57 |
58 | @Override
59 | public int getItemCount() {
60 | return mVideoGroup.getVideoInfoList().size();
61 | }
62 |
63 | class ViewHolder extends RecyclerView.ViewHolder {
64 | public ImageButton videoThumb;
65 | public TextView videoTitle;
66 | public TextView videoSize;
67 | public TextView videoDuration;
68 |
69 | public ViewHolder(View itemView) {
70 | super(itemView);
71 |
72 | videoThumb = (ImageButton) itemView.findViewById(R.id.local_video_thumb);
73 | videoTitle = (TextView) itemView.findViewById(R.id.local_video_title);
74 | videoSize = (TextView) itemView.findViewById(R.id.local_video_info);
75 | videoDuration = (TextView) itemView.findViewById(R.id.local_video_duration);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/ui/adapters/LocalVideoGroupAdapter.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.ui.adapters;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageButton;
9 | import android.widget.TextView;
10 |
11 | import com.nostra13.universalimageloader.core.ImageLoader;
12 | import com.shirlman.yiplayer.R;
13 | import com.shirlman.yiplayer.events.VideoEvents;
14 | import com.shirlman.yiplayer.models.VideoGroup;
15 | import com.shirlman.yiplayer.models.VideoInfo;
16 | import com.shirlman.yiplayer.util.StringUtils;
17 |
18 | import org.greenrobot.eventbus.EventBus;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * Created by KB-Server on 2016/6/25.
24 | */
25 | public class LocalVideoGroupAdapter extends RecyclerView.Adapter {
26 | private List mVideoGroupList;
27 | private LayoutInflater mLayoutInflater;
28 |
29 | public LocalVideoGroupAdapter(Context context, List videoGroupList) {
30 | mVideoGroupList = videoGroupList;
31 | mLayoutInflater = LayoutInflater.from(context);
32 | }
33 |
34 | @Override
35 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
36 | View rootView = mLayoutInflater.inflate(R.layout.local_video_item, parent, false);
37 |
38 | return new ViewHolder(rootView);
39 | }
40 |
41 | @Override
42 | public void onBindViewHolder(ViewHolder holder, int position) {
43 | final VideoGroup videoGroup = mVideoGroupList.get(position);
44 | VideoInfo firstVideoInfo = videoGroup.getVideoInfoList().get(0);
45 |
46 | ImageLoader.getInstance().displayImage("file://" + firstVideoInfo.getThumbPath(), holder.firstVideoThumb);
47 |
48 | holder.firstVideoDuration.setText(StringUtils.getTimeDisplayString(firstVideoInfo.getDuration()));
49 | holder.videoGroupName.setText(videoGroup.getGroupName());
50 |
51 | String videoCount = String.format(
52 | holder.itemView.getResources().getString(R.string.local_video_count),
53 | videoGroup.getVideoInfoList().size());
54 | holder.videoCount.setText(videoCount);
55 |
56 | holder.firstVideoThumb.setOnClickListener(new View.OnClickListener() {
57 | @Override
58 | public void onClick(View v) {
59 | EventBus.getDefault().post(new VideoEvents.OpenVideoGroup(videoGroup));
60 | }
61 | });
62 | }
63 |
64 | @Override
65 | public int getItemCount() {
66 | return mVideoGroupList.size();
67 | }
68 |
69 | class ViewHolder extends RecyclerView.ViewHolder {
70 | public ImageButton firstVideoThumb;
71 | public TextView videoGroupName;
72 | public TextView videoCount;
73 | public TextView firstVideoDuration;
74 |
75 | public ViewHolder(View itemView) {
76 | super(itemView);
77 |
78 | firstVideoThumb = (ImageButton) itemView.findViewById(R.id.local_video_thumb);
79 | videoGroupName = (TextView) itemView.findViewById(R.id.local_video_title);
80 | videoCount = (TextView) itemView.findViewById(R.id.local_video_info);
81 | firstVideoDuration = (TextView) itemView.findViewById(R.id.local_video_duration);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/ui/adapters/OnlineSubtitleAdapter.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.ui.adapters;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.util.Log;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.Button;
10 | import android.widget.TextView;
11 |
12 | import com.shirlman.yiplayer.R;
13 | import com.shirlman.yiplayer.core.OnlineQueryService;
14 | import com.shirlman.yiplayer.models.ShooterSubtitleDetailResponse;
15 | import com.shirlman.yiplayer.models.ShooterSubtitleResponse;
16 | import com.shirlman.yiplayer.util.StringUtils;
17 |
18 | import java.util.LinkedHashMap;
19 | import java.util.List;
20 | import java.util.Map;
21 |
22 | import retrofit2.Call;
23 | import retrofit2.Callback;
24 | import retrofit2.Response;
25 | import retrofit2.Retrofit;
26 | import retrofit2.converter.gson.GsonConverterFactory;
27 |
28 | /**
29 | * Created by KB-Server on 2016/7/24.
30 | */
31 | public class OnlineSubtitleAdapter extends RecyclerView.Adapter {
32 | private LayoutInflater mLayoutInflater;
33 | private List mSubtitleList;
34 |
35 | private class OnDownloadClickListener implements View.OnClickListener {
36 | private String mSubtitleId;
37 |
38 | OnDownloadClickListener(String subtitleId) {
39 | mSubtitleId = subtitleId;
40 | }
41 |
42 | @Override
43 | public void onClick(View view) {
44 | String shooterBaseUrl = "http://api.assrt.net/v1/sub/detail/";
45 | String shooterToken = "5fjG5Znw0KgfqL1QmDffB3A7qzaGAXzF";
46 |
47 | Map searchFilters = new LinkedHashMap<>();
48 | searchFilters.put("token", shooterToken);
49 | searchFilters.put("id", mSubtitleId);
50 |
51 | Retrofit retrofit = new Retrofit.Builder()
52 | .baseUrl(shooterBaseUrl)
53 | .addConverterFactory(GsonConverterFactory.create())
54 | .build();
55 |
56 | OnlineQueryService service = retrofit.create(OnlineQueryService.class);
57 | service.getSubtitleDetailFromShooter(searchFilters).enqueue(new Callback() {
58 | @Override
59 | public void onResponse(Call call, Response response) {
60 | if(response.isSuccessful() && response.body() != null && response.body().getSub() != null
61 | && response.body().getSub().getSubs() != null && response.body().getSub().getSubs().size() > 0) {
62 | String downloadUrl = response.body().getSub().getSubs().get(0).getUrl();
63 | }
64 | }
65 |
66 | @Override
67 | public void onFailure(Call call, Throwable t) {
68 | Log.e("OnDownloadClickListener", "querySubtitleFromShooter.onFailure: ", t);
69 | }
70 | });
71 | }
72 | }
73 |
74 | public OnlineSubtitleAdapter(Context context, List subtitleList) {
75 | mLayoutInflater = LayoutInflater.from(context);
76 | mSubtitleList = subtitleList;
77 | }
78 |
79 | @Override
80 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
81 | View rootView = mLayoutInflater.inflate(R.layout.online_subtitle_item, parent, false);
82 |
83 | return new ViewHolder(rootView);
84 | }
85 |
86 | @Override
87 | public void onBindViewHolder(ViewHolder holder, int position) {
88 | ShooterSubtitleResponse.SubBean.SubsBean subtitle = mSubtitleList.get(position);
89 |
90 | String title = StringUtils.nullOrEmpty(subtitle.getNative_name())
91 | ? subtitle.getVideoname() : subtitle.getNative_name();
92 | String language = subtitle.getLang() == null ? "未知" : subtitle.getLang().getDesc();
93 |
94 | holder.title.setText(title);
95 | holder.voteScore.setText(subtitle.getVote_score());
96 | holder.language.setText(language);
97 | holder.download.setOnClickListener(new OnDownloadClickListener(subtitle.getId()));
98 | }
99 |
100 | @Override
101 | public int getItemCount() {
102 | return mSubtitleList.size();
103 | }
104 |
105 | class ViewHolder extends RecyclerView.ViewHolder {
106 | public TextView title;
107 | public TextView language;
108 | public TextView voteScore;
109 | private Button download;
110 |
111 | public ViewHolder(View itemView) {
112 | super(itemView);
113 |
114 | title = (TextView) itemView.findViewById(R.id.online_subtitle_title);
115 | language = (TextView) itemView.findViewById(R.id.online_subtitle_language);
116 | voteScore = (TextView) itemView.findViewById(R.id.online_subtitle_vote_score);
117 | download = (Button) itemView.findViewById(R.id.online_subtitle_download);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/ui/fragments/LocalVideoFragment.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.ui.fragments;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v7.widget.GridLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.shirlman.yiplayer.R;
13 | import com.shirlman.yiplayer.models.VideoGroup;
14 | import com.shirlman.yiplayer.ui.adapters.LocalVideoAdapter;
15 |
16 | /**
17 | * Created by KB-Server on 2016/6/24.
18 | */
19 | public class LocalVideoFragment extends Fragment {
20 | private View mRootView;
21 | private RecyclerView mRecyclerView;
22 |
23 | @Nullable
24 | @Override
25 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
26 | super.onCreateView(inflater, container, savedInstanceState);
27 |
28 | VideoGroup videoGroup = (VideoGroup) getArguments().getSerializable(VideoGroup.class.getSimpleName());
29 |
30 | mRootView = inflater.inflate(R.layout.local_video_fragment, container, false);
31 |
32 | GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2);
33 | mRecyclerView = (RecyclerView) mRootView.findViewById(R.id.local_video_recycler_view);
34 | mRecyclerView.setLayoutManager(gridLayoutManager);
35 | mRecyclerView.setNestedScrollingEnabled(false);
36 |
37 | mRecyclerView.setAdapter(new LocalVideoAdapter(getActivity(), videoGroup));
38 |
39 | return mRootView;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/ui/fragments/LocalVideoGroupFragment.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.ui.fragments;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v7.widget.GridLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.shirlman.yiplayer.MyApplication;
13 | import com.shirlman.yiplayer.R;
14 | import com.shirlman.yiplayer.events.VideoEvents;
15 | import com.shirlman.yiplayer.jobs.GetLocalVideoListJob;
16 | import com.shirlman.yiplayer.models.VideoGroup;
17 | import com.shirlman.yiplayer.ui.adapters.LocalVideoGroupAdapter;
18 |
19 | import org.greenrobot.eventbus.EventBus;
20 | import org.greenrobot.eventbus.Subscribe;
21 | import org.greenrobot.eventbus.ThreadMode;
22 |
23 | import java.util.List;
24 |
25 | /**
26 | * Created by KB-Server on 2016/6/25.
27 | */
28 | public class LocalVideoGroupFragment extends Fragment{
29 | private View mRootView;
30 | private RecyclerView mRecyclerView;
31 |
32 | @Nullable
33 | @Override
34 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
35 | super.onCreateView(inflater, container, savedInstanceState);
36 |
37 | EventBus.getDefault().register(this);
38 |
39 | MyApplication.getJobManager().addJobInBackground(new GetLocalVideoListJob());
40 |
41 | mRootView = inflater.inflate(R.layout.local_video_fragment, container, false);
42 |
43 | GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2);
44 | mRecyclerView = (RecyclerView) mRootView.findViewById(R.id.local_video_recycler_view);
45 | mRecyclerView.setLayoutManager(gridLayoutManager);
46 | mRecyclerView.setNestedScrollingEnabled(false);
47 |
48 | return mRootView;
49 | }
50 |
51 | @Override
52 | public void onDestroyView() {
53 | super.onDestroyView();
54 |
55 | EventBus.getDefault().unregister(this);
56 | }
57 |
58 | @Subscribe(threadMode = ThreadMode.MAIN)
59 | public void onEventMainThread(VideoEvents.OnLocalVideoListGot event) {
60 | List videoGroupList = event.getVideoGroupList();
61 |
62 | if(videoGroupList.size() > 0) {
63 | mRecyclerView.setAdapter(new LocalVideoGroupAdapter(getActivity(), videoGroupList));
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/ui/widgets/VideoController.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.ui.widgets;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 |
6 |
7 | /**
8 | * Created by KB-Server on 2016/6/25.
9 | */
10 | public class VideoController {
11 | private Context mContext;
12 | private View mRootView;
13 | private boolean isLocked;
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/shirlman/yiplayer/util/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.shirlman.yiplayer.util;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.Locale;
7 | import java.util.TimeZone;
8 | import java.util.regex.Matcher;
9 | import java.util.regex.Pattern;
10 |
11 | public class StringUtils {
12 | private static final String TAG = StringUtils.class.getSimpleName();
13 |
14 | public static boolean notNullNorEmpty(String str) {
15 | return str != null && !str.isEmpty();
16 | }
17 |
18 | public static boolean nullOrEmpty(String str) {
19 | return str == null || str.isEmpty();
20 | }
21 |
22 | public static String join(List list, String separator) {
23 | if(list == null || list.size() == 0) {
24 | return "";
25 | }
26 |
27 | StringBuilder stringBuilder = new StringBuilder();
28 |
29 | for (int i = 0; i < list.size(); i++) {
30 | stringBuilder.append(list.get(i));
31 |
32 | if (i < list.size() - 1) {
33 | stringBuilder.append(separator);
34 | }
35 | }
36 |
37 | return stringBuilder.toString();
38 | }
39 |
40 | public static String join(final ArrayList array, final String separator) {
41 | StringBuffer result = new StringBuffer();
42 |
43 | if (array != null && array.size() > 0) {
44 | for (String str : array) {
45 | result.append(str);
46 | result.append(separator);
47 | }
48 |
49 | result.delete(result.length() - 1, result.length());
50 | }
51 |
52 | return result.toString();
53 | }
54 |
55 | public static String join(final String[] array, final String separator) {
56 | if(array == null || array.length == 0) {
57 | return "";
58 | }
59 |
60 | StringBuilder stringBuilder = new StringBuilder();
61 |
62 | for (int i = 0; i < array.length; i++) {
63 | stringBuilder.append(array[i]);
64 |
65 | if (i < array.length - 1) {
66 | stringBuilder.append(separator);
67 | }
68 | }
69 |
70 | return stringBuilder.toString();
71 | }
72 |
73 | public static String getTimeDisplayString(long milliSeconds) {
74 | String timeFormat = milliSeconds > 60 * 60 * 1000 ? "HH:mm:ss" : "mm:ss";
75 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeFormat, Locale.ENGLISH);
76 | simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));
77 | return simpleDateFormat.format(milliSeconds);
78 | }
79 |
80 | public static boolean isChineseChar(String str) {
81 | boolean temp = false;
82 | Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
83 | Matcher m = p.matcher(str);
84 |
85 | if (m.find()) {
86 | temp = true;
87 | }
88 |
89 | return temp;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_camera.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_gallery.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_manage.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_send.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_share.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_slideshow.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/video_controller_lock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/drawable-v21/video_controller_lock.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/video_controller_next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/drawable-v21/video_controller_next.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/video_controller_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/drawable-v21/video_controller_pause.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/video_controller_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/drawable-v21/video_controller_play.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/video_controller_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/drawable-v21/video_controller_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/local_video_info_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/seek_bar_background_fill.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
13 |
14 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/seek_bar_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
13 |
14 |
15 |
16 | -
17 |
18 |
19 |
20 |
27 |
28 |
29 |
30 |
31 | -
32 |
33 |
34 |
35 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/seek_bar_progress_fill.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/video_controller_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/video_lock_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/local_video_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
19 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/local_video_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
16 |
22 |
32 |
33 |
43 |
44 |
45 |
46 |
54 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
20 |
21 |
27 |
28 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/online_subtitle.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
13 |
20 |
21 |
25 |
34 |
39 |
40 |
41 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/online_subtitle_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
19 |
20 |
24 |
30 |
37 |
38 |
39 |
43 |
49 |
56 |
57 |
58 |
59 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/video_controller.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
20 |
21 |
36 |
37 |
41 |
52 |
61 |
62 |
71 |
72 |
73 |
79 |
87 |
88 |
89 |
97 |
107 |
108 |
116 |
117 |
118 |
127 |
135 |
136 |
145 |
146 |
152 |
156 |
165 |
166 |
176 |
177 |
182 |
183 |
184 |
195 |
196 |
197 |
198 |
199 |
203 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/video_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
17 |
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
13 |
17 |
21 |
22 |
23 | -
24 |
25 |
29 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #E4E5E5
7 | #FFFFFF
8 | #000000
9 | #00000000
10 | #D0232323
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 160dp
5 |
6 | 16dp
7 | 16dp
8 | 16dp
9 | 12sp
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 | - @android:drawable/ic_menu_camera
3 | - @android:drawable/ic_menu_gallery
4 | - @android:drawable/ic_menu_slideshow
5 | - @android:drawable/ic_menu_manage
6 | - @android:drawable/ic_menu_share
7 | - @android:drawable/ic_menu_send
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | YiPlayer
3 |
4 | Open navigation drawer
5 | Close navigation drawer
6 |
7 | Settings
8 | %1$d个视频
9 |
10 | 未查询到单词:%1$s
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.1.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Sun Jun 26 16:55:28 CST 2016
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/images/com.shirlman.yiplayer_main_activity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/images/com.shirlman.yiplayer_main_activity.png
--------------------------------------------------------------------------------
/images/com.shirlman.yiplayer_video_controller.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/images/com.shirlman.yiplayer_video_controller.png
--------------------------------------------------------------------------------
/images/微信图片_20170522195813.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/images/微信图片_20170522195813.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':vlc'
2 |
--------------------------------------------------------------------------------
/vlc/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/vlc/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "24.0.0"
6 |
7 | defaultConfig {
8 | minSdkVersion 15
9 | targetSdkVersion 24
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | testCompile 'junit:junit:4.12'
24 | compile 'com.android.support:appcompat-v7:24.0.0'
25 | }
26 |
--------------------------------------------------------------------------------
/vlc/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/vlc/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/AWindowNativeHandler.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * public class AWindowNativeHandler.java
3 | *****************************************************************************
4 | * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc;
22 |
23 | import android.view.Surface;
24 |
25 | public abstract class AWindowNativeHandler {
26 | /**
27 | * Callback called from {@link IVLCVout#sendMouseEvent}.
28 | *
29 | * @param nativeHandle handle passed by {@link #setCallback}.
30 | * @param action see ACTION_* in {@link android.view.MotionEvent}.
31 | * @param button see BUTTON_* in {@link android.view.MotionEvent}.
32 | * @param x x coordinate.
33 | * @param y y coordinate.
34 | */
35 | protected abstract void nativeOnMouseEvent(long nativeHandle, int action, int button, int x, int y);
36 |
37 | /**
38 | * Callback called from {@link IVLCVout#setWindowSize}.
39 | *
40 | * @param nativeHandle handle passed by {@link #setCallback}.
41 | * @param width width of the window.
42 | * @param height height of the window.
43 | */
44 | protected abstract void nativeOnWindowSize(long nativeHandle, int width, int height);
45 |
46 | /**
47 | * Get the valid Video surface.
48 | *
49 | * @return can be null if the surface was destroyed.
50 | */
51 | @SuppressWarnings("unused") /* Used by JNI */
52 | protected abstract Surface getVideoSurface();
53 |
54 | /**
55 | * Get the valid Subtitles surface.
56 | *
57 | * @return can be null if the surface was destroyed.
58 | */
59 | @SuppressWarnings("unused") /* Used by JNI */
60 | protected abstract Surface getSubtitlesSurface();
61 |
62 | /**
63 | * Set a callback in order to receive {@link #nativeOnMouseEvent} and {@link #nativeOnWindowSize} events.
64 | *
65 | * @param nativeHandle native Handle passed by {@link #nativeOnMouseEvent} and {@link #nativeOnWindowSize}
66 | * @return true if callback was successfully registered
67 | */
68 | @SuppressWarnings("unused") /* Used by JNI */
69 | protected abstract boolean setCallback(long nativeHandle);
70 |
71 | /**
72 | * This method is only used for ICS and before since ANativeWindow_setBuffersGeometry doesn't work before.
73 | * It is synchronous.
74 | *
75 | * @param surface surface returned by getVideoSurface or getSubtitlesSurface
76 | * @param width surface width
77 | * @param height surface height
78 | * @param format color format (or PixelFormat)
79 | * @return true if buffersGeometry were set (only before ICS)
80 | */
81 | @SuppressWarnings("unused") /* Used by JNI */
82 | protected abstract boolean setBuffersGeometry(Surface surface, int width, int height, int format);
83 |
84 | /**
85 | * Set the window Layout.
86 | * This call will result of {@link IVLCVout.Callback#onNewLayout} being called from the main thread.
87 | *
88 | * @param width Frame width
89 | * @param height Frame height
90 | * @param visibleWidth Visible frame width
91 | * @param visibleHeight Visible frame height
92 | * @param sarNum Surface aspect ratio numerator
93 | * @param sarDen Surface aspect ratio denominator
94 | */
95 | @SuppressWarnings("unused") /* Used by JNI */
96 | protected abstract void setWindowLayout(int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen);
97 |
98 | /**
99 | * TODO: temporary method, will be removed when VLC can handle decoder fallback
100 | * This call will result of {@link IVLCVout.Callback#onHardwareAccelerationError} being called from the main thread.
101 | *
102 | */
103 | @SuppressWarnings("unused") /* Used by JNI */
104 | protected abstract void sendHardwareAccelerationError();
105 | }
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/IVLCVout.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * public class IVLCVout.java
3 | *****************************************************************************
4 | * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc;
22 |
23 | import android.annotation.TargetApi;
24 | import android.graphics.SurfaceTexture;
25 | import android.os.Build;
26 | import android.support.annotation.MainThread;
27 | import android.view.Surface;
28 | import android.view.SurfaceHolder;
29 | import android.view.SurfaceView;
30 | import android.view.TextureView;
31 |
32 | @SuppressWarnings("unused")
33 | public interface IVLCVout {
34 | interface Callback {
35 | /**
36 | * This callback is called when the native vout call request a new Layout.
37 | *
38 | * @param vlcVout vlcVout
39 | * @param width Frame width
40 | * @param height Frame height
41 | * @param visibleWidth Visible frame width
42 | * @param visibleHeight Visible frame height
43 | * @param sarNum Surface aspect ratio numerator
44 | * @param sarDen Surface aspect ratio denominator
45 | */
46 | @MainThread
47 | void onNewLayout(IVLCVout vlcVout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen);
48 |
49 | /**
50 | * This callback is called when surfaces are created.
51 | */
52 | @MainThread
53 | void onSurfacesCreated(IVLCVout vlcVout);
54 |
55 | /**
56 | * This callback is called when surfaces are destroyed.
57 | */
58 | @MainThread
59 | void onSurfacesDestroyed(IVLCVout vlcVout);
60 |
61 | /**
62 | * TODO: temporary method, will be removed when VLC can handle decoder fallback
63 | */
64 | @MainThread
65 | void onHardwareAccelerationError(IVLCVout vlcVout);
66 | }
67 |
68 | /**
69 | * Set a surfaceView used for video out.
70 | * @see #attachViews()
71 | */
72 | @MainThread
73 | void setVideoView(SurfaceView videoSurfaceView);
74 |
75 | /**
76 | * Set a TextureView used for video out.
77 | * @see #attachViews()
78 | */
79 | @MainThread
80 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
81 | void setVideoView(TextureView videoTextureView);
82 |
83 | /**
84 | * Set a surface used for video out.
85 | * @param videoSurface if surfaceHolder is null, this surface must be valid and attached.
86 | * @param surfaceHolder optional, used to configure buffers geometry before Android ICS
87 | * and to get notified when surface is destroyed.
88 | * @see #attachViews()
89 | */
90 | @MainThread
91 | void setVideoSurface(Surface videoSurface, SurfaceHolder surfaceHolder);
92 |
93 | /**
94 | * Set a SurfaceTexture used for video out.
95 | * @param videoSurfaceTexture this surface must be valid and attached.
96 | * @see #attachViews()
97 | */
98 | @MainThread
99 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
100 | void setVideoSurface(SurfaceTexture videoSurfaceTexture);
101 |
102 | /**
103 | * Set a surfaceView used for subtitles out.
104 | * @see #attachViews()
105 | */
106 | @MainThread
107 | void setSubtitlesView(SurfaceView subtitlesSurfaceView);
108 |
109 | /**
110 | * Set a TextureView used for subtitles out.
111 | * @see #attachViews()
112 | */
113 | @MainThread
114 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
115 | void setSubtitlesView(TextureView subtitlesTextureView);
116 |
117 | /**
118 | * Set a surface used for subtitles out.
119 | * @param subtitlesSurface if surfaceHolder is null, this surface must be valid and attached.
120 | * @param surfaceHolder optional, used to configure buffers geometry before Android ICS
121 | * and to get notified when surface is destroyed.
122 | * @see #attachViews()
123 | */
124 | @MainThread
125 | void setSubtitlesSurface(Surface subtitlesSurface, SurfaceHolder surfaceHolder);
126 |
127 | /**
128 | * Set a SurfaceTexture used for subtitles out.
129 | * @param subtitlesSurfaceTexture this surface must be valid and attached.
130 | * @see #attachViews()
131 | */
132 | @MainThread
133 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
134 | void setSubtitlesSurface(SurfaceTexture subtitlesSurfaceTexture);
135 |
136 | /**
137 | * Attach views previously set by setVideoView, setSubtitlesView, setVideoSurface, setSubtitleSurface
138 | * @see #setVideoView(SurfaceView)
139 | * @see #setVideoView(TextureView)
140 | * @see #setVideoSurface(Surface, SurfaceHolder)
141 | * @see #setSubtitlesView(SurfaceView)
142 | * @see #setSubtitlesView(TextureView)
143 | * @see #setSubtitlesSurface(Surface, SurfaceHolder)
144 | */
145 | @MainThread
146 | void attachViews();
147 |
148 | /**
149 | * Detach views previously attached.
150 | * This will be called automatically when surfaces are destroyed.
151 | */
152 | @MainThread
153 | void detachViews();
154 |
155 | /**
156 | * Return true if views are attached. If surfaces were destroyed, this will return false.
157 | */
158 | @MainThread
159 | boolean areViewsAttached();
160 |
161 | /**
162 | * Add a callback to receive {@link Callback#onNewLayout} events.
163 | */
164 | @MainThread
165 | void addCallback(Callback callback);
166 |
167 | /**
168 | * Remove a callback.
169 | */
170 | @MainThread
171 | void removeCallback(Callback callback);
172 |
173 | /**
174 | * Send a mouse event to the native vout.
175 | * @param action see ACTION_* in {@link android.view.MotionEvent}.
176 | * @param button see BUTTON_* in {@link android.view.MotionEvent}.
177 | * @param x x coordinate.
178 | * @param y y coordinate.
179 | */
180 | @MainThread
181 | void sendMouseEvent(int action, int button, int x, int y);
182 |
183 | /**
184 | * Send the the window size to the native vout.
185 | * @param width width of the window.
186 | * @param height height of the window.
187 | */
188 | @MainThread
189 | void setWindowSize(int width, int height);
190 | }
191 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/LibVLC.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * LibVLC.java
3 | *****************************************************************************
4 | * Copyright © 2010-2013 VLC authors and VideoLAN
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc;
22 |
23 | import android.os.Build;
24 | import android.util.Log;
25 |
26 | import org.videolan.libvlc.util.HWDecoderUtil;
27 |
28 | import java.util.ArrayList;
29 |
30 | @SuppressWarnings("unused, JniMissingFunction")
31 | public class LibVLC extends VLCObject {
32 | private static final String TAG = "VLC/LibVLC";
33 |
34 | public static class Event extends VLCEvent {
35 | protected Event(int type) {
36 | super(type);
37 | }
38 | }
39 |
40 | /** Native crash handler */
41 | private static OnNativeCrashListener sOnNativeCrashListener;
42 |
43 | /**
44 | * Create a LibVLC withs options
45 | *
46 | * @param options
47 | */
48 | public LibVLC(ArrayList options) {
49 | loadLibraries();
50 |
51 | boolean setAout = true, setChroma = true;
52 | // check if aout/vout options are already set
53 | if (options != null) {
54 | for (String option : options) {
55 | if (option.startsWith("--aout="))
56 | setAout = false;
57 | if (option.startsWith("--androidwindow-chroma"))
58 | setChroma = false;
59 | if (!setAout && !setChroma)
60 | break;
61 | }
62 | }
63 |
64 | // set aout/vout options if they are not set
65 | if (setAout || setChroma) {
66 | if (options == null)
67 | options = new ArrayList();
68 | if (setAout) {
69 | final HWDecoderUtil.AudioOutput hwAout = HWDecoderUtil.getAudioOutputFromDevice();
70 | if (hwAout == HWDecoderUtil.AudioOutput.OPENSLES)
71 | options.add("--aout=opensles");
72 | else
73 | options.add("--aout=android_audiotrack");
74 | }
75 | if (setChroma) {
76 | options.add("--androidwindow-chroma");
77 | options.add("RV32");
78 | }
79 | }
80 |
81 | nativeNew(options.toArray(new String[options.size()]));
82 | }
83 |
84 | /**
85 | * Create a LibVLC
86 | */
87 | public LibVLC() {
88 | this(null);
89 | }
90 |
91 | /**
92 | * Get the libVLC version
93 | * @return the libVLC version string
94 | */
95 | public native String version();
96 |
97 | /**
98 | * Get the libVLC compiler
99 | * @return the libVLC compiler string
100 | */
101 | public native String compiler();
102 |
103 | /**
104 | * Get the libVLC changeset
105 | * @return the libVLC changeset string
106 | */
107 | public native String changeset();
108 |
109 | @Override
110 | protected Event onEventNative(int eventType, long arg1, float arg2) {
111 | return null;
112 | }
113 |
114 | @Override
115 | protected void onReleaseNative() {
116 | nativeRelease();
117 | }
118 |
119 | public interface OnNativeCrashListener {
120 | void onNativeCrash();
121 | }
122 |
123 | public static void setOnNativeCrashListener(OnNativeCrashListener l) {
124 | sOnNativeCrashListener = l;
125 | }
126 |
127 | private static void onNativeCrash() {
128 | if (sOnNativeCrashListener != null)
129 | sOnNativeCrashListener.onNativeCrash();
130 | }
131 |
132 | /**
133 | * Sets the application name. LibVLC passes this as the user agent string
134 | * when a protocol requires it.
135 | *
136 | * @param name human-readable application name, e.g. "FooBar player 1.2.3"
137 | * @param http HTTP User Agent, e.g. "FooBar/1.2.3 Python/2.6.0"
138 | */
139 | public void setUserAgent(String name, String http){
140 | nativeSetUserAgent(name, http);
141 | }
142 |
143 | /* JNI */
144 | private native void nativeNew(String[] options);
145 | private native void nativeRelease();
146 | private native void nativeSetUserAgent(String name, String http);
147 |
148 | private static boolean sLoaded = false;
149 |
150 | static synchronized void loadLibraries() {
151 | if (sLoaded)
152 | return;
153 | sLoaded = true;
154 |
155 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
156 | try {
157 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1)
158 | System.loadLibrary("anw.10");
159 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
160 | System.loadLibrary("anw.13");
161 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1)
162 | System.loadLibrary("anw.14");
163 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT_WATCH)
164 | System.loadLibrary("anw.18");
165 | else
166 | System.loadLibrary("anw.21");
167 | } catch (Throwable t) {
168 | Log.w(TAG, "Unable to load the anw library: " + t);
169 | }
170 |
171 | try {
172 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1)
173 | System.loadLibrary("iomx.10");
174 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2)
175 | System.loadLibrary("iomx.13");
176 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1)
177 | System.loadLibrary("iomx.14");
178 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2)
179 | System.loadLibrary("iomx.18");
180 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT)
181 | System.loadLibrary("iomx.19");
182 | } catch (Throwable t) {
183 | // No need to warn if it isn't found, when we intentionally don't build these except for debug
184 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
185 | Log.w(TAG, "Unable to load the iomx library: " + t);
186 | }
187 | }
188 |
189 | try {
190 | System.loadLibrary("compat.7");
191 | } catch (Throwable ignored) {}
192 |
193 | try {
194 | System.loadLibrary("vlc");
195 | System.loadLibrary("vlcjni");
196 | } catch (UnsatisfiedLinkError ule) {
197 | Log.e(TAG, "Can't load vlcjni library: " + ule);
198 | /// FIXME Alert user
199 | System.exit(1);
200 | } catch (SecurityException se) {
201 | Log.e(TAG, "Encountered a security issue when loading vlcjni library: " + se);
202 | /// FIXME Alert user
203 | System.exit(1);
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/MediaDiscoverer.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * MediaDiscoverer.java
3 | *****************************************************************************
4 | * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc;
22 |
23 | import android.support.annotation.Nullable;
24 |
25 | @SuppressWarnings("unused, JniMissingFunction")
26 | public class MediaDiscoverer extends VLCObject {
27 | private final static String TAG = "LibVLC/MediaDiscoverer";
28 |
29 | public static class Event extends VLCEvent {
30 |
31 | public static final int Started = 0x500;
32 | public static final int Ended = 0x501;
33 |
34 | protected Event(int type) {
35 | super(type);
36 | }
37 | }
38 |
39 | public static class Description {
40 | public static class Category {
41 | /** devices, like portable music player */
42 | public static final int Devices = 0;
43 | /** LAN/WAN services, like Upnp, SMB, or SAP */
44 | public static final int Lan = 1;
45 | /** Podcasts */
46 | public static final int Podcasts = 2;
47 | /** Local directories, like Video, Music or Pictures directories */
48 | public static final int LocalDirs = 3;
49 | }
50 | public final String name;
51 | public final String longName;
52 | public final int category;
53 |
54 | private Description(String name, String longName, int category)
55 | {
56 | this.name = name;
57 | this.longName = longName;
58 | this.category = category;
59 | }
60 | }
61 |
62 | @SuppressWarnings("unused") /* Used from JNI */
63 | private static Description createDescriptionFromNative(String name, String longName, int category)
64 | {
65 | return new Description(name, longName, category);
66 | }
67 |
68 | public interface EventListener extends VLCEvent.Listener {}
69 |
70 | private MediaList mMediaList = null;
71 |
72 | /**
73 | * Create a MediaDiscover.
74 | *
75 | * @param libVLC a valid LibVLC
76 | * @param name Name of the vlc service discovery ("dsm", "upnp", "bonjour"...).
77 | */
78 | public MediaDiscoverer(LibVLC libVLC, String name) {
79 | nativeNew(libVLC, name);
80 | }
81 |
82 | /**
83 | * Starts the discovery. This MediaDiscoverer should be alive (not released).
84 | *
85 | * @return true the service is started
86 | */
87 | public boolean start() {
88 | if (isReleased())
89 | throw new IllegalStateException("MediaDiscoverer is released");
90 | return nativeStart();
91 | }
92 |
93 | /**
94 | * Stops the discovery. This MediaDiscoverer should be alive (not released).
95 | * (You can also call {@link #release() to stop the discovery directly}.
96 | */
97 | public void stop() {
98 | if (isReleased())
99 | throw new IllegalStateException("MediaDiscoverer is released");
100 | nativeStop();
101 | }
102 |
103 | public void setEventListener(EventListener listener) {
104 | super.setEventListener(listener);
105 | }
106 |
107 | @Override
108 | protected Event onEventNative(int eventType, long arg1, float arg2) {
109 | switch (eventType) {
110 | case Event.Started:
111 | case Event.Ended:
112 | return new Event(eventType);
113 | }
114 | return null;
115 | }
116 |
117 | /**
118 | * Get the MediaList associated with the MediaDiscoverer.
119 | * This MediaDiscoverer should be alive (not released).
120 | *
121 | * @return MediaList. This MediaList should be released with {@link #release()}.
122 | */
123 | public MediaList getMediaList() {
124 | synchronized (this) {
125 | if (mMediaList != null) {
126 | mMediaList.retain();
127 | return mMediaList;
128 | }
129 | }
130 | final MediaList mediaList = new MediaList(this);
131 | synchronized (this) {
132 | mMediaList = mediaList;
133 | mMediaList.retain();
134 | return mMediaList;
135 | }
136 | }
137 |
138 | @Override
139 | protected void onReleaseNative() {
140 | if (mMediaList != null)
141 | mMediaList.release();
142 | nativeRelease();
143 | }
144 |
145 | /**
146 | * Get media discoverers by category
147 | * @param category see {@link Description.Category}
148 | */
149 | @Nullable
150 | public static Description[] list(LibVLC libVLC, int category) {
151 | return nativeList(libVLC, category);
152 | }
153 |
154 | /* JNI */
155 | private native void nativeNew(LibVLC libVLC, String name);
156 | private native void nativeRelease();
157 | private native boolean nativeStart();
158 | private native void nativeStop();
159 | private static native Description[] nativeList(LibVLC libVLC, int category);
160 | }
161 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/MediaList.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * MediaList.java
3 | *****************************************************************************
4 | * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc;
22 |
23 | import android.util.SparseArray;
24 |
25 | @SuppressWarnings("unused, JniMissingFunction")
26 | public class MediaList extends VLCObject {
27 | private final static String TAG = "LibVLC/MediaList";
28 |
29 | public static class Event extends VLCEvent {
30 |
31 | public static final int ItemAdded = 0x200;
32 | //public static final int WillAddItem = 0x201;
33 | public static final int ItemDeleted = 0x202;
34 | //public static final int WillDeleteItem = 0x203;
35 | public static final int EndReached = 0x204;
36 |
37 | /**
38 | * The media can be already released. If it's released, cached attributes are still
39 | * available (like media.getMrl()).
40 | * You should call {@link Media#retain()} and check the return value
41 | * before calling media native methods.
42 | */
43 | public final Media media;
44 | public final int index;
45 |
46 | protected Event(int type, Media media, int index) {
47 | super(type);
48 | this.media = media;
49 | this.index = index;
50 | }
51 | }
52 |
53 | public interface EventListener extends VLCEvent.Listener {}
54 |
55 | private int mCount = 0;
56 | private final SparseArray mMediaArray = new SparseArray();
57 | private boolean mLocked = false;
58 |
59 | private void init() {
60 | lock();
61 | mCount = nativeGetCount();
62 | for (int i = 0; i < mCount; ++i)
63 | mMediaArray.put(i, new Media(this, i));
64 | unlock();
65 | }
66 |
67 | /**
68 | * Create a MediaList from libVLC
69 | * @param libVLC a valid libVLC
70 | */
71 | public MediaList(LibVLC libVLC) {
72 | nativeNewFromLibVlc(libVLC);
73 | init();
74 | }
75 |
76 | /**
77 | *
78 | * @param md Should not be released
79 | */
80 | protected MediaList(MediaDiscoverer md) {
81 | nativeNewFromMediaDiscoverer(md);
82 | init();
83 | }
84 |
85 | /**
86 | *
87 | * @param m Should not be released
88 | */
89 | protected MediaList(Media m) {
90 | nativeNewFromMedia(m);
91 | init();
92 | }
93 |
94 | private synchronized Media insertMediaFromEvent(int index) {
95 | mCount++;
96 |
97 | for (int i = mCount - 1; i >= index; --i)
98 | mMediaArray.put(i + 1, mMediaArray.valueAt(i));
99 | final Media media = new Media(this, index);
100 | mMediaArray.put(index, media);
101 | return media;
102 | }
103 |
104 | private synchronized Media removeMediaFromEvent(int index) {
105 | mCount--;
106 | final Media media = mMediaArray.get(index);
107 | if (media != null)
108 | media.release();
109 | for (int i = index; i < mCount; ++i) {
110 | mMediaArray.put(i, mMediaArray.valueAt(i + 1));
111 | }
112 | return media;
113 | }
114 |
115 | public void setEventListener(EventListener listener) {
116 | super.setEventListener(listener);
117 | }
118 |
119 | @Override
120 | protected synchronized Event onEventNative(int eventType, long arg1, float arg2) {
121 | if (mLocked)
122 | throw new IllegalStateException("already locked from event callback");
123 | mLocked = true;
124 | Event event = null;
125 | int index;
126 |
127 | switch (eventType) {
128 | case Event.ItemAdded:
129 | index = (int) arg1;
130 | if (index != -1) {
131 | final Media media = insertMediaFromEvent(index);
132 | event = new Event(eventType, media, index);
133 | }
134 | break;
135 | case Event.ItemDeleted:
136 | index = (int) arg1;
137 | if (index != -1) {
138 | final Media media = removeMediaFromEvent(index);
139 | event = new Event(eventType, media, index);
140 | }
141 | break;
142 | case Event.EndReached:
143 | event = new Event(eventType, null, -1);
144 | break;
145 | }
146 | mLocked = false;
147 | return event;
148 | }
149 |
150 | /**
151 | * Get the number of Media.
152 | */
153 | public synchronized int getCount() {
154 | return mCount;
155 | }
156 |
157 | /**
158 | * Get a Media at specified index.
159 | *
160 | * @param index index of the media
161 | * @return Media hold by MediaList. This Media should be released with {@link #release()}.
162 | */
163 | public synchronized Media getMediaAt(int index) {
164 | if (index < 0 || index >= getCount())
165 | throw new IndexOutOfBoundsException();
166 | final Media media = mMediaArray.get(index);
167 | media.retain();
168 | return media;
169 | }
170 |
171 | @Override
172 | public void onReleaseNative() {
173 | for (int i = 0; i < mMediaArray.size(); ++i) {
174 | final Media media = mMediaArray.get(i);
175 | if (media != null)
176 | media.release();
177 | }
178 |
179 | nativeRelease();
180 | }
181 |
182 | private synchronized void lock() {
183 | if (mLocked)
184 | throw new IllegalStateException("already locked");
185 | mLocked = true;
186 | nativeLock();
187 | }
188 |
189 | private synchronized void unlock() {
190 | if (!mLocked)
191 | throw new IllegalStateException("not locked");
192 | mLocked = false;
193 | nativeUnlock();
194 | }
195 |
196 | protected synchronized boolean isLocked() {
197 | return mLocked;
198 | }
199 |
200 | /* JNI */
201 | private native void nativeNewFromLibVlc(LibVLC libvlc);
202 | private native void nativeNewFromMediaDiscoverer(MediaDiscoverer md);
203 | private native void nativeNewFromMedia(Media m);
204 | private native void nativeRelease();
205 | private native int nativeGetCount();
206 | private native void nativeLock();
207 | private native void nativeUnlock();
208 | }
209 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/VLCEvent.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * VLCEvent.java
3 | *****************************************************************************
4 | * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc;
22 |
23 | abstract class VLCEvent {
24 | public final int type;
25 | protected final long arg1;
26 | protected final float arg2;
27 |
28 | protected VLCEvent(int type) {
29 | this.type = type;
30 | this.arg1 = 0;
31 | this.arg2 = 0;
32 | }
33 | protected VLCEvent(int type, long arg1) {
34 | this.type = type;
35 | this.arg1 = arg1;
36 | this.arg2 = 0;
37 | }
38 | protected VLCEvent(int type, float arg2) {
39 | this.type = type;
40 | this.arg1 = 0;
41 | this.arg2 = arg2;
42 | }
43 |
44 | /**
45 | * Listener for libvlc events
46 | *
47 | * @see VLCEvent
48 | */
49 | public interface Listener {
50 | void onEvent(T event);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/VLCObject.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * VLCObject.java
3 | *****************************************************************************
4 | * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc;
22 |
23 | import android.os.Handler;
24 | import android.os.Looper;
25 |
26 | import java.lang.ref.WeakReference;
27 |
28 | @SuppressWarnings("JniMissingFunction")
29 | abstract class VLCObject {
30 | private VLCEvent.Listener mEventListener = null;
31 | private Handler mHandler = null;
32 | private int mNativeRefCount = 1;
33 |
34 | /**
35 | * Returns true if native object is released
36 | */
37 | public synchronized boolean isReleased() {
38 | return mNativeRefCount == 0;
39 | }
40 |
41 | /**
42 | * Increment internal ref count of the native object.
43 | * @return true if media is retained
44 | */
45 | public synchronized final boolean retain() {
46 | if (mNativeRefCount > 0) {
47 | mNativeRefCount++;
48 | return true;
49 | } else
50 | return false;
51 | }
52 |
53 | /**
54 | * Release the native object if ref count is 1.
55 | *
56 | * After this call, native calls are not possible anymore.
57 | * You can still call others methods to retrieve cached values.
58 | * For example: if you parse, then release a media, you'll still be able to retrieve all Metas or Tracks infos.
59 | */
60 | public final void release() {
61 | int refCount = -1;
62 | synchronized (this) {
63 | if (mNativeRefCount == 0)
64 | return;
65 | if (mNativeRefCount > 0) {
66 | refCount = --mNativeRefCount;
67 | }
68 | // clear event list
69 | if (refCount == 0)
70 | setEventListener(null);
71 | }
72 | if (refCount == 0) {
73 | // detach events when not synchronized since onEvent is executed synchronized
74 | nativeDetachEvents();
75 | synchronized (this) {
76 | onReleaseNative();
77 | }
78 | }
79 | }
80 |
81 | /**
82 | * Set an event listener.
83 | * Events are sent via the android main thread.
84 | *
85 | * @param listener see {@link VLCEvent.Listener}
86 | */
87 | protected synchronized void setEventListener(VLCEvent.Listener listener) {
88 | if (mHandler != null)
89 | mHandler.removeCallbacksAndMessages(null);
90 | mEventListener = listener;
91 | if (mEventListener != null && mHandler == null)
92 | mHandler = new Handler(Looper.getMainLooper());
93 | }
94 |
95 | /**
96 | * Called when libvlc send events.
97 | *
98 | * @param eventType event type
99 | * @param arg1 first argument
100 | * @param arg2 second argument
101 | * @return Event that will be dispatched to listeners
102 | */
103 | protected abstract T onEventNative(int eventType, long arg1, float arg2);
104 |
105 | /**
106 | * Called when native object is released (refcount is 0).
107 | *
108 | * This is where you must release native resources.
109 | */
110 | protected abstract void onReleaseNative();
111 |
112 | /* JNI */
113 | @SuppressWarnings("unused") /* Used from JNI */
114 | private long mInstance = 0;
115 | private synchronized void dispatchEventFromNative(int eventType, long arg1, float arg2) {
116 | if (isReleased())
117 | return;
118 | final T event = onEventNative(eventType, arg1, arg2);
119 |
120 | class EventRunnable implements Runnable {
121 | private final VLCEvent.Listener listener;
122 | private final T event;
123 |
124 | private EventRunnable(VLCEvent.Listener listener, T event) {
125 | this.listener = listener;
126 | this.event = event;
127 | }
128 | @Override
129 | public void run() {
130 | listener.onEvent(event);
131 | }
132 | }
133 |
134 | if (event != null && mEventListener != null && mHandler != null)
135 | mHandler.post(new EventRunnable(mEventListener, event));
136 | }
137 | private native void nativeDetachEvents();
138 |
139 | /* used only before API 7: substitute for NewWeakGlobalRef */
140 | @SuppressWarnings("unused") /* Used from JNI */
141 | private Object getWeakReference() {
142 | return new WeakReference(this);
143 | }
144 | @SuppressWarnings("unchecked,unused") /* Used from JNI */
145 | private static void dispatchEventFromWeakNative(Object weak, int eventType, long arg1, float arg2) {
146 | VLCObject obj = ((WeakReference)weak).get();
147 | if (obj != null)
148 | obj.dispatchEventFromNative(eventType, arg1, arg2);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/Caption.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | public class Caption {
4 |
5 | public Style style;
6 | public Region region;
7 |
8 | public Time start;
9 | public Time end;
10 |
11 | /**
12 | * Raw content, before cleaning up templates and markup.
13 | */
14 | public String rawContent="";
15 | /**
16 | * Cleaned-up subtitle content.
17 | */
18 | public String content="";
19 |
20 | @Override
21 | public String toString() {
22 | return "Caption{" +
23 | start + ".." + end +
24 | ", " + (style != null ? style.iD : null) + ", " + region + ": " + content +
25 | '}';
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/FatalParsingException.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | /**
4 | * This class represents problems that may arise during the parsing of a subttile file.
5 | *
6 | * @author J. David
7 | *
8 | */
9 | public class FatalParsingException extends Exception {
10 |
11 | private static final long serialVersionUID = 6798827566637277804L;
12 |
13 | private String parsingErrror;
14 |
15 | public FatalParsingException(String parsingError){
16 | super(parsingError);
17 | this.parsingErrror = parsingError;
18 | }
19 |
20 | @Override
21 | public String getLocalizedMessage(){
22 | return parsingErrror;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/FormatSRT.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.InputStreamReader;
7 | import java.util.ArrayList;
8 | import java.util.Collection;
9 | import java.util.Iterator;
10 |
11 |
12 | /**
13 | * This class represents the .SRT subtitle format
14 | *
15 | * Copyright (c) 2012 J. David Requejo
16 | * j[dot]david[dot]requejo[at] Gmail
17 | *
18 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
19 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
20 | * including without limitation the rights to use, copy, modify, merge, publish, distribute,
21 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
22 | * is furnished to do so, subject to the following conditions:
23 | *
24 | * The above copyright notice and this permission notice shall be included in all copies
25 | * or substantial portions of the Software.
26 | *
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
28 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
29 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
30 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
31 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 | * DEALINGS IN THE SOFTWARE.
33 | *
34 | * @author J. David Requejo
35 | *
36 | */
37 | public class FormatSRT implements TimedTextFileFormat {
38 |
39 |
40 | public TimedTextObject parseFile(String fileName, InputStream is) throws IOException {
41 |
42 | TimedTextObject tto = new TimedTextObject();
43 | Caption caption = new Caption();
44 | int captionNumber = 1;
45 | boolean allGood;
46 |
47 | //first lets load the file
48 | InputStreamReader in= new InputStreamReader(is);
49 | BufferedReader br = new BufferedReader(in);
50 |
51 | //the file name is saved
52 | tto.fileName = fileName;
53 |
54 | String line = br.readLine();
55 | line = line.replace("\uFEFF", ""); //remove BOM character
56 | int lineCounter = 0;
57 | try {
58 | while(line!=null){
59 | line = line.trim();
60 | lineCounter++;
61 | //if its a blank line, ignore it, otherwise...
62 | if (!line.isEmpty()){
63 | allGood = false;
64 | //the first thing should be an increasing number
65 | try {
66 | int num = Integer.parseInt(line);
67 | if (num != captionNumber)
68 | throw new Exception();
69 | else {
70 | captionNumber++;
71 | allGood = true;
72 | }
73 | } catch (Exception e) {
74 | tto.warnings+= captionNumber + " expected at line " + lineCounter;
75 | tto.warnings+= "\n skipping to next line\n\n";
76 | }
77 | if (allGood){
78 | //we go to next line, here the begin and end time should be found
79 | try {
80 | lineCounter++;
81 | line = br.readLine().trim();
82 | String start = line.substring(0, 12);
83 | String end = line.substring(line.length()-12, line.length());
84 | Time time = new Time("hh:mm:ss,ms",start);
85 | caption.start = time;
86 | time = new Time("hh:mm:ss,ms",end);
87 | caption.end = time;
88 | } catch (Exception e){
89 | tto.warnings += "incorrect time format at line "+lineCounter;
90 | allGood = false;
91 | }
92 | }
93 | if (allGood){
94 | //we go to next line where the caption text starts
95 | lineCounter++;
96 | line = br.readLine().trim();
97 | String text = "";
98 | while (!line.isEmpty()) {
99 | text += text.isEmpty() ? line : " " + line;
100 | line = br.readLine().trim();
101 | lineCounter++;
102 | }
103 | caption.content = text;
104 | int key = caption.start.mseconds;
105 | //in case the key is already there, we increase it by a millisecond, since no duplicates are allowed
106 | while (tto.captions.containsKey(key)) key++;
107 | if (key != caption.start.mseconds)
108 | tto.warnings+= "caption with same start time found...\n\n";
109 | //we add the caption.
110 | tto.captions.put(key, caption);
111 | }
112 | //we go to next blank
113 | while (!line.isEmpty()) {
114 | line = br.readLine().trim();
115 | lineCounter++;
116 | }
117 | caption = new Caption();
118 | }
119 | line = br.readLine();
120 | }
121 |
122 | } catch (NullPointerException e){
123 | tto.warnings+= "unexpected end of file, maybe last caption is not complete.\n\n";
124 | } finally{
125 | //we close the reader
126 | is.close();
127 | }
128 |
129 | tto.built = true;
130 | return tto;
131 | }
132 |
133 |
134 | public String[] toFile(TimedTextObject tto) {
135 |
136 | //first we check if the TimedTextObject had been built, otherwise...
137 | if(!tto.built)
138 | return null;
139 |
140 | //we will write the lines in an ArrayList,
141 | int index = 0;
142 | //the minimum size of the file is 4*number of captions, so we'll take some extra space.
143 | ArrayList file = new ArrayList<>(5 * tto.captions.size());
144 | //we iterate over our captions collection, they are ordered since they come from a TreeMap
145 | Collection c = tto.captions.values();
146 | Iterator itr = c.iterator();
147 | int captionNumber = 1;
148 |
149 | while(itr.hasNext()){
150 | //new caption
151 | Caption current = itr.next();
152 | //number is written
153 | file.add(index++, Integer.toString(captionNumber++));
154 | //we check for offset value:
155 | if(tto.offset != 0){
156 | current.start.mseconds += tto.offset;
157 | current.end.mseconds += tto.offset;
158 | }
159 | //time is written
160 | file.add(index++,current.start.getTime("hh:mm:ss,ms")+" --> "+current.end.getTime("hh:mm:ss,ms"));
161 | //offset is undone
162 | if(tto.offset != 0){
163 | current.start.mseconds -= tto.offset;
164 | current.end.mseconds -= tto.offset;
165 | }
166 | //text is added
167 | String[] lines = cleanTextForSRT(current);
168 | int i=0;
169 | while(i ");
194 | //clean XML
195 | for (int i = 0; i < lines.length; i++){
196 | //this will destroy all remaining XML tags
197 | lines[i] = lines[i].replaceAll("\\<.*?\\>", "");
198 | }
199 | return lines;
200 | }
201 |
202 | }
203 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/Region.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | public class Region {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/Style.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | public class Style {
4 |
5 | private static int styleCounter;
6 |
7 | /**
8 | * Constructor that receives a String to use a its identifier
9 | *
10 | * @param styleName = identifier of this style
11 | */
12 | protected Style(String styleName) {
13 | this.iD = styleName;
14 | }
15 |
16 | /**
17 | * Constructor that receives a String with the new styleName and a style to copy
18 | *
19 | * @param styleName
20 | * @param style
21 | */
22 | protected Style(String styleName, Style style) {
23 | this.iD = styleName;
24 | this.font = style.font;
25 | this.fontSize = style.fontSize;
26 | this.color = style.color;
27 | this.backgroundColor = style.backgroundColor;
28 | this.textAlign = style.textAlign;
29 | this.italic = style.italic;
30 | this.underline = style.underline;
31 | this.bold = style.bold;
32 |
33 | }
34 |
35 | /* ATTRIBUTES */
36 | protected String iD;
37 | protected String font;
38 | protected String fontSize;
39 | /**colors are stored as 8 chars long RGBA*/
40 | protected String color;
41 | protected String backgroundColor;
42 | protected String textAlign = "";
43 |
44 | protected boolean italic;
45 | protected boolean bold;
46 | protected boolean underline;
47 |
48 | /* METHODS */
49 |
50 | /**
51 | * To get the string containing the hex value to put into color or background color
52 | *
53 | * @param format supported: "name", "&HBBGGRR", "&HAABBGGRR", "decimalCodedBBGGRR", "decimalCodedAABBGGRR"
54 | * @param value RRGGBBAA string
55 | * @return
56 | */
57 | protected static String getRGBValue(String format, String value){
58 | String color = null;
59 | if (format.equalsIgnoreCase("name")){
60 | //standard color format from W3C
61 | if (value.equals("transparent"))
62 | color = "00000000";
63 | else if (value.equals("black"))
64 | color = "000000ff";
65 | else if (value.equals("silver"))
66 | color = "c0c0c0ff";
67 | else if (value.equals("gray"))
68 | color = "808080ff";
69 | else if (value.equals("white"))
70 | color = "ffffffff";
71 | else if (value.equals("maroon"))
72 | color = "800000ff";
73 | else if (value.equals("red"))
74 | color = "ff0000ff";
75 | else if (value.equals("purple"))
76 | color = "800080ff";
77 | else if (value.equals("fuchsia"))
78 | color = "ff00ffff";
79 | else if (value.equals("magenta"))
80 | color = "ff00ffff ";
81 | else if (value.equals("green"))
82 | color = "008000ff";
83 | else if (value.equals("lime"))
84 | color = "00ff00ff";
85 | else if (value.equals("olive"))
86 | color = "808000ff";
87 | else if (value.equals("yellow"))
88 | color = "ffff00ff";
89 | else if (value.equals("navy"))
90 | color = "000080ff";
91 | else if (value.equals("blue"))
92 | color = "0000ffff";
93 | else if (value.equals("teal"))
94 | color = "008080ff";
95 | else if (value.equals("aqua"))
96 | color = "00ffffff";
97 | else if (value.equals("cyan"))
98 | color = "00ffffff ";
99 | } else if (format.equalsIgnoreCase("&HBBGGRR")){
100 | //hex format from SSA
101 | StringBuilder sb = new StringBuilder();
102 | sb.append(value.substring(6));
103 | sb.append(value.substring(4,5));
104 | sb.append(value.substring(2,3));
105 | sb.append("ff");
106 | color = sb.toString();
107 | } else if (format.equalsIgnoreCase("&HAABBGGRR")){
108 | //hex format from ASS
109 | StringBuilder sb = new StringBuilder();
110 | sb.append(value.substring(8));
111 | sb.append(value.substring(6,7));
112 | sb.append(value.substring(4,5));
113 | sb.append(value.substring(2,3));
114 | color = sb.toString();
115 | } else if (format.equalsIgnoreCase("decimalCodedBBGGRR")){
116 | //normal format from SSA
117 | color = Integer.toHexString(Integer.parseInt(value));
118 | //any missing 0s are filled in
119 | while(color.length()<6)color="0"+color;
120 | //order is reversed
121 | color = color.substring(4)+color.substring(2,4)+color.substring(0,2)+"ff";
122 | } else if (format.equalsIgnoreCase("decimalCodedAABBGGRR")){
123 | //normal format from ASS
124 | color = Long.toHexString(Long.parseLong(value));
125 | //any missing 0s are filled in
126 | while(color.length()<8)color="0"+color;
127 | //order is reversed
128 | color = color.substring(6)+color.substring(4,6)+color.substring(2,4)+color.substring(0,2);
129 | }
130 | return color;
131 | }
132 |
133 | protected static String defaultID() {
134 | return "default"+styleCounter++;
135 | }
136 |
137 | @Override
138 | public String toString() {
139 | return "Style{" +
140 | "id='" + iD + '\'' +
141 | ", font='" + font + '\'' +
142 | ", fontSize='" + fontSize + '\'' +
143 | ", color='" + color + '\'' +
144 | ", backgroundColor='" + backgroundColor + '\'' +
145 | ", textAlign='" + textAlign + '\'' +
146 | ", italic=" + italic +
147 | ", bold=" + bold +
148 | ", underline=" + underline +
149 | '}';
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/SubtitleFormat.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | /**
4 | * Created by KB-Server on 2016/7/11.
5 | */
6 | public class SubtitleFormat {
7 | public final static String ASS = "ass";
8 | public final static String SCC = "scc";
9 | public final static String SRT = "srt";
10 | public final static String STL = "stl";
11 | public final static String TTML = "ttml";
12 | }
13 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/Time.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | public class Time {
4 |
5 | /**
6 | * Constructor to create a time object.
7 | *
8 | * @param format supported formats: "hh:mm:ss,ms", "h:mm:ss.cs" and "h:m:s:f/fps"
9 | * @param value string in the correct format
10 | */
11 | protected Time(String format, String value) {
12 | if (format.equalsIgnoreCase("hh:mm:ss,ms")){
13 | // this type of format: 01:02:22,501 (used in .SRT)
14 | int h, m, s, ms;
15 | h = Integer.parseInt(value.substring(0, 2));
16 | m = Integer.parseInt(value.substring(3, 5));
17 | s = Integer.parseInt(value.substring(6, 8));
18 | ms = Integer.parseInt(value.substring(9, 12));
19 |
20 | mseconds = ms + s*1000 + m*60000 + h*3600000;
21 |
22 | } else if (format.equalsIgnoreCase("h:mm:ss.cs")){
23 | // this type of format: 1:02:22.51 (used in .ASS/.SSA)
24 | int h, m, s, cs;
25 | String[] hms = value.split(":");
26 | h = Integer.parseInt(hms[0]);
27 | m = Integer.parseInt(hms[1]);
28 | s = Integer.parseInt(hms[2].substring(0, 2));
29 | cs = Integer.parseInt(hms[2].substring(3, 5));
30 |
31 | mseconds = cs*10 + s*1000 + m*60000 + h*3600000;
32 | } else if (format.equalsIgnoreCase("h:m:s:f/fps")){
33 | int h, m, s, f;
34 | float fps;
35 | String[] args = value.split("/");
36 | fps = Float.parseFloat(args[1]);
37 | args = args[0].split(":");
38 | h = Integer.parseInt(args[0]);
39 | m = Integer.parseInt(args[1]);
40 | s = Integer.parseInt(args[2]);
41 | f = Integer.parseInt(args[3]);
42 |
43 | mseconds = (int)(f*1000/fps) + s*1000 + m*60000 + h*3600000;
44 | }
45 | }
46 |
47 | // in an integer we can store 24 days worth of milliseconds, no need for a long
48 | protected int mseconds;
49 |
50 | public int getMseconds() {
51 | return mseconds;
52 | }
53 |
54 | public void setMseconds(int mseconds) {
55 | this.mseconds = mseconds;
56 | }
57 |
58 | /* METHODS */
59 |
60 | /**
61 | * Method to return a formatted value of the time stored
62 | *
63 | * @param string supported formats: "hh:mm:ss,ms", "h:mm:ss.cs" and "hhmmssff/fps"
64 | * @return formatted time in a string
65 | */
66 | protected String getTime(String format) {
67 | //we use string builder for efficiency
68 | StringBuilder time = new StringBuilder();
69 | String aux;
70 | if(format.equalsIgnoreCase("hh:mm:ss,ms")){
71 | // this type of format: 01:02:22,501 (used in .SRT)
72 | int h, m, s, ms;
73 | h = mseconds/3600000;
74 | aux = String.valueOf(h);
75 | if (aux.length()==1) time.append('0');
76 | time.append(aux);
77 | time.append(':');
78 | m = (mseconds/60000)%60;
79 | aux = String.valueOf(m);
80 | if (aux.length()==1) time.append('0');
81 | time.append(aux);
82 | time.append(':');
83 | s = (mseconds/1000)%60;
84 | aux = String.valueOf(s);
85 | if (aux.length()==1) time.append('0');
86 | time.append(aux);
87 | time.append(',');
88 | ms = mseconds%1000;
89 | aux = String.valueOf(ms);
90 | if (aux.length()==1) time.append("00");
91 | else if (aux.length()==2) time.append('0');
92 | time.append(aux);
93 |
94 | } else if(format.equalsIgnoreCase("h:mm:ss.cs")){
95 | // this type of format: 1:02:22.51 (used in .ASS/.SSA)
96 | int h, m, s, cs;
97 | h = mseconds/3600000;
98 | aux = String.valueOf(h);
99 | if (aux.length()==1) time.append('0');
100 | time.append(aux);
101 | time.append(':');
102 | m = (mseconds/60000)%60;
103 | aux = String.valueOf(m);
104 | if (aux.length()==1) time.append('0');
105 | time.append(aux);
106 | time.append(':');
107 | s = (mseconds/1000)%60;
108 | aux = String.valueOf(s);
109 | if (aux.length()==1) time.append('0');
110 | time.append(aux);
111 | time.append('.');
112 | cs = (mseconds/10)%100;
113 | aux = String.valueOf(cs);
114 | if (aux.length()==1) time.append('0');
115 | time.append(aux);
116 |
117 | } else if (format.startsWith("hhmmssff/")){
118 | //this format is used in EBU's STL
119 | int h, m, s, f;
120 | float fps;
121 | String[] args = format.split("/");
122 | fps = Float.parseFloat(args[1]);
123 | //now we concatenate time
124 | h = mseconds/3600000;
125 | aux = String.valueOf(h);
126 | if (aux.length()==1) time.append('0');
127 | time.append(aux);
128 | m = (mseconds/60000)%60;
129 | aux = String.valueOf(m);
130 | if (aux.length()==1) time.append('0');
131 | time.append(aux);
132 | s = (mseconds/1000)%60;
133 | aux = String.valueOf(s);
134 | if (aux.length()==1) time.append('0');
135 | time.append(aux);
136 | f = (mseconds%1000)*(int)fps/1000;
137 | aux = String.valueOf(f);
138 | if (aux.length()==1) time.append('0');
139 | time.append(aux);
140 |
141 | } else if (format.startsWith("h:m:s:f/")){
142 | //this format is used in EBU's STL
143 | int h, m, s, f;
144 | float fps;
145 | String[] args = format.split("/");
146 | fps = Float.parseFloat(args[1]);
147 | //now we concatenate time
148 | h = mseconds/3600000;
149 | aux = String.valueOf(h);
150 | //if (aux.length()==1) time.append('0');
151 | time.append(aux);
152 | time.append(':');
153 | m = (mseconds/60000)%60;
154 | aux = String.valueOf(m);
155 | //if (aux.length()==1) time.append('0');
156 | time.append(aux);
157 | time.append(':');
158 | s = (mseconds/1000)%60;
159 | aux = String.valueOf(s);
160 | //if (aux.length()==1) time.append('0');
161 | time.append(aux);
162 | time.append(':');
163 | f = (mseconds%1000)*(int)fps/1000;
164 | aux = String.valueOf(f);
165 | //if (aux.length()==1) time.append('0');
166 | time.append(aux);
167 | } else if (format.startsWith("hh:mm:ss:ff/")){
168 | //this format is used in SCC
169 | int h, m, s, f;
170 | float fps;
171 | String[] args = format.split("/");
172 | fps = Float.parseFloat(args[1]);
173 | //now we concatenate time
174 | h = mseconds/3600000;
175 | aux = String.valueOf(h);
176 | if (aux.length()==1) time.append('0');
177 | time.append(aux);
178 | time.append(':');
179 | m = (mseconds/60000)%60;
180 | aux = String.valueOf(m);
181 | if (aux.length()==1) time.append('0');
182 | time.append(aux);
183 | time.append(':');
184 | s = (mseconds/1000)%60;
185 | aux = String.valueOf(s);
186 | if (aux.length()==1) time.append('0');
187 | time.append(aux);
188 | time.append(':');
189 | f = (mseconds%1000)*(int)fps/1000;
190 | aux = String.valueOf(f);
191 | if (aux.length()==1) time.append('0');
192 | time.append(aux);
193 | }
194 |
195 | return time.toString();
196 | }
197 |
198 | /**
199 | * ASS/SSA time format.
200 | * @return ASS/SSA time format.
201 | */
202 | @Override
203 | public String toString() {
204 | return getTime("h:mm:ss.cs");
205 | }
206 |
207 | }
208 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/TimedTextFileFormat.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 |
6 | /**
7 | * This class specifies the interface for any format supported by the converter, these formats must
8 | * create a {@link TimedTextObject} from an {@link java.io.InputStream} (so it can process files form standard In or uploads)
9 | * and return a String array for text formats, or byte array for binary formats.
10 | *
11 | * Copyright (c) 2012 J. David Requejo
12 | * j[dot]david[dot]requejo[at] Gmail
13 | *
14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
15 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
16 | * including without limitation the rights to use, copy, modify, merge, publish, distribute,
17 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
18 | * is furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in all copies
21 | * or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
24 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
26 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
27 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 | * DEALINGS IN THE SOFTWARE.
29 | *
30 | * @author J. David Requejo
31 | *
32 | */
33 | public interface TimedTextFileFormat {
34 |
35 | /**
36 | * This methods receives the path to a file, parses it, and returns a TimedTextObject
37 | *
38 | * @param path String that contains the path to the file
39 | * @return TimedTextObject representing the parsed file
40 | * @throws java.io.IOException when having trouble reading the file from the given path
41 | */
42 | TimedTextObject parseFile(String fileName, InputStream is) throws IOException, FatalParsingException;
43 |
44 | /**
45 | * This method transforms a given TimedTextObject into a formated subtitle file
46 | *
47 | * @param tto the object to transform into a file
48 | * @return NULL if the given TimedTextObject has not been built first,
49 | * or String[] where each String is at least a line, if size is 2, then the file has at least two lines.
50 | * or byte[] in case the file is a binary (as is the case of STL format)
51 | */
52 | Object toFile(TimedTextObject tto);
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/TimedTextObject.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | import java.util.Hashtable;
4 | import java.util.Iterator;
5 | import java.util.TreeMap;
6 |
7 | /**
8 | * These objects can (should) only be created through the implementations of parseFile() in the {@link subtitleFile.TimedTextFileFormat} interface
9 | * They are an object representation of a subtitle file and contain all the captions and associated styles.
10 | *
11 | * Copyright (c) 2012 J. David Requejo
12 | * j[dot]david[dot]requejo[at] Gmail
13 | *
14 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
15 | * and associated documentation files (the "Software"), to deal in the Software without restriction,
16 | * including without limitation the rights to use, copy, modify, merge, publish, distribute,
17 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
18 | * is furnished to do so, subject to the following conditions:
19 | *
20 | * The above copyright notice and this permission notice shall be included in all copies
21 | * or substantial portions of the Software.
22 | *
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
24 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
26 | * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
27 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 | * DEALINGS IN THE SOFTWARE.
29 | *
30 | * @author J. David Requejo
31 | *
32 | */
33 | public class TimedTextObject {
34 |
35 | /*
36 | * Attributes
37 | *
38 | */
39 | //meta info
40 | public String title = "";
41 | public String description = "";
42 | public String copyrigth = "";
43 | public String author = "";
44 | public String fileName = "";
45 | public String language = "";
46 |
47 | //list of styles (id, reference)
48 | public Hashtable styling;
49 |
50 | //list of layouts (id, reference)
51 | public Hashtable layout;
52 |
53 | //list of captions (begin time, reference)
54 | //represented by a tree map to maintain order
55 | public TreeMap captions;
56 |
57 | //to store non fatal errors produced during parsing
58 | public String warnings;
59 |
60 | //**** OPTIONS *****
61 | //to know whether file should be saved as .ASS or .SSA
62 | public boolean useASSInsteadOfSSA = true;
63 | //to delay or advance the subtitles, parsed into +/- milliseconds
64 | public int offset = 0;
65 |
66 | //to know if a parsing method has been applied
67 | public boolean built = false;
68 |
69 |
70 | /**
71 | * Protected constructor so it can't be created from outside
72 | */
73 | protected TimedTextObject(){
74 |
75 | styling = new Hashtable<>();
76 | layout = new Hashtable<>();
77 | captions = new TreeMap<>();
78 |
79 | warnings = "List of non fatal errors produced during parsing:\n\n";
80 |
81 | }
82 |
83 |
84 | /*
85 | * Writing Methods
86 | *
87 | */
88 | /**
89 | * Method to generate the .SRT file
90 | *
91 | * @return an array of strings where each String represents a line
92 | */
93 | public String[] toSRT(){
94 | return new FormatSRT().toFile(this);
95 | }
96 |
97 |
98 | /**
99 | * Method to generate the .ASS file
100 | *
101 | * @return an array of strings where each String represents a line
102 | */
103 | public String[] toASS(){
104 | return new FormatASS().toFile(this);
105 | }
106 |
107 | /**
108 | * Method to generate the .STL file
109 | */
110 | public byte[] toSTL(){
111 | return new FormatSTL().toFile(this);
112 | }
113 |
114 | /**
115 | * Method to generate the .SCC file
116 | * @return
117 | */
118 | public String[] toSCC(){
119 | return new FormatSCC().toFile(this);
120 | }
121 |
122 | /**
123 | * Method to generate the .XML file
124 | * @return
125 | */
126 | public String[] toTTML(){
127 | return new FormatTTML().toFile(this);
128 | }
129 |
130 | /*
131 | * PROTECTED METHODS
132 | *
133 | */
134 |
135 | /**
136 | * This method simply checks the style list and eliminate any style not referenced by any caption
137 | * This might come useful when default styles get created and cover too much.
138 | * It require a unique iteration through all captions.
139 | *
140 | */
141 | protected void cleanUnusedStyles(){
142 | //here all used styles will be stored
143 | Hashtable usedStyles = new Hashtable<>();
144 | //we iterate over the captions
145 | Iterator itrC = captions.values().iterator();
146 | while(itrC.hasNext()){
147 | //new caption
148 | Caption current = itrC.next();
149 | //if it has a style
150 | if(current.style != null){
151 | String iD = current.style.iD;
152 | //if we haven't saved it yet
153 | if(!usedStyles.containsKey(iD))
154 | usedStyles.put(iD, current.style);
155 | }
156 | }
157 | //we saved the used styles
158 | this.styling = usedStyles;
159 | }
160 |
161 | }
162 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/subtitle/TimedTextProcessor.java:
--------------------------------------------------------------------------------
1 | package org.videolan.libvlc.subtitle;
2 |
3 | import android.net.Uri;
4 | import android.os.AsyncTask;
5 | import android.os.Handler;
6 | import android.text.Html;
7 | import android.text.Spanned;
8 | import android.util.Log;
9 | import android.widget.Toast;
10 |
11 | import java.io.File;
12 | import java.io.FileInputStream;
13 | import java.io.FileNotFoundException;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.net.MalformedURLException;
17 | import java.net.URL;
18 | import java.net.URLConnection;
19 | import java.util.Collection;
20 | import java.util.List;
21 | import java.util.Map;
22 | import java.util.TimerTask;
23 |
24 | /**
25 | * Created by KB-Server on 2016/7/11.
26 | */
27 | public abstract class TimedTextProcessor {
28 | private final String TAG = TimedTextProcessor.class.getName();
29 |
30 | private boolean mTimedTextLoaded;
31 | private AsyncTask mTimedTextProcessingTask;
32 | private TimerTask mTimedTextProcessor;
33 | private TimedTextObject mTimedTextObject;
34 | private Handler mTimedTextHandler = new Handler();
35 |
36 | public abstract void onTimedText(Spanned spanned);
37 |
38 | public abstract int getCurrentPosition();
39 |
40 | public void start(final Uri uri) {
41 | start(null, uri);
42 | }
43 |
44 | public void start(final String path) {
45 | start(path, null);
46 | }
47 |
48 | private void start(final String path, final Uri uri) {
49 | stop();
50 |
51 | mTimedTextProcessingTask = new AsyncTask() {
52 | @Override
53 | protected Object doInBackground(Object[] objects) {
54 | if(path != null) {
55 | mTimedTextObject = getTimedTextObject(path);
56 | } else if(uri != null) {
57 | mTimedTextObject = getTimedTextObject(uri);
58 | }
59 |
60 | if(mTimedTextObject != null) {
61 | mTimedTextLoaded = true;
62 | }
63 |
64 | return null;
65 | }
66 |
67 | @Override
68 | protected void onPostExecute(Object o) {
69 | if(!mTimedTextLoaded) {
70 | return;
71 | }
72 |
73 | mTimedTextProcessor = new TimerTask() {
74 | @Override
75 | public void run() {
76 | updateTimedText();
77 |
78 | mTimedTextHandler.postDelayed(this, 100);
79 | }
80 | };
81 |
82 | mTimedTextHandler.post(mTimedTextProcessor);
83 | }
84 | };
85 |
86 | mTimedTextProcessingTask.execute();
87 | }
88 |
89 | public void stop() {
90 | mTimedTextLoaded = false;
91 | mTimedTextObject = null;
92 |
93 | if(mTimedTextProcessingTask != null) {
94 | mTimedTextProcessingTask.cancel(true);
95 | mTimedTextProcessingTask = null;
96 | }
97 |
98 | if(mTimedTextProcessor != null) {
99 | mTimedTextProcessor.cancel();
100 | mTimedTextHandler.removeCallbacks(mTimedTextProcessor);
101 | mTimedTextProcessor = null;
102 | }
103 | }
104 |
105 | public void pause() {
106 | if(mTimedTextProcessor != null) {
107 | mTimedTextProcessor.cancel();
108 | mTimedTextHandler.removeCallbacks(mTimedTextProcessor);
109 | }
110 | }
111 |
112 | public void resume() {
113 | if(mTimedTextLoaded) {
114 | if(mTimedTextProcessor != null) {
115 | mTimedTextProcessor.cancel();
116 | mTimedTextHandler.removeCallbacks(mTimedTextProcessor);
117 | }
118 |
119 | mTimedTextHandler.post(mTimedTextProcessor);
120 | }
121 | }
122 |
123 | public void updateTimedText() {
124 | if(mTimedTextObject == null || mTimedTextObject.captions == null) {
125 | return;
126 | }
127 |
128 | int currentPosition = getCurrentPosition();
129 |
130 | if(currentPosition < 0) {
131 | return;
132 | }
133 |
134 | Collection subtitles = mTimedTextObject.captions.values();
135 |
136 | Caption currentCaption = null;
137 |
138 | for (Caption caption : subtitles) {
139 | if (currentPosition >= caption.start.getMseconds()
140 | && currentPosition <= caption.end.getMseconds()) {
141 | currentCaption = caption;
142 |
143 | break;
144 | }
145 | }
146 |
147 | Spanned spanned = currentCaption == null
148 | ? null
149 | : Html.fromHtml(currentCaption.content);
150 |
151 | onTimedText(spanned);
152 | }
153 |
154 | private TimedTextObject getTimedTextObject(Uri uri) {
155 | TimedTextObject timedTextObject = null;
156 |
157 | String path = uri.getPath();
158 | String subtitleFormat = path.substring(path.lastIndexOf(".") + 1).toLowerCase();
159 | String fileName = path.substring(0, path.lastIndexOf("."));
160 |
161 | if(fileName.lastIndexOf("/") != -1) {
162 | fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
163 | }
164 |
165 | try {
166 | URL url = new URL(uri.toString());
167 | InputStream inputStream = url.openStream();
168 |
169 | switch (subtitleFormat) {
170 | case SubtitleFormat.ASS:
171 | timedTextObject = new FormatASS().parseFile(fileName, inputStream);
172 | break;
173 | case SubtitleFormat.SCC:
174 | timedTextObject = new FormatSCC().parseFile(fileName, inputStream);
175 | break;
176 | case SubtitleFormat.SRT:
177 | timedTextObject = new FormatSRT().parseFile(fileName, inputStream);
178 | break;
179 | case SubtitleFormat.STL:
180 | timedTextObject = new FormatSTL().parseFile(fileName, inputStream);
181 | break;
182 | case SubtitleFormat.TTML:
183 | timedTextObject = new FormatTTML().parseFile(fileName, inputStream);
184 | break;
185 | default:
186 | break;
187 | }
188 | } catch (FileNotFoundException e) {
189 | Log.e(TAG, "doInBackground: ", e);
190 | } catch (IOException e) {
191 | Log.e(TAG, "doInBackground: ", e);
192 | } catch (FatalParsingException e) {
193 | Log.e(TAG, "doInBackground: ", e);
194 | } catch (Exception e) {
195 | Log.e(TAG, "doInBackground: ", e);
196 | }
197 |
198 | if(timedTextObject != null && timedTextObject.warnings != null && !timedTextObject.warnings.isEmpty()) {
199 | Log.w(TAG, "getTimedTextObject: " + timedTextObject.warnings);
200 | }
201 |
202 | return timedTextObject;
203 | }
204 |
205 | private TimedTextObject getTimedTextObject(String path) {
206 | TimedTextObject timedTextObject = null;
207 |
208 | if(!new File(path).exists()) {
209 | return timedTextObject;
210 | }
211 |
212 | String subtitleFormat = path.substring(path.lastIndexOf(".") + 1).toLowerCase();
213 | String fileName = path.substring(0, path.lastIndexOf("."));
214 |
215 | if(fileName.lastIndexOf("/") != -1) {
216 | fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
217 | }
218 |
219 | try {
220 | InputStream inputStream = new FileInputStream(path);
221 |
222 | switch (subtitleFormat) {
223 | case SubtitleFormat.ASS:
224 | timedTextObject = new FormatASS().parseFile(fileName, inputStream);
225 | break;
226 | case SubtitleFormat.SCC:
227 | timedTextObject = new FormatSCC().parseFile(fileName, inputStream);
228 | break;
229 | case SubtitleFormat.SRT:
230 | timedTextObject = new FormatSRT().parseFile(fileName, inputStream);
231 | break;
232 | case SubtitleFormat.STL:
233 | timedTextObject = new FormatSTL().parseFile(fileName, inputStream);
234 | break;
235 | case SubtitleFormat.TTML:
236 | timedTextObject = new FormatTTML().parseFile(fileName, inputStream);
237 | break;
238 | default:
239 | path = getSubtitlePathUnderSameFolder(path);
240 |
241 | if(path != null) {
242 | timedTextObject = getTimedTextObject(path);
243 | }
244 |
245 | break;
246 | }
247 | } catch (FileNotFoundException e) {
248 | e.printStackTrace();
249 | } catch (IOException e) {
250 | e.printStackTrace();
251 | } catch (FatalParsingException e) {
252 | e.printStackTrace();
253 | }
254 |
255 | if(timedTextObject != null && timedTextObject.warnings != null && !timedTextObject.warnings.isEmpty()) {
256 | Log.w(TAG, "getTimedTextObject: " + timedTextObject.warnings);
257 | }
258 |
259 | return timedTextObject;
260 | }
261 |
262 | private String getSubtitlePathUnderSameFolder(String path){
263 | String subtitlePath = null;
264 | String prefix = path.substring(0, path.lastIndexOf(".") + 1);
265 |
266 | String[] supportSubtitleFormat = new String[] {
267 | SubtitleFormat.ASS,
268 | SubtitleFormat.SCC,
269 | SubtitleFormat.SRT,
270 | SubtitleFormat.STL,
271 | SubtitleFormat.TTML
272 | };
273 |
274 | for(String subtitleFormat : supportSubtitleFormat){
275 | String subPath = prefix + subtitleFormat.toLowerCase();
276 |
277 | if(new File(subPath).exists()){
278 | subtitlePath = subPath;
279 |
280 | break;
281 | }
282 | }
283 |
284 | return subtitlePath;
285 | }
286 | }
287 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/util/AndroidUtil.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * AndroidUtil.java
3 | *****************************************************************************
4 | * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc.util;
22 |
23 | import android.net.Uri;
24 | import android.os.Build;
25 |
26 | import java.io.File;
27 |
28 | public class AndroidUtil {
29 | public static boolean isFroyoOrLater() {
30 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.FROYO;
31 | }
32 |
33 | public static boolean isGingerbreadOrLater() {
34 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD;
35 | }
36 |
37 | public static boolean isHoneycombOrLater() {
38 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB;
39 | }
40 |
41 | public static boolean isHoneycombMr1OrLater() {
42 | return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
43 | }
44 |
45 | public static boolean isHoneycombMr2OrLater() {
46 | return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2;
47 | }
48 |
49 | public static boolean isICSOrLater() {
50 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
51 | }
52 |
53 | public static boolean isJellyBeanOrLater() {
54 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
55 | }
56 |
57 | public static boolean isJellyBeanMR1OrLater() {
58 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
59 | }
60 |
61 | public static boolean isJellyBeanMR2OrLater() {
62 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
63 | }
64 |
65 | public static boolean isKitKatOrLater() {
66 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
67 | }
68 |
69 | public static boolean isLolliPopOrLater() {
70 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
71 | }
72 |
73 | public static boolean isMarshMallowOrLater() {
74 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
75 | }
76 |
77 | public static File UriToFile(Uri uri) {
78 | return new File(uri.getPath().replaceFirst("file://", ""));
79 | }
80 |
81 | /**
82 | * Quickly converts path to URIs, which are mandatory in libVLC.
83 | *
84 | * @param path The path to be converted.
85 | * @return A URI representation of path
86 | */
87 | public static Uri PathToUri(String path) {
88 | return Uri.fromFile(new File(path));
89 | }
90 |
91 | public static Uri LocationToUri(String location) {
92 | Uri uri = Uri.parse(location);
93 | if (uri.getScheme() == null)
94 | throw new IllegalArgumentException("location has no scheme");
95 | return uri;
96 | }
97 |
98 | public static Uri FileToUri(File file) {
99 | return Uri.fromFile(file);
100 | }
101 | }
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/util/Dumper.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * Dumper.java
3 | *****************************************************************************
4 | * Copyright © 2016 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc.util;
22 |
23 | import android.net.Uri;
24 | import android.support.annotation.MainThread;
25 |
26 | import org.videolan.libvlc.LibVLC;
27 | import org.videolan.libvlc.Media;
28 | import org.videolan.libvlc.MediaPlayer;
29 |
30 | import java.util.ArrayList;
31 |
32 | public class Dumper {
33 | public interface Listener {
34 | void onFinish(boolean success);
35 | void onProgress(float progress);
36 | }
37 |
38 | private final LibVLC mLibVLC;
39 | private final MediaPlayer mMediaPlayer;
40 | private final Listener mListener;
41 |
42 | /**
43 | * Create a Dumper that will download an Uri into a local filesystem path
44 | * @param uri the Uri to dump
45 | * @param filepath local filesystem path where to dump the Uri
46 | * @param listener listener in order to be notified when the dump is finished
47 | */
48 | @MainThread
49 | public Dumper(Uri uri, String filepath, Listener listener) {
50 | if (uri == null || filepath == null || listener == null)
51 | throw new IllegalArgumentException("arguments shouldn't be null");
52 | mListener = listener;
53 |
54 | ArrayList options = new ArrayList<>(8);
55 | options.add("--demux");
56 | options.add("dump2,none");
57 | options.add("--demuxdump-file");
58 | options.add(filepath);
59 | options.add("--no-video");
60 | options.add("--no-audio");
61 | options.add("--no-spu");
62 | options.add("-vvv");
63 | mLibVLC = new LibVLC(options);
64 |
65 | final Media media = new Media(mLibVLC, uri);
66 | mMediaPlayer = new MediaPlayer(media);
67 | mMediaPlayer.setEventListener(new MediaPlayer.EventListener() {
68 | @Override
69 | public void onEvent(MediaPlayer.Event event) {
70 | switch (event.type) {
71 | case MediaPlayer.Event.Buffering:
72 | mListener.onProgress(event.getBuffering());
73 | break;
74 | case MediaPlayer.Event.EncounteredError:
75 | case MediaPlayer.Event.EndReached:
76 | mListener.onFinish(event.type == MediaPlayer.Event.EndReached);
77 | cancel();
78 | break;
79 | }
80 |
81 | }
82 | });
83 | media.release();
84 | }
85 |
86 | /**
87 | * Start to dump
88 | */
89 | @MainThread
90 | public void start() {
91 | mMediaPlayer.play();
92 | }
93 |
94 | /**
95 | * Cancel the dump of the Uri.
96 | * Don't call this method if you already received the {@link Listener#onFinish(boolean)} callback.
97 | */
98 | @MainThread
99 | public void cancel() {
100 | mMediaPlayer.stop();
101 | mMediaPlayer.release();
102 | mLibVLC.release();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/util/Extensions.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * Extensions.java
3 | *****************************************************************************
4 | * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc.util;
22 |
23 | import java.util.Arrays;
24 | import java.util.HashSet;
25 |
26 | public class Extensions {
27 |
28 | public final static HashSet VIDEO = new HashSet();
29 | public final static HashSet AUDIO = new HashSet();
30 | public final static HashSet SUBTITLES = new HashSet();
31 | public final static HashSet PLAYLIST = new HashSet();
32 |
33 |
34 | static {
35 | final String[] videoExtensions = {
36 | ".3g2", ".3gp", ".3gp2", ".3gpp", ".amv", ".asf", ".avi", ".divx", ".drc", ".dv",
37 | ".f4v", ".flv", ".gvi", ".gxf", ".ismv", ".iso", ".m1v", ".m2v", ".m2t", ".m2ts",
38 | ".m4v", ".mkv", ".mov", ".mp2", ".mp2v", ".mp4", ".mp4v", ".mpe", ".mpeg",
39 | ".mpeg1", ".mpeg2", ".mpeg4", ".mpg", ".mpv2", ".mts", ".mtv", ".mxf", ".mxg",
40 | ".nsv", ".nut", ".nuv", ".ogm", ".ogv", ".ogx", ".ps", ".rec", ".rm", ".rmvb",
41 | ".tod", ".ts", ".tts", ".vob", ".vro", ".webm", ".wm", ".wmv", ".wtv", ".xesc" };
42 |
43 | final String[] audioExtensions = {
44 | ".3ga", ".a52", ".aac", ".ac3", ".adt", ".adts", ".aif", ".aifc", ".aiff", ".amr",
45 | ".aob", ".ape", ".awb", ".caf", ".dts", ".flac", ".it", ".m4a", ".m4b", ".m4p",
46 | ".mid", ".mka", ".mlp", ".mod", ".mpa", ".mp1", ".mp2", ".mp3", ".mpc", ".mpga",
47 | ".oga", ".ogg", ".oma", ".opus", ".ra", ".ram", ".rmi", ".s3m", ".spx", ".tta",
48 | ".voc", ".vqf", ".w64", ".wav", ".wma", ".wv", ".xa", ".xm" };
49 |
50 | final String[] subtitlesExtensions = {
51 | ".idx", ".sub", ".srt", ".ssa", ".ass", ".smi", ".utf", ".utf8", ".utf-8",
52 | ".rt", ".aqt", ".txt", ".usf", ".jss", ".cdg", ".psb", ".mpsub",".mpl2",
53 | ".pjs", ".dks", ".stl", ".vtt" };
54 |
55 | final String[] playlistExtensions = {".m3u", ".asx", ".b4s", ".pls", ".xspf"/*, ".zip"*/};
56 |
57 | VIDEO.addAll(Arrays.asList(videoExtensions));
58 | AUDIO.addAll(Arrays.asList(audioExtensions));
59 | SUBTITLES.addAll(Arrays.asList(subtitlesExtensions));
60 | PLAYLIST.addAll(Arrays.asList(playlistExtensions));
61 | }
62 | }
--------------------------------------------------------------------------------
/vlc/src/main/java/org/videolan/libvlc/util/HWDecoderUtil.java:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * HWDecUtil.java
3 | *****************************************************************************
4 | * Copyright © 2010-2013 VLC authors and VideoLAN
5 | *
6 | * This program is free software; you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation; either version 2.1 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program; if not, write to the Free Software Foundation,
18 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 | *****************************************************************************/
20 |
21 | package org.videolan.libvlc.util;
22 |
23 | import java.lang.reflect.Method;
24 | import java.util.HashMap;
25 |
26 | /**
27 | * Utility class that return the preferred hardware decoder from a list of known devices.
28 | */
29 | public class HWDecoderUtil {
30 |
31 | public static final boolean HAS_SUBTITLES_SURFACE = AndroidUtil.isGingerbreadOrLater();
32 |
33 | public enum Decoder {
34 | UNKNOWN, NONE, OMX, MEDIACODEC, ALL
35 | }
36 |
37 | public enum AudioOutput {
38 | OPENSLES, AUDIOTRACK, ALL
39 | }
40 |
41 | private static class DecoderBySOC {
42 | public final String key;
43 | public final String value;
44 | public final Decoder dec;
45 | public DecoderBySOC(String key, String value, Decoder dec) {
46 | this.key = key;
47 | this.value = value;
48 | this.dec = dec;
49 | }
50 | }
51 |
52 | private static class AudioOutputBySOC {
53 | public final String key;
54 | public final String value;
55 | public final AudioOutput aout;
56 |
57 | public AudioOutputBySOC(String key, String value, AudioOutput aout) {
58 | this.key = key;
59 | this.value = value;
60 | this.aout = aout;
61 | }
62 | }
63 |
64 | private static final DecoderBySOC[] sBlacklistedDecoderBySOCList = new DecoderBySOC[] {
65 | /*
66 | * FIXME: Theses cpu crash in MediaCodec. We need to get hands on these devices in order to debug it.
67 | */
68 | new DecoderBySOC("ro.product.board", "MSM8225", Decoder.NONE), //Samsung Galaxy Core
69 | new DecoderBySOC("ro.product.board", "hawaii", Decoder.NONE), // Samsung Galaxy Ace 4
70 | };
71 |
72 | private static final DecoderBySOC[] sDecoderBySOCList = new DecoderBySOC[] {
73 | /*
74 | * Put first devices you want to blacklist
75 | * because theses devices can match the next rules.
76 | */
77 | new DecoderBySOC("ro.product.brand", "SEMC", Decoder.NONE), // Xperia S
78 | new DecoderBySOC("ro.board.platform", "msm7627", Decoder.NONE), // QCOM S1
79 |
80 | /*
81 | * Even if omap, old Amazon devices don't work with OMX, so either use MediaCodec or SW.
82 | */
83 | new DecoderBySOC("ro.product.brand", "Amazon", Decoder.MEDIACODEC),
84 |
85 | /*
86 | * Devices working on OMX
87 | */
88 | new DecoderBySOC("ro.board.platform", "omap3", Decoder.OMX), // Omap 3
89 | new DecoderBySOC("ro.board.platform", "rockchip", Decoder.OMX), // Rockchip RK29
90 | new DecoderBySOC("ro.board.platform", "rk29", Decoder.OMX), // Rockchip RK29
91 | new DecoderBySOC("ro.board.platform", "msm7630", Decoder.OMX), // QCOM S2
92 | new DecoderBySOC("ro.board.platform", "s5pc", Decoder.OMX), // Exynos 3
93 | new DecoderBySOC("ro.board.platform", "montblanc", Decoder.OMX), // Montblanc
94 | new DecoderBySOC("ro.board.platform", "exdroid", Decoder.OMX), // Allwinner A31
95 | new DecoderBySOC("ro.board.platform", "sun6i", Decoder.OMX), // Allwinner A31
96 |
97 | /*
98 | * Devices working only on Mediacodec
99 | */
100 | new DecoderBySOC("ro.board.platform", "exynos4", Decoder.MEDIACODEC), // Exynos 4 (Samsung Galaxy S2/S3)
101 |
102 | /*
103 | * Devices working on Mediacodec and OMX
104 | */
105 | new DecoderBySOC("ro.board.platform", "omap4", Decoder.ALL), // Omap 4
106 | new DecoderBySOC("ro.board.platform", "tegra", Decoder.ALL), // Tegra 2 & 3
107 | new DecoderBySOC("ro.board.platform", "tegra3", Decoder.ALL), // Tegra 3
108 | new DecoderBySOC("ro.board.platform", "msm8660", Decoder.ALL), // QCOM S3
109 | new DecoderBySOC("ro.board.platform", "exynos5", Decoder.ALL), // Exynos 5 (Samsung Galaxy S4)
110 | new DecoderBySOC("ro.board.platform", "rk30", Decoder.ALL), // Rockchip RK30
111 | new DecoderBySOC("ro.board.platform", "rk31", Decoder.ALL), // Rockchip RK31
112 | new DecoderBySOC("ro.board.platform", "mv88de3100", Decoder.ALL), // Marvell ARMADA 1500
113 |
114 | new DecoderBySOC("ro.hardware", "mt83", Decoder.ALL), //MTK
115 | };
116 |
117 | private static final AudioOutputBySOC[] sAudioOutputBySOCList = new AudioOutputBySOC[] {
118 | /* getPlaybackHeadPosition returns an invalid position on Fire OS,
119 | * thus Audiotrack is not usable */
120 | new AudioOutputBySOC("ro.product.brand", "Amazon", AudioOutput.OPENSLES),
121 | new AudioOutputBySOC("ro.product.manufacturer", "Amazon", AudioOutput.OPENSLES),
122 | };
123 |
124 | private static final HashMap sSystemPropertyMap = new HashMap();
125 |
126 | /**
127 | * @return the hardware decoder known to work for the running device
128 | * (Always return Dec.ALL after Android 4.3)
129 | */
130 | public static Decoder getDecoderFromDevice() {
131 | /*
132 | * Try first blacklisted decoders (for all android versions)
133 | */
134 | for (DecoderBySOC decBySOC : sBlacklistedDecoderBySOCList) {
135 | final String prop = getSystemPropertyCached(decBySOC.key);
136 | if (prop != null) {
137 | if (prop.contains(decBySOC.value))
138 | return decBySOC.dec;
139 | }
140 | }
141 | /*
142 | * Always try MediaCodec after JellyBean MR2,
143 | * Try OMX or MediaCodec after HoneyComb depending on device properties.
144 | * Otherwise, use software decoder by default.
145 | */
146 | if (AndroidUtil.isJellyBeanMR2OrLater())
147 | return Decoder.ALL;
148 | else if (AndroidUtil.isHoneycombOrLater()) {
149 | for (DecoderBySOC decBySOC : sDecoderBySOCList) {
150 | final String prop = getSystemPropertyCached(decBySOC.key);
151 | if (prop != null) {
152 | if (prop.contains(decBySOC.value))
153 | return decBySOC.dec;
154 | }
155 | }
156 | }
157 | return Decoder.UNKNOWN;
158 | }
159 |
160 | /**
161 | * @return the audio output known to work for the running device
162 | * (By default, returns ALL, i.e AudioTrack + OpenSles)
163 | */
164 | public static AudioOutput getAudioOutputFromDevice() {
165 | if (!AndroidUtil.isGingerbreadOrLater()) {
166 | return AudioOutput.AUDIOTRACK;
167 | } else {
168 | for (AudioOutputBySOC aoutBySOC : sAudioOutputBySOCList) {
169 | final String prop = getSystemPropertyCached(aoutBySOC.key);
170 | if (prop != null) {
171 | if (prop.contains(aoutBySOC.value))
172 | return aoutBySOC.aout;
173 | }
174 | }
175 | return AudioOutput.ALL;
176 | }
177 | }
178 |
179 | private static String getSystemPropertyCached(String key) {
180 | String prop = sSystemPropertyMap.get(key);
181 | if (prop == null) {
182 | prop = getSystemProperty(key, "none");
183 | sSystemPropertyMap.put(key, prop);
184 | }
185 | return prop;
186 | }
187 |
188 | private static String getSystemProperty(String key, String def) {
189 | try {
190 | final ClassLoader cl = ClassLoader.getSystemClassLoader();
191 | final Class> SystemProperties = cl.loadClass("android.os.SystemProperties");
192 | final Class>[] paramTypes = new Class[] { String.class, String.class };
193 | final Method get = SystemProperties.getMethod("get", paramTypes);
194 | final Object[] params = new Object[] { key, def };
195 | return (String) get.invoke(SystemProperties, params);
196 | } catch (Exception e){
197 | return def;
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libanw.10.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libanw.10.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libanw.13.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libanw.13.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libanw.14.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libanw.14.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libanw.18.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libanw.18.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libanw.21.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libanw.21.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libcompat.7.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libcompat.7.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libiomx.10.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libiomx.10.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libiomx.13.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libiomx.13.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libiomx.14.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libiomx.14.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libvlc.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libvlc.so
--------------------------------------------------------------------------------
/vlc/src/main/jniLibs/armeabi-v7a/libvlcjni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shirlman/YiPlayer/4da831ccde874afe4f308073fce981743d3a9221/vlc/src/main/jniLibs/armeabi-v7a/libvlcjni.so
--------------------------------------------------------------------------------
/vlc/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | vlc
3 |
4 |
--------------------------------------------------------------------------------