I have used Movie in Processing for Windows from processing.video.* but cannot use it in android.
I have tried using FileDescriptor and getAssets etc with the video in data or other folder (located via Environment.getExternalStorageDirectory()) but I just get a null pointer, although it is looking in the correct folder.
Any ideas where the problem lies? I have searched on the web but none of the solutions work. The manifest has the correct permissions.
@paturn === i gave a look to this old code and made some modifs; it runs; you have ony to put your video in the data folder (and change the name, of course; now i have another solution with a videoView; if you want i can put the code.Tested with MM and Nougat.
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.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.content.*;
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.os.Environment;
import android.content.pm.PackageManager;
import android.os.Build;
import android.Manifest;
import android.os.Build;
////////////////////////////////////////////////
int MyVersion = Build.VERSION.SDK_INT;
AssetFileDescriptor afd;
Context context;
Activity act;
SurfaceView mySurface;
SurfaceHolder mSurfaceHolder;
MediaMetadataRetriever metaRetriever;
MediaPlayer mp;
FrameLayout fl;
boolean surfacecreated = false;///new, in order to avoid taht the mp is created but not the surface
//String pathstr = Environment.getExternalStorageDirectory();////i put the video in the data folder
void setup() {
size(10, 10);// to show that the surface is created
permissions();///new, normally it is notneeded, yet i am prudent with that (after lollypop they are asked on runtime and not only through the Manifest)
Looper.prepare();//as you modify the main ui thread
}
void permissions(){
if (MyVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (!permissionsDejaAccordees()) {
demandePermissionParticuliere();
}
};
};
private boolean permissionsDejaAccordees() {
/// in some cases i have seen that an error is fired if the permissision is allready granted
int result = act.checkSelfPermission( Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (result == PackageManager.PERMISSION_GRANTED) {
println("permission déjà accordée");
return true;
} else {
println("je demande particulière");
return false;
}
};
private void demandePermissionParticuliere() {
act.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},101);////you can also ask only for read but...
};
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 101:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
println("permissions accordées");
} else {
println("permissions not granted");
}
break;
default:
act.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
void prepareMP(){
try {
afd = context.getAssets().openFd("who.mp4");
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
println("la hauteur2 de la video est=="+ height);///in order to be sure that the video was found and also, if needed to work with the height or the width of the video and the surface (scaling)
}
catch (IOException e) {
e.printStackTrace();
}
mp = new MediaPlayer();
try {
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp.prepare();
}catch (IOException e) {
e.printStackTrace();
}
if(surfacecreated){
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();
prepareMP();//new, because it happens that onStart is performed before settings() and mp is not //instantiated
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) {
surfacecreated = true;//new, i am very prudent....
println("la surface a été créé");
if(mp !=null){
mp.setDisplay(surfaceHolder);
startVideo();
}else{
println("le mediaplayer n'est pas ok");
prepareMP();
mp.setDisplay(surfaceHolder);
startVideo();
}
}
@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);
}
That is all. One line. Not even a list or an explanation of what “a” is.
I must be missing something which your code requires and my previous code did not require.
I get the surface view from this, but I still get the error message file not found. This applies to the data folder or any folder located from the Environment source.
Whenever I use any other of my android apps (via Eclipse) the correct video file is found.
I assume my settings in Processing are not correct. Any suggestions?
@paturn === i heve verified, the code is ok; there wa probably a typo with cut && copy; i put the code again: dont forget the permission and put the orientation according to your video.
import android.R;
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.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.content.*;
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.os.Environment;
import android.content.pm.PackageManager;
import android.os.Build;
import android.Manifest;
import android.os.Build;
////////////////////////////////////////////////
int MyVersion = Build.VERSION.SDK_INT;
AssetFileDescriptor afd;
Context context;
Activity act;
SurfaceView mySurface;
SurfaceHolder mSurfaceHolder;
MediaMetadataRetriever metaRetriever;
MediaPlayer mp;
FrameLayout fl;
boolean surfacecreated = false;///new, in order to avoid taht the mp is created but not the surface
//String pathstr = Environment.getExternalStorageDirectory();////i put the video in the data folder
void setup() {
size(10, 10);// to show that the surface is created
permissions();///new, normally it is notneeded, yet i am prudent with that (after lollypop they are asked on runtime and not only through the Manifest)
Looper.prepare();//as you modify the main ui thread
}
void permissions(){
if (MyVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (!permissionsDejaAccordees()) {
demandePermissionParticuliere();
}
};
};
private boolean permissionsDejaAccordees() {
/// in some cases i have seen that an error is fired if the permissision is allready granted
int result = act.checkSelfPermission( Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (result == PackageManager.PERMISSION_GRANTED) {
println("permission déjà accordée");
return true;
} else {
println("je demande particulière");
return false;
}
};
private void demandePermissionParticuliere() {
act.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},101);////you can also ask only for read but...
};
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 101:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
println("permissions accordées");
} else {
println("permissions not granted");
}
break;
default:
act.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
void prepareMP(){
try {
afd = context.getAssets().openFd("who.mp4");
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
println("la hauteur2 de la video est=="+ height);///in order to be sure that the video was found and also, if needed to work with the height or the width of the video and the surface (scaling)
}
catch (IOException e) {
e.printStackTrace();
}
mp = new MediaPlayer();
try {
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp.prepare();
}catch (IOException e) {
e.printStackTrace();
}
if(surfacecreated){
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();
prepareMP();//new, because it happens that onStart is performed before settings() and mp is not //instantiated
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) {
surfacecreated = true;//new, i am very prudent....
println("la surface a été créé");
if(mp !=null){
mp.setDisplay(surfaceHolder);
startVideo();
}else{
println("le mediaplayer n'est pas ok");
prepareMP();
mp.setDisplay(surfaceHolder);
startVideo();
}
}
@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);
}
When you have some time could you please install APDE and test the code of the link above? It will only take a minute or two. Because when I use a file in the data folder, I don’t need any permission at all. I’m curious if it can be device-dependent,
@noel
I have tried the sketch with APDE and it doesn’t work. I have retried previous examples in APDE and they work correctly. I am using Samsung Galaxy A40 with android 10.
Did you use APDE’s App mode? Could you try it with this video, placing it in the data folder? (maybe it’s the file) I’ve tested it on Samsung Android 10.
Edit: Wich sketch are you referring to; mine or yours?