I'm trying to copy a part of a video, and save it as a GIF into the disk. The video can be local or remote, and the copy should be 2s max. I don't need to save every single frame, but every other frame (12-15 fps). I have the "frames to gif" part working, but the "get the frames" part is not great.
Here is what I tried so far:
- MediaMetadataRetriever: too slow (~1s per frame on a Nexus4), and only works with local files
- FFmpegMediaMetadataRetriever: same latency, but works with remote video
- TextureView.getBitmap(): I'm using a ScheduledExecutorService and every 60ms, grab the Bitmap (while playing...) It works well with small size getBitmap(100, 100), but for bigger ones (> 400), the whole process becomes really slow. And as the doc says Do not invoke this method from a drawing method anyway.
It seems that the best solution would be to access every frame while decoding, and save them. I tried OpenCV for Android but couldn't find an API to grab a frame at a specific time.
Now, I'm looking into those samples to understand how to use MediaCodec, but while running ExtractMpegFramesTest.java, I can't seem to extract any frame ("no output from decoder available").
Am I on the right track? Any other suggestion?
edit: went further with ExtractMpegFramesTest.java, thanks for this post.
edit 2: just to clarify, what I'm trying to achieve here is to play a video, and press a button to start capturing the frames.
Related
What I try to do
I made a video player app by using the source code from the following link.
https://github.com/kylelo/VideoPlayerGH
I want to implement some methods to calculate the complexity for each frame, then I can do some image processing after the calculation.
So the first step I need to do is to get the bitmap or pixel values from the video frame to analyze before it render on the screen, I have used glReadPixels() to get the pixel values into a new ByteBuffer in the draw() function. I can get the RGBA values successfully, but the frame rate droped from 60 fps to 20 fps on my device(HTC buffterfly s), I even have not did any image processing on it...
My question is
Is there any other more efficient way to realize this task? Even working on other layers of Android system is fine.
I really need some hints on it...
Because I am new in Android, so if there is any concept I am wrong, please tell me! I am really appreciate for everyone's help!
My Android app does live video processing using OpenGL. I'm trying to save it to video using MediaMuxer and MediaCodex.
The performance it not good enough. Each cycle the screen is updated, and it is saved to file. The screen is smooth, the video file is horrible. By this I mean major motion blur when it changes quickly and the frame-rate appears to be 1/2 or 1/3rd of what it should be.
It seems to be a limitation due to clamping of settings internally. I can't get it to spit out a video with a bit rate greater than 288KBPS. I think it is not clamping the requested parameters because there is no difference in frame rate for 1024x1024, 480x480, and 240x240. If it was having trouble keeping up, it should at least improve when the number of pixels drops by a factor > 10.
The app is here : https://play.google.com/store/apps/details?id=com.matthewjmouellette.snapdat.
I would love to post a code sample, but my program is 10K lines of code, with a lot of relevant code just for this problem.
Any help would be greatly appreciated.
EDIT:
I've tried like 10+ different things. I'm out of ideas right now. I wish I could just save the video uncompressed, the hard-drive should be able to keep up with a small enough image and medium fps.
It seems to be that the encoding method just doesn't work for my video. The frames differ to much, to try to "move" one part of the frame, as a sort of encoding. Instead I need full frames throughout. I am thinking something along the lines of M-JPEG would work really well. JPEGs tend to take 1/10th the size of a bitmap. It should allow a reasonable size, with almost no processing power required by the CPU, since it is image compression not video compression which we are doing. I wish I had a good library for this.
My app should show a bunch of animated images (within a list or grid, ~10-20 images on a screen depending on the screen size). Each of these images can contain a lot of frames (up to 150). Actually these images are gifs initially. I get them as encoded mp4 files (to reduce the data size transferred through the network) and decode them on a device. For decoding I use android.media.MediaMetadataRetriever (it doesn't work well on Samsung devices) and I do it the following way: when I show the current frame I put a new decoding task - actually a task to get the next frame - to a priority queue. Priority depends on the time to which I need to get the next frame. If task "expires" (isn't processed by workers before expected time) I just put to a queue next task and etc. But my algorithm doesn't work well - animations are very slow and buggy (I don't also exclude that my implementation can have some bugs)..
So, here are the questions:
1) Are there any other possibly better ways to decode mp4?
2) Could someone please give me and advice which algorithm I should use to effectively decode mp4 files, so there weren't any animation lags?
3) I can't use simple AnimationDrawable because of out of memory errors, so how can I effectively manage frames cache?
Thanks!
I am trying to get specific frames at specific times as images from a movie using MediaExtractor and MediaCodec. I can do it successfully if:
I use extractor.seekTo(time, MediaExtractor.SEEK_TO_PREVIOUS_SYNC); , however, this only gives the nearest sync frame not the target frame.
I sequentially extract all frames using extractor.advance(); , but I need to get the target frame not all.
So, I try the following:
extractor.seekTo(time, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
while(extractor.getSampleTime()<time /*target time*/) extractor.advance();
This provides the correct frame, but for some reason the image is corrupted. It looks like the correct image (the one I get from the successful cases), but with some pixelation and a strange haze.
The while-loop is the only thing that is different between the successful cases and the corrupted ones. What to do to advance MediaExtractor to a specific time (not just sync time) without getting a corrupted image?
Thanks to fadden comment, I have to keep feeding the encoder since the I-frame has the full picture and the P and B frames have differences (this is how compression is achieved). So I need to start with an I-frame (it was same as sync frame) and keep feeding the other frames to the decoder to receive the full image.
The main question is if it is possible to somehow go around the frame index checking that ffmpeg does when writing the frame to a file.
Now I will explain my exact problem so you can understand better what I need or maybe think of an alternative solution.
Problem n0.1: I am getting video stream from two independent cameras and for some reason I want to save it in the same video file. First the frames from the first camera and then the frames from the second. When writing the frames from the second camera av_write_frame would return the error code -22 and will fail to add the frame. That's because the writing context is expecting a frame index following the index of the previously written frame (the last frame from camera 1) but he receives a frame with the index 0, the first frame from the second camera.
Problem no.2: Consider the following problem independently to the first one.
I am trying to save a video stream to a file but the frame rate is double the real speed. So because I couldn't find any working solution to speed down the frame rate i thought to write every frame twice in the video file. But it won't make any difference to the frame rate.
I also tried a different approach on the frame rate problem but it also failed(question here).
Any kind of working solution would be highly appreciated.
Also it's important that I can't use console commands, I need C code, as I need to integrate those functionalities in an Android application that is automated.