目录
一:界面显示与解码的同步进行--线程
二:测试
三:因为路径问题导致的图片不显示
四:QString字符串分割函数---获取文件名称
一:界面显示与解码的同步进行--线程
解码利用线程的方式进行改造
videodecode.h .cpp
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
#ifndef VIDEODECODE_H
#define VIDEODECODE_H
#include <QObject>
#include<QThread>//使用线程
//当前C++兼容C语言
extern "C"
{
//avcodec:编解码(最重要的库)
#include <libavcodec/avcodec.h>
//avformat:封装格式处理
#include <libavformat/avformat.h>
//swscale:视频像素数据格式转换
#include <libswscale/swscale.h>
//avdevice:各种设备的输入输出
#include <libavdevice/avdevice.h>
//avutil:工具库(大部分库都需要这个库的支持)
#include <libavutil/avutil.h>
}
class videoDecodeThread : public QThread//利用线程基类
{
Q_OBJECT
public:
// explicit videoDecodeThread(QObject *parent = 0);
videoDecodeThread(QString videoname);
QString videoname;
//视频文件上下文格式
AVFormatContext* avformat_context;
//编解码器上下文格式
AVCodecContext* avcodec_context;
//解码器上下文格式
AVCodec* avcodec;
AVPacket* av_packet;
//流的标志位
int av_stream_index;
//线程函数的引入
void run();
virtual ~videoDecodeThread();
//定义停止的标志位
bool m_stop;
signals:
public slots:
};
#endif // VIDEODECODE_H
#include "videodecode.h"
#include<QDebug>
#include<QCoreApplication>
#include<QThread>
//解码初始化操作
//1.注册所有组件
//2.打开视频输入文件
//3.查找视频流信息
//4.查找解码器
//5.打开解码器
//videoDecode::videoDecode(QObject *parent) : QObject(parent)
//{
//}
videoDecodeThread::videoDecodeThread(QString videoname)
{
//初始线程未启动
this->m_stop = false;
qDebug()<<"1.注册所有组件";
av_register_all();
qDebug()<<"2.打开视频输入文件";
QString filename = QCoreApplication::applicationDirPath();
qDebug()<<"获取程序运行目录 "<<filename;
QString cinputFilePath = "test.avi"; //本地视频文件放入程序运行目录
avformat_context = avformat_alloc_context();
//参数一:封装格式上下文->AVFormatContext->包含了视频信息(视频格式、大小等等...)
//参数二:打开文件(入口文件)->url
qDebug()<<"打开"<<videoname<<"视频文件进行播放";
int avformat_open_result = avformat_open_input(&avformat_context,videoname.toStdString().c_str(),NULL,NULL);
if (avformat_open_result != 0)
{
//获取异常信息
char* error_info = new char[32];
av_strerror(avformat_open_result, error_info, 1024);
qDebug()<<QString("异常信息 %1").arg(error_info);
};
qDebug()<<"3.查找视频流信息";
//参数一:封装格式上下文->AVFormatContext
//参数二:配置
//返回值:0>=返回OK,否则失败
int avformat_find_stream_info_result = avformat_find_stream_info(avformat_context, NULL);
if (avformat_find_stream_info_result < 0){
//获取失败
char* error_info = new char[32];
av_strerror(avformat_find_stream_info_result, error_info, 1024);
qDebug()<<QString("异常信息 %1").arg(error_info);
}
qDebug()<<"4.查找解码器";
//第一点:获取当前解码器是属于什么类型解码器->找到了视频流
//音频解码器、视频解码器、字幕解码器等等...
//获取视频解码器流引用
av_stream_index = -1;
for (int i = 0; i < avformat_context->nb_streams; ++i) {
//循环遍历每一流
//视频流、音频流、字幕流等等...
if (avformat_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
//找到了
av_stream_index = i;
break;
}
}
if (av_stream_index == -1)
{
qDebug()<<QString("没有找到视频流");
}
//第二点:根据视频流->查找到视频解码器上下文->视频压缩数据
//编解码器上下文
avcodec_context = avformat_context->streams[av_stream_index]->codec;
//第三点:根据解码器上下文->获取解码器ID
avcodec = avcodec_find_decoder(avcodec_context->codec_id);
if (avcodec == NULL)
{
qDebug()<<QString("没有找到视频解码器");
}
qDebug()<<"5.打开解码器";
int avcodec_open2_result = avcodec_open2(avcodec_context,avcodec,NULL);
if (avcodec_open2_result != 0)
{
char* error_info = new char[32];
av_strerror(avformat_find_stream_info_result, error_info, 1024);
qDebug()<<QString("异常信息 %1").arg(error_info);
}
qDebug()<<"视频详细信息输出";
//此函数自动打印输入或输出的详细信息
av_dump_format(avformat_context, 0, cinputFilePath.toStdString().c_str(), 0);
qDebug()<<"----------------解码准备工作完成-----------------";
}
void videoDecodeThread::run()
{
qDebug()<<"----------------开始循环解码操作-----------------";
qDebug()<<"6.循环解码";
//读取帧数据换成到哪里->缓存到packet里面
av_packet = (AVPacket*)av_malloc(sizeof(AVPacket));
//解码的状态类型(0:表示解码完毕,非0:表示正在解码)
int current_frame_index = 0;
//>=0:说明有数据,继续读取 <0:说明读取完毕,结束
//从视频文件上下文中读取包--- 有数据就一直读取
while (av_read_frame(avformat_context,av_packet) >= 0)
{
//解码什么类型流(视频流、音频流、字幕流等等...)
if (av_packet->stream_index == av_stream_index)
{
//遍历每一帧的信息进行打印
current_frame_index++;
//延时操作 1秒显示25帧--1000/25=40
QThread::msleep(40);
qDebug()<<QString("当前遍历第 %1 帧").arg(current_frame_index);
}
}
qDebug()<<"7.关闭所有解码组件";
av_packet_free(&av_packet);
//关闭流
avcodec_close(avcodec_context);
avformat_free_context(avformat_context);
}
videoDecodeThread::~videoDecodeThread()
{
qDebug()<<"7.关闭所有解码组件";
av_packet_free(&av_packet);
//关闭流
avcodec_close(avcodec_context);
avformat_free_context(avformat_context);
}
二:测试
if(btnName == "儿童")
{
QMessageBox::question(NULL,"儿童",btn->text());
QString cinputFilePath = "test.avi";
videoDecodeThread *p = new videoDecodeThread(cinputFilePath);
p->start();
}
点击其他的按钮,找到对应的item项下的视频进行播放
三:因为路径问题导致的图片不显示
QString videopath = QDir::currentPath()+"/image";
qDebug()<<videopath;
QDir dir(videopath);//确定路径 从此dir路径下往下找
将image文件夹拷贝到bin文件目录下
图片即可以正常显示
视频播放器中的视频图片尽量和片源名字保持一致
四:QString字符串分割函数---获取文件名称
void IndexWin::videoWidgetShowSlot(QListWidgetItem *item)
{
qDebug()<<item->text()<<"界面创建";
QStringList list = item->text().split(".");//QString字符串分割函数
qDebug()<<list[0];
//视频文件名称后缀:.avi
QString cinputFilePath = list[0]+".avi";
// 解码线程的使用
videoDecodeThread *p = new videoDecodeThread(cinputFilePath);
//新建视频播放界面
// 通过设置按钮进行视频的播放
// p->start();
}
注意点:视频文件名称后缀为.avi
若是没有根据工程目录下视频文件后缀名称命名---会导致程序的异常结束
//视频文件名称后缀:.avi
QString cinputFilePath = list[0]+".avi";
点击列表中的item进行解码操作---模拟视频播放器
如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓