culturered_client/ProjectorDisplay/ReverseDecodThread.cpp

282 lines
7.8 KiB
C++
Raw Permalink Normal View History

2024-09-07 03:34:44 +00:00
//指定文件的编码为UTF-8
#pragma execution_character_set("utf-8")
#include "ReverseDecodThread.h"
ReverseDecodThread::ReverseDecodThread()
{
qDebug() << "FFMPEG版本信息:" << av_version_info();
}
ReverseDecodThread::~ReverseDecodThread()
{
}
/*
:
*/
int ReverseDecodThread::set_VideoFile(QString media)
{
//打开媒体文件
QByteArray array=media.toUtf8();
strncpy(m_MediaFile, array.data(), sizeof(m_MediaFile));
m_run = 1;
return 1;
}
void ReverseDecodThread::SetSate(int run)
{
m_run = run;
}
int ReverseDecodThread::GetSate()
{
return m_run;
}
//跳转视频帧
void ReverseDecodThread::SetSeekPos(qint64 pos)
{
is_CurrentSeekPos = 1;
m_n64CurrentSeekPos = pos;
m_run=1; //运行状态
//获取系统本地时间
play_base_time=QDateTime::currentMSecsSinceEpoch();
}
void ReverseDecodThread::PausePlay()
{
m_run = 2;
}
void ReverseDecodThread::StopPlay()
{
m_run = 0;
}
void ReverseDecodThread::LogSend(QString text)
{
//qDebug() << text;
}
//线程执行起点
void ReverseDecodThread::run()
{
LogSend("开始播放视频.\n");
StartPlay();
}
//播放视频
int ReverseDecodThread::StartPlay()
{
format_ctx = avformat_alloc_context();
if (!format_ctx) {
LogSend(tr("初始化失败 无法打开视频文件: %1").arg(m_MediaFile));
return -1;
}
//1.打开多媒体流,并且获取一些信息
if(avformat_open_input(&format_ctx, m_MediaFile, nullptr, nullptr) != 0)
{
LogSend(tr("无法打开视频文件: %1").arg(m_MediaFile));
return -1;
}
//2. 读取媒体文件的数据包以获取流信息
if(avformat_find_stream_info(format_ctx, nullptr) < 0)
{
LogSend(tr("无法获取流信息.\n"));
return -1;
}
// context = avcodec_alloc_context3(codec)
AVCodecContext* avctx = avcodec_alloc_context3(NULL);
if (nullptr == avctx) {
return -1;
}
st_index[AVMEDIA_TYPE_VIDEO] = av_find_best_stream(format_ctx, AVMEDIA_TYPE_VIDEO, st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
st_index[AVMEDIA_TYPE_AUDIO] = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO,
st_index[AVMEDIA_TYPE_AUDIO],
st_index[AVMEDIA_TYPE_VIDEO],
NULL, 0);
//3.打印视频的信息
LogSend(tr("视频中流的数量: %1\n").arg(format_ctx->nb_streams));
for(int i = 0; i < format_ctx->nb_streams; ++i)
{
const AVStream* stream = format_ctx->streams[i];
if(stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
int ret = avcodec_parameters_to_context(avctx, stream->codecpar);
if (ret < 0) {
return -1;
}
//查找解码器
const AVCodec *video_pCodec=avcodec_find_decoder(avctx->codec_id);
//打开解码器
if(avcodec_open2(avctx, video_pCodec,nullptr)!=0)
{
LogSend(tr("解码器打开失败.\n"));
return -1;
}
video_stream_index = i;
bool flag = false;
if (video_width != stream->codecpar->width) {
video_width = stream->codecpar->width;
flag = true;
}
if (video_height != stream->codecpar->height) {
video_height = stream->codecpar->height;
flag = true;
}
if (flag) {
emit VideoSizeChanged(video_width, video_height);
}
LogSend(tr("视频帧的尺寸(以像素为单位): (宽X高)%1x%2 像素格式: %3\n").arg(
stream->codecpar->width).arg(stream->codecpar->height).arg(stream->codecpar->format));
}
}
if (video_stream_index == -1)
{
LogSend("没有检测到视频流.\n");
return -1;
}
AVRational frameRate = format_ctx->streams[video_stream_index]->avg_frame_rate;
/*设置视频转码器*/
SRC_VIDEO_pFrame = av_frame_alloc();
RGB24_pFrame = av_frame_alloc();// 存放解码后YUV数据的缓冲区
//将解码后的YUV数据转换成RGB24
img_convert_ctx = sws_getContext(video_width, video_height,
avctx->pix_fmt,video_width, video_height,
AV_PIX_FMT_RGBA, SWS_BICUBIC, nullptr, nullptr, nullptr);
//计算RGB图像所占字节大小
int numBytes= av_image_get_buffer_size(AV_PIX_FMT_RGBA,video_width,video_height, 1);
//申请空间存放RGB图像数据
out_buffer_rgb = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
// avpicture_fill函数将ptr指向的数据填充到picture内,但并没有拷贝,只是将picture结构内的data指针指向了ptr的数据
/*avpicture_fill((AVPicture *) RGB24_pFrame, out_buffer_rgb, AV_PIX_FMT_RGB24,
video_width, video_height);*/
av_image_fill_arrays(RGB24_pFrame->data, RGB24_pFrame->linesize, out_buffer_rgb, AV_PIX_FMT_RGBA,
video_width, video_height, 1);
qDebug()<<"format_ctx->duration:"<<format_ctx->duration;
//获取系统本地时间
play_base_time=QDateTime::currentMSecsSinceEpoch();
// m_run = 1;
//表示视频加载成功
while(m_run)
{
if(m_run == 2)
{
msleep(100); //暂停播放
continue;
}
if (is_CurrentSeekPos)
{
is_CurrentSeekPos = 0;
//偏移到指定位置再开始解码 AVSEEK_FLAG_BACKWARD 向后找最近的关键帧
av_seek_frame(format_ctx, -1, m_n64CurrentSeekPos* AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
qDebug()<<"跳转的位置:"<<m_n64CurrentSeekPos;
}
double video_clock;
AVPacket pkt;
//1. 读取一帧数据
if(av_read_frame(format_ctx, &pkt) < 0)
{
m_run=2; //设置为暂停状态
// qDebug()<<"数据读取完毕.";
continue;
}
if(pkt.stream_index == video_stream_index)
{
//当前时间
video_clock = av_q2d(format_ctx->streams[video_stream_index]->time_base) * pkt.pts;
// qDebug()<<"pkt.pts:"<<pkt.pts<<"video_clock:"<<video_clock;
//解码视频 frame
//2. 发送视频帧
if (avcodec_send_packet(avctx,&pkt) != 0)
{
av_packet_unref(&pkt);//不成功就释放这个pkt
continue;
}
//3. 接受后对视频帧进行解码
if (avcodec_receive_frame(avctx, SRC_VIDEO_pFrame) != 0)
{
av_packet_unref(&pkt);//不成功就释放这个pkt
continue;
}
//4. 转格式
sws_scale(img_convert_ctx,
(uint8_t const **) SRC_VIDEO_pFrame->data,
SRC_VIDEO_pFrame->linesize, 0, video_height, RGB24_pFrame->data,
RGB24_pFrame->linesize);
//5. 加载图片数据
QImage image(out_buffer_rgb,video_width,video_height,QImage::Format_RGBA8888);
//通知界面更新
VideoDataOutput(image.copy());
//时间信号
sig_getCurrentTime(video_clock, format_ctx->duration *1.0 / AV_TIME_BASE);
QThread::msleep(40);
}
//释放包
av_packet_unref(&pkt);
}
LogSend("视频音频解码播放器的线程退出成功.\n");
if(SRC_VIDEO_pFrame) av_frame_free(&SRC_VIDEO_pFrame);
if(RGB24_pFrame) av_frame_free(&RGB24_pFrame);
if(img_convert_ctx)sws_freeContext(img_convert_ctx);
if(out_buffer_rgb)av_free(out_buffer_rgb);
SRC_VIDEO_pFrame=nullptr;
RGB24_pFrame=nullptr;
img_convert_ctx=nullptr;
out_buffer_rgb=nullptr;
if(format_ctx)
{
avcodec_free_context(&avctx);
avformat_close_input(&format_ctx);//释放解封装器的空间,以防空间被快速消耗完
avformat_free_context(format_ctx);
}
return 0;
}