当前位置:网站首页>QT display ffmpeg decoded pictures
QT display ffmpeg decoded pictures
2022-06-25 13:09:00 【Bellerian】
One 、 Preface
As I said before, we passed FFmpeg Decode video , Save video frames as pictures , This time we will play the decoded pictures ;
Ideas :
- First , Decoding is still a ten step strategy , But this cannot be placed in the main thread , Time consuming operations will jam the interface , So we put the decoding operation into the sub thread to run ;
- secondly , The child thread cannot directly modify the main interface UI, So the sub threads are decoded through the signal slot QImage Transfer to the main interface display ;
- Last , The main interface updates the transmitted pictures to QLabel You can go up. ;
Two 、 Effect display
Qt Show FFmpeg Decoded picture
3、 ... and 、 Detailed code
Decoding thread class
#ifndef VIDEOPLAYER_H
#define VIDEOPLAYER_H
extern "C"{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/pixfmt.h"
#include "libswscale/swscale.h"
}
#include <stdio.h>
#include <QThread>
#include <QImage>
#include <QDebug>
class VideoPlayer : public QThread
{
Q_OBJECT
public:
VideoPlayer();
protected:
void run();
signals:
void sig_post_oneFrame(const QImage& image);
};
#endif // VIDEOPLAYER_H
#include "videoplayer.h"
VideoPlayer::VideoPlayer()
{
}
void VideoPlayer::run()
{
// Variable definitions
//==================================================================================
char *file_path = "C:/Users/wangjichuan/Desktop/2.mp4"; // File path
///===== First step =====
// initialization FFMPEG Only by calling this can the encoder and decoder be used normally
av_register_all();
///===================================================================
///===== The second step =====
AVFormatContext *pFormatCtx; // Describes the composition and basic information of a media file or media stream
pFormatCtx = avformat_alloc_context(); // Assign a unpacked context pointer
// Open file
if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {
// File information is stored in the file context , It can be processed later
printf(" Can't open file ");
return;
}
///===================================================================
///===== The third step =====
// Find out if there is information flow in the file
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
printf(" No information flow found in the file ");
return;
}
// Loop to find the stream information contained in the video , Until you find a video type stream
// And then I recorded it Save to videoStream variable
// Here we only deal with video streaming The audio stream ignores him first
int videoStream = -1;
int i;
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
}
}
// If videoStream by -1 The video stream was not found
if (videoStream == -1) {
printf(" No video stream found in file ");
return;
}
///===================================================================
///===== Step four =====
AVCodecContext *pCodecCtx; // Describe the data structure of the codec context , It contains many parameters needed by codec
AVCodec *pCodec; // A structure that stores codec information
// Find the decoder
pCodecCtx = pFormatCtx->streams[videoStream]->codec; // Get the encoder context in the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id); // Get the encoder of the video stream
if (pCodec == NULL) {
printf(" Encoder not found ");
return;
}
///===================================================================
///===== Step five =====
// Turn on the decoder
//==================================================================================
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
printf(" Unable to open encoder ");
return;
}
///===================================================================
///===== Step six =====
static struct SwsContext *img_convert_ctx; // For video image conversion
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_BGR32, SWS_BICUBIC, NULL, NULL, NULL);
///===================================================================
///===== Step seven =====
int numBytes;
numBytes = avpicture_get_size(AV_PIX_FMT_BGR32, pCodecCtx->width,pCodecCtx->height);
///===================================================================
///===== Step eight =====
AVFrame *pFrame, *pFrameRGB; // Store audio and video raw data ( That is, uncoded data ) The structure of the body
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
uint8_t *out_buffer; // cache
out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *) pFrameRGB, out_buffer, AV_PIX_FMT_BGR32,
pCodecCtx->width, pCodecCtx->height);
///===================================================================
///===== Step nine =====
AVPacket *packet; // Save to understand reuse (demuxer) after , decode (decode) Previous data ( It's still compressed data ) And some additional information about the data
int ret, got_picture;
int y_size = pCodecCtx->width * pCodecCtx->height;
packet = (AVPacket *) malloc(sizeof(AVPacket)); // Allocate one packet
av_new_packet(packet, y_size); // Distribute packet The data of
av_dump_format(pFormatCtx, 0, file_path, 0); // Output video information
while (1)
{
if (av_read_frame(pFormatCtx, packet) < 0) {
break; // I think the video is finished
}
if (packet->stream_index == videoStream) {
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);
if (ret < 0) {
printf("decode error.");
return;
}
if (got_picture) {
sws_scale(img_convert_ctx,
(uint8_t const * const *) pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
pFrameRGB->linesize);
QImage image(pFrameRGB->data[0], pCodecCtx->width, pCodecCtx->height, pFrameRGB->linesize[0], QImage::Format_RGB32);
emit sig_post_oneFrame(image);
}
}
av_free_packet(packet);
}
///===================================================================
///===== Step 10 =====
av_free(out_buffer);
av_free(pFrameRGB);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
///===================================================================
}
Main form class
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QLabel>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow; }
QT_END_NAMESPACE
#include "videoplayer.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QLabel* label;
VideoPlayer* m_player;
public slots:
void slot_get_oneFrame(const QImage& image);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
label = new QLabel(this);
this->setCentralWidget(label);
m_player = new VideoPlayer;
connect(m_player,SIGNAL(sig_post_oneFrame(QImage)),this,SLOT(slot_get_oneFrame(QImage)));
m_player->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::slot_get_oneFrame(const QImage& image)
{
label->setPixmap(QPixmap::fromImage(image));
}
边栏推荐
- 字节跳动Dev Better技术沙龙来啦!参与活动赢好礼,限时免费报名中!
- Sword finger offer 04 Find in 2D array
- torch.tensor拼接与list(tensors)
- 解析数仓lazyagg查询重写优化
- MySQL writes user-defined functions and stored procedure syntax (a detailed case is attached, and the problem has been solved: errors are reported when running user-defined functions, and errors are r
- 剑指 Offer 04. 二维数组中的查找
- 阿里稳定性之故障应急处理流程
- 时间过滤器(el-table)中使用
- Introduction to string 18 lectures Collection 4
- 药物设计新福音:腾讯联合中科大、浙大开发自适应图学习方法,预测分子相互作用及分子性质
猜你喜欢
@Scheduled implementation of scheduled tasks (concurrent execution of multiple scheduled tasks)
Update PIP & Download jupyter Lab
Seven competencies required by architects
Serevlt初识
Maui的学习之路(二)--设置
PPT绘论文图之导出分辨率
利用cmd(命令提示符)安装mysql&&配置环境
字符串各操作函数与内存函数详解
Configuring pytorch in win10 environment
[data visualization] 360 ° teaching you how to comprehensively learn visualization - Part 1
随机推荐
[machine learning] model and cost function
Capabilities required by architects
Django框架——缓存、信号、跨站请求伪造、 跨域问题、cookie-session-token
使用Visio画立方体
Module 5 (microblog comments)
A half search method for sequential tables
Back test of quantitative trading - example of futures CTA strategy (tqzfuturerenkoscalpingstrategy)
线上服务应急攻关方法论
剑指 Offer II 025. 链表中的两数相加
ByteDance dev better technology salon is coming! Participate in the activity to win a good gift, and sign up for free within a limited time!
Koa 框架
Serenvlt first met
WIN10环境下配置pytorch
[AI helps scientific research] fool drawing of loss curve
It is extraordinary to make a move, which is very Oracle!
德国举行全球粮食安全团结会议
[转]以终为始,详细分析高考志愿该怎么填
Spoken English - weak reading
20220620 面试复盘
5 kinds of viewer for browser