当前位置:网站首页>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;
}

边栏推荐
- 《微信小程序-进阶篇》Lin-ui组件库源码分析-Button组件(二)
- HTTP缓存
- Altium designer outputs Gerber and other production documents
- Polygon zkEVM——Hermez 2.0简介
- Kbxxxxx is not necessarily a patch, but also a description of a solution to a problem
- 3D intelligent factory process flow visualization interactive display application advantages
- On Multithreading
- 4年测试经验,好不容易进了阿里,两个月后我选择了裸辞...
- FPGA skimming memory (Verilog implementation of ram and FIFO)
- Multimodal unsupervised image to image translation
猜你喜欢

How does the Devops team defend against API attacks?

After 4 years of testing experience, I finally entered Alibaba. Two months later, I chose to resign naked

C语言实现三子棋游戏

Understanding service governance in distributed development

Shell 脚本 快速入门 -01

3D intelligent factory process flow visualization interactive display application advantages

Talk about the implementation principle of feign

Double write consistency of MySQL and redis

Altium designer outputs Gerber and other production documents

一款好看的iapp捐赠榜单源码
随机推荐
0728~ sorting out interview questions
6年测试经验,教大家测试~如何把控项目
MySQL和Redis的双写一致性
ECCV 2022 | AirDet:无需微调的小样本目标检测方法
time_ Wait and close_ Cause of wait
Time for white horses to pass the gap
Three implementation methods of Servlet
Split, an avalanche caused by connection pool parameters
Talk about the implementation principle of feign
物联网组件
What should I do if excel opens a CSV file containing Chinese characters and there is garbled code?
Continuous learning / life long learning
C language to achieve the three chess game
Shell 脚本 快速入门 -01
Rust 列表(Vec)复制
Code implementation - the greatest common factor of polynomials (linear algebra)
Redis队列实现秒杀
HTTP cache
【报错】node:internal/modules/cjs/loader:936 【解决方法】
一文读懂Okaleido Tiger近期动态,挖掘背后价值与潜力