当前位置:网站首页>Ffmpeg+sdl+qt is a simple video player
Ffmpeg+sdl+qt is a simple video player
2022-07-29 02:43:00 【rjszcb】
————————————————
Copyright notice : This paper is about CSDN Blogger 「 Deng Wenyao 」 The original article of , follow CC 4.0 BY-SA Copyright agreement , For reprint, please attach the original source link and this statement .
Link to the original text :https://blog.csdn.net/AlonewaitingNew/article/details/109001130
FFmpeg Audio and video decoding
FFmpeg Is a library for audio and video decoding ,FFmpeg The decoding process of can be divided into the following steps :
av_register_all(): Register all components
avformat_open_input(): Open the input video file
av_format_find_stream_info(): Get video file information
avcodec_find_decoder(): Find the corresponding decoder
avcodec_open2(): Turn on the decoder
avcodec_decode_video2(): Decompress a frame of data
avcodec_close(): Turn off decoder
avformat_close_input(): Turn off input video
FFmpeg Data structure of :
because FFmepg yes C Language completion , Therefore, we mainly need to understand the structure type .
FFmpeg The decoded data structure is as follows :
stay AVFormatContext This structure mainly stores video information . The main thing is AVStream*, AVInputFormat. stay AVstream Save the video stream and audio stream information in . namely AVCodecContext. Each corresponding video and audio stream information has a corresponding decoder AVCodec.AVFrame A frame of decoded data is saved in 

FFmpeg code
Based on the above information , I wrote one myself Class, Used to decode video into YUV data .
FFmpeg.h
#pragma once
#include<string>
#define __STDC_CONSTANT_MACROS
#ifdef __cplusplus
extern "C"
{
#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#ifdef __cplusplus
}
#endif
#include<memory>
enum class INITERRO {
INIT_ERRO_NO_ERRO,
INIT_ERRO_ALLOC_FAILED,
INIT_ERRO_OPEN_FAILED,
INIT_ERRO_FIND_FAILED,
INIT_ERRO_NO_VIDEO,
INIT_ERRO_NO_AUDIO,
INIT_ERRO_DECODE_FAILED,
INIT_ERRO_OPEN2_FAILED
};
class FFmpeg
{
public:
FFmpeg();
FFmpeg(std::string path);
INITERRO initFFmpeg(const std::string& path="");
std::shared_ptr<uint8_t> getFrameYUV(int& isVideo);
int getWidth();
int getHeight();
~FFmpeg();
private:
std::string filePath;
int videoIndex;
int audioIndex;
AVFormatContext* pFormatCtx;
AVCodecContext* pCodercCtxVideo;
AVCodecContext* pCodercCtxAudio;
AVCodec* pCodercVideo;
AVFrame* pFrame;
AVFrame* pFrameYUV;
AVPacket* pPacket;
struct SwsContext* imgConvertCtx;
};
FFmpeg.cpp
#include "FFmpeg.h"
#include<iostream>
FFmpeg::FFmpeg()
{
}
FFmpeg::FFmpeg(std::string path)
{
}
INITERRO FFmpeg::initFFmpeg(const std::string& path)
{
if (path.empty() && this->filePath.empty()) {
return INITERRO::INIT_ERRO_OPEN_FAILED;
}
// Give priority to the incoming parameters
std::string pathTemp = path.empty() ? this->filePath : path;
// initialization
av_register_all();
avformat_network_init();
this->pFormatCtx = avformat_alloc_context();
//open_input
if (avformat_open_input(&this->pFormatCtx, pathTemp.c_str(), NULL,NULL) != 0) {
return INITERRO::INIT_ERRO_OPEN_FAILED;
}
//find_stream_infomation
if (avformat_find_stream_info(this->pFormatCtx, NULL) < 0) {
return INITERRO::INIT_ERRO_FIND_FAILED;
}
//find_decoder
videoIndex = -1;
audioIndex = -1;
for (int i = 0; i < this->pFormatCtx->nb_streams; ++i) {
if (this->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoIndex = i;
}
if (this->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
audioIndex = i;
}
}
if (videoIndex != -1) {
pCodercCtxVideo = pFormatCtx->streams[videoIndex]->codec;
pCodercVideo = avcodec_find_decoder(pCodercCtxVideo->codec_id);
if (pCodercVideo == NULL) {
printf("Codec not found.\n");
return INITERRO::INIT_ERRO_DECODE_FAILED;
}
}
if (audioIndex != -1) {
pCodercCtxAudio = pFormatCtx->streams[audioIndex]->codec;
//
}
//open2
if (avcodec_open2(pCodercCtxVideo, pCodercVideo, NULL) < 0) {
return INITERRO::INIT_ERRO_OPEN2_FAILED;
}
//init
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
uint8_t* outBuffer = (uint8_t*)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodercCtxVideo->width, pCodercCtxVideo->height));
avpicture_fill((AVPicture*)pFrameYUV, outBuffer, AV_PIX_FMT_YUV420P, pCodercCtxVideo->width, pCodercCtxVideo->height);
pPacket = (AVPacket*)av_malloc(sizeof(AVPacket));
//Output Info-----------------------------
/*printf("--------------- File Information ----------------\n"); av_dump_format(pFormatCtx, 0, pathTemp.c_str(), 0); printf("-------------------------------------------------\n");*/
imgConvertCtx = sws_getContext(pCodercCtxVideo->width, pCodercCtxVideo->height, pCodercCtxVideo->pix_fmt,
pCodercCtxVideo->width, pCodercCtxVideo->height, AV_PIX_FMT_YUV420P, 4, NULL, NULL, NULL);
return INITERRO::INIT_ERRO_NO_ERRO;
}
std::shared_ptr<uint8_t> FFmpeg::getFrameYUV(int& isVideo)
{
int y_size = pCodercCtxVideo->width * pCodercCtxVideo->height;
std::shared_ptr<uint8_t> bufferFram(new uint8_t[y_size * 3 / 2]);
int ret = -1;
int gotPic = -1;
if (av_read_frame(pFormatCtx, pPacket) < 0) {
isVideo = -2;
return bufferFram;
}
if (pPacket->stream_index == videoIndex) {
ret = avcodec_decode_video2(pCodercCtxVideo, pFrame, &gotPic, pPacket);
if (gotPic) {
sws_scale(imgConvertCtx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodercCtxVideo->height,
pFrameYUV->data, pFrameYUV->linesize);
// U V The data are Y Of 1/4 Reduce the width and height by half
memcpy(bufferFram.get(), pFrameYUV->data[0], y_size);
memcpy(bufferFram.get() + y_size, pFrameYUV->data[1], y_size / 4);
memcpy(bufferFram.get() + y_size + y_size / 4, pFrameYUV->data[2], y_size / 4);
isVideo = 1;
}
else {
isVideo = -1;
}
}
else {
isVideo = 0;
}
av_free_packet(pPacket);
return bufferFram;
}
int FFmpeg::getWidth()
{
return this->pCodercCtxVideo->width;
}
int FFmpeg::getHeight()
{
return this->pCodercCtxVideo->height;
}
FFmpeg::~FFmpeg()
{
sws_freeContext(imgConvertCtx);
av_frame_free(&pFrameYUV);
av_frame_free(&pFrame);
avcodec_close(pCodercCtxVideo);
avcodec_close(pCodercCtxAudio);
avformat_close_input(&pFormatCtx);
}
Finally, the function returns a smart pointer , The pointer points to an array , This array contains YUV data . Use SDL The player can play the video 

SDLPlayer.h
#pragma once
#include<string>
#ifdef __cplusplus
extern "C"
{
#endif
#include"sdl/SDL.h"
#ifdef __cplusplus
}
#endif
//Refresh Event
#define REFRESH_EVENT (SDL_USEREVENT + 1)
//Break
#define BREAK_EVENT (SDL_USEREVENT + 2)
class SDLPlayer
{
public:
SDLPlayer();
int initPlayer(void* winID=NULL);
void setHeight(int height);
void setWidth(int width);
void setPlayerTitle(std::string title);
int playYUV(uint8_t* buffer, SDL_Rect sdlRect, int delayTime = 40);
int playYUV(uint8_t* buffer, int delayTime = 40);
void pause();
void start();
void quit();
static int refreshThread(void* opaque);
~SDLPlayer();
private:
int windowH;
int windowW;
int height;
int width;
std::string title;
//SDL WINDOW
SDL_Window* window;
SDL_Texture* sdlTexture;
SDL_Renderer* sdlRanderer;
// event
SDL_Event event;
int threadExit;
int threadPause;
int delayTime;
};
SDLPlayer.cpp
#include "SDLPlayer.h"
SDLPlayer::SDLPlayer():
height(420),
width(640),
title("SDL player"),
window(nullptr),
sdlTexture(nullptr),
sdlRanderer(nullptr),
threadExit(0),
threadPause(0),
delayTime(40)
{
}
int SDLPlayer::initPlayer(void* winID)
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
windowW = this->width;
windowH = this->height;
if (winID != NULL) {
window = SDL_CreateWindowFrom(winID);
}
else {
window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
windowW, windowH, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
}
if (window == nullptr) {
printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
return -1;
}
sdlRanderer = SDL_CreateRenderer(window, -1, 0);
SDL_ShowWindow(window);
Uint32 pixformat = 0;
pixformat = SDL_PIXELFORMAT_IYUV;
sdlTexture = SDL_CreateTexture(sdlRanderer, pixformat,
SDL_TEXTUREACCESS_STREAMING, this->width, this->height);
// Create a new thread
SDL_CreateThread(SDLPlayer::refreshThread, NULL, this);
return 1;
}
void SDLPlayer::setHeight(int _height)
{
height = _height;
}
void SDLPlayer::setWidth(int _width)
{
this->width = _width;
}
void SDLPlayer::setPlayerTitle(std::string _title)
{
title = _title;
}
int SDLPlayer::playYUV(uint8_t* buffer, SDL_Rect sdlRect, int delayTime)
{
SDL_WaitEvent(&event);
if (event.type == REFRESH_EVENT) {
SDL_UpdateTexture(sdlTexture, NULL, buffer, this->width);
SDL_RenderClear(sdlRanderer);
SDL_RenderCopy(sdlRanderer, sdlTexture, NULL, &sdlRect);
SDL_RenderPresent(sdlRanderer);
//Delay 40ms
this->delayTime = delayTime;
}
else if (event.type == SDL_QUIT) {
this->threadExit = 1;
}
else if (event.type == BREAK_EVENT) {
return -1;
}
else if (event.type == SDL_WINDOWEVENT) {
//If Resize
SDL_GetWindowSize(window, &windowW, &windowH);
}
return 0;
}
int SDLPlayer::playYUV(uint8_t* buffer,int delayTime)
{
SDL_WaitEvent(&event);
if (event.type == REFRESH_EVENT) {
SDL_Rect sdlRect;
SDL_UpdateTexture(sdlTexture, NULL, buffer, this->width);
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = windowW;
sdlRect.h = windowH;
SDL_RenderClear(sdlRanderer);
SDL_RenderCopy(sdlRanderer, sdlTexture, NULL, &sdlRect);
SDL_RenderPresent(sdlRanderer);
//Delay 40ms
this->delayTime = delayTime;
}
else if (event.type == SDL_QUIT) {
this->threadExit = 1;
}
else if (event.type == SDL_WINDOWEVENT) {
//If Resize
SDL_GetWindowSize(window, &windowW, &windowH);
}
else if (event.type == BREAK_EVENT) {
return -1;
}
return 0;
}
void SDLPlayer::pause()
{
if (this->threadPause == 1) {
this->threadPause = 0;
}
else {
this->threadPause = 1;
}
}
void SDLPlayer::start()
{
this->threadPause = 0;
}
void SDLPlayer::quit()
{
this->threadExit = 1;
}
int SDLPlayer::refreshThread(void* opaque)
{
SDLPlayer* sdl = (SDLPlayer*)opaque;
while (!sdl->threadExit)
{
if (!sdl->threadPause) {
SDL_Event _event;
_event.type = REFRESH_EVENT;
SDL_PushEvent(&_event);
SDL_Delay(sdl->delayTime);
}
}
SDL_Event event;
event.type = BREAK_EVENT;
SDL_PushEvent(&event);
return 0;
}
SDLPlayer::~SDLPlayer()
{
SDL_DestroyWindow(window);
SDL_Quit();
}
SDL+FFmpe You can complete a video player .
QT The embedded SDL
playThread = new PlayThread;
ui.setupUi(this);
// Core code
playThread->setWindow((void*)ui.labelPlay->winId());
putenv(winID);
connect(ui.pushButtonPlay, &QPushButton::clicked, this, &FFmpegPlayer::play);
connect(ui.pushButtonPause, &QPushButton::clicked, this, &FFmpegPlayer::pause);
connect(ui.pushButtonClose, &QPushButton::clicked, this, &FFmpegPlayer::playerExit);
connect(ui.pushButtonOpen, &QPushButton::clicked, this, &FFmpegPlayer::openFile);
QT Thread functions
PlayThread.h
#pragma once
#include <qthread.h>
#include"FFmpeg.h"
#include"SDLPlayer.h"
#include<QString>
class PlayThread :
public QThread
{
public:
PlayThread();
~PlayThread();
void setWindow(void*);
virtual void run();
void pause();
void stop();
void setFilePath(QString filePath);
int isStop = 0;
private:
QString filePath;
void* winID;
SDLPlayer sdlPlayer;
};
PlayThread.cpp
#include "PlayThread.h"
PlayThread::PlayThread():filePath("Titanic.ts"),winID(NULL)
{
}
PlayThread::~PlayThread()
{
}
void PlayThread::setWindow(void* winID)
{
this->winID = winID;
}
void PlayThread::run()
{
FFmpeg ffmpeg;
auto r = ffmpeg.initFFmpeg(this->filePath.toStdString().c_str());
if (r != INITERRO::INIT_ERRO_NO_ERRO) {
return;
}
//SDL player
sdlPlayer.setWidth(ffmpeg.getWidth());
sdlPlayer.setHeight(ffmpeg.getHeight());
sdlPlayer.setPlayerTitle("myplayer");
sdlPlayer.initPlayer(this->winID);
int isVideo = -2;
auto buffer = ffmpeg.getFrameYUV(isVideo);
while (isVideo != -2)
{
buffer = ffmpeg.getFrameYUV(isVideo);
if (isVideo == 1) {
auto r = sdlPlayer.playYUV(buffer.get());
if (r == -1) {
break;
}
}
}
}
void PlayThread::pause()
{
sdlPlayer.pause();
}
void PlayThread::stop()
{
sdlPlayer.quit();
}
void PlayThread::setFilePath(QString filePath)
{
this->filePath = filePath;
}

边栏推荐
- 云开发口袋工具箱微信小程序源码
- 手把手教你安装VSCode(附带图解步骤)
- Talk about the implementation principle of feign
- 自动分账系统哪家好?
- When I look at the source code, what am I thinking?
- 网络基础概论
- owt-server源码剖析(四)--video模块分析之Mixer Out
- Redis主从模式、哨兵集群、分片集群
- Multimodal Unsupervised Image-to-Image Translation多通道无监督图像翻译
- What should I do if excel opens a CSV file containing Chinese characters and there is garbled code?
猜你喜欢
随机推荐
ASEMI整流桥S25VB100,S25VB100参数,S25VB100应用
Explain asynchronous tasks in detail: task status and lifecycle management
HTTP breakpoint resume and cache problems
Altium designer outputs Gerber and other production documents
NVIDIA-VPI(Vision Programming Interface)
MQTT例程
Read the recent trends of okaleido tiger and tap the value and potential behind it
家庭亲戚关系计算器微信小程序源码
如何把thinkphp5的项目迁移到阿里云函数计算来应对流量洪峰?
物联网组件
3D intelligent factory process flow visualization interactive display application advantages
3种过期策略
6-21漏洞利用-mysql弱口令破解
快速掌握Nodejs安装以及入门
redis为什么快,消息队列,单线程
一文理解分布式开发中的服务治理
Virsh console connection failure
How to quickly design a set of cross end components that support rendering rich text content
Cuda-npp image and video processing
FPGA刷题——存储器(RAM和FIFO的Verilog实现)









