Android: Record and play video in the same SurfaceView - android

I want to see the video that I'm currently recording in a SurfaceView and if the recodring finished I wanto to replay the video in the same SurfaceView.
Even though I thought it would be a common feature in Apps, I couldn't find any example and couldn't make my code work.
private void prepareRecorder() {
try {
recorder = new MediaRecorder();
recorder.setPreviewDisplay(holder.getSurface());
camera.unlock();
recorder.setCamera(camera);
recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
camcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW);
recorder.setProfile(camcorderProfile);
File newFile = new File(videoFilePath);
recorder.setOutputFile(newFile.getAbsolutePath());
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}catch(Exception e){
releaseCamera();
}
}
//
public void onClick(View v) {
if(mediaPlayer!=null) {
mediaPlayer.reset();
mediaPlayer.release();
}
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(videoFile.getAbsolutePath());
SurfaceView surfaceView = (SurfaceView) getView().findViewById(R.id.videoInvitationFragSurfaceView);
mediaPlayer.setSurface(surfaceView.getHolder().getSurface());
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
If I just record the video my code works, if just play the video it works as well. Any ideas?
Thanks in advance
Edit: As a current workaround I use two SurfaceViews and "hide" them (set size to 0) if needed

If I just record the video my code works, if just play the video it works as well. Any ideas?
As much I understand, you can reuse same surface view only after it is destroyed and regenerated, i.e you can reuse same SurfaceView only after surfaceDestroyed() is called and then surfaceCreated() is called only after this destroy and create cycle you can reuse SurfaceView.
To achive this all you have to do is: after video recording is done set SurfaceView visibility to GONE which will ensure surfaceDestroyed() call back and again set SurfaceView visibility to VISIBLE which will call surfaceCreated() after that start video playback.
This is very cumbersome process so I used same SurfaceView for recording and playback in following way:
when Activity is created check if VideoFile is available in Intent
if yes use SurfaceView for playback
now if user deletes video restart activity
As VideoFile is not found in intent use SurfaceView for recording
Once recording is done and user want to playback video restart
Activity with VideoFile information attached in Intent

Related

How to use the same recorder object repeatedly

I am creating a MediaRecorder and using it to generate a video clip. It works perfectly the first time. I end the video shooting process by setting the maximum file size to 5MB, after which it enters the onInfo method and the completely that particular video snap.
Now I want to generate 5 such clips, one after the other. For which I add the following to the onInfo method:
#Override
public void onInfo(MediaRecorder mr, int what, int extra) {
// TODO Auto-generated method stub
//System.out.println("Reached onInfoListener");
if(what==android.media.MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED)
{
Toast.makeText(getApplicationContext(), "Video clip "+video_count+" recorded", Toast.LENGTH_SHORT).show();
recorder.stop(); //recorder is an object of type MediaRecorder
recorder.reset();
initRecorder(); //Reinitializing for subsequent video generation
prepareRecorder(); //Re preparing for subsequent video generation
}
}
private void initRecorder() {
recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),"/FOLDERNAME");
if(!dir.exists())
{
dir.mkdir();
}
CamcorderProfile cpHigh = CamcorderProfile
.get(CamcorderProfile.QUALITY_HIGH);
recorder.setProfile(cpHigh);
recorder.setOutputFile("/sdcard/FOLDERNAME/video"+video_count+".mp4");
recorder.setMaxDuration(50000); // 50 seconds
recorder.setMaxFileSize(5*1048576); // Approximately 5 megabytes
}
private void prepareRecorder() {
recorder.setPreviewDisplay(cameraView.getHolder().getSurface());
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
finish();
} catch (IOException e) {
e.printStackTrace();
finish();
}
}
NOTE: videocount is a variable used to give a distinct name to each generated video clip.
However after successfully capturing the first video clip, and just before the second clip an start recording, a IllegalStateException is encountered when I try to start the recorder object again. Since I am using recorder.reset() API, I thought that I would be able to reuse the recorder object for subsequent iterations. But it is giving this problem.
How to solve this issue? Is it neccessary to provide some delay after reinitializing the recorder object?
EDIT: If I keep the recorder.start() inside a button click, this works, that is, on every button click, a separate video is taken. But if I ask it to take say, 5 videos, on a single button click, the app crashes before it starts taking the second video, that is, it works only once. How to overcome this non-uniformity?
Going by the official documentation you need to call the setOutputFormat() method before you can call prepare(), like this:
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

android -how to program button next for playing new media

I already initialise a media by setDataSource and doing function prépare() start(). I want starting new média by click on button next, but what doing? Stop already media and do setDataSource and prépare()
Start() for next media?
Just reset mediaplayer before playing next song,then set new datasource and start it
public void startPlaying(String audioURL)
{
mediaPlayer.reset();
try
{
if(audioURL != null)
{
mediaPlayer.setDataSource(audioURL);
}
mediaPlayer.prepare();
mediaPlayer.start();
}
catch (IOException e)
{
e.printStackTrace();
}
}
You can set a callback when the playback of your MediaPlayer has finished. There you can set a new Datasource.

MediaPlayer setDisplay when returning to an activity not working

I want to play video with MediaPlayer in the background so when the user leave my app he will still hear the audio and when he is returning to the app he will see the video. I managed to do the first part with Service that plays the MediaPlayer, but I have a problem in the second part. When I leave the app and return the video does not show in the SurfaceView.
When the user return I created new Surface, so I tried this:
public void surfaceCreated(SurfaceHolder holder) {
if(mService!=null && mService.player.isPlaying()){
try {
mService.player.setDisplay(holder);
mService.player.prepare();
mService.player.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
While mService is my Service and he holds the MediaPlayer player.
In my research I saw this post:
Black screen when returning to video playback activity in Android
But this was posted a year ago so maybe anyone has any different and new answer.
EDIT:
I forgot to say that the video is streaming, so reset is not good option (i tried :)).
is it possible to save the SurfaceView in the Service and when the user return to take the view and add it dynamically to the current layout?
When you first launch Activity: onResume()->onSurfaceCreated()->onSurfaceChanged().
When you leave Activity: onPause()->onSurfaceDestroyed()
So i you leave your app, surface will be automatically destroy, you also can not save surfaceview in service.
Remember, if you want to show video again, surfaceview and holder callback must created again in onStart in case your home or lockscreen pressed
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
holder = surfaceView.getHolder();
holder.setFixedSize(800, 480);
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

how to clear surface holder when media player is finished?

I made a video player with surfaceview and mediaplayer.
i have 10 videos and 10 buttons.
if click on each buttons, each videos are playing.
here is my code..
//onCreate
holder = surfaceview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//Button1
if(mp == null)mp = new MediaPlayer();
mp.setDataSource(mediaplay_path);
mp.setDisplay(holder);
mp.setScreenOnWhilePlaying(true);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.prepare();
mp.start();
//Button2
if(mp != null){
mp.stop();
mp.reset();
}
mp.setDataSource(mediaplay_path2);
mp.setDisplay(holder);
mp.setScreenOnWhilePlaying(true);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.prepare();
mp.start();
//Button3~Button10 is same as Button2..
everything is fine.
my custom videoview is working alright.
but when the video turns to the next, the last scene of the previous video is remain for a while and turns to the next video scene.
i think it's because the previous surfaceview should be clear before next video is playing.
but i have no idea how to clear the surfaceview or surface holder.
i've searched for this but only could find how to play the video, not how to clear the surfaceview which is set the disaply from mediaplayer.
please help me~~!
Took me two weeks to figure this out. By setting the surfaceholder to TRANSPARENT, Android will destroy the surface. Then setting it back to OPAQUE creates a new surface "clearing" the surface. Note surfacecreate and surfacedestroy events will fire, so if you have code there, beware. I put a imageview set to black to give it a black background. There maybe better ways for that.
private void playVideoA() {
imageViewBlack.bringToFront();
surfaceHolder.setFormat(PixelFormat.TRANSPARENT);
surfaceHolder.setFormat(PixelFormat.OPAQUE);
surfaceView.bringToFront();
mediaPlayerA.setDisplay(surfaceHolder);
//surfaceView.setAlpha((float) 0.01);
mediaPlayerA.start();
};
private void prepareVideoA(String url) {
try {
mediaPlayerA = new MediaPlayer();
mediaPlayerA.setDataSource(url);
mediaPlayerA.prepareAsync();
mediaPlayerA.setOnPreparedListener(this);
mediaPlayerA.setOnCompletionListener(this);
mediaPlayerA.setOnBufferingUpdateListener(this);
mediaPlayerA.setOnInfoListener(this);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
#Override
public void onPrepared(MediaPlayer mp) {
playVideoA()
}
video.getHolder().setFormat(PixelFormat.TRANSPARENT);
video.getHolder().setFormat(PixelFormat.OPAQUE);
video.setVideoURI(Uri.parse(temp));
video.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
it work for me
The SurfaceHolder has lockCanvas methods that will allow you to draw directly to the Surface. Use the drawColor method of the Canvas to fill it with black.
That said, it may be preferable to remove the SurfaceView (as suggested by smile2you), because that should destroy the Surface altogether and free up unused resources. And definitely make sure you are calling release on the MediaPlayers after they are done with playback. Holding on to too many video resources will crash your app.
may be you can use removeView to remove the old custome videoview ,then add the new view
surfaceview.setVisibility(View.GONE);

How to play audio only from video file on Android?

I have mp4 and wmv movie files and need to play only sound not video screen. How to do it?? Could I get sound track from movie file??
I know if I hide the SurfaceView from screen, I can only hear sound.. but I have tried a lot but.. it is impossible.
If you have any solution to extract sound track from movie file, please let me know..
Thanks in advance.
If you are using the mediaplayer API in your app then don't call the API public void setDisplay (SurfaceHolder sh). This will ensure that only the audio is played out even if the video content is present..
More info in android doc here
Use following code, Optimize following code as per your requirement. It play video from youtube.
try {
final MediaPlayer m = new MediaPlayer();
Thread t = new Thread(new Runnable() {
public void run() {
try {
m.setDataSource("rtsp://v8.cache3.c.youtube.com/CjgLENy73wIaLwlQP1m32SiSYxMYJCAkFEIJbXYtZ29vZ2xlSARSB3JlbGF0ZWRggqG7w9aS2-1MDA==/0/0/0/video.3gp");
m.prepare();
m.start();
} catch (Exception e) {
e.printStackTrace();
}
}
});
t.start();
} catch (Exception e) {
e.printStackTrace();
}

Categories

Resources