├── .gitignore ├── LICENSE ├── README.md ├── app ├── build.gradle └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wass08 │ │ └── vlcsimpleplayer │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── com │ │ └── wass08 │ │ │ └── vlcsimpleplayer │ │ │ ├── FullscreenVlcPlayer.java │ │ │ ├── MediaSelector.java │ │ │ └── util │ │ │ ├── SystemUiHider.java │ │ │ ├── SystemUiHiderBase.java │ │ │ └── SystemUiHiderHoneycomb.java │ └── org │ │ └── videolan │ │ └── libvlc │ │ ├── Aout.java │ │ ├── EventHandler.java │ │ ├── IVideoPlayer.java │ │ ├── LibVLC.java │ │ ├── LibVlcException.java │ │ ├── LibVlcUtil.java │ │ ├── Media.java │ │ ├── MediaList.java │ │ └── TrackInfo.java │ ├── jniLibs │ └── armeabi-v7a │ │ ├── libiomx-gingerbread.so │ │ ├── libiomx-hc.so │ │ ├── libiomx-ics.so │ │ └── libvlcjni.so │ └── res │ ├── drawable-hdpi │ ├── ic_action_pause_over_video.png │ ├── ic_action_play_over_video.png │ └── ic_launcher.png │ ├── drawable-mdpi │ └── ic_launcher.png │ ├── drawable-xhdpi │ └── ic_launcher.png │ ├── drawable-xxhdpi │ └── ic_launcher.png │ ├── layout │ ├── activity_fullscreen_vlc_player.xml │ └── activity_media_selector.xml │ ├── menu │ └── menu_media_selector.xml │ ├── values-v11 │ └── styles.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ └── gradle-wrapper.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Log Files 26 | *.log 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Wassim SAMAD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | VLC-Simple-Player-Android 2 | ========================= 3 | 4 | **Basic Movie Player for Android using VLC Library** 5 | 6 | *The project was created with Android Studio* 7 | 8 | ##What is it ? 9 | 10 | This project is to understand how to implement VLC Library in your Android Project. 11 | 12 | It works with direct URL for streaming or you can directly put local movie path. 13 | 14 | ![alt tag](http://wassimsamad.fr/images/home.png) 15 | ![alt tag](http://wassimsamad.fr/images/fullscreen.png) 16 | ![alt tag](http://wassimsamad.fr/images/fullscreen_overlay.png) 17 | 18 | ##Improvements ? 19 | 20 | You are free to do whatever you want with it. It's very basic. 21 | 22 | Improve the UI to your needs, add functionnalities and make your powerful player. 23 | 24 | 25 | # Thank you ! 26 | ### For more tutorials : [Visit my blog here ](http://www.wassimsamad.fr/blog) -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 20 5 | buildToolsVersion "20.0.0" 6 | 7 | defaultConfig { 8 | applicationId "com.wass08.vlcsimpleplayer" 9 | minSdkVersion 12 10 | targetSdkVersion 20 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | runProguard false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | } 25 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/wass08/vlcsimpleplayer/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.wass08.vlcsimpleplayer; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/wass08/vlcsimpleplayer/FullscreenVlcPlayer.java: -------------------------------------------------------------------------------- 1 | package com.wass08.vlcsimpleplayer; 2 | 3 | import com.wass08.vlcsimpleplayer.util.SystemUiHider; 4 | 5 | import android.annotation.TargetApi; 6 | import android.app.Activity; 7 | import android.content.pm.ActivityInfo; 8 | import android.content.res.Configuration; 9 | import android.graphics.PixelFormat; 10 | import android.os.Build; 11 | import android.os.Bundle; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.util.DisplayMetrics; 15 | import android.util.Log; 16 | import android.view.Gravity; 17 | import android.view.MotionEvent; 18 | import android.view.SurfaceHolder; 19 | import android.view.SurfaceView; 20 | import android.view.View; 21 | import android.view.ViewGroup; 22 | import android.view.Window; 23 | import android.view.WindowManager; 24 | import android.widget.FrameLayout; 25 | import android.widget.ImageView; 26 | import android.widget.LinearLayout; 27 | import android.widget.ScrollView; 28 | import android.widget.SeekBar; 29 | import android.widget.TextView; 30 | import android.widget.Toast; 31 | 32 | import org.videolan.libvlc.EventHandler; 33 | import org.videolan.libvlc.IVideoPlayer; 34 | import org.videolan.libvlc.LibVLC; 35 | import org.videolan.libvlc.Media; 36 | import org.videolan.libvlc.MediaList; 37 | 38 | import java.lang.ref.WeakReference; 39 | 40 | 41 | /** 42 | * An example full-screen activity that shows and hides the system UI (i.e. 43 | * status bar and navigation/system bar) with user interaction. 44 | * 45 | * @see SystemUiHider 46 | */ 47 | public class FullscreenVlcPlayer extends Activity implements SurfaceHolder.Callback, IVideoPlayer { 48 | 49 | private String urlToStream; 50 | 51 | // Display Surface 52 | private LinearLayout vlcContainer; 53 | private SurfaceView mSurface; 54 | private SurfaceHolder holder; 55 | 56 | // Overlay / Controls 57 | 58 | private FrameLayout vlcOverlay; 59 | private ImageView vlcButtonPlayPause; 60 | private Handler handlerOverlay; 61 | private Runnable runnableOverlay; 62 | private Handler handlerSeekbar; 63 | private Runnable runnableSeekbar; 64 | private SeekBar vlcSeekbar; 65 | private TextView vlcDuration; 66 | private TextView overlayTitle; 67 | 68 | // media player 69 | private LibVLC libvlc; 70 | private int mVideoWidth; 71 | private int mVideoHeight; 72 | private final static int VideoSizeChanged = -1; 73 | 74 | @Override 75 | protected void onCreate(Bundle savedInstanceState) { 76 | super.onCreate(savedInstanceState); 77 | 78 | // Retrieve our url 79 | Bundle b = getIntent().getExtras(); 80 | urlToStream = b.getString("url", null); 81 | 82 | 83 | // HIDE THE ACTION BAR 84 | getActionBar().hide(); 85 | 86 | // SETUP THE UI 87 | setContentView(R.layout.activity_fullscreen_vlc_player); 88 | 89 | // VLC 90 | vlcContainer = (LinearLayout) findViewById(R.id.vlc_container); 91 | mSurface = (SurfaceView) findViewById(R.id.vlc_surface); 92 | 93 | 94 | // OVERLAY / CONTROLS 95 | vlcOverlay = (FrameLayout) findViewById(R.id.vlc_overlay); 96 | vlcButtonPlayPause = (ImageView) findViewById(R.id.vlc_button_play_pause); 97 | vlcSeekbar = (SeekBar) findViewById(R.id.vlc_seekbar); 98 | vlcDuration = (TextView) findViewById(R.id.vlc_duration); 99 | 100 | overlayTitle = (TextView) findViewById(R.id.vlc_overlay_title); 101 | overlayTitle.setText(urlToStream); 102 | 103 | // AUTOSTART 104 | playMovie(); 105 | 106 | } 107 | 108 | private void showOverlay() { 109 | vlcOverlay.setVisibility(View.VISIBLE); 110 | } 111 | 112 | private void hideOverlay() { 113 | vlcOverlay.setVisibility(View.GONE); 114 | } 115 | 116 | private void setupControls() { 117 | getActionBar().hide(); 118 | // PLAY PAUSE 119 | vlcButtonPlayPause.setOnClickListener(new View.OnClickListener() { 120 | @Override 121 | public void onClick(View view) { 122 | if (libvlc.isPlaying()) { 123 | libvlc.pause(); 124 | vlcButtonPlayPause.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_play_over_video)); 125 | } else { 126 | libvlc.play(); 127 | vlcButtonPlayPause.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_pause_over_video)); 128 | } 129 | } 130 | }); 131 | 132 | // SEEKBAR 133 | handlerSeekbar = new Handler(); 134 | runnableSeekbar = new Runnable() { 135 | @Override 136 | public void run() { 137 | if (libvlc != null) { 138 | long curTime = libvlc.getTime(); 139 | long totalTime = (long) (curTime / libvlc.getPosition()); 140 | int minutes = (int) (curTime / (60 * 1000)); 141 | int seconds = (int) ((curTime / 1000) % 60); 142 | int endMinutes = (int) (totalTime / (60 * 1000)); 143 | int endSeconds = (int) ((totalTime / 1000) % 60); 144 | String duration = String.format("%02d:%02d / %02d:%02d", minutes, seconds, endMinutes, endSeconds); 145 | vlcSeekbar.setProgress((int) (libvlc.getPosition() * 100)); 146 | vlcDuration.setText(duration); 147 | } 148 | handlerSeekbar.postDelayed(runnableSeekbar, 1000); 149 | } 150 | }; 151 | 152 | runnableSeekbar.run(); 153 | vlcSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 154 | @Override 155 | public void onProgressChanged(SeekBar seekBar, int i, boolean b) { 156 | Log.v("NEW POS", "pos is : " + i); 157 | //if (i != 0) 158 | // libvlc.setPosition(((float) i / 100.0f)); 159 | } 160 | 161 | @Override 162 | public void onStartTrackingTouch(SeekBar seekBar) { 163 | 164 | } 165 | 166 | @Override 167 | public void onStopTrackingTouch(SeekBar seekBar) { 168 | 169 | } 170 | }); 171 | 172 | // OVERLAY 173 | handlerOverlay = new Handler(); 174 | runnableOverlay = new Runnable() { 175 | @Override 176 | public void run() { 177 | vlcOverlay.setVisibility(View.GONE); 178 | toggleFullscreen(true); 179 | } 180 | }; 181 | final long timeToDisappear = 3000; 182 | handlerOverlay.postDelayed(runnableOverlay, timeToDisappear); 183 | vlcContainer.setOnClickListener(new View.OnClickListener() { 184 | @Override 185 | public void onClick(View view) { 186 | vlcOverlay.setVisibility(View.VISIBLE); 187 | 188 | handlerOverlay.removeCallbacks(runnableOverlay); 189 | handlerOverlay.postDelayed(runnableOverlay, timeToDisappear); 190 | } 191 | }); 192 | } 193 | 194 | public void playMovie() { 195 | if (libvlc != null && libvlc.isPlaying()) 196 | return ; 197 | vlcContainer.setVisibility(View.VISIBLE); 198 | holder = mSurface.getHolder(); 199 | holder.addCallback(this); 200 | createPlayer(urlToStream); 201 | } 202 | 203 | 204 | private void toggleFullscreen(boolean fullscreen) 205 | { 206 | WindowManager.LayoutParams attrs = getWindow().getAttributes(); 207 | if (fullscreen) 208 | { 209 | attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; 210 | vlcContainer.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE 211 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 212 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 213 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 214 | | View.SYSTEM_UI_FLAG_FULLSCREEN 215 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 216 | } 217 | else 218 | { 219 | attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN; 220 | } 221 | getWindow().setAttributes(attrs); 222 | } 223 | 224 | @Override 225 | public void onConfigurationChanged(Configuration newConfig) { 226 | super.onConfigurationChanged(newConfig); 227 | setSize(mVideoWidth, mVideoHeight); 228 | } 229 | 230 | @Override 231 | protected void onResume() { 232 | super.onResume(); 233 | } 234 | 235 | @Override 236 | protected void onPause() { 237 | super.onPause(); 238 | //releasePlayer(); 239 | } 240 | 241 | @Override 242 | protected void onDestroy() { 243 | super.onDestroy(); 244 | releasePlayer(); 245 | } 246 | 247 | /** 248 | * ********** 249 | * Surface 250 | * *********** 251 | */ 252 | 253 | public void surfaceCreated(SurfaceHolder holder) { 254 | } 255 | 256 | public void surfaceChanged(SurfaceHolder surfaceholder, int format, 257 | int width, int height) { 258 | if (libvlc != null) 259 | libvlc.attachSurface(surfaceholder.getSurface(), this); 260 | } 261 | 262 | public void surfaceDestroyed(SurfaceHolder surfaceholder) { 263 | } 264 | 265 | private void setSize(int width, int height) { 266 | mVideoWidth = width; 267 | mVideoHeight = height; 268 | if (mVideoWidth * mVideoHeight <= 1) 269 | return; 270 | 271 | // get screen size 272 | int w = getWindow().getDecorView().getWidth(); 273 | int h = getWindow().getDecorView().getHeight(); 274 | 275 | // getWindow().getDecorView() doesn't always take orientation into 276 | // account, we have to correct the values 277 | boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 278 | if (w > h && isPortrait || w < h && !isPortrait) { 279 | int i = w; 280 | w = h; 281 | h = i; 282 | } 283 | 284 | float videoAR = (float) mVideoWidth / (float) mVideoHeight; 285 | float screenAR = (float) w / (float) h; 286 | 287 | if (screenAR < videoAR) 288 | h = (int) (w / videoAR); 289 | else 290 | w = (int) (h * videoAR); 291 | 292 | // force surface buffer size 293 | if (holder != null) 294 | holder.setFixedSize(mVideoWidth, mVideoHeight); 295 | 296 | // set display size 297 | ViewGroup.LayoutParams lp = mSurface.getLayoutParams(); 298 | lp.width = w; 299 | lp.height = h; 300 | mSurface.setLayoutParams(lp); 301 | mSurface.invalidate(); 302 | } 303 | 304 | @Override 305 | public void setSurfaceSize(int width, int height, int visible_width, 306 | int visible_height, int sar_num, int sar_den) { 307 | Message msg = Message.obtain(mHandler, VideoSizeChanged, width, height); 308 | msg.sendToTarget(); 309 | } 310 | 311 | /** 312 | * ********** 313 | * Player 314 | * *********** 315 | */ 316 | 317 | private void createPlayer(String media) { 318 | releasePlayer(); 319 | setupControls(); 320 | try { 321 | if (media.length() > 0) { 322 | Toast toast = Toast.makeText(this, media, Toast.LENGTH_LONG); 323 | toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 324 | 0); 325 | toast.show(); 326 | } 327 | 328 | // Create a new media player 329 | libvlc = LibVLC.getInstance(); 330 | libvlc.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL); 331 | libvlc.eventVideoPlayerActivityCreated(true); 332 | libvlc.setSubtitlesEncoding(""); 333 | libvlc.setAout(LibVLC.AOUT_OPENSLES); 334 | libvlc.setTimeStretching(true); 335 | libvlc.setChroma("RV32"); 336 | libvlc.setVerboseMode(true); 337 | LibVLC.restart(this); 338 | EventHandler.getInstance().addHandler(mHandler); 339 | holder.setFormat(PixelFormat.RGBX_8888); 340 | holder.setKeepScreenOn(true); 341 | MediaList list = libvlc.getMediaList(); 342 | list.clear(); 343 | list.add(new Media(libvlc, LibVLC.PathToURI(media)), false); 344 | libvlc.playIndex(0); 345 | } catch (Exception e) { 346 | Toast.makeText(this, "Could not create Vlc Player", Toast.LENGTH_LONG).show(); 347 | } 348 | } 349 | 350 | private void releasePlayer() { 351 | if (handlerSeekbar != null && runnableSeekbar != null) 352 | handlerSeekbar.removeCallbacks(runnableSeekbar); 353 | EventHandler.getInstance().removeHandler(mHandler); 354 | if (libvlc == null) 355 | return; 356 | libvlc.stop(); 357 | libvlc.detachSurface(); 358 | holder = null; 359 | libvlc.closeAout(); 360 | 361 | mVideoWidth = 0; 362 | mVideoHeight = 0; 363 | } 364 | 365 | /** 366 | * ********** 367 | * Events 368 | * *********** 369 | */ 370 | 371 | private Handler mHandler = new MyHandler(this); 372 | 373 | private static class MyHandler extends Handler { 374 | private WeakReference mOwner; 375 | 376 | public MyHandler(FullscreenVlcPlayer owner) { 377 | mOwner = new WeakReference(owner); 378 | } 379 | 380 | @Override 381 | public void handleMessage(Message msg) { 382 | FullscreenVlcPlayer player = mOwner.get(); 383 | 384 | // Player events 385 | if (msg.what == VideoSizeChanged) { 386 | player.setSize(msg.arg1, msg.arg2); 387 | return; 388 | } 389 | 390 | // Libvlc events 391 | Bundle b = msg.getData(); 392 | switch (b.getInt("event")) { 393 | case EventHandler.MediaPlayerEndReached: 394 | player.releasePlayer(); 395 | break; 396 | case EventHandler.MediaPlayerPlaying: 397 | case EventHandler.MediaPlayerPaused: 398 | case EventHandler.MediaPlayerStopped: 399 | default: 400 | break; 401 | } 402 | } 403 | } 404 | 405 | } 406 | -------------------------------------------------------------------------------- /app/src/main/java/com/wass08/vlcsimpleplayer/MediaSelector.java: -------------------------------------------------------------------------------- 1 | package com.wass08.vlcsimpleplayer; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.Menu; 7 | import android.view.MenuItem; 8 | import android.view.View; 9 | import android.widget.EditText; 10 | import android.widget.TextView; 11 | 12 | 13 | public class MediaSelector extends Activity { 14 | 15 | private EditText urlGetter; 16 | private TextView buttonStart; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_media_selector); 22 | urlGetter = (EditText)findViewById(R.id.url_getter); 23 | buttonStart = (TextView)findViewById(R.id.button_start); 24 | buttonStart.setOnClickListener(new View.OnClickListener() { 25 | @Override 26 | public void onClick(View view) { 27 | Intent toFullscreen = new Intent(MediaSelector.this, FullscreenVlcPlayer.class); 28 | Bundle b = new Bundle(); 29 | 30 | // Pass the url from the input to the player 31 | b.putString("url", urlGetter.getText().toString()); 32 | toFullscreen.putExtras(b); //Put your id to your next Intent 33 | startActivity(toFullscreen); 34 | } 35 | }); 36 | } 37 | 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/wass08/vlcsimpleplayer/util/SystemUiHider.java: -------------------------------------------------------------------------------- 1 | package com.wass08.vlcsimpleplayer.util; 2 | 3 | import android.app.Activity; 4 | import android.os.Build; 5 | import android.view.View; 6 | 7 | /** 8 | * A utility class that helps with showing and hiding system UI such as the 9 | * status bar and navigation/system bar. This class uses backward-compatibility 10 | * techniques described in 12 | * Creating Backward-Compatible UIs to ensure that devices running any 13 | * version of ndroid OS are supported. More specifically, there are separate 14 | * implementations of this abstract class: for newer devices, 15 | * {@link #getInstance} will return a {@link SystemUiHiderHoneycomb} instance, 16 | * while on older devices {@link #getInstance} will return a 17 | * {@link SystemUiHiderBase} instance. 18 | *

19 | * For more on system bars, see System Bars. 22 | * 23 | * @see android.view.View#setSystemUiVisibility(int) 24 | * @see android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 25 | */ 26 | public abstract class SystemUiHider { 27 | /** 28 | * When this flag is set, the 29 | * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN} 30 | * flag will be set on older devices, making the status bar "float" on top 31 | * of the activity layout. This is most useful when there are no controls at 32 | * the top of the activity layout. 33 | *

34 | * This flag isn't used on newer devices because the action 36 | * bar, the most important structural element of an Android app, should 37 | * be visible and not obscured by the system UI. 38 | */ 39 | public static final int FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES = 0x1; 40 | 41 | /** 42 | * When this flag is set, {@link #show()} and {@link #hide()} will toggle 43 | * the visibility of the status bar. If there is a navigation bar, show and 44 | * hide will toggle low profile mode. 45 | */ 46 | public static final int FLAG_FULLSCREEN = 0x2; 47 | 48 | /** 49 | * When this flag is set, {@link #show()} and {@link #hide()} will toggle 50 | * the visibility of the navigation bar, if it's present on the device and 51 | * the device allows hiding it. In cases where the navigation bar is present 52 | * but cannot be hidden, show and hide will toggle low profile mode. 53 | */ 54 | public static final int FLAG_HIDE_NAVIGATION = FLAG_FULLSCREEN | 0x4; 55 | 56 | /** 57 | * The activity associated with this UI hider object. 58 | */ 59 | protected Activity mActivity; 60 | 61 | /** 62 | * The view on which {@link View#setSystemUiVisibility(int)} will be called. 63 | */ 64 | protected View mAnchorView; 65 | 66 | /** 67 | * The current UI hider flags. 68 | * 69 | * @see #FLAG_FULLSCREEN 70 | * @see #FLAG_HIDE_NAVIGATION 71 | * @see #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES 72 | */ 73 | protected int mFlags; 74 | 75 | /** 76 | * The current visibility callback. 77 | */ 78 | protected OnVisibilityChangeListener mOnVisibilityChangeListener = sDummyListener; 79 | 80 | /** 81 | * Creates and returns an instance of {@link SystemUiHider} that is 82 | * appropriate for this device. The object will be either a 83 | * {@link SystemUiHiderBase} or {@link SystemUiHiderHoneycomb} depending on 84 | * the device. 85 | * 86 | * @param activity The activity whose window's system UI should be 87 | * controlled by this class. 88 | * @param anchorView The view on which 89 | * {@link View#setSystemUiVisibility(int)} will be called. 90 | * @param flags Either 0 or any combination of {@link #FLAG_FULLSCREEN}, 91 | * {@link #FLAG_HIDE_NAVIGATION}, and 92 | * {@link #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES}. 93 | */ 94 | public static SystemUiHider getInstance(Activity activity, View anchorView, int flags) { 95 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 96 | return new SystemUiHiderHoneycomb(activity, anchorView, flags); 97 | } else { 98 | return new SystemUiHiderBase(activity, anchorView, flags); 99 | } 100 | } 101 | 102 | protected SystemUiHider(Activity activity, View anchorView, int flags) { 103 | mActivity = activity; 104 | mAnchorView = anchorView; 105 | mFlags = flags; 106 | } 107 | 108 | /** 109 | * Sets up the system UI hider. Should be called from 110 | * {@link Activity#onCreate}. 111 | */ 112 | public abstract void setup(); 113 | 114 | /** 115 | * Returns whether or not the system UI is visible. 116 | */ 117 | public abstract boolean isVisible(); 118 | 119 | /** 120 | * Hide the system UI. 121 | */ 122 | public abstract void hide(); 123 | 124 | /** 125 | * Show the system UI. 126 | */ 127 | public abstract void show(); 128 | 129 | /** 130 | * Toggle the visibility of the system UI. 131 | */ 132 | public void toggle() { 133 | if (isVisible()) { 134 | hide(); 135 | } else { 136 | show(); 137 | } 138 | } 139 | 140 | /** 141 | * Registers a callback, to be triggered when the system UI visibility 142 | * changes. 143 | */ 144 | public void setOnVisibilityChangeListener(OnVisibilityChangeListener listener) { 145 | if (listener == null) { 146 | listener = sDummyListener; 147 | } 148 | 149 | mOnVisibilityChangeListener = listener; 150 | } 151 | 152 | /** 153 | * A dummy no-op callback for use when there is no other listener set. 154 | */ 155 | private static OnVisibilityChangeListener sDummyListener = new OnVisibilityChangeListener() { 156 | @Override 157 | public void onVisibilityChange(boolean visible) { 158 | } 159 | }; 160 | 161 | /** 162 | * A callback interface used to listen for system UI visibility changes. 163 | */ 164 | public interface OnVisibilityChangeListener { 165 | /** 166 | * Called when the system UI visibility has changed. 167 | * 168 | * @param visible True if the system UI is visible. 169 | */ 170 | public void onVisibilityChange(boolean visible); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /app/src/main/java/com/wass08/vlcsimpleplayer/util/SystemUiHiderBase.java: -------------------------------------------------------------------------------- 1 | package com.wass08.vlcsimpleplayer.util; 2 | 3 | import android.app.Activity; 4 | import android.view.View; 5 | import android.view.WindowManager; 6 | 7 | /** 8 | * A base implementation of {@link SystemUiHider}. Uses APIs available in all 9 | * API levels to show and hide the status bar. 10 | */ 11 | public class SystemUiHiderBase extends SystemUiHider { 12 | /** 13 | * Whether or not the system UI is currently visible. This is a cached value 14 | * from calls to {@link #hide()} and {@link #show()}. 15 | */ 16 | private boolean mVisible = true; 17 | 18 | /** 19 | * Constructor not intended to be called by clients. Use 20 | * {@link SystemUiHider#getInstance} to obtain an instance. 21 | */ 22 | protected SystemUiHiderBase(Activity activity, View anchorView, int flags) { 23 | super(activity, anchorView, flags); 24 | } 25 | 26 | @Override 27 | public void setup() { 28 | if ((mFlags & FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES) == 0) { 29 | mActivity.getWindow().setFlags( 30 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 31 | | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, 32 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 33 | | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 34 | } 35 | } 36 | 37 | @Override 38 | public boolean isVisible() { 39 | return mVisible; 40 | } 41 | 42 | @Override 43 | public void hide() { 44 | if ((mFlags & FLAG_FULLSCREEN) != 0) { 45 | mActivity.getWindow().setFlags( 46 | WindowManager.LayoutParams.FLAG_FULLSCREEN, 47 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 48 | } 49 | mOnVisibilityChangeListener.onVisibilityChange(false); 50 | mVisible = false; 51 | } 52 | 53 | @Override 54 | public void show() { 55 | if ((mFlags & FLAG_FULLSCREEN) != 0) { 56 | mActivity.getWindow().setFlags( 57 | 0, 58 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 59 | } 60 | mOnVisibilityChangeListener.onVisibilityChange(true); 61 | mVisible = true; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/wass08/vlcsimpleplayer/util/SystemUiHiderHoneycomb.java: -------------------------------------------------------------------------------- 1 | package com.wass08.vlcsimpleplayer.util; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.os.Build; 6 | import android.view.View; 7 | import android.view.WindowManager; 8 | 9 | /** 10 | * An API 11+ implementation of {@link SystemUiHider}. Uses APIs available in 11 | * Honeycomb and later (specifically {@link View#setSystemUiVisibility(int)}) to 12 | * show and hide the system UI. 13 | */ 14 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 15 | public class SystemUiHiderHoneycomb extends SystemUiHiderBase { 16 | /** 17 | * Flags for {@link View#setSystemUiVisibility(int)} to use when showing the 18 | * system UI. 19 | */ 20 | private int mShowFlags; 21 | 22 | /** 23 | * Flags for {@link View#setSystemUiVisibility(int)} to use when hiding the 24 | * system UI. 25 | */ 26 | private int mHideFlags; 27 | 28 | /** 29 | * Flags to test against the first parameter in 30 | * {@link android.view.View.OnSystemUiVisibilityChangeListener#onSystemUiVisibilityChange(int)} 31 | * to determine the system UI visibility state. 32 | */ 33 | private int mTestFlags; 34 | 35 | /** 36 | * Whether or not the system UI is currently visible. This is cached from 37 | * {@link android.view.View.OnSystemUiVisibilityChangeListener}. 38 | */ 39 | private boolean mVisible = true; 40 | 41 | /** 42 | * Constructor not intended to be called by clients. Use 43 | * {@link SystemUiHider#getInstance} to obtain an instance. 44 | */ 45 | protected SystemUiHiderHoneycomb(Activity activity, View anchorView, int flags) { 46 | super(activity, anchorView, flags); 47 | 48 | mShowFlags = View.SYSTEM_UI_FLAG_VISIBLE; 49 | mHideFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE; 50 | mTestFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE; 51 | 52 | if ((mFlags & FLAG_FULLSCREEN) != 0) { 53 | // If the client requested fullscreen, add flags relevant to hiding 54 | // the status bar. Note that some of these constants are new as of 55 | // API 16 (Jelly Bean). It is safe to use them, as they are inlined 56 | // at compile-time and do nothing on pre-Jelly Bean devices. 57 | mShowFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 58 | mHideFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 59 | | View.SYSTEM_UI_FLAG_FULLSCREEN; 60 | } 61 | 62 | if ((mFlags & FLAG_HIDE_NAVIGATION) != 0) { 63 | // If the client requested hiding navigation, add relevant flags. 64 | mShowFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 65 | mHideFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 66 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 67 | mTestFlags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 68 | } 69 | } 70 | 71 | /** 72 | * {@inheritDoc} 73 | */ 74 | @Override 75 | public void setup() { 76 | mAnchorView.setOnSystemUiVisibilityChangeListener(mSystemUiVisibilityChangeListener); 77 | } 78 | 79 | /** 80 | * {@inheritDoc} 81 | */ 82 | @Override 83 | public void hide() { 84 | mAnchorView.setSystemUiVisibility(mHideFlags); 85 | } 86 | 87 | /** 88 | * {@inheritDoc} 89 | */ 90 | @Override 91 | public void show() { 92 | mAnchorView.setSystemUiVisibility(mShowFlags); 93 | } 94 | 95 | /** 96 | * {@inheritDoc} 97 | */ 98 | @Override 99 | public boolean isVisible() { 100 | return mVisible; 101 | } 102 | 103 | private View.OnSystemUiVisibilityChangeListener mSystemUiVisibilityChangeListener 104 | = new View.OnSystemUiVisibilityChangeListener() { 105 | @Override 106 | public void onSystemUiVisibilityChange(int vis) { 107 | // Test against mTestFlags to see if the system UI is visible. 108 | if ((vis & mTestFlags) != 0) { 109 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 110 | // Pre-Jelly Bean, we must manually hide the action bar 111 | // and use the old window flags API. 112 | mActivity.getActionBar().hide(); 113 | mActivity.getWindow().setFlags( 114 | WindowManager.LayoutParams.FLAG_FULLSCREEN, 115 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 116 | } 117 | 118 | // Trigger the registered listener and cache the visibility 119 | // state. 120 | mOnVisibilityChangeListener.onVisibilityChange(false); 121 | mVisible = false; 122 | 123 | } else { 124 | mAnchorView.setSystemUiVisibility(mShowFlags); 125 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 126 | // Pre-Jelly Bean, we must manually show the action bar 127 | // and use the old window flags API. 128 | mActivity.getActionBar().show(); 129 | mActivity.getWindow().setFlags( 130 | 0, 131 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 132 | } 133 | 134 | // Trigger the registered listener and cache the visibility 135 | // state. 136 | mOnVisibilityChangeListener.onVisibilityChange(true); 137 | mVisible = true; 138 | } 139 | } 140 | }; 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/java/org/videolan/libvlc/Aout.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Aout.java 3 | ***************************************************************************** 4 | * Copyright © 2011-2012 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.media.AudioFormat; 24 | import android.media.AudioManager; 25 | import android.media.AudioTrack; 26 | import android.util.Log; 27 | 28 | public class Aout { 29 | /** 30 | * Java side of the audio output module for Android. 31 | * Uses an AudioTrack to play decoded audio buffers. 32 | * 33 | * TODO Use MODE_STATIC instead of MODE_STREAM with a MemoryFile (ashmem) 34 | */ 35 | 36 | public Aout() { 37 | } 38 | 39 | private AudioTrack mAudioTrack; 40 | private static final String TAG = "LibVLC/aout"; 41 | 42 | public void init(int sampleRateInHz, int channels, int samples) { 43 | Log.d(TAG, sampleRateInHz + ", " + channels + ", " + samples + "=>" + channels * samples); 44 | int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz, 45 | AudioFormat.CHANNEL_OUT_STEREO, 46 | AudioFormat.ENCODING_PCM_16BIT); 47 | mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 48 | sampleRateInHz, 49 | AudioFormat.CHANNEL_OUT_STEREO, 50 | AudioFormat.ENCODING_PCM_16BIT, 51 | Math.max(minBufferSize, channels * samples * 2), 52 | AudioTrack.MODE_STREAM); 53 | } 54 | 55 | public void release() { 56 | if (mAudioTrack != null) { 57 | mAudioTrack.release(); 58 | } 59 | mAudioTrack = null; 60 | } 61 | 62 | public void playBuffer(byte[] audioData, int bufferSize) { 63 | if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED) 64 | return; 65 | if (mAudioTrack.write(audioData, 0, bufferSize) != bufferSize) { 66 | Log.w(TAG, "Could not write all the samples to the audio device"); 67 | } 68 | mAudioTrack.play(); 69 | } 70 | 71 | public void pause() { 72 | mAudioTrack.pause(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/org/videolan/libvlc/EventHandler.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * EventHandler.java 3 | ***************************************************************************** 4 | * Copyright © 2011-2014 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 java.util.ArrayList; 24 | 25 | import android.os.Bundle; 26 | import android.os.Handler; 27 | import android.os.Message; 28 | 29 | public class EventHandler { 30 | 31 | /* 32 | * Be sure to subscribe to events you need in the JNI too. 33 | */ 34 | 35 | //public static final int MediaMetaChanged = 0; 36 | //public static final int MediaSubItemAdded = 1; 37 | //public static final int MediaDurationChanged = 2; 38 | public static final int MediaParsedChanged = 3; 39 | //public static final int MediaFreed = 4; 40 | //public static final int MediaStateChanged = 5; 41 | 42 | //public static final int MediaPlayerMediaChanged = 0x100; 43 | //public static final int MediaPlayerNothingSpecial = 0x101; 44 | //public static final int MediaPlayerOpening = 0x102; 45 | //public static final int MediaPlayerBuffering = 0x103; 46 | public static final int MediaPlayerPlaying = 0x104; 47 | public static final int MediaPlayerPaused = 0x105; 48 | public static final int MediaPlayerStopped = 0x106; 49 | //public static final int MediaPlayerForward = 0x107; 50 | //public static final int MediaPlayerBackward = 0x108; 51 | public static final int MediaPlayerEndReached = 0x109; 52 | public static final int MediaPlayerEncounteredError = 0x10a; 53 | //public static final int MediaPlayerTimeChanged = 0x10b; 54 | public static final int MediaPlayerPositionChanged = 0x10c; 55 | //public static final int MediaPlayerSeekableChanged = 0x10d; 56 | //public static final int MediaPlayerPausableChanged = 0x10e; 57 | //public static final int MediaPlayerTitleChanged = 0x10f; 58 | //public static final int MediaPlayerSnapshotTaken = 0x110; 59 | //public static final int MediaPlayerLengthChanged = 0x111; 60 | public static final int MediaPlayerVout = 0x112; 61 | 62 | //public static final int MediaListItemAdded = 0x200; 63 | //public static final int MediaListWillAddItem = 0x201; 64 | //public static final int MediaListItemDeleted = 0x202; 65 | //public static final int MediaListWillDeleteItem = 0x203; 66 | 67 | //public static final int MediaListViewItemAdded = 0x300; 68 | //public static final int MediaListViewWillAddItem = 0x301; 69 | //public static final int MediaListViewItemDeleted = 0x302; 70 | //public static final int MediaListViewWillDeleteItem = 0x303; 71 | 72 | //public static final int MediaListPlayerPlayed = 0x400; 73 | //public static final int MediaListPlayerNextItemSet = 0x401; 74 | //public static final int MediaListPlayerStopped = 0x402; 75 | 76 | //public static final int MediaDiscovererStarted = 0x500; 77 | //public static final int MediaDiscovererEnded = 0x501; 78 | 79 | //public static final int VlmMediaAdded = 0x600; 80 | //public static final int VlmMediaRemoved = 0x601; 81 | //public static final int VlmMediaChanged = 0x602; 82 | //public static final int VlmMediaInstanceStarted = 0x603; 83 | //public static final int VlmMediaInstanceStopped = 0x604; 84 | //public static final int VlmMediaInstanceStatusInit = 0x605; 85 | //public static final int VlmMediaInstanceStatusOpening = 0x606; 86 | //public static final int VlmMediaInstanceStatusPlaying = 0x607; 87 | //public static final int VlmMediaInstanceStatusPause = 0x608; 88 | //public static final int VlmMediaInstanceStatusEnd = 0x609; 89 | //public static final int VlmMediaInstanceStatusError = 0x60a; 90 | 91 | public static final int CustomMediaListExpanding = 0x2000; 92 | public static final int CustomMediaListExpandingEnd = 0x2001; 93 | public static final int CustomMediaListItemAdded = 0x2002; 94 | public static final int CustomMediaListItemDeleted = 0x2003; 95 | public static final int CustomMediaListItemMoved = 0x2004; 96 | 97 | public static final int HardwareAccelerationError = 0x3000; 98 | 99 | private ArrayList mEventHandler; 100 | private static EventHandler mInstance; 101 | 102 | EventHandler() { 103 | mEventHandler = new ArrayList(); 104 | } 105 | 106 | public static EventHandler getInstance() { 107 | if (mInstance == null) { 108 | mInstance = new EventHandler(); 109 | } 110 | return mInstance; 111 | } 112 | 113 | public void addHandler(Handler handler) { 114 | if (!mEventHandler.contains(handler)) 115 | mEventHandler.add(handler); 116 | } 117 | 118 | public void removeHandler(Handler handler) { 119 | mEventHandler.remove(handler); 120 | } 121 | 122 | /** This method is called by a native thread **/ 123 | public void callback(int event, Bundle b) { 124 | b.putInt("event", event); 125 | for (int i = 0; i < mEventHandler.size(); i++) { 126 | Message msg = Message.obtain(); 127 | msg.setData(b); 128 | mEventHandler.get(i).sendMessage(msg); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/org/videolan/libvlc/IVideoPlayer.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * IVideoPlayer.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 | public interface IVideoPlayer { 24 | /** 25 | * This method is called by native vout to request a surface resize when frame size doesn't match surface size. 26 | * @param width Frame width 27 | * @param height Frame height 28 | * @param visible_width Visible frame width 29 | * @param visible_height Visible frame height 30 | * @param sar_num Surface aspect ratio numerator 31 | * @param sar_den Surface aspect ratio denominator 32 | */ 33 | void setSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den); 34 | } 35 | -------------------------------------------------------------------------------- /app/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 java.util.ArrayList; 24 | import java.util.Map; 25 | 26 | import android.content.Context; 27 | import android.os.Build; 28 | import android.util.Log; 29 | import android.view.Surface; 30 | 31 | public class LibVLC { 32 | private static final String TAG = "VLC/LibVLC"; 33 | public static final int AOUT_AUDIOTRACK_JAVA = 0; 34 | public static final int AOUT_AUDIOTRACK = 1; 35 | public static final int AOUT_OPENSLES = 2; 36 | 37 | public static final int VOUT_ANDROID_SURFACE = 0; 38 | public static final int VOUT_OPEGLES2 = 1; 39 | 40 | public static final int HW_ACCELERATION_AUTOMATIC = -1; 41 | public static final int HW_ACCELERATION_DISABLED = 0; 42 | public static final int HW_ACCELERATION_DECODING = 1; 43 | public static final int HW_ACCELERATION_FULL = 2; 44 | 45 | private static LibVLC sInstance; 46 | 47 | /** libVLC instance C pointer */ 48 | private long mLibVlcInstance = 0; // Read-only, reserved for JNI 49 | /** libvlc_media_player pointer and index */ 50 | private int mInternalMediaPlayerIndex = 0; // Read-only, reserved for JNI 51 | private long mInternalMediaPlayerInstance = 0; // Read-only, reserved for JNI 52 | 53 | private MediaList mMediaList; // Pointer to media list being followed 54 | private MediaList mPrimaryList; // Primary/default media list; see getPrimaryMediaList() 55 | 56 | /** Buffer for VLC messages */ 57 | private StringBuffer mDebugLogBuffer; 58 | private boolean mIsBufferingLog = false; 59 | 60 | private Aout mAout; 61 | 62 | /** Keep screen bright */ 63 | //private WakeLock mWakeLock; 64 | 65 | /** Settings */ 66 | private int hardwareAcceleration = HW_ACCELERATION_AUTOMATIC; 67 | private String subtitlesEncoding = ""; 68 | private int aout = LibVlcUtil.isGingerbreadOrLater() ? AOUT_OPENSLES : AOUT_AUDIOTRACK_JAVA; 69 | private int vout = VOUT_ANDROID_SURFACE; 70 | private boolean timeStretching = false; 71 | private int deblocking = -1; 72 | private String chroma = ""; 73 | private boolean verboseMode = true; 74 | private float[] equalizer = null; 75 | private boolean frameSkip = false; 76 | private int networkCaching = 0; 77 | 78 | /** Native crash handler */ 79 | private OnNativeCrashListener mOnNativeCrashListener; 80 | 81 | /** Check in libVLC already initialized otherwise crash */ 82 | private boolean mIsInitialized = false; 83 | public native void attachSurface(Surface surface, IVideoPlayer player); 84 | 85 | public native void detachSurface(); 86 | 87 | public native void attachSubtitlesSurface(Surface surface); 88 | public native void detachSubtitlesSurface(); 89 | 90 | public native void eventVideoPlayerActivityCreated(boolean created); 91 | 92 | /* Load library before object instantiation */ 93 | static { 94 | try { 95 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) 96 | System.loadLibrary("iomx-gingerbread"); 97 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR2) 98 | System.loadLibrary("iomx-hc"); 99 | else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2) 100 | System.loadLibrary("iomx-ics"); 101 | } catch (Throwable t) { 102 | Log.w(TAG, "Unable to load the iomx library: " + t); 103 | } 104 | try { 105 | System.loadLibrary("vlcjni"); 106 | } catch (UnsatisfiedLinkError ule) { 107 | Log.e(TAG, "Can't load vlcjni library: " + ule); 108 | /// FIXME Alert user 109 | System.exit(1); 110 | } catch (SecurityException se) { 111 | Log.e(TAG, "Encountered a security issue when loading vlcjni library: " + se); 112 | /// FIXME Alert user 113 | System.exit(1); 114 | } 115 | } 116 | 117 | /** 118 | * Singleton constructor of libVLC Without surface and vout to create the 119 | * thumbnail and get information e.g. on the MediaLibraryActivity 120 | * 121 | * @return libVLC instance 122 | * @throws LibVlcException 123 | */ 124 | public static LibVLC getInstance() throws LibVlcException { 125 | synchronized (LibVLC.class) { 126 | if (sInstance == null) { 127 | /* First call */ 128 | sInstance = new LibVLC(); 129 | } 130 | } 131 | 132 | return sInstance; 133 | } 134 | 135 | /** 136 | * Return an existing instance of libVLC Call it when it is NOT important 137 | * that this fails 138 | * 139 | * @return libVLC instance OR null 140 | */ 141 | public static LibVLC getExistingInstance() { 142 | synchronized (LibVLC.class) { 143 | return sInstance; 144 | } 145 | } 146 | 147 | /** 148 | * Constructor 149 | * It is private because this class is a singleton. 150 | */ 151 | private LibVLC() { 152 | mAout = new Aout(); 153 | } 154 | 155 | /** 156 | * Destructor: 157 | * It is bad practice to rely on them, so please don't forget to call 158 | * destroy() before exiting. 159 | */ 160 | @Override 161 | public void finalize() { 162 | if (mLibVlcInstance != 0) { 163 | Log.d(TAG, "LibVLC is was destroyed yet before finalize()"); 164 | destroy(); 165 | } 166 | } 167 | 168 | /** 169 | * Get the media list that LibVLC is following right now. 170 | * 171 | * @return The media list object being followed 172 | */ 173 | public MediaList getMediaList() { 174 | return mMediaList; 175 | } 176 | 177 | /** 178 | * Set the media list for LibVLC to follow. 179 | * 180 | * @param mediaList The media list object to follow 181 | */ 182 | public void setMediaList(MediaList mediaList) { 183 | mMediaList = mediaList; 184 | } 185 | 186 | /** 187 | * Sets LibVLC to follow the default media list (see below) 188 | */ 189 | public void setMediaList() { 190 | mMediaList = mPrimaryList; 191 | } 192 | 193 | /** 194 | * Gets the primary media list, or the "currently playing" list. 195 | * Not to be confused with the media list pointer from above, which 196 | * refers the the MediaList object that libVLC is currently following. 197 | * This list is just one out of many lists that it can be pointed towards. 198 | * 199 | * This list will be used for lists of songs that are not user-defined. 200 | * For example: selecting a song from the Songs list, or from the list 201 | * displayed after selecting an album. 202 | * 203 | * It is loaded as the default list. 204 | * 205 | * @return The primary media list 206 | */ 207 | public MediaList getPrimaryMediaList() { 208 | return mPrimaryList; 209 | } 210 | 211 | /** 212 | * Give to LibVLC the surface to draw the video. 213 | * @param f the surface to draw 214 | */ 215 | public native void setSurface(Surface f); 216 | 217 | public static synchronized void restart(Context context) { 218 | if (sInstance != null) { 219 | try { 220 | sInstance.destroy(); 221 | sInstance.init(context); 222 | } catch (LibVlcException lve) { 223 | Log.e(TAG, "Unable to reinit libvlc: " + lve); 224 | } 225 | } 226 | } 227 | 228 | /** 229 | * those get/is* are called from native code to get settings values. 230 | */ 231 | 232 | public int getHardwareAcceleration() { 233 | return this.hardwareAcceleration; 234 | } 235 | 236 | public void setHardwareAcceleration(int hardwareAcceleration) { 237 | if (hardwareAcceleration < 0) { 238 | // Automatic mode: activate MediaCodec opaque direct rendering for 4.3 and above. 239 | if (LibVlcUtil.isJellyBeanMR2OrLater()) 240 | this.hardwareAcceleration = HW_ACCELERATION_FULL; 241 | else 242 | this.hardwareAcceleration = HW_ACCELERATION_DISABLED; 243 | } 244 | else 245 | this.hardwareAcceleration = hardwareAcceleration; 246 | } 247 | 248 | public String getSubtitlesEncoding() { 249 | return subtitlesEncoding; 250 | } 251 | 252 | public void setSubtitlesEncoding(String subtitlesEncoding) { 253 | this.subtitlesEncoding = subtitlesEncoding; 254 | } 255 | 256 | public int getAout() { 257 | return aout; 258 | } 259 | 260 | public void setAout(int aout) { 261 | if (aout < 0) 262 | this.aout = LibVlcUtil.isICSOrLater() ? AOUT_OPENSLES : AOUT_AUDIOTRACK_JAVA; 263 | else 264 | this.aout = aout; 265 | } 266 | 267 | public int getVout() { 268 | return vout; 269 | } 270 | 271 | public void setVout(int vout) { 272 | if (vout < 0) 273 | this.vout = VOUT_ANDROID_SURFACE; 274 | else 275 | this.vout = vout; 276 | } 277 | 278 | public boolean timeStretchingEnabled() { 279 | return timeStretching; 280 | } 281 | 282 | public void setTimeStretching(boolean timeStretching) { 283 | this.timeStretching = timeStretching; 284 | } 285 | 286 | public int getDeblocking() { 287 | int ret = deblocking; 288 | if(deblocking < 0) { 289 | /** 290 | * Set some reasonable deblocking defaults: 291 | * 292 | * Skip all (4) for armv6 and MIPS by default 293 | * Skip non-ref (1) for all armv7 more than 1.2 Ghz and more than 2 cores 294 | * Skip non-key (3) for all devices that don't meet anything above 295 | */ 296 | LibVlcUtil.MachineSpecs m = LibVlcUtil.getMachineSpecs(); 297 | if( (m.hasArmV6 && !(m.hasArmV7)) || m.hasMips ) 298 | ret = 4; 299 | else if(m.bogoMIPS > 1200 && m.processors > 2) 300 | ret = 1; 301 | else 302 | ret = 3; 303 | } else if(deblocking > 4) { // sanity check 304 | ret = 3; 305 | } 306 | return ret; 307 | } 308 | 309 | public void setDeblocking(int deblocking) { 310 | this.deblocking = deblocking; 311 | } 312 | 313 | public String getChroma() { 314 | return chroma; 315 | } 316 | 317 | public void setChroma(String chroma) { 318 | this.chroma = chroma.equals("YV12") && !LibVlcUtil.isGingerbreadOrLater() ? "" : chroma; 319 | } 320 | 321 | public boolean isVerboseMode() { 322 | return verboseMode; 323 | } 324 | 325 | public void setVerboseMode(boolean verboseMode) { 326 | this.verboseMode = verboseMode; 327 | } 328 | 329 | public float[] getEqualizer() 330 | { 331 | return equalizer; 332 | } 333 | 334 | public void setEqualizer(float[] equalizer) 335 | { 336 | this.equalizer = equalizer; 337 | applyEqualizer(); 338 | } 339 | 340 | private void applyEqualizer() 341 | { 342 | setNativeEqualizer(mInternalMediaPlayerInstance, this.equalizer); 343 | } 344 | private native int setNativeEqualizer(long mediaPlayer, float[] bands); 345 | 346 | public boolean frameSkipEnabled() { 347 | return frameSkip; 348 | } 349 | 350 | public void setFrameSkip(boolean frameskip) { 351 | this.frameSkip = frameskip; 352 | } 353 | 354 | public int getNetworkCaching() { 355 | return this.networkCaching; 356 | } 357 | 358 | public void setNetworkCaching(int networkcaching) { 359 | this.networkCaching = networkcaching; 360 | } 361 | 362 | /** 363 | * Initialize the libVLC class. 364 | * 365 | * This function must be called before using any libVLC functions. 366 | * 367 | * @throws LibVlcException 368 | */ 369 | public void init(Context context) throws LibVlcException { 370 | Log.v(TAG, "Initializing LibVLC"); 371 | mDebugLogBuffer = new StringBuffer(); 372 | if (!mIsInitialized) { 373 | if(!LibVlcUtil.hasCompatibleCPU(context)) { 374 | Log.e(TAG, LibVlcUtil.getErrorMsg()); 375 | throw new LibVlcException(); 376 | } 377 | nativeInit(); 378 | mMediaList = mPrimaryList = new MediaList(this); 379 | setEventHandler(EventHandler.getInstance()); 380 | mIsInitialized = true; 381 | } 382 | } 383 | 384 | /** 385 | * Destroy this libVLC instance 386 | * @note You must call it before exiting 387 | */ 388 | public void destroy() { 389 | Log.v(TAG, "Destroying LibVLC instance"); 390 | nativeDestroy(); 391 | detachEventHandler(); 392 | mIsInitialized = false; 393 | } 394 | 395 | /** 396 | * Open the Java audio output. 397 | * This function is called by the native code 398 | */ 399 | public void initAout(int sampleRateInHz, int channels, int samples) { 400 | Log.d(TAG, "Opening the java audio output"); 401 | mAout.init(sampleRateInHz, channels, samples); 402 | } 403 | 404 | /** 405 | * Play an audio buffer taken from the native code 406 | * This function is called by the native code 407 | */ 408 | public void playAudio(byte[] audioData, int bufferSize) { 409 | mAout.playBuffer(audioData, bufferSize); 410 | } 411 | 412 | /** 413 | * Pause the Java audio output 414 | * This function is called by the native code 415 | */ 416 | public void pauseAout() { 417 | Log.d(TAG, "Pausing the java audio output"); 418 | mAout.pause(); 419 | } 420 | 421 | /** 422 | * Close the Java audio output 423 | * This function is called by the native code 424 | */ 425 | public void closeAout() { 426 | Log.d(TAG, "Closing the java audio output"); 427 | mAout.release(); 428 | } 429 | 430 | /** 431 | * Play a media from the media list (playlist) 432 | * 433 | * @param position The index of the media 434 | */ 435 | public void playIndex(int position) { 436 | String mrl = mMediaList.getMRL(position); 437 | if (mrl == null) 438 | return; 439 | String[] options = mMediaList.getMediaOptions(position); 440 | mInternalMediaPlayerIndex = position; 441 | playMRL(mLibVlcInstance, mrl, options); 442 | } 443 | 444 | /** 445 | * Play an MRL directly. 446 | * 447 | * @param mrl MRL of the media to play. 448 | */ 449 | public void playMRL(String mrl) { 450 | // index=-1 will return options from libvlc instance without relying on MediaList 451 | String[] options = mMediaList.getMediaOptions(-1); 452 | mInternalMediaPlayerIndex = 0; 453 | playMRL(mLibVlcInstance, mrl, options); 454 | } 455 | 456 | public TrackInfo[] readTracksInfo(String mrl) { 457 | return readTracksInfo(mLibVlcInstance, mrl); 458 | } 459 | 460 | /** 461 | * Get a media thumbnail. 462 | */ 463 | public byte[] getThumbnail(String mrl, int i_width, int i_height) { 464 | return getThumbnail(mLibVlcInstance, mrl, i_width, i_height); 465 | } 466 | 467 | /** 468 | * Return true if there is a video track in the file 469 | */ 470 | public boolean hasVideoTrack(String mrl) throws java.io.IOException { 471 | return hasVideoTrack(mLibVlcInstance, mrl); 472 | } 473 | 474 | /** 475 | * Sets the speed of playback (1 being normal speed, 2 being twice as fast) 476 | * 477 | * @param rate 478 | */ 479 | public native void setRate(float rate); 480 | 481 | /** 482 | * Get the current playback speed 483 | */ 484 | public native float getRate(); 485 | 486 | /** 487 | * Initialize the libvlc C library 488 | * @return a pointer to the libvlc instance 489 | */ 490 | private native void nativeInit() throws LibVlcException; 491 | 492 | /** 493 | * Close the libvlc C library 494 | * @note mLibVlcInstance should be 0 after a call to destroy() 495 | */ 496 | private native void nativeDestroy(); 497 | 498 | /** 499 | * Start buffering to the mDebugLogBuffer. 500 | */ 501 | public native void startDebugBuffer(); 502 | public native void stopDebugBuffer(); 503 | public String getBufferContent() { 504 | return mDebugLogBuffer.toString(); 505 | } 506 | 507 | public void clearBuffer() { 508 | mDebugLogBuffer.setLength(0); 509 | } 510 | 511 | public boolean isDebugBuffering() { 512 | return mIsBufferingLog; 513 | } 514 | 515 | /** 516 | * Play an mrl 517 | */ 518 | private native void playMRL(long instance, String mrl, String[] mediaOptions); 519 | 520 | /** 521 | * Returns true if any media is playing 522 | */ 523 | public native boolean isPlaying(); 524 | 525 | /** 526 | * Returns true if any media is seekable 527 | */ 528 | public native boolean isSeekable(); 529 | 530 | /** 531 | * Plays any loaded media 532 | */ 533 | public native void play(); 534 | 535 | /** 536 | * Pauses any playing media 537 | */ 538 | public native void pause(); 539 | 540 | /** 541 | * Stops any playing media 542 | */ 543 | public native void stop(); 544 | 545 | /** 546 | * Gets volume as integer 547 | */ 548 | public native int getVolume(); 549 | 550 | /** 551 | * Sets volume as integer 552 | * @param volume: Volume level passed as integer 553 | */ 554 | public native int setVolume(int volume); 555 | 556 | /** 557 | * Gets the current movie time (in ms). 558 | * @return the movie time (in ms), or -1 if there is no media. 559 | */ 560 | public native long getTime(); 561 | 562 | /** 563 | * Sets the movie time (in ms), if any media is being played. 564 | * @param time: Time in ms. 565 | * @return the movie time (in ms), or -1 if there is no media. 566 | */ 567 | public native long setTime(long time); 568 | 569 | /** 570 | * Gets the movie position. 571 | * @return the movie position, or -1 for any error. 572 | */ 573 | public native float getPosition(); 574 | 575 | /** 576 | * Sets the movie position. 577 | * @param pos: movie position. 578 | */ 579 | public native void setPosition(float pos); 580 | 581 | /** 582 | * Gets current movie's length in ms. 583 | * @return the movie length (in ms), or -1 if there is no media. 584 | */ 585 | public native long getLength(); 586 | 587 | /** 588 | * Get the libVLC version 589 | * @return the libVLC version string 590 | */ 591 | public native String version(); 592 | 593 | /** 594 | * Get the libVLC compiler 595 | * @return the libVLC compiler string 596 | */ 597 | public native String compiler(); 598 | 599 | /** 600 | * Get the libVLC changeset 601 | * @return the libVLC changeset string 602 | */ 603 | public native String changeset(); 604 | 605 | /** 606 | * Get a media thumbnail. 607 | * @return a bytearray with the RGBA thumbnail data inside. 608 | */ 609 | private native byte[] getThumbnail(long instance, String mrl, int i_width, int i_height); 610 | 611 | /** 612 | * Return true if there is a video track in the file 613 | */ 614 | private native boolean hasVideoTrack(long instance, String mrl); 615 | 616 | private native TrackInfo[] readTracksInfo(long instance, String mrl); 617 | 618 | public native TrackInfo[] readTracksInfoInternal(); 619 | 620 | public native int getAudioTracksCount(); 621 | 622 | public native Map getAudioTrackDescription(); 623 | 624 | public native int getAudioTrack(); 625 | 626 | public native int setAudioTrack(int index); 627 | 628 | public native int getVideoTracksCount(); 629 | 630 | public native int addSubtitleTrack(String path); 631 | 632 | public native Map getSpuTrackDescription(); 633 | 634 | public native int getSpuTrack(); 635 | 636 | public native int setSpuTrack(int index); 637 | 638 | public native int getSpuTracksCount(); 639 | 640 | public static native String nativeToURI(String path); 641 | 642 | public native static void sendMouseEvent( int action, int button, int x, int y); 643 | 644 | /** 645 | * Quickly converts path to URIs, which are mandatory in libVLC. 646 | * 647 | * @param path 648 | * The path to be converted. 649 | * @return A URI representation of path 650 | */ 651 | public static String PathToURI(String path) { 652 | if(path == null) { 653 | throw new NullPointerException("Cannot convert null path!"); 654 | } 655 | return LibVLC.nativeToURI(path); 656 | } 657 | 658 | public static native void nativeReadDirectory(String path, ArrayList res); 659 | 660 | public native static boolean nativeIsPathDirectory(String path); 661 | 662 | /** 663 | * Expand and continue playing the current media. 664 | * 665 | * @return the index of the media was expanded, and -1 if no media was expanded 666 | */ 667 | public int expandAndPlay() { 668 | int r = mMediaList.expandMedia(mInternalMediaPlayerIndex); 669 | if(r == 0) 670 | this.playIndex(mInternalMediaPlayerIndex); 671 | return r; 672 | } 673 | 674 | /** 675 | * Expand the current media. 676 | * @return the index of the media was expanded, and -1 if no media was expanded 677 | */ 678 | public int expand() { 679 | return mMediaList.expandMedia(mInternalMediaPlayerIndex); 680 | } 681 | 682 | private native void setEventHandler(EventHandler eventHandler); 683 | 684 | private native void detachEventHandler(); 685 | 686 | public native float[] getBands(); 687 | 688 | public native String[] getPresets(); 689 | 690 | public native float[] getPreset(int index); 691 | 692 | public static interface OnNativeCrashListener { 693 | public void onNativeCrash(); 694 | } 695 | 696 | public void setOnNativeCrashListener(OnNativeCrashListener l) { 697 | mOnNativeCrashListener = l; 698 | } 699 | 700 | private void onNativeCrash() { 701 | if (mOnNativeCrashListener != null) 702 | mOnNativeCrashListener.onNativeCrash(); 703 | } 704 | } 705 | -------------------------------------------------------------------------------- /app/src/main/java/org/videolan/libvlc/LibVlcException.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * LibVlcException.java 3 | ***************************************************************************** 4 | * Copyright © 2011-2012 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 | /** 22 | * LibVlcException: exceptions thrown by the native LibVLC interface 23 | */ 24 | package org.videolan.libvlc; 25 | 26 | /** 27 | * @author jpeg 28 | * 29 | */ 30 | public class LibVlcException extends Exception { 31 | private static final long serialVersionUID = -1909522348226924189L; 32 | 33 | /** 34 | * Create an empty error 35 | */ 36 | public LibVlcException() { 37 | super(); 38 | } 39 | 40 | /** 41 | * @param detailMessage 42 | */ 43 | public LibVlcException(String detailMessage) { 44 | super(detailMessage); 45 | } 46 | 47 | /** 48 | * @param throwable 49 | */ 50 | public LibVlcException(Throwable throwable) { 51 | super(throwable); 52 | } 53 | 54 | /** 55 | * @param detailMessage 56 | * @param throwable 57 | */ 58 | public LibVlcException(String detailMessage, Throwable throwable) { 59 | super(detailMessage, throwable); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/org/videolan/libvlc/LibVlcUtil.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * LibVlcUtil.java 3 | ***************************************************************************** 4 | * Copyright © 2011-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 java.io.BufferedReader; 24 | import java.io.File; 25 | import java.io.FileNotFoundException; 26 | import java.io.FileReader; 27 | import java.io.IOException; 28 | import java.io.RandomAccessFile; 29 | import java.nio.ByteBuffer; 30 | import java.nio.ByteOrder; 31 | import java.util.Locale; 32 | 33 | import android.content.Context; 34 | import android.net.Uri; 35 | import android.os.Build; 36 | import android.util.Log; 37 | 38 | public class LibVlcUtil { 39 | public final static String TAG = "VLC/LibVLC/Util"; 40 | 41 | public static boolean isFroyoOrLater() 42 | { 43 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.FROYO; 44 | } 45 | 46 | public static boolean isGingerbreadOrLater() 47 | { 48 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD; 49 | } 50 | 51 | public static boolean isHoneycombOrLater() 52 | { 53 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB; 54 | } 55 | 56 | public static boolean isICSOrLater() 57 | { 58 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH; 59 | } 60 | 61 | public static boolean isJellyBeanOrLater() 62 | { 63 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN; 64 | } 65 | 66 | public static boolean isJellyBeanMR1OrLater() 67 | { 68 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 69 | } 70 | 71 | public static boolean isJellyBeanMR2OrLater() 72 | { 73 | return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 74 | } 75 | 76 | private static String errorMsg = null; 77 | private static boolean isCompatible = false; 78 | public static String getErrorMsg() { 79 | return errorMsg; 80 | } 81 | 82 | public static File URItoFile(String URI) { 83 | return new File(Uri.decode(URI).replace("file://","")); 84 | } 85 | 86 | public static String URItoFileName(String URI) { 87 | return URItoFile(URI).getName(); 88 | } 89 | 90 | public static boolean hasCompatibleCPU(Context context) 91 | { 92 | // If already checked return cached result 93 | if(errorMsg != null || isCompatible) return isCompatible; 94 | 95 | ElfData elf = readLib(context.getApplicationInfo().dataDir + "/lib/libvlcjni.so"); 96 | if(elf == null) { 97 | Log.e(TAG, "WARNING: Unable to read libvlcjni.so; cannot check device ABI!"); 98 | Log.e(TAG, "WARNING: Cannot guarantee correct ABI for this build (may crash)!"); 99 | return true; 100 | } 101 | 102 | String CPU_ABI = android.os.Build.CPU_ABI; 103 | String CPU_ABI2 = "none"; 104 | if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { // CPU_ABI2 since 2.2 105 | try { 106 | CPU_ABI2 = (String)android.os.Build.class.getDeclaredField("CPU_ABI2").get(null); 107 | } catch (Exception e) { } 108 | } 109 | 110 | Log.i(TAG, "machine = " + (elf.e_machine == EM_ARM ? "arm" : elf.e_machine == EM_386 ? "x86" : "mips")); 111 | Log.i(TAG, "arch = " + elf.att_arch); 112 | Log.i(TAG, "fpu = " + elf.att_fpu); 113 | boolean hasNeon = false, hasFpu = false, hasArmV6 = false, 114 | hasArmV7 = false, hasMips = false, hasX86 = false; 115 | float bogoMIPS = -1; 116 | int processors = 0; 117 | 118 | if(CPU_ABI.equals("x86")) { 119 | hasX86 = true; 120 | } else if(CPU_ABI.equals("armeabi-v7a") || 121 | CPU_ABI2.equals("armeabi-v7a")) { 122 | hasArmV7 = true; 123 | hasArmV6 = true; /* Armv7 is backwards compatible to < v6 */ 124 | } else if(CPU_ABI.equals("armeabi") || 125 | CPU_ABI2.equals("armeabi")) { 126 | hasArmV6 = true; 127 | } 128 | 129 | try { 130 | FileReader fileReader = new FileReader("/proc/cpuinfo"); 131 | BufferedReader br = new BufferedReader(fileReader); 132 | String line; 133 | while((line = br.readLine()) != null) { 134 | if(!hasArmV7 && line.contains("ARMv7")) { 135 | hasArmV7 = true; 136 | hasArmV6 = true; /* Armv7 is backwards compatible to < v6 */ 137 | } 138 | if(!hasArmV7 && !hasArmV6 && line.contains("ARMv6")) 139 | hasArmV6 = true; 140 | // "clflush size" is a x86-specific cpuinfo tag. 141 | // (see kernel sources arch/x86/kernel/cpu/proc.c) 142 | if(line.contains("clflush size")) 143 | hasX86 = true; 144 | // "microsecond timers" is specific to MIPS. 145 | // see arch/mips/kernel/proc.c 146 | if(line.contains("microsecond timers")) 147 | hasMips = true; 148 | if(!hasNeon && line.contains("neon")) 149 | hasNeon = true; 150 | if(!hasFpu && line.contains("vfp")) 151 | hasFpu = true; 152 | if(line.startsWith("processor")) 153 | processors++; 154 | if(bogoMIPS < 0 && line.toLowerCase(Locale.ENGLISH).contains("bogomips")) { 155 | String[] bogo_parts = line.split(":"); 156 | try { 157 | bogoMIPS = Float.parseFloat(bogo_parts[1].trim()); 158 | } catch(NumberFormatException e) { 159 | bogoMIPS = -1; // invalid bogomips 160 | } 161 | } 162 | } 163 | fileReader.close(); 164 | } catch(IOException ex){ 165 | ex.printStackTrace(); 166 | errorMsg = "IOException whilst reading cpuinfo flags"; 167 | isCompatible = false; 168 | return false; 169 | } 170 | if(processors == 0) 171 | processors = 1; // possibly borked cpuinfo? 172 | 173 | // Enforce proper architecture to prevent problems 174 | if(elf.e_machine == EM_386 && !hasX86) { 175 | errorMsg = "x86 build on non-x86 device"; 176 | isCompatible = false; 177 | return false; 178 | } else if(elf.e_machine == EM_ARM && hasX86) { 179 | errorMsg = "ARM build on x86 device"; 180 | isCompatible = false; 181 | return false; 182 | } 183 | 184 | if(elf.e_machine == EM_MIPS && !hasMips) { 185 | errorMsg = "MIPS build on non-MIPS device"; 186 | isCompatible = false; 187 | return false; 188 | } else if(elf.e_machine == EM_ARM && hasMips) { 189 | errorMsg = "ARM build on MIPS device"; 190 | isCompatible = false; 191 | return false; 192 | } 193 | 194 | if(elf.e_machine == EM_ARM && elf.att_arch.startsWith("v7") && !hasArmV7) { 195 | errorMsg = "ARMv7 build on non-ARMv7 device"; 196 | isCompatible = false; 197 | return false; 198 | } 199 | if(elf.e_machine == EM_ARM) { 200 | if(elf.att_arch.startsWith("v6") && !hasArmV6) { 201 | errorMsg = "ARMv6 build on non-ARMv6 device"; 202 | isCompatible = false; 203 | return false; 204 | } else if(elf.att_fpu && !hasFpu) { 205 | errorMsg = "FPU-enabled build on non-FPU device"; 206 | isCompatible = false; 207 | return false; 208 | } 209 | } 210 | 211 | errorMsg = null; 212 | isCompatible = true; 213 | // Store into MachineSpecs 214 | machineSpecs = new MachineSpecs(); 215 | machineSpecs.hasArmV6 = hasArmV6; 216 | machineSpecs.hasArmV7 = hasArmV7; 217 | machineSpecs.hasFpu = hasFpu; 218 | machineSpecs.hasMips = hasMips; 219 | machineSpecs.hasNeon = hasNeon; 220 | machineSpecs.hasX86 = hasX86; 221 | machineSpecs.bogoMIPS = bogoMIPS; 222 | machineSpecs.processors = processors; 223 | return true; 224 | } 225 | 226 | public static MachineSpecs getMachineSpecs() { 227 | return machineSpecs; 228 | } 229 | private static MachineSpecs machineSpecs = null; 230 | public static class MachineSpecs { 231 | public boolean hasNeon; 232 | public boolean hasFpu; 233 | public boolean hasArmV6; 234 | public boolean hasArmV7; 235 | public boolean hasMips; 236 | public boolean hasX86; 237 | public float bogoMIPS; 238 | public int processors; 239 | } 240 | 241 | private static final int EM_386 = 3; 242 | private static final int EM_MIPS = 8; 243 | private static final int EM_ARM = 40; 244 | private static final int ELF_HEADER_SIZE = 52; 245 | private static final int SECTION_HEADER_SIZE = 40; 246 | private static final int SHT_ARM_ATTRIBUTES = 0x70000003; 247 | private static class ElfData { 248 | ByteOrder order; 249 | int e_machine; 250 | int e_shoff; 251 | int e_shnum; 252 | int sh_offset; 253 | int sh_size; 254 | String att_arch; 255 | boolean att_fpu; 256 | } 257 | 258 | /** '*' prefix means it's unsupported */ 259 | private static String[] CPU_archs = {"*Pre-v4", "*v4", "*v4T", 260 | "v5T", "v5TE", "v5TEJ", 261 | "v6", "v6KZ", "v6T2", "v6K", "v7", 262 | "*v6-M", "*v6S-M", "*v7E-M", "*v8"}; 263 | 264 | private static ElfData readLib(String path) { 265 | File file = new File(path); 266 | if (!file.exists() || !file.canRead()) 267 | return null; 268 | 269 | RandomAccessFile in = null; 270 | try { 271 | in = new RandomAccessFile(file, "r"); 272 | 273 | ElfData elf = new ElfData(); 274 | if (!readHeader(in, elf)) 275 | return null; 276 | 277 | switch (elf.e_machine) { 278 | case EM_386: 279 | case EM_MIPS: 280 | return elf; 281 | case EM_ARM: 282 | in.close(); 283 | in = new RandomAccessFile(file, "r"); 284 | if (!readSection(in, elf)) 285 | return null; 286 | in.close(); 287 | in = new RandomAccessFile(file, "r"); 288 | if (!readArmAttributes(in, elf)) 289 | return null; 290 | break; 291 | default: 292 | return null; 293 | } 294 | return elf; 295 | } catch (FileNotFoundException e) { 296 | e.printStackTrace(); 297 | } catch (IOException e) { 298 | e.printStackTrace(); 299 | } finally { 300 | try { 301 | if (in != null) 302 | in.close(); 303 | } catch (IOException e) { 304 | } 305 | } 306 | return null; 307 | } 308 | 309 | private static boolean readHeader(RandomAccessFile in, ElfData elf) throws IOException { 310 | // http://www.sco.com/developers/gabi/1998-04-29/ch4.eheader.html 311 | byte[] bytes = new byte[ELF_HEADER_SIZE]; 312 | in.readFully(bytes); 313 | if (bytes[0] != 127 || 314 | bytes[1] != 'E' || 315 | bytes[2] != 'L' || 316 | bytes[3] != 'F' || 317 | bytes[4] != 1) { // ELFCLASS32, Only 32bit header is supported 318 | return false; 319 | } 320 | 321 | elf.order = bytes[5] == 1 322 | ? ByteOrder.LITTLE_ENDIAN // ELFDATA2LSB 323 | : ByteOrder.BIG_ENDIAN; // ELFDATA2MSB 324 | 325 | // wrap bytes in a ByteBuffer to force endianess 326 | ByteBuffer buffer = ByteBuffer.wrap(bytes); 327 | buffer.order(elf.order); 328 | 329 | elf.e_machine = buffer.getShort(18); /* Architecture */ 330 | elf.e_shoff = buffer.getInt(32); /* Section header table file offset */ 331 | elf.e_shnum = buffer.getShort(48); /* Section header table entry count */ 332 | return true; 333 | } 334 | 335 | private static boolean readSection(RandomAccessFile in, ElfData elf) throws IOException { 336 | byte[] bytes = new byte[SECTION_HEADER_SIZE]; 337 | in.seek(elf.e_shoff); 338 | 339 | for (int i = 0; i < elf.e_shnum; ++i) { 340 | in.readFully(bytes); 341 | 342 | // wrap bytes in a ByteBuffer to force endianess 343 | ByteBuffer buffer = ByteBuffer.wrap(bytes); 344 | buffer.order(elf.order); 345 | 346 | int sh_type = buffer.getInt(4); /* Section type */ 347 | if (sh_type != SHT_ARM_ATTRIBUTES) 348 | continue; 349 | 350 | elf.sh_offset = buffer.getInt(16); /* Section file offset */ 351 | elf.sh_size = buffer.getInt(20); /* Section size in bytes */ 352 | return true; 353 | } 354 | 355 | return false; 356 | } 357 | 358 | private static boolean readArmAttributes(RandomAccessFile in, ElfData elf) throws IOException { 359 | byte[] bytes = new byte[elf.sh_size]; 360 | in.seek(elf.sh_offset); 361 | in.readFully(bytes); 362 | 363 | // wrap bytes in a ByteBuffer to force endianess 364 | ByteBuffer buffer = ByteBuffer.wrap(bytes); 365 | buffer.order(elf.order); 366 | 367 | //http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf 368 | //http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_addenda.pdf 369 | if (buffer.get() != 'A') // format-version 370 | return false; 371 | 372 | // sub-sections loop 373 | while (buffer.remaining() > 0) { 374 | int start_section = buffer.position(); 375 | int length = buffer.getInt(); 376 | String vendor = getString(buffer); 377 | if (vendor.equals("aeabi")) { 378 | // tags loop 379 | while (buffer.position() < start_section + length) { 380 | int start = buffer.position(); 381 | int tag = buffer.get(); 382 | int size = buffer.getInt(); 383 | // skip if not Tag_File, we don't care about others 384 | if (tag != 1) { 385 | buffer.position(start + size); 386 | continue; 387 | } 388 | 389 | // attributes loop 390 | while (buffer.position() < start + size) { 391 | tag = getUleb128(buffer); 392 | if (tag == 6) { // CPU_arch 393 | int arch = getUleb128(buffer); 394 | elf.att_arch = CPU_archs[arch]; 395 | } 396 | else if (tag == 27) { // ABI_HardFP_use 397 | getUleb128(buffer); 398 | elf.att_fpu = true; 399 | } 400 | else { 401 | // string for 4=CPU_raw_name / 5=CPU_name / 32=compatibility 402 | // string for >32 && odd tags 403 | // uleb128 for other 404 | tag %= 128; 405 | if (tag == 4 || tag == 5 || tag == 32 || (tag > 32 && (tag & 1) != 0)) 406 | getString(buffer); 407 | else 408 | getUleb128(buffer); 409 | } 410 | } 411 | } 412 | break; 413 | } 414 | } 415 | return true; 416 | } 417 | 418 | private static String getString(ByteBuffer buffer) { 419 | StringBuilder sb = new StringBuilder(buffer.limit()); 420 | while (buffer.remaining() > 0) { 421 | char c = (char) buffer.get(); 422 | if (c == 0) 423 | break; 424 | sb.append(c); 425 | } 426 | return sb.toString(); 427 | } 428 | 429 | private static int getUleb128(ByteBuffer buffer) { 430 | int ret = 0; 431 | int c; 432 | do { 433 | ret <<= 7; 434 | c = buffer.get(); 435 | ret |= c & 0x7f; 436 | } while((c & 0x80) > 0); 437 | 438 | return ret; 439 | } 440 | } 441 | -------------------------------------------------------------------------------- /app/src/main/java/org/videolan/libvlc/Media.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Media.java 3 | ***************************************************************************** 4 | * Copyright © 2011-2013 VLC authors and VideoLAN 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 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 General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. 19 | *****************************************************************************/ 20 | 21 | package org.videolan.libvlc; 22 | 23 | import java.lang.reflect.InvocationTargetException; 24 | import java.lang.reflect.Method; 25 | import java.util.HashSet; 26 | import java.util.Locale; 27 | 28 | import android.content.Context; 29 | import android.graphics.Bitmap; 30 | import android.util.Log; 31 | 32 | public class Media implements Comparable { 33 | public final static String TAG = "VLC/LibVLC/Media"; 34 | 35 | public final static HashSet VIDEO_EXTENSIONS; 36 | public final static HashSet AUDIO_EXTENSIONS; 37 | public final static String EXTENSIONS_REGEX; 38 | public final static HashSet FOLDER_BLACKLIST; 39 | 40 | static { 41 | String[] video_extensions = { 42 | ".3g2", ".3gp", ".3gp2", ".3gpp", ".amv", ".asf", ".avi", ".divx", "drc", ".dv", 43 | ".f4v", ".flv", ".gvi", ".gxf", ".ismv", ".iso", ".m1v", ".m2v", ".m2t", ".m2ts", 44 | ".m4v", ".mkv", ".mov", ".mp2", ".mp2v", ".mp4", ".mp4v", ".mpe", ".mpeg", 45 | ".mpeg1", ".mpeg2", ".mpeg4", ".mpg", ".mpv2", ".mts", ".mtv", ".mxf", ".mxg", 46 | ".nsv", ".nut", ".nuv", ".ogm", ".ogv", ".ogx", ".ps", ".rec", ".rm", ".rmvb", 47 | ".tod", ".ts", ".tts", ".vob", ".vro", ".webm", ".wm", ".wmv", ".wtv", ".xesc" }; 48 | 49 | String[] audio_extensions = { 50 | ".3ga", ".a52", ".aac", ".ac3", ".adt", ".adts", ".aif", ".aifc", ".aiff", ".amr", 51 | ".aob", ".ape", ".awb", ".caf", ".dts", ".flac", ".it", ".m4a", ".m4b", ".m4p", 52 | ".mid", ".mka", ".mlp", ".mod", ".mpa", ".mp1", ".mp2", ".mp3", ".mpc", ".mpga", 53 | ".oga", ".ogg", ".oma", ".opus", ".ra", ".ram", ".rmi", ".s3m", ".spx", ".tta", 54 | ".voc", ".vqf", ".w64", ".wav", ".wma", ".wv", ".xa", ".xm" }; 55 | 56 | String[] folder_blacklist = { 57 | "/alarms", 58 | "/notifications", 59 | "/ringtones", 60 | "/media/alarms", 61 | "/media/notifications", 62 | "/media/ringtones", 63 | "/media/audio/alarms", 64 | "/media/audio/notifications", 65 | "/media/audio/ringtones", 66 | "/Android/data/" }; 67 | 68 | VIDEO_EXTENSIONS = new HashSet(); 69 | for (String item : video_extensions) 70 | VIDEO_EXTENSIONS.add(item); 71 | AUDIO_EXTENSIONS = new HashSet(); 72 | for (String item : audio_extensions) 73 | AUDIO_EXTENSIONS.add(item); 74 | 75 | StringBuilder sb = new StringBuilder(115); 76 | sb.append(".+(\\.)((?i)("); 77 | sb.append(video_extensions[0].substring(1)); 78 | for(int i = 1; i < video_extensions.length; i++) { 79 | sb.append('|'); 80 | sb.append(video_extensions[i].substring(1)); 81 | } 82 | for(int i = 0; i < audio_extensions.length; i++) { 83 | sb.append('|'); 84 | sb.append(audio_extensions[i].substring(1)); 85 | } 86 | sb.append("))"); 87 | EXTENSIONS_REGEX = sb.toString(); 88 | FOLDER_BLACKLIST = new HashSet(); 89 | for (String item : folder_blacklist) 90 | FOLDER_BLACKLIST.add(android.os.Environment.getExternalStorageDirectory().getPath() + item); 91 | } 92 | 93 | public final static int TYPE_ALL = -1; 94 | public final static int TYPE_VIDEO = 0; 95 | public final static int TYPE_AUDIO = 1; 96 | public final static int TYPE_GROUP = 2; 97 | 98 | /** Metadata from libvlc_media */ 99 | protected String mTitle; 100 | private String mArtist; 101 | private String mGenre; 102 | private String mCopyright; 103 | private String mAlbum; 104 | private String mTrackNumber; 105 | private String mDescription; 106 | private String mRating; 107 | private String mDate; 108 | private String mSettings; 109 | private String mNowPlaying; 110 | private String mPublisher; 111 | private String mEncodedBy; 112 | private String mTrackID; 113 | private String mArtworkURL; 114 | 115 | private final String mLocation; 116 | private String mFilename; 117 | private long mTime = 0; 118 | private int mAudioTrack = -1; 119 | private int mSpuTrack = -2; 120 | private long mLength = 0; 121 | private int mType; 122 | private int mWidth = 0; 123 | private int mHeight = 0; 124 | private Bitmap mPicture; 125 | private boolean mIsPictureParsed; 126 | 127 | /** 128 | * Create a new Media 129 | * @param libVLC A pointer to the libVLC instance. Should not be NULL 130 | * @param URI The URI of the media. 131 | */ 132 | public Media(LibVLC libVLC, String URI) { 133 | if(libVLC == null) 134 | throw new NullPointerException("libVLC was null"); 135 | 136 | mLocation = URI; 137 | 138 | mType = TYPE_ALL; 139 | TrackInfo[] tracks = libVLC.readTracksInfo(mLocation); 140 | 141 | extractTrackInfo(tracks); 142 | } 143 | 144 | private void extractTrackInfo(TrackInfo[] tracks) { 145 | if (tracks == null) 146 | return; 147 | 148 | for (TrackInfo track : tracks) { 149 | if (track.Type == TrackInfo.TYPE_VIDEO) { 150 | mType = TYPE_VIDEO; 151 | mWidth = track.Width; 152 | mHeight = track.Height; 153 | } else if (mType == TYPE_ALL && track.Type == TrackInfo.TYPE_AUDIO){ 154 | mType = TYPE_AUDIO; 155 | } else if (track.Type == TrackInfo.TYPE_META) { 156 | mLength = track.Length; 157 | mTitle = track.Title; 158 | mArtist = getValueWrapper(track.Artist, UnknownStringType.Artist); 159 | mAlbum = getValueWrapper(track.Album, UnknownStringType.Album); 160 | mGenre = getValueWrapper(track.Genre, UnknownStringType.Genre); 161 | mArtworkURL = track.ArtworkURL; 162 | Log.d(TAG, "Title " + mTitle); 163 | Log.d(TAG, "Artist " + mArtist); 164 | Log.d(TAG, "Genre " + mGenre); 165 | Log.d(TAG, "Album " + mAlbum); 166 | } 167 | } 168 | 169 | /* No useful ES found */ 170 | if (mType == TYPE_ALL) { 171 | int dotIndex = mLocation.lastIndexOf("."); 172 | if (dotIndex != -1) { 173 | String fileExt = mLocation.substring(dotIndex); 174 | if( Media.VIDEO_EXTENSIONS.contains(fileExt) ) { 175 | mType = TYPE_VIDEO; 176 | } else if (Media.AUDIO_EXTENSIONS.contains(fileExt)) { 177 | mType = TYPE_AUDIO; 178 | } 179 | } 180 | } 181 | } 182 | 183 | public Media(String location, long time, long length, int type, 184 | Bitmap picture, String title, String artist, String genre, String album, 185 | int width, int height, String artworkURL, int audio, int spu) { 186 | mLocation = location; 187 | mFilename = null; 188 | mTime = time; 189 | mAudioTrack = audio; 190 | mSpuTrack = spu; 191 | mLength = length; 192 | mType = type; 193 | mPicture = picture; 194 | mWidth = width; 195 | mHeight = height; 196 | 197 | mTitle = title; 198 | mArtist = getValueWrapper(artist, UnknownStringType.Artist); 199 | mGenre = getValueWrapper(genre, UnknownStringType.Genre); 200 | mAlbum = getValueWrapper(album, UnknownStringType.Album); 201 | mArtworkURL = artworkURL; 202 | } 203 | 204 | private enum UnknownStringType { Artist , Genre, Album }; 205 | /** 206 | * Uses introspection to read VLC l10n databases, so that we can sever the 207 | * hard-coded dependency gracefully for 3rd party libvlc apps while still 208 | * maintaining good l10n in VLC for Android. 209 | * 210 | * @see org.videolan.vlc.Util#getValue(String, int) 211 | * 212 | * @param string The default string 213 | * @param type Alias for R.string.xxx 214 | * @return The default string if not empty or string from introspection 215 | */ 216 | private static String getValueWrapper(String string, UnknownStringType type) { 217 | if(string != null && string.length() > 0) return string; 218 | 219 | try { 220 | Class stringClass = Class.forName("org.videolan.vlc.R$string"); 221 | Class utilClass = Class.forName("org.videolan.vlc.Util"); 222 | 223 | Integer value; 224 | switch(type) { 225 | case Album: 226 | value = (Integer)stringClass.getField("unknown_album").get(null); 227 | break; 228 | case Genre: 229 | value = (Integer)stringClass.getField("unknown_genre").get(null); 230 | break; 231 | case Artist: 232 | default: 233 | value = (Integer)stringClass.getField("unknown_artist").get(null); 234 | break; 235 | } 236 | 237 | Method getValueMethod = utilClass.getDeclaredMethod("getValue", String.class, Integer.TYPE); 238 | // Util.getValue(string, R.string.xxx); 239 | return (String) getValueMethod.invoke(null, string, value); 240 | } catch (ClassNotFoundException e) { 241 | } catch (IllegalArgumentException e) { 242 | } catch (IllegalAccessException e) { 243 | } catch (NoSuchFieldException e) { 244 | } catch (NoSuchMethodException e) { 245 | } catch (InvocationTargetException e) { 246 | } 247 | 248 | // VLC for Android translations not available (custom app perhaps) 249 | // Use hardcoded English phrases. 250 | switch(type) { 251 | case Album: 252 | return "Unknown Album"; 253 | case Genre: 254 | return "Unknown Genre"; 255 | case Artist: 256 | default: 257 | return "Unknown Artist"; 258 | } 259 | } 260 | 261 | /** 262 | * Compare the filenames to sort items 263 | */ 264 | @Override 265 | public int compareTo(Media another) { 266 | return mTitle.toUpperCase(Locale.getDefault()).compareTo( 267 | another.getTitle().toUpperCase(Locale.getDefault())); 268 | } 269 | 270 | public String getLocation() { 271 | return mLocation; 272 | } 273 | 274 | public void updateMeta() { 275 | 276 | } 277 | 278 | public String getFileName() { 279 | if (mFilename == null) { 280 | mFilename = LibVlcUtil.URItoFileName(mLocation); 281 | } 282 | return mFilename; 283 | } 284 | 285 | public long getTime() { 286 | return mTime; 287 | } 288 | 289 | public void setTime(long time) { 290 | mTime = time; 291 | } 292 | 293 | public int getAudioTrack() { 294 | return mAudioTrack; 295 | } 296 | 297 | public void setAudioTrack(int track) { 298 | mAudioTrack = track; 299 | } 300 | 301 | public int getSpuTrack() { 302 | return mSpuTrack; 303 | } 304 | 305 | public void setSpuTrack(int track) { 306 | mSpuTrack = track; 307 | } 308 | 309 | public long getLength() { 310 | return mLength; 311 | } 312 | 313 | public int getType() { 314 | return mType; 315 | } 316 | 317 | public int getWidth() { 318 | return mWidth; 319 | } 320 | 321 | public int getHeight() { 322 | return mHeight; 323 | } 324 | 325 | /** 326 | * Returns the raw picture object. Likely to be NULL in VLC for Android 327 | * due to lazy-loading. 328 | * 329 | * Use {@link org.videolan.vlc.Util#getPictureFromCache(Media)} instead. 330 | * 331 | * @return The raw picture or NULL 332 | */ 333 | public Bitmap getPicture() { 334 | return mPicture; 335 | } 336 | 337 | /** 338 | * Sets the raw picture object. 339 | * 340 | * In VLC for Android, use {@link org.videolan.vlc.Util#setPicture(Context, Media, Bitmap)} instead. 341 | * 342 | * @param p 343 | */ 344 | public void setPicture(Bitmap p) { 345 | mPicture = p; 346 | } 347 | 348 | public boolean isPictureParsed() { 349 | return mIsPictureParsed; 350 | } 351 | 352 | public void setPictureParsed(boolean isParsed) { 353 | mIsPictureParsed = isParsed; 354 | } 355 | 356 | public String getTitle() { 357 | if (mTitle != null && mType != TYPE_VIDEO) 358 | return mTitle; 359 | else { 360 | int end = getFileName().lastIndexOf("."); 361 | if (end <= 0) 362 | return getFileName(); 363 | return getFileName().substring(0, end); 364 | } 365 | } 366 | 367 | public String getSubtitle() { 368 | return mType != TYPE_VIDEO ? mArtist + " - " + mAlbum : ""; 369 | } 370 | 371 | public String getArtist() { 372 | return mArtist; 373 | } 374 | 375 | public String getGenre() { 376 | if(getValueWrapper(null, UnknownStringType.Genre).equals(mGenre)) 377 | return mGenre; 378 | else if( mGenre.length() > 1)/* Make genres case insensitive via normalisation */ 379 | return Character.toUpperCase(mGenre.charAt(0)) + mGenre.substring(1).toLowerCase(Locale.getDefault()); 380 | else 381 | return mGenre; 382 | } 383 | 384 | public String getCopyright() { 385 | return mCopyright; 386 | } 387 | 388 | public String getAlbum() { 389 | return mAlbum; 390 | } 391 | 392 | public String getTrackNumber() { 393 | return mTrackNumber; 394 | } 395 | 396 | public String getDescription() { 397 | return mDescription; 398 | } 399 | 400 | public String getRating() { 401 | return mRating; 402 | } 403 | 404 | public String getDate() { 405 | return mDate; 406 | } 407 | 408 | public String getSettings() { 409 | return mSettings; 410 | } 411 | 412 | public String getNowPlaying() { 413 | return mNowPlaying; 414 | } 415 | 416 | public String getPublisher() { 417 | return mPublisher; 418 | } 419 | 420 | public String getEncodedBy() { 421 | return mEncodedBy; 422 | } 423 | 424 | public String getTrackID() { 425 | return mTrackID; 426 | } 427 | 428 | public String getArtworkURL() { 429 | return mArtworkURL; 430 | } 431 | } 432 | -------------------------------------------------------------------------------- /app/src/main/java/org/videolan/libvlc/MediaList.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * MediaList.java 3 | ***************************************************************************** 4 | * Copyright © 2013 VLC authors and VideoLAN 5 | * Copyright © 2013 Edward Wang 6 | * 7 | * This program is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 2.1 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this program; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. 20 | *****************************************************************************/ 21 | package org.videolan.libvlc; 22 | 23 | import java.util.ArrayList; 24 | 25 | import android.os.Bundle; 26 | 27 | /** 28 | * Java/JNI wrapper for the libvlc_media_list_t structure. 29 | */ 30 | public class MediaList { 31 | private static final String TAG = "VLC/LibVLC/MediaList"; 32 | 33 | /* Since the libvlc_media_t is not created until the media plays, we have 34 | * to cache them here. */ 35 | private class MediaHolder { 36 | Media m; 37 | boolean noVideo; // default false 38 | boolean noHardwareAcceleration; // default false 39 | 40 | public MediaHolder(Media media) { 41 | m = media; noVideo = false; noHardwareAcceleration = false; 42 | } 43 | public MediaHolder(Media m_, boolean noVideo_, boolean noHardwareAcceleration_) { 44 | m = m_; noVideo = noVideo_; noHardwareAcceleration = noHardwareAcceleration_; 45 | } 46 | } 47 | 48 | /* TODO: add locking */ 49 | private ArrayList mInternalList; 50 | private LibVLC mLibVLC; // Used to create new objects that require a libvlc instance 51 | private EventHandler mEventHandler; 52 | 53 | public MediaList(LibVLC libVLC) { 54 | mEventHandler = new EventHandler(); // used in init() below to fire events at the correct targets 55 | mInternalList = new ArrayList(); 56 | mLibVLC = libVLC; 57 | } 58 | 59 | /** 60 | * Adds a media URI to the media list. 61 | * 62 | * @param mrl 63 | * The MRL to add. Must be a location and not a path. 64 | * {@link LibVLC#PathToURI(String)} can be used to convert a path 65 | * to a MRL. 66 | */ 67 | public void add(String mrl) { 68 | add(new Media(mLibVLC, mrl)); 69 | } 70 | public void add(Media media) { 71 | add(media, false, false); 72 | } 73 | public void add(Media media, boolean noVideo) { 74 | add(media, noVideo, false); 75 | } 76 | public void add(Media media, boolean noVideo, boolean noHardwareAcceleration) { 77 | mInternalList.add(new MediaHolder(media, noVideo, noHardwareAcceleration)); 78 | signal_list_event(EventHandler.CustomMediaListItemAdded, mInternalList.size() - 1, media.getLocation()); 79 | } 80 | 81 | /** 82 | * Clear the media list. (remove all media) 83 | */ 84 | public void clear() { 85 | // Signal to observers of media being deleted. 86 | for(int i = 0; i < mInternalList.size(); i++) { 87 | signal_list_event(EventHandler.CustomMediaListItemDeleted, i, mInternalList.get(i).m.getLocation()); 88 | } 89 | mInternalList.clear(); 90 | } 91 | 92 | private boolean isValid(int position) { 93 | return position >= 0 && position < mInternalList.size(); 94 | } 95 | 96 | /** 97 | * This function checks the currently playing media for subitems at the given 98 | * position, and if any exist, it will expand them at the same position 99 | * and replace the current media. 100 | * 101 | * @param position The position to expand 102 | * @return -1 if no subitems were found, 0 if subitems were expanded 103 | */ 104 | public int expandMedia(int position) { 105 | ArrayList children = new ArrayList(); 106 | int ret = expandMedia(mLibVLC, position, children); 107 | if(ret == 0) { 108 | mEventHandler.callback(EventHandler.CustomMediaListExpanding, new Bundle()); 109 | this.remove(position); 110 | for(String mrl : children) { 111 | this.insert(position, mrl); 112 | } 113 | mEventHandler.callback(EventHandler.CustomMediaListExpandingEnd, new Bundle()); 114 | } 115 | return ret; 116 | } 117 | private native int expandMedia(LibVLC libvlc_instance, int position, ArrayList children); 118 | 119 | public void loadPlaylist(String mrl) { 120 | ArrayList items = new ArrayList(); 121 | loadPlaylist(mLibVLC, mrl, items); 122 | this.clear(); 123 | for(String item : items) { 124 | this.add(item); 125 | } 126 | } 127 | private native void loadPlaylist(LibVLC libvlc_instance, String mrl, ArrayList items); 128 | 129 | public void insert(int position, String mrl) { 130 | insert(position, new Media(mLibVLC, mrl)); 131 | } 132 | public void insert(int position, Media media) { 133 | mInternalList.add(position, new MediaHolder(media)); 134 | signal_list_event(EventHandler.CustomMediaListItemAdded, position, media.getLocation()); 135 | } 136 | 137 | /** 138 | * Move a media from one position to another 139 | * 140 | * @param startPosition start position 141 | * @param endPosition end position 142 | * @throws IndexOutOfBoundsException 143 | */ 144 | public void move(int startPosition, int endPosition) { 145 | if (!(isValid(startPosition) 146 | && endPosition >= 0 && endPosition <= mInternalList.size())) 147 | throw new IndexOutOfBoundsException("Indexes out of range"); 148 | 149 | MediaHolder toMove = mInternalList.get(startPosition); 150 | mInternalList.remove(startPosition); 151 | if (startPosition >= endPosition) 152 | mInternalList.add(endPosition, toMove); 153 | else 154 | mInternalList.add(endPosition - 1, toMove); 155 | Bundle b = new Bundle(); 156 | b.putInt("index_before", startPosition); 157 | b.putInt("index_after", endPosition); 158 | mEventHandler.callback(EventHandler.CustomMediaListItemMoved, b); 159 | } 160 | 161 | public void remove(int position) { 162 | if (!isValid(position)) 163 | return; 164 | String uri = mInternalList.get(position).m.getLocation(); 165 | mInternalList.remove(position); 166 | signal_list_event(EventHandler.CustomMediaListItemDeleted, position, uri); 167 | } 168 | 169 | public void remove(String location) { 170 | for (int i = 0; i < mInternalList.size(); ++i) { 171 | String uri = mInternalList.get(i).m.getLocation(); 172 | if (uri.equals(location)) { 173 | mInternalList.remove(i); 174 | signal_list_event(EventHandler.CustomMediaListItemDeleted, i, uri); 175 | i--; 176 | } 177 | } 178 | } 179 | 180 | public int size() { 181 | return mInternalList.size(); 182 | } 183 | 184 | public Media getMedia(int position) { 185 | if (!isValid(position)) 186 | return null; 187 | return mInternalList.get(position).m; 188 | } 189 | 190 | /** 191 | * @param position The index of the media in the list 192 | * @return null if not found 193 | */ 194 | public String getMRL(int position) { 195 | if (!isValid(position)) 196 | return null; 197 | return mInternalList.get(position).m.getLocation(); 198 | } 199 | 200 | public String[] getMediaOptions(int position) { 201 | boolean noHardwareAcceleration = mLibVLC.getHardwareAcceleration() == 0; 202 | boolean noVideo = false; 203 | if (isValid(position)) 204 | { 205 | if (!noHardwareAcceleration) 206 | noHardwareAcceleration = mInternalList.get(position).noHardwareAcceleration; 207 | noVideo = mInternalList.get(position).noVideo; 208 | } 209 | ArrayList options = new ArrayList(); 210 | 211 | if (!noHardwareAcceleration) { 212 | /* 213 | * Set higher caching values if using iomx decoding, since some omx 214 | * decoders have a very high latency, and if the preroll data isn't 215 | * enough to make the decoder output a frame, the playback timing gets 216 | * started too soon, and every decoded frame appears to be too late. 217 | * On Nexus One, the decoder latency seems to be 25 input packets 218 | * for 320x170 H.264, a few packets less on higher resolutions. 219 | * On Nexus S, the decoder latency seems to be about 7 packets. 220 | */ 221 | options.add(":file-caching=1500"); 222 | options.add(":network-caching=1500"); 223 | options.add(":codec=mediacodec,iomx,all"); 224 | } 225 | if (noVideo) 226 | options.add(":no-video"); 227 | 228 | return options.toArray(new String[options.size()]); 229 | } 230 | 231 | public EventHandler getEventHandler() { 232 | return mEventHandler; 233 | } 234 | 235 | @Override 236 | public String toString() { 237 | StringBuilder sb = new StringBuilder(); 238 | sb.append("LibVLC Media List: {"); 239 | for(int i = 0; i < size(); i++) { 240 | sb.append(((Integer)i).toString()); 241 | sb.append(": "); 242 | sb.append(getMRL(i)); 243 | sb.append(", "); 244 | } 245 | sb.append("}"); 246 | return sb.toString(); 247 | } 248 | 249 | private void signal_list_event(int event, int position, String uri) { 250 | Bundle b = new Bundle(); 251 | b.putString("item_uri", uri); 252 | b.putInt("item_index", position); 253 | mEventHandler.callback(event, b); 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /app/src/main/java/org/videolan/libvlc/TrackInfo.java: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * TrackInfo.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 | public class TrackInfo { 24 | 25 | public static final int TYPE_UNKNOWN = -1; 26 | public static final int TYPE_AUDIO = 0; 27 | public static final int TYPE_VIDEO = 1; 28 | public static final int TYPE_TEXT = 2; 29 | public static final int TYPE_META = 3; 30 | 31 | public int Type; 32 | public int Id; 33 | public String Codec; 34 | public String Language; 35 | 36 | /* Video */ 37 | public int Height; 38 | public int Width; 39 | public float Framerate; 40 | 41 | /* Audio */ 42 | public int Channels; 43 | public int Samplerate; 44 | 45 | /* MetaData */ 46 | public long Length; 47 | public String Title; 48 | public String Artist; 49 | public String Album; 50 | public String Genre; 51 | public String ArtworkURL; 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libiomx-gingerbread.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/jniLibs/armeabi-v7a/libiomx-gingerbread.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libiomx-hc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/jniLibs/armeabi-v7a/libiomx-hc.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libiomx-ics.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/jniLibs/armeabi-v7a/libiomx-ics.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libvlcjni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/jniLibs/armeabi-v7a/libvlcjni.so -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_pause_over_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/res/drawable-hdpi/ic_action_pause_over_video.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_play_over_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/res/drawable-hdpi/ic_action_play_over_video.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wass08/VLC-Simple-Player-Android/e677e6644837e3785b0ec4d58adf0165bcd3b8c7/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_fullscreen_vlc_player.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | 18 | 19 | 25 | 31 | 32 | 38 | 39 | 44 | 45 | 50 | 51 | 55 | 56 | 63 | 64 | 65 | 66 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_media_selector.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 22 | 23 | 33 | 34 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_media_selector.xml: -------------------------------------------------------------------------------- 1 |

3 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #66000000 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | VLC Simple Player 5 | Settings 6 | Stream this movie 7 | Here enter the URL of a movie file : 8 | http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4 9 | FullscreenVlcPlayer 10 | Dummy Button 11 | DUMMY\nCONTENT 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 15 | 16 | 23 | 24 |