#include "VideoPlayer.h" #include "DecodeVedio.h" #include #include #include #include "spdlog/spdlog.h" VideoPlayer::VideoPlayer(QWidget *parent) : QWidget(parent) { /* 初始化解码线程 */ m_threadDecode = new QThread(this); m_decodeVedio = new DecodeVedio(m_threadDecode); m_semRefresh = new QSemaphore(0); m_timerRefreshUI.setSingleShot(false); /* 设置精度毫秒级 */ m_timerRefreshUI.setTimerType(Qt::PreciseTimer); connect(&m_timerRefreshUI, &QTimer::timeout, this, &VideoPlayer::do_refreshUI); connect(m_decodeVedio, &DecodeVedio::signal_oneImage, this, &VideoPlayer::do_refreshOneUI); connect(m_decodeVedio, &DecodeVedio::signal_playCompleted, this, &VideoPlayer::do_playCompleted); SPDLOG_TRACE("UI线程ID:{}", QThread::currentThreadId()); } VideoPlayer::~VideoPlayer() { if(m_timerRefreshUI.isActive()) { m_timerRefreshUI.stop(); } delete m_decodeVedio; if(m_image) { delete m_image; } } /** * @brief 设置播放视频,启动定时器,定时器间隔决定播放的速度 * 视频的宽和高使用QImage进行缩放 * 视频大小在直接设置这个类的resize即可,有最小大小限制 * * @param fileName */ void VideoPlayer::setPlayVedio(const QString& fileName) { if(isSetVedioFile) { isSetVedioFile = false; } if(m_decodeVedio->isInitFFmpeg()) { m_decodeVedio->unInitFFmpeg(); } m_fileName = fileName; isSetVedioFile = true; m_decodeVedio->initFFmpeg(m_fileName); // m_decodeVedio->setVideoSize(this->width(), this->height()); /* 获取原始视频信息 */ m_srcWidth = m_decodeVedio->getSrcVideoWidth(); m_srcHeight = m_decodeVedio->getSrcVideoHeight(); m_frameCount = m_decodeVedio->getFrameCount(); SPDLOG_DEBUG("视频宽:{} 高:{} 帧数:{}", m_srcWidth, m_srcHeight, m_frameCount); /* 设置视频宽和高的最小大小 */ this->setMinimumSize(160,90); /* 开启定时器刷新 */ if(m_frameCount < 0) { /* HEVC帧率,获取不到,就按照24帧来刷新 */ if(m_frameCount == -2) { m_frameCount = 24; } else { m_frameCount = 25; } } else if(m_frameCount == 0) { m_frameCount = 25; } SPDLOG_INFO("帧率:{}", m_frameCount); /* 开启解码,手动刷新第一帧 */ m_decodeVedio->startDecodeVedio(); m_semRefresh->release(2); // m_timerRefreshUI.setSingleShot(true); // m_timerRefreshUI.start(500); } /* 播放视频 */ bool VideoPlayer::play() { if(!isSetVedioFile) { SPDLOG_ERROR("文件名为空"); return false; } if(m_playStatus) { return false; } /* 设置刷新时间 */ m_timerRefreshUI.setSingleShot(false); m_interval = 1000/m_frameCount; if(1000 % m_frameCount > 5) { m_frameCount += 1; } SPDLOG_TRACE("刷新UI的定时间隔:{}",m_interval); m_timerRefreshUI.start(m_interval); m_playStatus = true; return true; } /* 暂停播放 */ void VideoPlayer::pause() { if(!m_playStatus) { return; } m_timerRefreshUI.stop(); m_playStatus = false; } /* 停止播放,停止后停止解码,将时间等复位到开始时间 */ void VideoPlayer::stop() { SPDLOG_DEBUG("...停止播放..."); // m_fileName = QString(); if(m_timerRefreshUI.isActive()) { m_timerRefreshUI.stop(); } // SPDLOG_DEBUG("...停止解码..."); /* 重新设置播放视频 */ setPlayVedio(m_fileName); /* 绘制黑帧 */ // SPDLOG_DEBUG("绘制黑帧"); // m_image = new QImage(m_nowWidth, m_nowHeight, QImage::Format_RGB32); // m_image->fill(Qt::black); // update(); m_playStatus = false; // isSetVedioFile = false; } /* 获取视频时长 */ qint64 VideoPlayer::getDuration() { return m_decodeVedio->getDuration(); } /* 获取当前播放位置 */ qint64 VideoPlayer::getCurrentPos() { return m_decodeVedio->getCurrentPos(); } /* 设置当前播放位置 */ void VideoPlayer::setCurrentPos(quint64 pos) { /* 先停止播放 */ bool temp = m_playStatus; if(m_playStatus) { m_timerRefreshUI.stop(); m_playStatus = false; } m_decodeVedio->setCurrentPos(pos); /* 继续播放 */ if(temp) { // SPDLOG_INFO("..........开启定时器.........."); m_timerRefreshUI.start(m_interval); m_playStatus = true; }else { /* 刷新5张照片,防止第一张是跳转前的时间段 */ m_semRefresh->release(5); } } /* 设置播放视频大小 */ void VideoPlayer::setPlayVedioSize(int width,int height) { /* 对宽和高就行缩放,保持比例,同时将其居中放置 * 先计算出比例,和16/9相对比 * 大于16/9,以高为最大极限,计算出宽度和x坐标 * 小于16/9,以宽为最大极限,计算出高度和y坐标 */ double srcRatio = m_srcWidth*1.0 / m_srcHeight; double ratio = width*1.0 / height; long w1 = 0, h1 = 0; int srcX = this->pos().rx(), srcY = this->pos().ry(); int x1 = srcX, y1 = srcY; if(ratio > srcRatio) { w1 = height * srcRatio; x1 = (width - w1) / 2; h1 = height; y1 = srcY; } else if(ratio < srcRatio) { h1 = width / srcRatio; y1 = (height - h1) / 2; w1 = width; x1 = srcX; }else { w1 = width; h1 = height; x1 = srcX; y1 = srcY; } this->move(x1, y1); m_nowWidth = w1; m_nowHeight = h1; this->resize(w1, h1); // SPDLOG_DEBUG("设置窗口位置:{}x{}, 大小:{}x{}, 传入大小:{}x{}", x1, y1, w1, h1, width, height); SPDLOG_DEBUG("现在位置和大小:{}x{}, {}x{}", this->pos().rx(), this->pos().ry(), this->width(), this->height()); } /* 设置播放回调函数 */ void VideoPlayer::setPlayCallBack(std::function playCallBack,void* context) { m_funcPlayCB = playCallBack; m_context = context; } void VideoPlayer::paintEvent(QPaintEvent *event) { if(m_image) { // SPDLOG_TRACE("开始绘制画面..."); /* 对图像进行缩放 */ QImage image; if(m_srcWidth != m_nowWidth || m_srcHeight != m_nowHeight) { image = m_image->scaled(m_nowWidth, m_nowHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); } QPainter painter(this); painter.drawImage(0, 0, image); } } void VideoPlayer::resizeEvent(QResizeEvent *event) { SPDLOG_TRACE("窗口大小改变..."); m_nowWidth = event->size().width(); m_nowHeight = event->size().height(); /* 传递给解码器 */ // m_decodeVedio->setVideoSize(m_nowWidth, m_nowHeight); QWidget::resizeEvent(event); } /* 刷新一张图片,直到有图片为止 */ void VideoPlayer::refreshOneUIUntilHave() { if(m_decodeVedio != nullptr) { // SPDLOG_DEBUG("取出一帧图片..."); /* 删除上一帧图片 */ if(m_image != nullptr) { delete m_image; m_image = nullptr; } /* 如果没有图片,这个函数会阻塞 */ m_image = m_decodeVedio->getOneImageUntilHave(); if(m_image) { // if(m_srcWidth != m_nowWidth || m_srcHeight != m_nowHeight) // { // *m_image = m_image->scaled(m_nowWidth, m_nowHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); // } // SPDLOG_DEBUG("绘制画面..."); update(); } m_decodeVedio->wakeUpCondQueueNoEmpty(); } } /* 双击事件函数 */ void VideoPlayer::mouseDoubleClickEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { // SPDLOG_DEBUG("双击事件..."); if(m_funcPlayCB != nullptr) { m_funcPlayCB(this, 5, nullptr, 0, m_context); }else { SPDLOG_INFO("没有设置回调函数"); } } } /* 取出画面,刷新UI */ void VideoPlayer::do_refreshUI() { if(m_decodeVedio != nullptr) { // SPDLOG_DEBUG("取出一帧图片..."); /* 删除上一帧图片 */ if(m_image != nullptr) { delete m_image; m_image = nullptr; } m_image = m_decodeVedio->getOneImage(); if(m_image) { if(m_srcWidth != m_nowWidth || m_srcHeight != m_nowHeight) { *m_image = m_image->scaled(m_nowWidth, m_nowHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); } // SPDLOG_DEBUG("绘制画面..."); update(); } m_decodeVedio->wakeUpCondQueueNoEmpty(); } } /* 通过信号刷新第一张图片 */ void VideoPlayer::do_refreshOneUI() { if(!m_semRefresh->tryAcquire(1)) { return; } /* 取出第一张 */ if(m_decodeVedio != nullptr) { // SPDLOG_DEBUG("取出一帧图片..."); /* 删除上一帧图片 */ if(m_image != nullptr) { delete m_image; m_image = nullptr; } m_image = m_decodeVedio->getOneImage(); if(m_image) { if(m_srcWidth != m_nowWidth || m_srcHeight != m_nowHeight) { *m_image = m_image->scaled(m_nowWidth, m_nowHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); } SPDLOG_DEBUG("绘制预览画面..."); update(); } m_decodeVedio->wakeUpCondQueueNoEmpty(); } } /* 播放完成 */ void VideoPlayer::do_playCompleted() { SPDLOG_INFO("Video 播放完成..."); m_timerRefreshUI.stop(); m_playStatus = false; if(m_funcPlayCB != nullptr) { /* 播放完成的回调函数 */ m_funcPlayCB(this, 2, nullptr, 0, m_context); } }