|
@@ -4,16 +4,19 @@
|
|
|
#include <QDebug>
|
|
|
|
|
|
#include "LHQLogAPI.h"
|
|
|
+#include "Transcode.h"
|
|
|
|
|
|
|
|
|
CameraPlayer::CameraPlayer(QObject *parent) : QObject(parent)
|
|
|
{
|
|
|
// qDebug() << "主线程ID:" << QThread::currentThreadId();
|
|
|
|
|
|
- m_yuvQueue = new RingQueue<Image_YUV420*>(10);
|
|
|
- m_yuvQueue->setDefaultValue(nullptr);
|
|
|
+ // m_imageQueue = new RingQueue<Image_YUV420*>(10);
|
|
|
+ m_imageQueue.setQueueCapacity(10);
|
|
|
+ m_imageQueue.setDefaultValue(nullptr);
|
|
|
|
|
|
- m_player = new PlayerGLWidget();
|
|
|
+ // m_player = new PlayerGLWidget();
|
|
|
+ m_player = new PlayerWidget();
|
|
|
/* 连接信号和槽 */
|
|
|
connect(&m_frameTimer, &QTimer::timeout, this, &CameraPlayer::do_updateFrame);
|
|
|
}
|
|
@@ -117,6 +120,12 @@ bool CameraPlayer::realPlay(int channel)
|
|
|
// NET_DVR_SetStandardDataCallBack(m_realPlayHandle, realDataCallBackStandard, 0);
|
|
|
// NET_DVR_SetRealDataCallBackEx(m_realPlayHandle, realDataCallBack, nullptr);
|
|
|
|
|
|
+ /* 创建转码实例 */
|
|
|
+ if(m_transCode == nullptr)
|
|
|
+ {
|
|
|
+ m_transCode = new TransCode();
|
|
|
+ }
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -158,13 +167,13 @@ void CameraPlayer::setPlayWndSize(int width, int height)
|
|
|
void CameraPlayer::do_updateFrame()
|
|
|
{
|
|
|
/* 获取一帧 */
|
|
|
- if(m_yuvQueue->isEmpty())
|
|
|
+ if(m_imageQueue.isEmpty())
|
|
|
{
|
|
|
- LH_WRITE_LOG("环形队列为空,无法更新一帧数据");
|
|
|
+ // LH_WRITE_LOG("图像环形队列为空,无法更新一帧数据");
|
|
|
return;
|
|
|
}
|
|
|
/* 以非阻塞的方式先获取一帧数据,获取成功后再出队 */
|
|
|
- auto one = m_yuvQueue->front_pop_NoBlock();
|
|
|
+ auto one = m_imageQueue.front_pop_NoBlock();
|
|
|
if(one != nullptr)
|
|
|
{
|
|
|
m_player->updateFrame(*one);
|
|
@@ -246,7 +255,7 @@ void CameraPlayer::realDataCallBack(LONG realHandle, DWORD dataType, BYTE *pBuff
|
|
|
{
|
|
|
cameraPlayer->m_playPort = playPort;
|
|
|
/* 最后一个参数是 设置播放器中存放数据流的缓冲区大小,不能太大也不能太小 */
|
|
|
- if(!PlayM4_OpenStream(playPort, pBuffer, bufSize, 1024 * 1024))
|
|
|
+ if(!PlayM4_OpenStream(playPort, pBuffer, bufSize, 1024 * 1024 * 10))
|
|
|
{
|
|
|
auto ret = PlayM4_GetLastError(playPort);
|
|
|
LH_WRITE_ERROR(QString("打开流失败,错误代码: %1").arg(ret));
|
|
@@ -285,10 +294,18 @@ void CameraPlayer::realDataCallBack(LONG realHandle, DWORD dataType, BYTE *pBuff
|
|
|
if(bufSize > 0 && playPort != -1)
|
|
|
{
|
|
|
auto ret = PlayM4_InputData(playPort, pBuffer, bufSize);
|
|
|
- if(!ret)
|
|
|
+ while(!ret)
|
|
|
{
|
|
|
- LH_WRITE_ERROR("解码数据失败");
|
|
|
- break;
|
|
|
+ auto errNum = PlayM4_GetLastError(playPort);
|
|
|
+ if(errNum == PLAYM4_BUF_OVER)
|
|
|
+ {
|
|
|
+ LH_WRITE_ERROR("数据解码失败, 缓冲区满, 需要重新输入");
|
|
|
+ /* 重新发送给解码器 */
|
|
|
+ ret = PlayM4_InputData(playPort, pBuffer, bufSize);
|
|
|
+ }else {
|
|
|
+ LH_WRITE_ERROR(QString("数据解码失败, 其他错误: %1").arg(errNum));
|
|
|
+ }
|
|
|
+ // std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
@@ -344,6 +361,9 @@ void CameraPlayer::realDataCallBackStandard(LONG realHandle, DWORD dataType, BYT
|
|
|
*/
|
|
|
void CameraPlayer::DecCallBack(int nPort,char * pBuf,int nSize,FRAME_INFO * pFrameInfo, void* nUser,int nReserved2)
|
|
|
{
|
|
|
+ /* 获取当前时间 */
|
|
|
+ // auto now = std::chrono::system_clock::now();
|
|
|
+
|
|
|
auto player = static_cast<CameraPlayer*>(nUser);
|
|
|
// LH_WRITE_LOG(QString("解码回调函数,解码通道号: %1 %2").arg(nPort).arg(player->m_playPort));
|
|
|
// qDebug() << "DecCallBack所在的线程:" << QThread::currentThreadId();
|
|
@@ -361,21 +381,26 @@ void CameraPlayer::DecCallBack(int nPort,char * pBuf,int nSize,FRAME_INFO * pFra
|
|
|
}
|
|
|
int width = pFrameInfo->nWidth;
|
|
|
int height = pFrameInfo->nHeight;
|
|
|
- LH_WRITE_LOG_DEBUG(QString("视频宽高: %1 x %2, 视频帧率: %3").arg(width).arg(height).arg(frameRate));
|
|
|
+
|
|
|
+ LH_WRITE_LOG_DEBUG(QString("视频宽高: %1 x %2, 视频帧率: %3, 当前队列数目: %4").arg(width).arg(height).arg(frameRate).arg(player->m_imageQueue.QueueSize()));
|
|
|
|
|
|
/* 截图标志位,保存图片 */
|
|
|
|
|
|
/* 转换成yuv,保存到环形队列中 */
|
|
|
- Image_YUV420* image = new Image_YUV420();
|
|
|
- player->YV12ToYUV420((unsigned char*)pBuf, *image, width, height);
|
|
|
+ // Image_YUV420* image = new Image_YUV420();
|
|
|
+ // player->m_transCode->YV12ToYUV420((unsigned char*)pBuf, *image, width, height);
|
|
|
+
|
|
|
+ Image_QImage* image = new Image_QImage();
|
|
|
+ player->m_transCode->YV12ToQImage((unsigned char*)pBuf, *image, width, height);
|
|
|
+
|
|
|
/* 判断环形队列是否满了,满了就出队一个 */
|
|
|
- if(player->m_yuvQueue->isFull())
|
|
|
+ if(player->m_imageQueue.isFull())
|
|
|
{
|
|
|
- LH_WRITE_LOG_DEBUG("环形队列满了,出队一个");
|
|
|
- auto one = player->m_yuvQueue->front_pop();
|
|
|
+ // LH_WRITE_LOG_DEBUG("图像环形队列满了,出队一个");
|
|
|
+ auto one = player->m_imageQueue.front_pop();
|
|
|
delete one;
|
|
|
}
|
|
|
- player->m_yuvQueue->push_NoBlock(image);
|
|
|
+ player->m_imageQueue.push_NoBlock(image);
|
|
|
}
|
|
|
else if(pFrameInfo->nType == T_AUDIO16)
|
|
|
{
|
|
@@ -384,109 +409,10 @@ void CameraPlayer::DecCallBack(int nPort,char * pBuf,int nSize,FRAME_INFO * pFra
|
|
|
{
|
|
|
LH_WRITE_LOG("其他数据");
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
-/* YV12转RGB888 */
|
|
|
-void CameraPlayer::YV12ToRGB888(unsigned char *pYV12Data, unsigned char *pRGB24Data, int width, int height)
|
|
|
-{
|
|
|
- int ySize = width * height;
|
|
|
- int uvSize = ySize / 4;
|
|
|
-
|
|
|
- const uint8_t* yData = pYV12Data;
|
|
|
- const uint8_t* vData = pYV12Data + ySize;
|
|
|
- const uint8_t* uData = pYV12Data + ySize + uvSize;
|
|
|
-
|
|
|
- for (int y = 0; y < height; y++) {
|
|
|
- for (int x = 0; x < width; x++) {
|
|
|
- int yIndex = y * width + x;
|
|
|
- int uvIndex = (y / 2) * (width / 2) + (x / 2);
|
|
|
-
|
|
|
- uint8_t Y = yData[yIndex];
|
|
|
- uint8_t U = uData[uvIndex];
|
|
|
- uint8_t V = vData[uvIndex];
|
|
|
-
|
|
|
- // YUV 转 RGB
|
|
|
- int R = Y + 1.403 * (V - 128);
|
|
|
- int G = Y - 0.344 * (U - 128) - 0.714 * (V - 128);
|
|
|
- int B = Y + 1.770 * (U - 128);
|
|
|
-
|
|
|
- // 限制范围 [0, 255]
|
|
|
- R = std::min(std::max(R, 0), 255);
|
|
|
- G = std::min(std::max(G, 0), 255);
|
|
|
- B = std::min(std::max(B, 0), 255);
|
|
|
-
|
|
|
- // 存储 RGB 数据
|
|
|
- int rgbIndex = yIndex * 3;
|
|
|
- pRGB24Data[rgbIndex] = static_cast<uint8_t>(R);
|
|
|
- pRGB24Data[rgbIndex + 1] = static_cast<uint8_t>(G);
|
|
|
- pRGB24Data[rgbIndex + 2] = static_cast<uint8_t>(B);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* YV12转YUV420 */
|
|
|
-// void CameraPlayer::YV12ToYUV420(unsigned char *pYV12Data, Image_YUV420& yuvData, int width, int height)
|
|
|
-// {
|
|
|
- // int y_size = width * height;
|
|
|
- // int uv_size = y_size / 4;
|
|
|
-
|
|
|
- // // 分配 YUV 数据的空间
|
|
|
- // yuvData.yData.resize(y_size);
|
|
|
- // yuvData.uData.resize(uv_size);
|
|
|
- // yuvData.vData.resize(uv_size);
|
|
|
-
|
|
|
- // // 提取 Y、V、U 分量
|
|
|
- // const uint8_t* y = vecYUV.data();
|
|
|
- // const uint8_t* v = vecYUV.data() + y_size;
|
|
|
- // const uint8_t* u = vecYUV.data() + y_size + uv_size;
|
|
|
-
|
|
|
- // // 复制 Y 分量
|
|
|
- // std::memcpy(vecYUV.data(), y, y_size);
|
|
|
-
|
|
|
- // // 复制 U 分量
|
|
|
- // uint8_t* yuv_u = vecYUV.data() + y_size;
|
|
|
- // for (int i = 0; i < uv_size; ++i) {
|
|
|
- // yuv_u[i] = u[i];
|
|
|
- // }
|
|
|
-
|
|
|
- // // 复制 V 分量
|
|
|
- // uint8_t* yuv_v = vecYUV.data() + y_size + uv_size;
|
|
|
- // for (int i = 0; i < uv_size; ++i) {
|
|
|
- // yuv_v[i] = v[i];
|
|
|
- // }
|
|
|
-// }
|
|
|
-
|
|
|
-void CameraPlayer::YV12ToYUV420(unsigned char *pYV12Data, Image_YUV420& yuvData, int width, int height)
|
|
|
-{
|
|
|
- int y_size = width * height;
|
|
|
- int uv_size = y_size / 4;
|
|
|
-
|
|
|
- // 分配 YUV 数据的空间
|
|
|
- yuvData.yData.resize(y_size);
|
|
|
- yuvData.uData.resize(uv_size);
|
|
|
- yuvData.vData.resize(uv_size);
|
|
|
-
|
|
|
- // 提取 Y、V、U 分量
|
|
|
- const uint8_t* y = pYV12Data;
|
|
|
- const uint8_t* v = pYV12Data + y_size;
|
|
|
- const uint8_t* u = pYV12Data + y_size + uv_size;
|
|
|
-
|
|
|
- // 复制 Y 分量
|
|
|
- // std::memcpy(yuvData.yData.data(), y, y_size);
|
|
|
- yuvData.yData = QByteArray((const char*)y, y_size);
|
|
|
-
|
|
|
- // 复制 U 分量
|
|
|
- // std::memcpy(yuvData.uData.data(), u, uv_size);
|
|
|
- yuvData.uData.append((const char*)u, uv_size);
|
|
|
-
|
|
|
- // 复制 V 分量
|
|
|
- // std::memcpy(yuvData.vData.data(), v, uv_size);
|
|
|
- yuvData.vData.append((const char*)v, uv_size);
|
|
|
-
|
|
|
- /* 设置宽和高 */
|
|
|
- yuvData.width = width;
|
|
|
- yuvData.height = height;
|
|
|
+ /* 计算解码时间 */
|
|
|
+ // auto lastTime = std::chrono::system_clock::now();
|
|
|
+ // auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(lastTime - now);
|
|
|
+ // LH_WRITE_LOG_DEBUG(QString("解码时间: %1 ms").arg(duration.count()));
|
|
|
}
|
|
|
|