How to take frame from playing video in TextureView in concrete time? - android

// Play video when the media source is ready for playback.
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mMediaPlayer.start();
// mMediaPlayer.getDuration();
MediaMetadataRetriever mMMR = new MediaMetadataRetriever();
mMMR.setDataSource(FILE_NAME, new HashMap<String, String>());
String time = mMMR.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
Bitmap bitmap;
int fps = 24;
int deltaT= (int)1/fps;
for (int time_ms=1;time_ms<Integer.valueOf(time)*1000;time_ms+=24){
bitmap = mMMR.getFrameAtTime(5000);
if (bitmap==null) break;
}
}
});
I tried to connect MediaMetadataRetriever but then the video is not played.
It is interesting how to implement it in an asynchronous way: video is playing and on the background we taking a picture for instance on 5 seconds of video?

TextureView has SurfaceTexture. You can use this function in the 5s loop:
Bitmap bitmap = SurfaceTexture.getBitmap([with,height])

Related

How to manage videos on Android via Unity? [duplicate]

MovieTexture is finally deprecated after Unity 5.6.0b1 release and new API that plays video on both Desktop and Mobile devices is now released.
VideoPlayer and VideoClip can be used to play video and retrieve texture for each frame if needed.
I've managed to get the video working but coduldn't get the audio to play as-well from the Editor on Windows 10. Anyone know why audio is not playing?
//Raw Image to Show Video Images [Assign from the Editor]
public RawImage image;
//Video To Play [Assign from the Editor]
public VideoClip videoToPlay;
private VideoPlayer videoPlayer;
private VideoSource videoSource;
//Audio
private AudioSource audioSource;
// Use this for initialization
void Start()
{
Application.runInBackground = true;
StartCoroutine(playVideo());
}
IEnumerator playVideo()
{
//Add VideoPlayer to the GameObject
videoPlayer = gameObject.AddComponent<VideoPlayer>();
//Add AudioSource
audioSource = gameObject.AddComponent<AudioSource>();
//Disable Play on Awake for both Video and Audio
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
//We want to play from video clip not from url
videoPlayer.source = VideoSource.VideoClip;
//Set video To Play then prepare Audio to prevent Buffering
videoPlayer.clip = videoToPlay;
videoPlayer.Prepare();
//Wait until video is prepared
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
yield return null;
}
Debug.Log("Done Preparing Video");
//Set Audio Output to AudioSource
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
//Assign the Audio from Video to AudioSource to be played
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
//Assign the Texture from Video to RawImage to be displayed
image.texture = videoPlayer.texture;
//Play Video
videoPlayer.Play();
//Play Sound
audioSource.Play();
Debug.Log("Playing Video");
while (videoPlayer.isPlaying)
{
Debug.LogWarning("Video Time: " + Mathf.FloorToInt((float)videoPlayer.time));
yield return null;
}
Debug.Log("Done Playing Video");
}
Found the problem. Below is the FIXED code that plays Video and Audio:
//Raw Image to Show Video Images [Assign from the Editor]
public RawImage image;
//Video To Play [Assign from the Editor]
public VideoClip videoToPlay;
private VideoPlayer videoPlayer;
private VideoSource videoSource;
//Audio
private AudioSource audioSource;
// Use this for initialization
void Start()
{
Application.runInBackground = true;
StartCoroutine(playVideo());
}
IEnumerator playVideo()
{
//Add VideoPlayer to the GameObject
videoPlayer = gameObject.AddComponent<VideoPlayer>();
//Add AudioSource
audioSource = gameObject.AddComponent<AudioSource>();
//Disable Play on Awake for both Video and Audio
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
//We want to play from video clip not from url
videoPlayer.source = VideoSource.VideoClip;
//Set Audio Output to AudioSource
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
//Assign the Audio from Video to AudioSource to be played
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
//Set video To Play then prepare Audio to prevent Buffering
videoPlayer.clip = videoToPlay;
videoPlayer.Prepare();
//Wait until video is prepared
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
yield return null;
}
Debug.Log("Done Preparing Video");
//Assign the Texture from Video to RawImage to be displayed
image.texture = videoPlayer.texture;
//Play Video
videoPlayer.Play();
//Play Sound
audioSource.Play();
Debug.Log("Playing Video");
while (videoPlayer.isPlaying)
{
Debug.LogWarning("Video Time: " + Mathf.FloorToInt((float)videoPlayer.time));
yield return null;
}
Debug.Log("Done Playing Video");
}
Why Audio was not playing:
//Set Audio Output to AudioSource
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
//Assign the Audio from Video to AudioSource to be played
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
must be called before videoPlayer.Prepare(); not after it. This is took hours of experiment to find this this was the problem I was having.
Stuck at "Preparing Video"?
Wait 5 seconds after videoPlayer.Prepare(); is called then exit the while loop.
Replace:
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
yield return null;
}
with:
//Wait until video is prepared
WaitForSeconds waitTime = new WaitForSeconds(5);
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
//Prepare/Wait for 5 sceonds only
yield return waitTime;
//Break out of the while loop after 5 seconds wait
break;
}
This should work but you may experience buffering when the video starts playing. While using this temporary fix, my suggestion is to file for bug with the title of "videoPlayer.isPrepared always true" because this is a bug.
Some people also fixed it by changing:
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
to
videoPlayer.playOnAwake = true;
audioSource.playOnAwake = true;
Play Video From URL:
Replace:
//We want to play from video clip not from url
videoPlayer.source = VideoSource.VideoClip;
with:
//We want to play from url
videoPlayer.source = VideoSource.Url;
videoPlayer.url = "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4";
then Remove:
public VideoClip videoToPlay; and videoPlayer.clip = videoToPlay; as these are not needed anymore.
Play Video From StreamingAssets folder:
string url = "file://" + Application.streamingAssetsPath + "/" + "VideoName.mp4";
if !UNITY_EDITOR && UNITY_ANDROID
url = Application.streamingAssetsPath + "/" + "VideoName.mp4";
#endif
//We want to play from url
videoPlayer.source = VideoSource.Url;
videoPlayer.url = url;
All supported video formats:
ogv
vp8
webm
mov
dv
mp4
m4v
mpg
mpeg
Extra supported video formats on Windows:
avi
asf
wmf
Some of these formats don't work on some platforms. See this post for more information on supported video formats.
Similar to what the other answers have been saying. You could use callbacks for when preparing and end of video states. Rather than using coroutines and yield return.
videoPlayer.loopPointReached += EndReached;
videoPlayer.prepareCompleted += PrepareCompleted;
void PrepareCompleted(VideoPlayer vp) {
vp.Play();
}
void EndReached(VideoPlayer vp) {
// do something
}
I used #Programmer 's answer to play videos from a URL, but I couldn't get any sound to play. Eventually I found the answer in the comments of a YouTube tutorial.
To get the audio to play for a movie loaded via URL, you need to add the following line before the call to EnableAudioTrack:
videoPlayer.controlledAudioTrackCount = 1;
By now the VideoPlayer should be updated enough you don't need to write code to get to work correctly. Here are the settings I found to have the most desirable effect:
These settings are:
Video Player:
Play On Awake: True
Wait For First Frame: False
Audio Output Mode: None
Audio Source:
Play On Awake: True
Don't forget to have a VideoClip for the VideoPlayer and an AudioClip for the AudioSource. The file formats I found to work the best are .ogv for video and .wav for audio.

Downloading rtsp stream to play locally

I manage to play a live stream from a url such as this
rtsp://192.168.0.18:554/user=admin&password=&channel=1&stream=0.sdp?
But I want to download this stream into a temporary file and then play it locally so that I can make it seems like the buffering time is short (around 2-4 seconds delay maybe)
Is it possible to do this with rtsp? or do I have to use http?Because this url only works on rtsp protocol
If so,a bit of example would help me alot
Example of my codes
cA.mPlayer1 = new MediaPlayer();
try {
cA.mPlayer1.setDataSource("rtsp://192.168.0.18:554/user=admin&password=&channel=1&stream=0.sdp?");
cA.mPlayer1.prepareAsync();
cA.mPlayer1.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
cA.mPlayer1.start();
Toast.makeText(getBaseContext(), "Connecting...", Toast.LENGTH_LONG).show();
}
});
} catch (IOException e) {
e.printStackTrace();
}
cA.mCallback1 = new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
cA.mPlayer1.setDisplay(surfaceHolder);
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
};
final SurfaceView surfaceView1 =
(SurfaceView) findViewById(R.id.surfaceView1);
// Configure the Surface View.
surfaceView1.setKeepScreenOn(true);
// Configure the Surface Holder and register the callback.
SurfaceHolder holder1 = surfaceView1.getHolder();
holder1.addCallback(cA.mCallback1);
holder1.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
you can not use MediaPlayer to save a Raw stream in file . you can use one of these :
use 'vlc' to save the stream like this:
https://wiki.videolan.org/Documentation:Streaming_HowTo/Receive_and_Save_a_Stream/
or use 'VLC lib' for android that can downloaded from :
https://github.com/mrmaffen/vlc-android-sdk
use FFMPEG library to record RTSP recording locally in sd card :
1- Capture or decode the RAW frames from live stream and pass them to ffmpeg and save them to sdcard in .h264 format.
2- Then again pick .h264 raw file and decode the file using ffmpeg, and save the file with extention .mp4 into sd card.
3- delete the .h264 file programmatically, and save only .mp4, or which format you want.
Try .mp4 playback.
https://stackoverflow.com/a/24586256/6502368

Android play video in TextureView from raw or assets

I'm having an annoying problem with playing a video in TextureView from raw or assets folder... or even from the external storage. The code in the fragment looks something like this
public class MainFragment extends Fragment implements TextureView.SurfaceTextureListener, MediaPlayer.OnBufferingUpdateListener,
MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnVideoSizeChangedListener {
private ParallaxAdapter mAdapter;
private MediaPlayer mMediaPlayer;
private MediaPlayer mMediaPlayer2;
private TextureView tv;
private TextureView tv2;
private ImageView imageview;
private TextureView mTexture;
String path;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
super.onCreateView(inflater, container, savedInstance);
View v = inflater.inflate(R.layout.view_fragment, container, false);
path = getArguments().getString("path");
Log.d("Fragment","" + path);
String tag = getArguments().getString("Tag");
imageview = (ImageView) v.findViewById(R.id.imageView);
if (tag == "image") {
imageview.setImageResource(getArguments().getInt("image"));
} else if (tag == "video") {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmapThumb = ThumbnailUtils.createVideoThumbnail(path, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND);
imageview.setImageBitmap(bitmapThumb);
tv = (TextureView) v.findViewById(R.id.textureView);
tv.setSurfaceTextureListener(this);
}
return v;
}
public void setAdapter(ParallaxAdapter Adapter) {
mAdapter = Adapter;
}
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Surface s = new Surface(surface);
try {
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(path);
mp.setSurface(s);
mp.prepare();
mp.setOnBufferingUpdateListener(this);
mp.setOnCompletionListener(this);
mp.setOnPreparedListener(this);
mp.setOnVideoSizeChangedListener(this);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setVolume(0, 0);
mMediaPlayer.setLooping(true);
mMediaPlayer.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
It looks like the MediaPlayer cannot find the file from raw:
defpath = "android.resource://" + getPackageName() + "/" + R.raw.video;
or from assets:
AssetFileDescriptor afd = getAssets().openFd(FILE_NAME);
mp.setDataSource(afd.getFileDescriptor());
and i've tried to copy the assets to the sdcard with some codes from this discussion: android-how-to-copy-files-from-assets-folder-to-sdcard
but if I copy it, the file is somehow corrupt. I cannot even play it with the normal VideoPlayer in my device.
It is not a codec error! If I put the video into my device like on a USB and set the path and it's working with all 3 test videos. The manifest has read and write permission. And the VideoView makes even more problems with the ViewPager and paths.
Hopefully I'm just making some kind of stupid mistake... Thank you!
Only because you can play the video with the default video player of your device doesn't mean it's not a codec problem or another detail it doesn't like about it.
What I' missing here is a MediaPlayer.OnErrorListener
If you get something like
/MediaPlayer﹕ error (1, -2147483648), which indicates a MEDIA_ERROR_UNKNOWN with the extra info MEDIA_ERROR_SYSTEM (-2147483648) - low-level system error it's probably a video issue.
You could take a look at the video metadata with ffmpeg:
ffmpeg -i video.mp4
Check for:
Codec
Metadata (e.g. video is rotated)
Video width/height too big
Didn't get a reasonable error message for any of these.
Here's the official info: Supported Media Formats which doesn't help much IMHO

get frame of remote video in short time and set it as background of imageview

I want to display a frame from a remote video in an imageview
for that I am using this code :
Uri vidFile = Uri.parse(url);
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
if (Build.VERSION.SDK_INT >= 14)
retriever.setDataSource(url,
new HashMap<String, String>());
else
retriever.setDataSource(url);
} catch (RuntimeException e) {
e.printStackTrace();
}
;
Bitmap b1 = retriever.getFrameAtTime();
but this code is very slow
I have to wait many secondes to show the frame of this video
can you give an alternatif of this knowing that I have to use it to get a frame of a lot of videos and put them in a list

MediaMetadataRetriever getFrameAtTime to retrieve video frame

private void sample(){
int FRAME_BYTES=326;
int FRAMESMAX=36;
String subFolder="media";
String mediafileName="sample.mp4";
MediaMetadataRetriever mediaMetadata=new MediaMetadataRetriever();
try{
AssetFileDescriptor afd=getApplicationContext().getAssets().openFd(subFolder+File.separator+mediaFileName);
;
mediaMetadata.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
Bitmap frame=null;
for(int currentFrame=0;currentFrame<FRAMESMAX; currentFrame++){
if(currentFrame<=0){
frame = mediaMetadata.getFrameAtTime();
}else{
frame = mediaMetadata.getFrameAtTime(FRAME_BYTES*currentFrame*1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC );
//currentFrame++;
}
// do some thing with frame
}
}catch(Exception e){
Log.i(TAG, " unable to get file descriptor of the frame"+e.toString());
}
}
}
I am able to read frames from mp4 media files, on emulator and other devices but Samsung galaxy S III throws and error saying that
MediaMetadataRetriever getFrameAttime failed to retrieve video frames .
Any input on this?
For to get data source, you can use:
mediaMetadata.setDataSource(Environment.getExternalStorageDirectory().getPath()+"your_folder/your_file");

Categories

Resources