基于FFmpeg实现实时反向播放(ffmpeg+SDL2+vs2017)

FFmpeg实现实时反向播放(ffmpeg+sdl+vs2017)

在某些场合下需要实现视频的倒放效果,实现倒放有很多种思路。比如直接用libavfilter下提供的reverse命令行输出一个反转过来的视频;或者比较直接的想法是把所有frame缓存起来,然后再反向逐个输出到屏幕。
如果我们需要实时的在屏幕预览,那命令行的方法大概是不行了,而第二种方法需要在播放前预先加载所有需要播放的帧,这一方面增加了耗时,另一方面占用了大量的内存空间。所以基于第二种方法的倒放必须要进行优化。
本文使用的思路是基于av_seek_frame实现的方法,大致思路如图所示(原谅我对XML图形的滥用)。
在这里插入图片描述
1.在解码线程我们需要得到即将被输出的帧,使用cur变量初始化为视频的末尾的位置,用来记录当前seek执行的时间戳,使用av_seek_frame函数设置参数为backward,也就是寻找cur这一位置之前的最近的关键帧。
2.随后我们就可以单单解码从找到的关键帧到cur之间的frame,把他们输出到一个vector中,然后更新cur = vector[0] - 1也就是关键帧的上一个位置,接下来再次对cur执行seek得到的就会是上一个关键帧了。
3.得到的vector输出到一个队列中,由sdl的线程获取,最后从vector的end到begin反向输出到屏幕,这样就可以实现倒放预览了。

分析这一过程不难发现,只有储存在队列中即将的frame占用了内存空间,而且使用双线程配合队列,这样在解码下个I帧及其后继B帧P帧时不会出现需要等待而卡顿的情况。
在这里插入图片描述

最后贴一下代码,这里的代码是直接从雷霄骅先生的代码进行更改完成的,如果增加一个packet队列进一步提高并发性应该能进一步优化性能。

#include <stdio.h>
#include <string>
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <thread>
#include <mutex>
#define __STDC_CONSTANT_MACROS

extern "C"
{
   
   
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "SDL2/SDL.h"
};

//Output YUV420P data as a file 
#define OUTPUT_YUV420P 0
using namespace std;

queue<vector<AVFrame*>> Q;
mutex mutex_;
condition_variable cvfull;
condition_variable cvempt;

//SDL---------------------------
int screen_w = 0, screen_h = 0;
SDL_Window *screen;
SDL_Renderer* sdlRenderer;
SDL_Texture* sdlTexture;
SDL_Rect sdlRect;

void Show() {
   
   
	while (1) {
   
   
		vector<AVFrame*> V;
		{
   
   
			unique_lock<mutex> lk(mutex_);
			cvfull.wait(lk, [&]() {
   
    return Q.size() > 0; });
			cout <<"队列大小:"<< Q.size()<<endl;
			V = Q.front();
			Q.pop();
			cvempt.notify_one();
		}

		if (V.size() == 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值