1

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.

Community
  • 1
  • 1
mbmc
  • 5,024
  • 5
  • 25
  • 53
  • Some additional examples are available in Grafika (https://github.com/google/grafika). What version of Android are you targeting? You can do more (and with less weirdness) on >= 4.3. – fadden Jul 10 '14 at 15:40
  • I did play around with the different activities, all great stuff! Ideally, I'm targeting 4.0, but looks like I'm gonna stick with 4.3. Also, I found a potential solution, but not sure if it's ok: using the ExtractMpegFramesTest.java, I do extract each frame, convert to a bitmap, and send them to an ImageView. That way, I can "play" the video, and can capture frames anytime. – mbmc Jul 10 '14 at 18:06
  • About my last comment, it seems to work but the whole conversion process is a bit slow, so it doesn't play at 30fps... Back to square 1. – mbmc Jul 10 '14 at 20:33
  • There's no great way to do this. What you really want is to decode to a SurfaceTexture, then render the texture with GLES (to show it) and then for the GIF-convert frames access the Surface data with the ImageReader class. Unfortunately, as of 4.4 ImageReader only works with Camera output. So you're stuck with decode + render + glReadPixels(), which can be slow on some platforms... though as noted on bigflake, with recent devices like the Nexus 5, nearly all of the time in the extract sample was spent in the PNG compression and file I/O. Only way to reduce that is to encode small images. – fadden Jul 10 '14 at 23:13
  • Also, I tried to play the video using a TextureView (or a SurfaceView or even a VideoView), and when starting the capture, pause the video, and initiate the MediaCodec / MediaExtractor process with something like this: mediaExtractor.seekTo(mediaPlayer.getCurrentPosition). But there's no OPTION_CLOSEST (like the MediaMetadataRetriever), so the beginning of the capture is often off (because it's syncing to the nearest key frame)... Maybe there's a way to get a better seekTo accuracy? – mbmc Jul 11 '14 at 05:46
  • This [post](http://stackoverflow.com/questions/21103347/problems-with-mediaextractor/) suggested to sync to the previous i-frame then extract frames until we reach the expected time, but I still can't get the exact frame... Any suggestion? – mbmc Jul 14 '14 at 21:59

0 Answers0