基于 FFMPEG + SDL2 的视频播放器
本文是在雷神的 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0) 的基础上修改的,对雷神代码中 ffmpeg 弃用的函数做了修改。与雷神博客一样同样实现了普通版本和 su 版本。
SU 版特征如下:
- SDL弹出的窗口可以移动了
- 画面显示是严格的40ms一帧
所有代码均在 VS2017 C++17,SDL-2.0.14 版本上测试通过。
FFMPEG 解码流程
VideoPlayer 类声明
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "SDL.h"
#ifdef __cplusplus
}
#endif
#include <iostream>
class VideoPlayer {
public:
VideoPlayer(const std::string& file_path);
~VideoPlayer();
// call this function before use VideoPlayer.
bool InitVideoPlayer();
void Show();
private:
AVFormatContext* fmt_ctx_{
nullptr };
AVCodecContext* codec_ctx_{
nullptr };
AVCodec* codec_{
nullptr };
AVCodecParameters *parameters_{
nullptr };
struct SwsContext *sws_ctx_{
nullptr };
AVFrame* frame_{
nullptr };
AVFrame* yuv_frame_{
nullptr };
AVPacket* packet_{
nullptr };
bool is_init_{
false };
int video_index_{
-1 };
std::string file_path_;
unsigned char* out_buffer_{
nullptr };
SDL_Window* window_{
nullptr };
};
测试主程序
#include "VideoPlayer.h"
int main(int argc, char** argv) {
std::string file_path("output.mp4");
VideoPlayer player(file_path);
if (!player.InitVideoPlayer()) {
return -1;
}
// 如果使用 Su 版本调用 player.SuShow()
// player.SuShow()
player.Show();
return 0;
}
VideoPlayer 实现
#include "VideoPlayer.h"
// 定义刷新事件
#define SFM_REFRESH_EVENT (SDL_USEREVENT + 1)
#define SFM_BREAK_EVENT (SDL_USEREVENT + 2)
static bool thread_exit = 0;
static bool thread_pause = 0;
static int SfpRefreshThread(void *opaque) {
thread_exit = false;
thread_pause = false;
while (!thread_exit) {
if (!thread_pause) {
SDL_Event event;
event.type = SFM_REFRESH_EVENT;
SDL_PushEvent(&event);
}
SDL_Delay(40);
}
thread_exit = false;
thread_pause = false;
SDL_Event event;
event.type = SFM_