问题
I am implementing a video player using ffmpeg multimedia framework. I am able to achieve play, pause, increase speed, decrease speed, forward seek, backward seek functionalities. But reverse playback of the video is not so smooth, it stutters a lot. Please help me in understanding video reverse playback. What is the better approach for this?
Is there any other multimedia framework which support reverse video playback?
Many thanks in advance.
回答1:
So, first, some framing of this issue. FFmpeg is an extremely low-level library which tries to give a thin API on top of raw media file access. This means that you basically get quite literally what's in the media file. For video, that's the stream of compressed video packets from the demuxer, and then a stream of decoded pictures from the decoder. Because of B/P-frame prediction, this is a strictly linear and unidirectional process. Note also that FFmpeg in most practical cases uses multi-threading, which is again a strictly linear process. If you have 4 thread decoding frame 8, 9, 10, 11, and you seek to frame 7 after that (thus decoding frame 7, 8, 9 and 10), you're essentially generating eternal waste.
So: reverse playback using inverse-ordered av_seek_frame()
is inherently incompatible with FFmpeg basic design. That doesn't mean that you can't do it using FFmpeg at all, but it does mean that if you do use FFmpeg to do it, it takes some effort. Having said that, how would you accomplish reverse playback? You cache!
You can create groups of N frames (where N is at least as large as the number of threads, but still allows you to hold so many frames in memory), e.g. N=10 or N=100 (depending on frame size). Then, forward-decode N frames using sequential calls to av_read_frame()
and avcodec_decode_videoN()
, and hold them in memory in your application. For example, you might now have frame 7-17 in memory. Start displaying frame 17, and next display 16, 15, and so on (from memory), until you hit index=7. When you hit 7, seek to the next position allowing you to hold N frames in memory (in the case of N=10, that would be index=0), and hold frame 0-6 in memory, and display index=6, 5 and so on until 0.
I've actually implemented this exact feature and it works quite well using this approach, and it does still use multi-threading (almost) correctly. It does take quite a bit of memory for large N values on high-resolution video, so you're encouraged to make N dependent on frame size and make N * resolution either settable in the preferences of your application, or at least make it depend on the total amount of memory available on the computer the software runs on.
Note that seeking isn't the easiest thing, because you can't randomly seek to any point within any video and expect it to work. For most codecs implementing P-frames or B-frames, you can only seek to keyframes or I/IDR-frames. This means that the file format needs to set the keyframe flag in its index. If that's not the case, you'll have to synthetically generate an index while initially loading the file (e.g. call av_read_frame()
until you hit EOF).
Regarding your other question: I'm sure there's other media frameworks implementing trick play (reverse playback etc.), e.g. GStreamer does. However, this typically works only for a limited number of file formats, not for all supported file formats in the media framework.
来源:https://stackoverflow.com/questions/34804311/reverse-video-playback-through-ffmpeg