|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
#include "decodestream.h"
|
|
|
|
|
|
|
|
|
|
DecodeStream::DecodeStream(QObject *parent) : QObject{parent} {}
|
|
|
|
|
DecodeStream::DecodeStream(QObject *parent) : QObject{parent}, m_playSpeed{1} {}
|
|
|
|
|
|
|
|
|
|
bool DecodeStream::init(AVPacketQueueManager *queueManager,
|
|
|
|
|
AVFormatContext *formatContext, int videoIndex) {
|
|
|
|
@ -17,6 +17,12 @@ bool DecodeStream::init(AVPacketQueueManager *queueManager,
|
|
|
|
|
} else {
|
|
|
|
|
m_isFile = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_fps = av_q2d(formatContext->streams[videoIndex]->avg_frame_rate);
|
|
|
|
|
if (m_fps <= 0) {
|
|
|
|
|
m_fps = 30.0; // 默认帧率
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return initDecoder(formatContext, videoIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -34,31 +40,98 @@ void DecodeStream::startDecode() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
bool isPlayEnd = false;
|
|
|
|
|
// m_firstFramePTS = AV_NOPTS_VALUE;
|
|
|
|
|
// m_startDecodeTime = AV_NOPTS_VALUE;
|
|
|
|
|
int64_t lastPts = AV_NOPTS_VALUE;
|
|
|
|
|
auto lastDisplayTime =
|
|
|
|
|
std::chrono::high_resolution_clock::now(); // 记录上一帧的显示时间
|
|
|
|
|
m_queueManager->m_isDecodeEnd = false;
|
|
|
|
|
|
|
|
|
|
double startTime = m_startTime / static_cast<double>(AV_TIME_BASE);
|
|
|
|
|
int64_t duration = static_cast<int64_t>(m_duration / AV_TIME_BASE);
|
|
|
|
|
|
|
|
|
|
while (m_start) {
|
|
|
|
|
try {
|
|
|
|
|
// 检查跳转状态
|
|
|
|
|
if (m_queueManager->m_isSeeking) {
|
|
|
|
|
m_queueManager->clearDecodeQueue();
|
|
|
|
|
// 清空解码器缓冲区
|
|
|
|
|
avcodec_flush_buffers(m_codecContext);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AVPacket *inputPacket = m_queueManager->dequeueDecodePacket();
|
|
|
|
|
if (inputPacket) {
|
|
|
|
|
AVFrame *frame = decodePacket(inputPacket);
|
|
|
|
|
// 更新当前播放时间进度
|
|
|
|
|
if (frame && m_isFile) {
|
|
|
|
|
double currentTime = frame->best_effort_timestamp *
|
|
|
|
|
av_q2d(m_outStreamTimeBase);
|
|
|
|
|
double startTime =
|
|
|
|
|
m_startTime / static_cast<double>(AV_TIME_BASE);
|
|
|
|
|
int64_t duration =
|
|
|
|
|
static_cast<int64_t>(m_duration / AV_TIME_BASE);
|
|
|
|
|
qDebug() << currentTime - startTime;
|
|
|
|
|
int64_t currentTime1 =
|
|
|
|
|
static_cast<int64_t>(currentTime - startTime);
|
|
|
|
|
emit updateVideoCurrentTime(currentTime1, duration);
|
|
|
|
|
if (m_queueManager->isEmptyDecodeQueue()) isPlayEnd = true;
|
|
|
|
|
|
|
|
|
|
if (frame) {
|
|
|
|
|
// 播放本地视频
|
|
|
|
|
if (m_isFile) {
|
|
|
|
|
// 计算帧间隔
|
|
|
|
|
if (lastPts != AV_NOPTS_VALUE &&
|
|
|
|
|
frame->pts != AV_NOPTS_VALUE) {
|
|
|
|
|
int64_t ptsDiff = frame->pts - lastPts;
|
|
|
|
|
if (ptsDiff < 0) {
|
|
|
|
|
// 如果 ptsDiff 为负数,说明 pts
|
|
|
|
|
// 不连续,跳过该帧
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
double frameDuration = av_q2d(m_outStreamTimeBase) *
|
|
|
|
|
ptsDiff; // 转换为秒
|
|
|
|
|
// 根据播放速度调整
|
|
|
|
|
double adjustedDuration =
|
|
|
|
|
frameDuration / m_playSpeed;
|
|
|
|
|
|
|
|
|
|
// 计算实际延迟
|
|
|
|
|
auto now =
|
|
|
|
|
std::chrono::high_resolution_clock::now();
|
|
|
|
|
auto elapsed = std::chrono::duration_cast<
|
|
|
|
|
std::chrono::milliseconds>(
|
|
|
|
|
now - lastDisplayTime)
|
|
|
|
|
.count() /
|
|
|
|
|
1000.0;
|
|
|
|
|
double sleepTime = adjustedDuration - elapsed;
|
|
|
|
|
|
|
|
|
|
if (sleepTime > 0) {
|
|
|
|
|
std::this_thread::sleep_for(
|
|
|
|
|
std::chrono::microseconds(
|
|
|
|
|
static_cast<int64_t>(
|
|
|
|
|
sleepTime *
|
|
|
|
|
1000000))); // 微秒级延迟
|
|
|
|
|
}
|
|
|
|
|
// qDebug() << "delay:" << sleepTime * 1000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastPts = frame->pts;
|
|
|
|
|
lastDisplayTime = std::chrono::high_resolution_clock::
|
|
|
|
|
now(); // 更新上一帧的显示时间
|
|
|
|
|
|
|
|
|
|
// qDebug() << frame->best_effort_timestamp;
|
|
|
|
|
// int64_t aaa = frame->best_effort_timestamp;
|
|
|
|
|
// 更新当前播放时间进度
|
|
|
|
|
double currentTime = frame->best_effort_timestamp *
|
|
|
|
|
av_q2d(m_outStreamTimeBase);
|
|
|
|
|
|
|
|
|
|
// qDebug() << currentTime - startTime;
|
|
|
|
|
int64_t currentTime1 =
|
|
|
|
|
static_cast<int64_t>(currentTime - startTime);
|
|
|
|
|
emit updateVideoCurrentTime(currentTime1, duration);
|
|
|
|
|
if (m_queueManager->isEmptyDecodeQueue() &&
|
|
|
|
|
m_queueManager->m_isReadEnd) {
|
|
|
|
|
isPlayEnd = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit repaintSignal(frame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit repaintSignal(frame);
|
|
|
|
|
av_packet_unref(inputPacket);
|
|
|
|
|
av_packet_free(&inputPacket);
|
|
|
|
|
inputPacket = nullptr;
|
|
|
|
|
if (isPlayEnd && m_isFile) break;
|
|
|
|
|
if (isPlayEnd && m_isFile && !m_queueManager->m_isSeeking) {
|
|
|
|
|
m_queueManager->m_isDecodeEnd = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// QThread::usleep(1000);
|
|
|
|
|
// av_usleep(1000);
|
|
|
|
@ -70,9 +143,15 @@ void DecodeStream::startDecode() {
|
|
|
|
|
|
|
|
|
|
free();
|
|
|
|
|
qDebug() << "Decoding Thread End!";
|
|
|
|
|
emit decodeEndSignal();
|
|
|
|
|
emit sendErrorMessageSignal("视频解码结束!", 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DecodeStream::changePlaySpeedSlot(double speed) {
|
|
|
|
|
m_playSpeed = speed;
|
|
|
|
|
qDebug() << "receive changePlaySpeedSlot:" << m_playSpeed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DecodeStream::close() {
|
|
|
|
|
m_start = false;
|
|
|
|
|
qDebug() << "decode Stream close!" << m_start;
|
|
|
|
|