Help with displaying video

Hello all,

Currently working on porting my windows app to Android. The Windows app has a startup animation in the form of a video. I tried to use the built in video library of Processing, but that just crashes the app and yields this in the console:

FATAL EXCEPTION: Animation Thread
Process: com.TechMasterIndustries.TechmasterQueueManager, PID: 4912
java.lang.ExceptionInInitializerError
	at processing.video.Video.init(Unknown Source:0)
	at processing.video.Movie.initGStreamer(Unknown Source:6)
	at processing.video.Movie.<init>(Unknown Source:28)
	at com.TechMasterIndustries.TechmasterQueueManager.TechMasterQueueManagerAndroidBeta.setup(TechMasterQueueManagerAndroidBeta.java:89)
	at processing.core.PApplet.handleDraw(PApplet.java:1835)
	at processing.core.PSurfaceNone.callDraw(PSurfaceNone.java:476)
	at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:516)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.indexOf(int)' on a null object reference
	at processing.core.PApplet.parseInt(PApplet.java:6791)
	at processing.core.PApplet.parseInt(PApplet.java:6782)
	at processing.video.Video.<clinit>(Unknown Source:29)
	... 7 more

I then did some digging and found this Library which claims to be a video mode for android. This also crashes the app and yields this in the console:

FATAL EXCEPTION: Animation Thread
Process: com.TechMasterIndustries.TechmasterQueueManager, PID: 2504
java.lang.NoSuchMethodError: No virtual method getSurfaceView()Landroid/view/SurfaceView; in class Lprocessing/core/PApplet; or its super classes (declaration of 'processing.core.PApplet' appears in /data/app/com.TechMasterIndustries.TechmasterQueueManager-KQpbRXVpXCnyeeuQo0LY8g==/base.apk)
	at in.omerjerk.processing.video.android.VideoBase.<init>(Unknown Source:48)
	at in.omerjerk.processing.video.android.Movie.<init>(Unknown Source:1)
	at com.TechMasterIndustries.TechmasterQueueManager.TechMasterQueueManagerAndroidBeta.setup(TechMasterQueueManagerAndroidBeta.java:93)
	at processing.core.PApplet.handleDraw(PApplet.java:1835)
	at processing.core.PSurfaceNone.callDraw(PSurfaceNone.java:476)
	at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:516)


Not sure what I’m doing wrong, but here’s my code: My Code

Anyone know how to fix this/what I’m doing wrong?

Thanks in advance

Hi @TechMaster04
Have you tried this one?

No, not yet. I’ll give it a try now

Unfortunately, it still crashes. I get this error in the console:

FATAL EXCEPTION: Animation Thread
Process: processing.test.gettingstartedmovie, PID: 2084
java.lang.NoSuchMethodError: No virtual method getSurfaceView()Landroid/view/SurfaceView; in class Lprocessing/core/PApplet; or its super classes (declaration of 'processing.core.PApplet' appears in /data/app/processing.test.gettingstartedmovie-xiS_47YJhoSqxEq49WQytw==/base.apk)
	at in.omerjerk.processing.video.android.VideoBase.<init>(Unknown Source:48)
	at in.omerjerk.processing.video.android.Movie.<init>(Unknown Source:1)
	at processing.test.gettingstartedmovie.GettingStartedMovie.setup(GettingStartedMovie.java:31)
	at processing.core.PApplet.handleDraw(PApplet.java:1835)
	at processing.core.PSurfaceNone.callDraw(PSurfaceNone.java:476)
	at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:516)

Have you seen this topic?

I have, but it confused me quite a bit. I’ll take another look and see if I can get it to work

UPDATE: Turns out that the topic wasn’t going to achieve the end result I desire. I’m gonna do some more research with broader terms and see if that helps, because at this point I am extremely stumped

@TechMaster04 ===

  • Could be better to put the relevant code here
  • Processing video lib does not work with android
  • Anyway why not using the Mediaplayer class from android?- I have already posted code for that on this forum or previous one, i dont know

@akenaton
Code below is running quite well, but when I set the surface xy values, the movie(placed in data folder) disappears as if it were below the actually sketch layout frame.
Any idea?
(Using APDE app mode)

import android.media.MediaMetadataRetriever;
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 mp;

void setup() {
  size(400, 400, P2D);
  act = this.getActivity();
  context = act.getApplicationContext();
  Looper.prepare();
  mp = new MediaPlayer();
  try {
    afd = context.getAssets().openFd("m.mp4");
    MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
    metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
  }
    catch (IOException e) {
    e.printStackTrace();
  }
    mySurface = new SurfaceView(act);
    mSurfaceHolder = mySurface.getHolder();
    mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
    @Override
      public void surfaceCreated(SurfaceHolder surfaceHolder) {
      mp.setDisplay(surfaceHolder);
    }
    @Override
      public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
      mp.setDisplay(surfaceHolder);
    }
    @Override
      public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    }
  }
  );
    startVideo();
}

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

void draw() {
}

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

@noel ===
yes, your video is behind the surfaceView (normally if it has sound you can hear it) you have created and that is exactly what your code is doing; onStart you have to create a VideoView and that is the view you add to the surface; dont forget also to set the zOrder “on top” param to true. If needed i can put code for that but i am quite sure that you can find by yourself!

@noel ===
excuse me; i have not taken time enough to look to your code in details; the zOrder param is not only the culprit in your code, there is another error / your player: you have to setDataSource and prepare() BEFORE starting the runnable. With some modifs i can get your code running successfully (and there is no need for a videoView which is only a sublclass for the player itself) - If you want i can put the code (i think it will run the same with APDE)_

@akenaton
I’ve attached the surface View to a FrameLayout like I normally do The sketch runs well with video and sound. But still behind my sketch window. How can I set this order.

import android.media.MediaMetadataRetriever;
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;
import android.widget.FrameLayout;
import android.R;
import android.content.*; 
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;

AssetFileDescriptor afd;
Context context;
Activity act;
SurfaceView mySurface;
SurfaceHolder mSurfaceHolder;
MediaMetadataRetriever metaRetriever;
MediaPlayer mp;
FrameLayout fl;

void setup() {
  size(10, 10);
  Looper.prepare();
  try {
    afd = context.getAssets().openFd("m.mp4");
    MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
    metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
  }
    catch (IOException e) {
    e.printStackTrace();
  }
  mp = new MediaPlayer();
  try {
    mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());   
    mp.prepare();
  }
  catch (IOException e) {
    e.printStackTrace();
  }
  startVideo();
}

void startVideo() {
  act.runOnUiThread(new Runnable() {
    public void run() {

      if (mp.isPlaying() == false) {
        mp.start();
      }
    }
  }
  );
}

void draw() {
}

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

@Override 
  public void onStart() {
  act = this.getActivity();
  context = act.getApplicationContext();
  mySurface = new SurfaceView(act);
  mSurfaceHolder = mySurface.getHolder();
  mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
    @Override
      public void surfaceCreated(SurfaceHolder surfaceHolder) {
      mp.setDisplay(surfaceHolder);
    }
    @Override
      public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
      mp.setDisplay(surfaceHolder);
    }
    @Override
      public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    }
  }
  );
  mySurface.bringToFront();
  //mySurface.setX(100);
  //mySurface.setY(100);
  fl = (FrameLayout)act.findViewById(R.id.content);
  FrameLayout.LayoutParams params1 = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
  fl.addView(mySurface);
}

@noel ===
working code (from the first one you posted ) but i have also the version getting the frameLayout::


import android.media.MediaMetadataRetriever;
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 mp;
int videoH = 0;
int videoL= 0;

void settings(){
  size(displayWidth, displayHeight);
}

void setup() {
  //size(400, 400, P2D);
  background(0);
  act = this.getActivity();
  context = act.getApplicationContext();
  Looper.prepare();
  mp = new MediaPlayer();
  try {
    afd = context.getAssets().openFd("who.mp4");
    MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
    metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    String h = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
    String w = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
    videoL= int(w);
      videoH=int(h);
  mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
  mp.prepare();

}
    catch (IOException e) {
    e.printStackTrace();
  }
    mySurface = new SurfaceView(act);
    mSurfaceHolder = mySurface.getHolder();
    mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
    @Override
      public void surfaceCreated(SurfaceHolder surfaceHolder) {
      mp.setDisplay(surfaceHolder);
      println("surface créeé");
    }
    @Override
      public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
      mp.setDisplay(surfaceHolder);
      println("surface changée");
    }
    @Override
      public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        println("surface détruite");
    }
  }
  );
    startVideo();
}

void startVideo() {
  act.runOnUiThread(new Runnable() {
    public void run() {
      //try {
        println("jexecute le runnable");
        //mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
        mSurfaceHolder = mySurface.getHolder();
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        
        //mp.prepare();
        act.addContentView(mySurface, new ViewGroup.LayoutParams(videoL, videoH));
        mySurface.bringToFront();
      mySurface.setZOrderOnTop(true);
        mySurface.setX(displayWidth/2-videoL/2);
        mySurface.setY((displayHeight/2)-videoH/2);
        if (mp.isPlaying() == false) {
          mp.start();
        }
      //}
      //catch (IOException e) {
        //e.printStackTrace();
      //}
    }
  }
    );
}

void draw() {
}

void onStop() {
    if (mp!=null) {
        mp.release();
        mp = null;
  }
    super.onStop() ;
}
1 Like

@akenaton
Thank you very much.
I understood the setDataSource and prepare() tip.
But the mySurface.setZOrderOnTop(true); really did the trick.
Great!

@noel ===
yes; i have told you that in the previous post… Note that this solution is one (as often) among others (videoView…textureView) but that is not really important!

I don"t know what you precisely want to achieve, but if you are still interested I uploaded a code for a video player with the play/pause/rewind buttons and a slider to fast forward/backward. here

vtvt

How do I draw OVER the video?

I have responded here.

@Mesalcode ===
yes, that is possible; in the thread that starts the surfaceview you comment the setZOrderOnTop ; instead of it you write mySurface.setZOrderMediaOverlay(true);
in your setup() or before (onStart()) you create the view for your rect, the most simple way is to create a button from Button class, setting its text (if needed!), its textColor, its coordinates and layout params; then you add it to the contentView; if you want only the text just before adding you set its background color to transparent. Of course you can also a) create a drawable shape and use the same code or b) create another surface wiew for your shape and put it upon the first one with the video.

Thank you for your help!

That is very unfortunate for me as I am using Processing for its buildin functions for rendering textured cubes etc. I already spent alot of time building this app and don’t want to throw all my work away for the background.

My idea was to split the video into each frame, store the frames in an array and then iterate through the frames every time draw is called. This however leads the app into crashing without any error message after a few seconds. An OutOfMemoryError would be an explanation, but I also tried loading only 20 images with 10kb each and it would still crash.

Do you have any explanation for why this is happening?