# Playing Video in Android mode

**URL:** <https://discourse.processing.org/t/playing-video-in-android-mode/3476>\
**Category:** Processing for Android\
**Created:** [September 12, 2018, 12:32am UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476 "2018-09-12T00:32:11Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![philspitler](https://avatars.discourse-cdn.com/v4/letter/p/f1d935/32.png) [@philspitler](https://discourse.processing.org/u/philspitler)\
**Post date:** [September 12, 2018, 12:32am UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/1 "2018-09-12T00:32:11Z")

</div>

hi, I want to play a video in Android mode, I believe there used to be a library to do this but I read that it’s no longer supported.

There is a partial thread here.

> [@Video in Android Mode](https://discourse.processing.org/t/video-in-android-mode/1498):
>
> … this takes over and continues from the thread at the old forum @flashbacker The line … afd = context.getAssets().openFd(“machine\_compr.mp4”); generates a file error for me too if the video is in the project folder. if you create a Data folder and put the video in there it works! When Processing turns your sketch into ‘proper’ Java/Android, the video is put into the apps Assets folder which is where getAssets() looks for it. I am guessing that this is why trying to load from and SD with…

But it doesn’t seem to have a final solution.

Are there any code snippets out there that will get me up and running…

Seems like something that a lot of people would have done…

Thanks

Phil

---

<div class="post-metadata">

**Author:** ![akenaton](https://avatars.discourse-cdn.com/v4/letter/a/a88e4f/32.png) [@akenaton](https://discourse.processing.org/u/akenaton)\
**Post date:** [September 12, 2018, 8:42am UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/2 "2018-09-12T08:42:34Z")

</div>

@philspitler===

i dont understand: in the previous forum i have put code examples for that and (if i can remember) everything was ok, though not simple because the question was not only about video but for full screen video, which means using surfaceView. Anyway, in the most simple case, you have 1) to use mediaPlayer from Android and add a videoView 2) give it the path to your video, which can be some url on line, some file on your sd card or some file in your app: code for doing that depends of your choice 3) add if you want some mediaController.  
more details here: [https://developer.android.com/reference/android/widget/VideoView](https://developer.android.com/reference/android/widget/VideoView)

Try doing that and if you have any problem put your code: without it is difficult to help.

---

<div class="post-metadata">

**Author:** ![shedMusic](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/shedmusic/32/601_2.png) [@shedMusic](https://discourse.processing.org/u/shedMusic)\
**Post date:** [September 12, 2018, 11:17am UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/3 "2018-09-12T11:17:03Z")

</div>

@philspitler

Yes, @akenaton is right … there is code that works. I did it just to learn how … I will post later the complete code I eventually got working.

EDIT: Here’s the code … it is messy, and is still (for me) experimental, but it runs. There are things unrelated to the video itself like getting the SD card details, and drawing a rect in Draw() … for my future use …and the SurfaceHolder.setType method is showing as deprecated. But it does play an mp4 video so hopefully will get you going?!

Good luck …

```auto
import android.media.MediaMetadataRetriever;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.app.Activity;
import android.view.ViewGroup;
import android.view.View;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.content.res.Resources;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.content.Context;

AssetFileDescriptor afd;
Context context;
Activity act;
SurfaceView mySurface;
SurfaceHolder mSurfaceHolder;
MediaMetadataRetriever metaRetriever;
MediaPlayer mMediaPlayer;

File[] SDcards ; 
String primarySD, externalSD;

void setup() {
  fullScreen(P2D);
  //size(400,400,P2D);
  act = this.getActivity();
  context = act.getApplicationContext();
  SDcards = context.getExternalFilesDirs(null);
  primarySD = SDcards[0].getPath().split("/Android")[0];
  externalSD = SDcards[1].getPath().split("/Android")[0];
  println("primarySD = " + primarySD) ;
  Looper.prepare();
  mMediaPlayer = new MediaPlayer();
  try {
    afd = context.getAssets().openFd("your_video.mp4"); /// video is in the sketch Data folder
    MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
    metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); 
    if (int(height) < 2) {
      throw new IOException();
    }
  }
  catch (IllegalArgumentException e) {
    e.printStackTrace();
  }
  catch (IllegalStateException e) {
    e.printStackTrace();
  } 
  catch (IOException e) {
    e.printStackTrace();
  }

  mySurface = new SurfaceView(act);
  mySurface.setZOrderOnTop(true) ;
  mSurfaceHolder = mySurface.getHolder();
  mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
    //<a href="/two/profile/Override">@Override</a>
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
      mMediaPlayer.setDisplay(surfaceHolder);
    }

    // <a href="/two/profile/Override">@Override</a>
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
      mMediaPlayer.setDisplay(surfaceHolder);
    }

    // <a href="/two/profile/Override">@Override</a>
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    }
  }
  );
  startVideo();
}

void startVideo() {
  act.runOnUiThread(new Runnable() {
    public void run() {
      try {
        mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
        mSurfaceHolder = mySurface.getHolder();
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mMediaPlayer.prepare();
        // act.addContentView(mySurface, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT));
        act.addContentView(mySurface, new ViewGroup.LayoutParams(400, 400));
        if (mMediaPlayer.isPlaying() == false) {
          mMediaPlayer.start();
        }
      }
      catch (IllegalArgumentException e) {
        e.printStackTrace();
      }
      catch (IllegalStateException e) {
        e.printStackTrace();
      } 
      catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  );
};

void draw() {
  rect(mouseX,mouseY,40,40);
}

void onPause() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onPause() ;
}

void onStop() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onStop() ;
}

void onDestroy() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onDestroy() ;
}

void onResume() {
  super.onResume() ;
}

```

---

<div class="post-metadata">

**Author:** ![philspitler](https://avatars.discourse-cdn.com/v4/letter/p/f1d935/32.png) [@philspitler](https://discourse.processing.org/u/philspitler)\
**Post date:** [September 12, 2018, 2:52pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/4 "2018-09-12T14:52:56Z")

</div>

Great, I’ll re-read the old thread as I must have missed something thanks.

Phil

---

<div class="post-metadata">

**Author:** ![akenaton](https://avatars.discourse-cdn.com/v4/letter/a/a88e4f/32.png) [@akenaton](https://discourse.processing.org/u/akenaton)\
**Post date:** [September 12, 2018, 2:58pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/5 "2018-09-12T14:58:22Z")

</div>

@philspitler===

i got a look to the post; everything is ok and i am sure that it works; yet, as i have told to you, this code is for using videos on the sdcard and it uses surface view (you can also do the same with textureview); if you want to use videos that are in your data or assets folder you have to change the code (that is not very complicated) and if you want only the videoview the code could be more simple.

---

<div class="post-metadata">

**Author:** ![philspitler](https://avatars.discourse-cdn.com/v4/letter/p/f1d935/32.png) [@philspitler](https://discourse.processing.org/u/philspitler)\
**Post date:** [September 15, 2018, 1:05am UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/6 "2018-09-15T01:05:14Z")

</div>

Hi, I tried the code and got a weird error about a theme ?

See below.

Any thoughts?

Thanks,

Phil

```auto
FATAL EXCEPTION: main
Process: processing.test.androidvideo_v01, PID: 9266
java.lang.RuntimeException: Unable to start activity ComponentInfo{processing.test.androidvideo_v01/processing.test.androidvideo_v01.MainActivity}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
	at android.app.ActivityThread.access$800(ActivityThread.java:151)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
	at android.os.Handler.dispatchMessage(Handler.java:102)
	at android.os.Looper.loop(Looper.java:135)
	at android.app.ActivityThread.main(ActivityThread.java:5254)
	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:920)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:715)
Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
	at android.support.v7.app.AppCompatDelegateImplV9.createSubDecor(AppCompatDelegateImplV9.java:354)
	at android.support.v7.app.AppCompatDelegateImplV9.ensureSubDecor(AppCompatDelegateImplV9.java:323)
	at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:293)
	at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:149)
	at processing.test.androidvideo_v01.MainActivity.onCreate(MainActivity.java:21)
	at android.app.Activity.performCreate(Activity.java:5990)
	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
	... 10 more

```

---

<div class="post-metadata">

**Author:** ![philspitler](https://avatars.discourse-cdn.com/v4/letter/p/f1d935/32.png) [@philspitler](https://discourse.processing.org/u/philspitler)\
**Post date:** [September 15, 2018, 1:17am UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/7 "2018-09-15T01:17:39Z")

</div>

I fixed that issue by adding this line to my manifest.xml

android:theme="@style/Theme.AppCompat.Light"

I have one mp4 file in my data folder.

But now I’m getting a different error…

```auto
FATAL EXCEPTION: GLThread 538
Process: processing.test.androidvideo_v01, PID: 12079
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
	at processing.test.androidvideo_v01.AndroidVideo_v01.setup(AndroidVideo_v01.java:69)
	at processing.core.PApplet.handleDraw(PApplet.java:1846)
	at processing.opengl.PSurfaceGLES$RendererGLES.onDrawFrame(PSurfaceGLES.java:264)
	at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1522)
	at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239)

```

And my code looks like this.

```auto
import android.media.MediaMetadataRetriever;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.app.Activity;
import android.view.ViewGroup;
import android.view.View;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.content.res.Resources;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.content.Context;

AssetFileDescriptor afd;
Context context;
Activity act;
SurfaceView mySurface;
SurfaceHolder mSurfaceHolder;
MediaMetadataRetriever metaRetriever;
MediaPlayer mMediaPlayer;

File[] SDcards ; 
String primarySD, externalSD;

void setup() {
  fullScreen(P2D);
  //size(400,400,P2D);
  act = this.getActivity();
  context = act.getApplicationContext();
  SDcards = context.getExternalFilesDirs(null);
  primarySD = SDcards[0].getPath().split("/Android")[0];
  externalSD = SDcards[1].getPath().split("/Android")[0];
  println("primarySD = " + primarySD) ;
  Looper.prepare();
  mMediaPlayer = new MediaPlayer();
  try {
    afd = context.getAssets().openFd("video1.mp4"); /// video is in the sketch Data folder
    MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
    metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); 
    if (int(height) < 2) {
      throw new IOException();
    }
  }
  catch (IllegalArgumentException e) {
    e.printStackTrace();
  }
  catch (IllegalStateException e) {
    e.printStackTrace();
  } 
  catch (IOException e) {
    e.printStackTrace();
  }

  mySurface = new SurfaceView(act);
  mySurface.setZOrderOnTop(true) ;
  mSurfaceHolder = mySurface.getHolder();
  mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
    //<a href="/two/profile/Override">@Override</a>
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
      mMediaPlayer.setDisplay(surfaceHolder);
    }

    // <a href="/two/profile/Override">@Override</a>
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
      mMediaPlayer.setDisplay(surfaceHolder);
    }

    // <a href="/two/profile/Override">@Override</a>
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    }
  }
  );
  startVideo();
}

void startVideo() {
  act.runOnUiThread(new Runnable() {
    public void run() {
      try {
        mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
        mSurfaceHolder = mySurface.getHolder();
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mMediaPlayer.prepare();
        // act.addContentView(mySurface, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT));
        act.addContentView(mySurface, new ViewGroup.LayoutParams(400, 400));
        if (mMediaPlayer.isPlaying() == false) {
          mMediaPlayer.start();
        }
      }
      catch (IllegalArgumentException e) {
        e.printStackTrace();
      }
      catch (IllegalStateException e) {
        e.printStackTrace();
      } 
      catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  );
};

void draw() {
  rect(mouseX,mouseY,40,40);
}

void onPause() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onPause() ;
}

void onStop() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onStop() ;
}

void onDestroy() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onDestroy() ;
}

void onResume() {
  super.onResume() ;
}

```

---

<div class="post-metadata">

**Author:** ![akenaton](https://avatars.discourse-cdn.com/v4/letter/a/a88e4f/32.png) [@akenaton](https://discourse.processing.org/u/akenaton)\
**Post date:** [September 15, 2018, 7:59am UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/8 "2018-09-15T07:59:11Z")

</div>

@philspitler===  
the error is with the theme= change it in the Manifest.

---

<div class="post-metadata">

**Author:** ![akenaton](https://avatars.discourse-cdn.com/v4/letter/a/a88e4f/32.png) [@akenaton](https://discourse.processing.org/u/akenaton)\
**Post date:** [September 15, 2018, 8:11am UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/9 "2018-09-15T08:11:07Z")

</div>

@philspitler===

sorry! i have read the first post and answered without reading next one! - As for the second error it s difficult to help without more details: yet it claims about an arrayoutof bounds and i guess that this is caused by your code about SD cards; is your println() ok???

---

<div class="post-metadata">

**Author:** ![philspitler](https://avatars.discourse-cdn.com/v4/letter/p/f1d935/32.png) [@philspitler](https://discourse.processing.org/u/philspitler)\
**Post date:** [September 15, 2018, 4:41pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/10 "2018-09-15T16:41:56Z")

</div>

The code fails before the println()

I am not using any SD cards in the project as my mp4 file is my data folder.

I can look at stripping out all the SD card stuff.

Thanks

Phil

---

<div class="post-metadata">

**Author:** ![akenaton](https://avatars.discourse-cdn.com/v4/letter/a/a88e4f/32.png) [@akenaton](https://discourse.processing.org/u/akenaton)\
**Post date:** [September 15, 2018, 4:45pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/11 "2018-09-15T16:45:48Z")

</div>

@philspitler ===

that is exactly what i guessed: your SDCards array returns only the primary card and it is not so easy to get the second one; try the code without these lines about SDcards and tell me what happens…

---

<div class="post-metadata">

**Author:** ![philspitler](https://avatars.discourse-cdn.com/v4/letter/p/f1d935/32.png) [@philspitler](https://discourse.processing.org/u/philspitler)\
**Post date:** [September 18, 2018, 7:50pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/12 "2018-09-18T19:50:01Z")

</div>

Getting rid of the SD code worked great and everything seems to be working.

onDestroy()  
onStop()

Curious if there is any reference to what these functions do.

Some of the functions seem to have the same code inside them.

Thanks for the help.

Phil

```auto
void onPause() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onPause() ;
}

void onStop() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onStop() ;
}

void onDestroy() {
  if (mMediaPlayer!=null) {
    mMediaPlayer.release();
    mMediaPlayer = null;
  }
  super.onDestroy() ;
}

void onResume() {
  super.onResume() ;
}

```

---

<div class="post-metadata">

**Author:** ![philspitler](https://avatars.discourse-cdn.com/v4/letter/p/f1d935/32.png) [@philspitler](https://discourse.processing.org/u/philspitler)\
**Post date:** [September 18, 2018, 10:26pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/13 "2018-09-18T22:26:28Z")

</div>

What I’m actually trying to do is have the video stop (and show a black screen) when I tap the screen (then start again on another tap).

Seems like the video is over the top of my current draw function though. I tried adjusting the z order

mySurface.setZOrderOnTop(true) ;

to false but then I didn’t see the video at all.

Any thoughts?

Thanks,

Phil

---

<div class="post-metadata">

**Author:** ![akenaton](https://avatars.discourse-cdn.com/v4/letter/a/a88e4f/32.png) [@akenaton](https://discourse.processing.org/u/akenaton)\
**Post date:** [September 19, 2018, 1:20pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/14 "2018-09-19T13:20:29Z")

</div>

@philspitler===  
these functions are called automatically and according to the fragment lifecycle one after the other but not all in any case: that depends of the os, its needs for other app and what your app is doing: onDestroy() for example is called if the os needs to get free of your app because another one has been launched. Anyway it s quite always a good idea to write all of them, especially when you app uses resources which the user could want to use: video, sound, cam, mic (and generally speaking any mediaplayer stuff). As for the code, you are right, it is redundant to release the player three times!  
As for the other point, do you want that the whole screen becomes (on tap) black or only space occupied by the video?

---

<div class="post-metadata">

**Author:** ![philspitler](https://avatars.discourse-cdn.com/v4/letter/p/f1d935/32.png) [@philspitler](https://discourse.processing.org/u/philspitler)\
**Post date:** [September 19, 2018, 5:24pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/15 "2018-09-19T17:24:49Z")

</div>

Thanks for the info

The video is playing full screen and I would like to use the whole screen as start / stop button.

Cheers

Phil

---

<div class="post-metadata">

**Author:** ![shedMusic](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/shedmusic/32/601_2.png) [@shedMusic](https://discourse.processing.org/u/shedMusic)\
**Post date:** [September 19, 2018, 6:34pm UTC](https://discourse.processing.org/t/playing-video-in-android-mode/3476/16 "2018-09-19T18:34:26Z")

</div>

@philspitler

I was just trying things with that code … I knew it was a mess!
