Can a videoview play a video stored on internal storage? - android

I'm trying to provide my users with the ability to use either external or internal storage. I'm displaying both images and videos (of a scientific nature). When storing the media on the SD card, all is fine. But when I store the media internally, only the images will display. No matter what I try I get various errors when trying to load and display the media stored under the applicationcontext.getFilesDir().
Is there a trick to setting a videoview's content to such a file?
Can a ContentResolver help me?
On a related note, is it considered bad form to assume that external storage exists?
Thanks in advance,
Sid
Below is one version that fails with "Cannot play video. Sorry, this video cannot be played". But I have many other modes of failure. I can copy the internal video to temp storage (external) and play it, so this copy to internal does indeed create a valid movie. It only fails when I try to play it directly from the internal storage.
videoFile = new File(this.getFilesDir() + File.separator + "test.mp4");
InputStream data = res.openRawResource(R.raw.moviegood);
try {
OutputStream myOutputStream = new FileOutputStream(videoFile);
byte[] buffer = new byte[8192];
int length;
while ( (length = data.read(buffer)) > 0 ) {
myOutputStream.write(buffer);
}
//Close the streams
myOutputStream.flush();
myOutputStream.close();
data.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
vview.setKeepScreenOn(true);
vview.setVideoPath(videoFile.getAbsolutePath());
vview.start();

MediaPlayer requires that the file being played has world-readable permissions. You can view the permissions of the file with the following command in adb shell:
ls -al /data/data/com.mypackage/myfile
You will probably see "-rw------", which means that only the owner (your app, not MediaPlayer) has read/write permissions.
Note: Your phone must be rooted in order to use the ls command without specifying the file (in the internal memory).
If your phone is rooted, you can add world-read permissions in adb shell with the following command:
chmod o+r /data/data/com.mypackage/myfile
If you need to modify these permissions programmatically (requires rooted phone!), you can use the following command in your app code:
Runtime.getRuntime().exec("chmod o+r /data/data/com.mypackage/myfile");
Which is basically a linux command. See https://help.ubuntu.com/community/FilePermissions for more on chmod.
EDIT: Found another simple approach here (useful for those without rooted phones). Since the application owns the file, it can create a file descriptor and pass that to mediaPlayer.setDataSource():
FileInputStream fileInputStream = new FileInputStream("/data/data/com.mypackage/myfile");
mediaPlayer.setDataSource(fileInputStream.getFD());
This approach avoids the permission issue completely.

You can use:
videoView.setVideoURI(Uri.parse(file.getAbsolutePath()));
if the file is world readable
Or you can use a content provider

For detail check this tutorial
public class AndroidVideoViewExample extends Activity {
private VideoView myVideoView;
private int position = 0;
private ProgressDialog progressDialog;
private MediaController mediaControls;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set the main layout of the activity
setContentView(R.layout.activity_main);
//set the media controller buttons
if (mediaControls == null) {
mediaControls = new MediaController(AndroidVideoViewExample.this);
}
//initialize the VideoView
myVideoView = (VideoView) findViewById(R.id.video_view);
// create a progress bar while the video file is loading
progressDialog = new ProgressDialog(AndroidVideoViewExample.this);
// set a title for the progress bar
progressDialog.setTitle("JavaCodeGeeks Android Video View Example");
// set a message for the progress bar
progressDialog.setMessage("Loading...");
//set the progress bar not cancelable on users' touch
progressDialog.setCancelable(false);
// show the progress bar
progressDialog.show();
try {
//set the media controller in the VideoView
myVideoView.setMediaController(mediaControls);
//set the uri of the video to be played
myVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.kitkat));
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
myVideoView.requestFocus();
//we also set an setOnPreparedListener in order to know when the video file is ready for playback
myVideoView.setOnPreparedListener(new OnPreparedListener() {
public void onPrepared(MediaPlayer mediaPlayer) {
// close the progress bar and play the video
progressDialog.dismiss();
//if we have a position on savedInstanceState, the video playback should start from here
myVideoView.seekTo(position);
if (position == 0) {
myVideoView.start();
} else {
//if we come from a resumed activity, video playback will be paused
myVideoView.pause();
}
}
});
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
//we use onSaveInstanceState in order to store the video playback position for orientation change
savedInstanceState.putInt("Position", myVideoView.getCurrentPosition());
myVideoView.pause();
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//we use onRestoreInstanceState in order to play the video playback from the stored position
position = savedInstanceState.getInt("Position");
myVideoView.seekTo(position);
}
}

I posted a custom VideoView implementation there.
The VideoView implementation has the setVideoFD(FileDescriptor fd) method and solves this issue.

I came across this thread with the same problem, I'm downloading my videos from the web to the internal storage, turns out when saving you can specify the RW mode, i.e change from PRIVATE to WORLD_READABLE
URL url = new URL(_url);
InputStream input = null;
FileOutputStream output = null;
try {
String outputName = "video.mp4";
input = url.openConnection().getInputStream();
output = c.openFileOutput(outputName, Context.MODE_WORLD_READABLE);
int read;
byte[] data = new byte[5120]; //5MB byte array
while ((read = input.read(data)) != -1)
output.write(data, 0, read);
return true;
} finally {
if (output != null)
output.close();
if (input != null)
input.close();
}
}

You can't just play it directly.
You need to implement a ContentProvider then pass the defined Uri to setVideoUri(uri) method.

Related

Android - VideoView unable to play video in external storage

Inside of a fragment in my android application, I take a video using an intent and then save it to my external storage:
private void dispatchTakeVideoIntent() {
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if (takeVideoIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent intent) {
if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == Activity.RESULT_OK) {
takenVideoUri = intent.getData();
String ext = ".mp4";
String filename = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss.SSS")
.format(System.currentTimeMillis()) + ext;
File root = getContext().getExternalFilesDir(Environment.DIRECTORY_MOVIES);
File file = new File(root, filename);
try(
InputStream is = getContext().getContentResolver().openInputStream(takenVideoUri);
FileOutputStream fos = new FileOutputStream(file)
) {
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] buf = new byte[1024];
while(is.read(buf)!=-1) {
bos.write(buf);
}
bos.close();
fos.close();
videoUri = Uri.fromFile(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then, inside of another fragment, I have a VideoView to which I want to pass the Uri of the saved video for it to play it.
Uri videoUri = /* gotten from the other fragment */
videoView.setVideoURI(videoUri);
However, when I open that fragment, I get the errors:
2022-04-28 18:53:59.273 23764-23821/my.app E/MediaPlayerNative: error (1, -2147483648)
2022-04-28 18:53:59.305 23764-23764/my.app E/MediaPlayer: Error (1,-2147483648)
I understand those are generic errors, which makes it worse because I have no clue as to where the error is.
My manifest file does include permission for both reading and writing external storage. I have tried saving the video to internal storage too, but nothing changed.
What am I doing wrong?
It seems to me the file is incomplete/empty. You could check its size using file.length() before trying to play it. Copying the file might be unnecessary as you could simply call takeVideoIntent.putExtra(EXTRA_OUTPUT, uri) to the intent to specify the path(uri) the captured video's location.
What usually happens with camera capture outputs is that onActivityResult is called before the file contents were properly written to storage (bytes flushed and file closed) especially with slower storages (sd cards) so what you get is an incomplete file (often times even empty).
You can delay video playing after onActivityResult while checking if the video file's size and last modified time (file.lastModified()) have increased to see if writing/flushing has actually finished and you can play it. If it's a long video (more than a few seconds) and depending on the enconding used you may start playing it before its fully written to storage but if the video player reaches the end before the recording app has finished writing the playing will end abruptly and you'll probably need to reload the video in the player.
It's a big problem of linux with the slow writing on (ex/V)FAT partitions which are used on portable storage for interoperability with other OSs (Windows) especially over USB. It's always a long wait to copy a few GB of data on a USB stick.

How to store video files in android without exposing raw files to the users?

I am developing a VR Application using Google VR SDK.Due to nature of app users very frequently play same video in a day.Using the code below i play videos from URL and this consumes so much bandwidth
I want to decrease bandwidth usage.I think i can store videos in phone memory so next time they play it can simply be played from memory but in this case users would easily access my files and steal it
So is there a way to do this (like some kind of cache) but without simply exposing users to my raw video files?
class VideoLoaderTask extends AsyncTask<Pair<Uri, Options>, Void, Boolean> {
#Override
protected Boolean doInBackground(Pair<Uri, Options>... fileInformation) {
try {
Options options = new Options();
options.inputFormat= Options.FORMAT_DEFAULT;
options.inputType = Options.TYPE_MONO;
Uri myUri = Uri.parse("video.mp4");
videoWidgetView.loadVideo(myUri, options);
} catch (IOException e) {
// An error here is normally due to being unable to locate the file.
loadVideoStatus = LOAD_VIDEO_STATUS_ERROR;
// Since this is a background thread, we need to switch to the main thread to show a toast.
videoWidgetView.post(new Runnable() {
#Override
public void run() {
Toast
.makeText(SimpleVrVideoActivity.this, "Error opening file. ", Toast.LENGTH_LONG)
.show();
}
});
Log.e(TAG, "Could not open video: " + e);
}
return true;
}
}
I found the solution in developer.android.com.I can simply just save files to the storage
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
//Context.MODE_PRIVATE makes them invisible to users
fos.write(string.getBytes());
fos.close();

How to make reverse video and editing in video file in android programmatically? [duplicate]

I have created functionality to record video in my app.
When I play a song, that song is recorded with video and a video file is created, similar to a dubshmash application.
Now the problem that I am facing is that other voices such as near by sounds also get recorded. The song file is recorded in the video record screen and I play the song when video recording activity launches.
How can I have my application record only song with video?
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
Is there any solution in audio source set as a speaker , because song sound going through a speaker? if is it another possible way please reply me.
You can record video without audio and merge audio later on using mp4 parser like this:
/*
* #param videoFile path to video file
* #param audioFile path to audiofile
*/
public String mux(String videoFile, String audioFile) {
Movie video = null;
try {
video = new MovieCreator().build(videoFile);
} catch (RuntimeException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
Movie audio = null;
try {
audio = new MovieCreator().build(audioFile);
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (NullPointerException e) {
e.printStackTrace();
return null;
}
int size = audio.getTracks().size();
Track audioTrack = audio.getTracks().get((size - 1));
video.addTrack(audioTrack);
Container out = new DefaultMp4Builder().build(video);
File myDirectory = new File(Environment.getExternalStorageDirectory(), "/Folder Name");
if (!myDirectory.exists()) {
myDirectory.mkdirs();
}
filePath = myDirectory + "/video" + System.currentTimeMillis() + ".mp4";
try {
RandomAccessFile ram = new RandomAccessFile(String.format(filePath), "rw");
FileChannel fc = ram.getChannel();
out.writeContainer(fc);
ram.close();
} catch (IOException e) {
e.printStackTrace();
return null;
}
return filePath;
}
In build.gradle add following dependency
compile 'com.googlecode.mp4parser:isoparser:1.0.5.4'
If you want to working with video then you have to use FFMPEG library
That can be you can work with Video.
That for i have already give answer to How to use ffmpeg in android studio? see this LINK. Go step by step and import in your project
You can use a MediaRecorder without calling setAudio* on it.
remove this line
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
see this link
There is currently no way to directly record android output without "background noise".
Note that this is a security concern to restrict access to other apps audio output, therefore it is very unlikely that it could be achieved directly.
See this answer

How to video record with specific sound programmatically in android?

I have created functionality to record video in my app.
When I play a song, that song is recorded with video and a video file is created, similar to a dubshmash application.
Now the problem that I am facing is that other voices such as near by sounds also get recorded. The song file is recorded in the video record screen and I play the song when video recording activity launches.
How can I have my application record only song with video?
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
Is there any solution in audio source set as a speaker , because song sound going through a speaker? if is it another possible way please reply me.
You can record video without audio and merge audio later on using mp4 parser like this:
/*
* #param videoFile path to video file
* #param audioFile path to audiofile
*/
public String mux(String videoFile, String audioFile) {
Movie video = null;
try {
video = new MovieCreator().build(videoFile);
} catch (RuntimeException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
Movie audio = null;
try {
audio = new MovieCreator().build(audioFile);
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (NullPointerException e) {
e.printStackTrace();
return null;
}
int size = audio.getTracks().size();
Track audioTrack = audio.getTracks().get((size - 1));
video.addTrack(audioTrack);
Container out = new DefaultMp4Builder().build(video);
File myDirectory = new File(Environment.getExternalStorageDirectory(), "/Folder Name");
if (!myDirectory.exists()) {
myDirectory.mkdirs();
}
filePath = myDirectory + "/video" + System.currentTimeMillis() + ".mp4";
try {
RandomAccessFile ram = new RandomAccessFile(String.format(filePath), "rw");
FileChannel fc = ram.getChannel();
out.writeContainer(fc);
ram.close();
} catch (IOException e) {
e.printStackTrace();
return null;
}
return filePath;
}
In build.gradle add following dependency
compile 'com.googlecode.mp4parser:isoparser:1.0.5.4'
If you want to working with video then you have to use FFMPEG library
That can be you can work with Video.
That for i have already give answer to How to use ffmpeg in android studio? see this LINK. Go step by step and import in your project
You can use a MediaRecorder without calling setAudio* on it.
remove this line
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
see this link
There is currently no way to directly record android output without "background noise".
Note that this is a security concern to restrict access to other apps audio output, therefore it is very unlikely that it could be achieved directly.
See this answer

Android: Play local video with mediaplayer

I am trying to play a video i have saved in my project. I have download this
(an .mp4 test video) then created a folder within my project called vid on the root of the project. I have then used this code:
public void PlayLocalVideo(View view)
{
VideoView video=(VideoView) findViewById(R.id.video1);
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(video);
video.setMediaController(mediaController);
video.setKeepScreenOn(true);
video.setVideoPath("android.resource://uk.co.SplashActivity/vid/big_buck_bunny.mp4");
video.start();
video.requestFocus();
}
my xml looks like this:
<VideoView
android:id="#+id/video1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
PlayLocalVideo is a method i have then used on the onclick event on a button. but when i press play nothing happens :(
Just paste the file into res/raw/big_buck_bunny.mp4 instead vid folder and change
your videoPath to:
video.setVideoPath("android.resource://" + getPackageName() + "/" + R.raw.big_buck_bunny);
The problem may be in Android OS defect, which doesn't let you access normally files more than 1Mb size Load files bigger than 1M from assets folder
You probably need to split your video file into 1Mb sized parts. Then merge this parts into one file on sdcard and play it.
For example, I've splited big_buck_bunny.mp4 into 5 parts big_buck_bunny.mp4.part0, big_buck_bunny.mp4.part1 and so on. To merge them you can use this method
private void copyVideoFromAssets(String inFilePrefix, String outFileName) throws IOException {
// Get list of files in assets and sort them
final String[] assetsFiles = getAssets().list("");
Arrays.sort(assetsFiles);
// Open the empty file as the output stream
final OutputStream output = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024 * 128];
for (String file: assetsFiles) {
if (file.startsWith(inFilePrefix)) {
// Open part of file stored in assets as the input stream
final InputStream input = getAssets().open(file);
// Transfer bytes from the input file to the output file
int length = input.read(buffer);
while (length > 0) {
output.write(buffer, 0, length);
length = input.read(buffer);
}
input.close();
}
}
// Close the streams
output.flush();
output.close();
}
public void PlayLocalVideo(View view)
try {
copyVideoFromAssets("big_buck_bunny.mp4.part", "/mnt/sdcard/big_buck_bunny.mp4");
} catch (IOException e) {
e.printStackTrace();
}
VideoView video=(VideoView) findViewById(R.id.video);
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(video);
video.setMediaController(mediaController);
video.setKeepScreenOn(true);
video.setVideoPath("/mnt/sdcard/big_buck_bunny.mp4");
video.start();
video.requestFocus();
}
Try this code....
1st make folder name raw in res directory, Copy your video in that folder and try out this code...
video1=(VideoView)findViewById(R.id.myvideoview);
video1.setVideoURI(Uri.parse("android.resource://" +getPackageName()+ "/"+R.raw.YOUR_VIDEO_FILE_NAME));
video1.setMediaController(new MediaController(this));
video1.requestFocus();
video1.start();

Categories

Resources