decode.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. void HaiKangHelper::yv12toYuv(const quint8 *yuv420, quint8 *y, quint8 *u, quint8 *v, int width, int height)
  2. {
  3. //Y分量的长度
  4. int yLen = width * height;
  5. //U和V分量的长度
  6. int uvLen = width / 2 * height / 2;
  7. //海康的uv是反的需要反过来否则颜色发蓝
  8. memcpy((quint8 *)y, yuv420, yLen);
  9. memcpy((quint8 *)v, yuv420 + yLen, uvLen);
  10. memcpy((quint8 *)u, yuv420 + yLen + uvLen, uvLen);
  11. }
  12. void HaiKangHelper::yv12toYuv(const quint8 *yv12, quint8 *yuv, int width, int height, int widthStep)
  13. {
  14. int col, row;
  15. int tmp, idx;
  16. uint y, u, v;
  17. for (row = 0; row < height; row++) {
  18. idx = row * widthStep;
  19. for (col = 0; col < width; col++) {
  20. tmp = (row / 2) * (width / 2) + (col / 2);
  21. y = (uint)yv12[row * width + col];
  22. u = (uint)yv12[width * height + width * height / 4 + tmp];
  23. v = (uint)yv12[width * height + tmp];
  24. yuv[idx + col * 3] = y;
  25. yuv[idx + col * 3 + 1] = u;
  26. yuv[idx + col * 3 + 2] = v;
  27. }
  28. }
  29. }
  30. void HaiKangHelper::ExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser)
  31. {
  32. //具体类型含义看头文件或者手册即可
  33. HaiKangThread *thread = (HaiKangThread *)pUser;
  34. thread->debug("异常回调", "");
  35. switch (dwType) {
  36. case EXCEPTION_RECONNECT:
  37. thread->debug("超时重连", "");
  38. break;
  39. default:
  40. break;
  41. }
  42. }
  43. void HaiKangHelper::RealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser)
  44. {
  45. //每个类都对应自己的port
  46. HaiKangCallbackData *callbackData = (HaiKangCallbackData *)pUser;
  47. HaiKangThread *thread = callbackData->thread;
  48. LONG nPort = thread->port;
  49. DWORD dRet;
  50. switch (dwDataType) {
  51. case NET_DVR_SYSHEAD:
  52. //获取播放库未使用的通道号
  53. if (!PlayM4_GetPort(&nPort)) {
  54. break;
  55. }
  56. if (dwBufSize > 0) {
  57. thread->port = nPort;
  58. if (!PlayM4_OpenStream(nPort, pBuffer, dwBufSize, 1024 * 1024)) {
  59. dRet = PlayM4_GetLastError(nPort);
  60. break;
  61. }
  62. //设置解码回调函数,只解码不显示
  63. bool result = PlayM4_SetDecCallBackMend(nPort, DecCallBack, pUser);
  64. if (!result) {
  65. dRet = PlayM4_GetLastError(nPort);
  66. break;
  67. }
  68. //打开视频解码
  69. if (!PlayM4_Play(nPort, NULL)) {
  70. dRet = PlayM4_GetLastError(nPort);
  71. break;
  72. }
  73. //打开音频解码,需要码流是复合流
  74. if (!PlayM4_PlaySound(nPort)) {
  75. dRet = PlayM4_GetLastError(nPort);
  76. break;
  77. }
  78. }
  79. break;
  80. case NET_DVR_STREAMDATA:
  81. //解码数据
  82. if (dwBufSize > 0 && nPort != -1) {
  83. BOOL inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);
  84. while (!inData) {
  85. //sleep(10);
  86. qApp->processEvents();
  87. inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);
  88. }
  89. }
  90. break;
  91. }
  92. }
  93. void HaiKangHelper::FileEndCallback(LONG nPort, void *pUser)
  94. {
  95. HaiKangThread *thread = (HaiKangThread *)pUser;
  96. thread->stop2();
  97. }
  98. //void HaiKangHelper::DecCallBack(LONG nPort, char *pBuf, LONG nSize, FRAME_INFO *pFrameInfo, LONG pUser, LONG nReserved2)
  99. #ifdef Q_OS_WIN
  100. void HaiKangHelper::DecCallBack(LONG nPort, char *pBuf, LONG nSize, FRAME_INFO *pFrameInfo, void *pUser, void *nReserved2)
  101. #else
  102. void HaiKangHelper::DecCallBack(LONG nPort, char *pBuf, LONG nSize, FRAME_INFO *pFrameInfo, void *pUser, LONG nReserved2)
  103. #endif
  104. {
  105. HaiKangCallbackData *callbackData = (HaiKangCallbackData *)pUser;
  106. HaiKangThread *thread = callbackData->thread;
  107. if (thread->getIsPause()) {
  108. return;
  109. }
  110. quint8 *data = (quint8 *)pBuf;
  111. long frameType = pFrameInfo->nType;
  112. //编码时产生的图像帧率(如果是音频数据则为采样率)
  113. long frameRate = pFrameInfo->nFrameRate;
  114. //视频数据是 T_YV12 音频数据是 T_AUDIO16
  115. if (frameType == T_YV12) {
  116. long width = pFrameInfo->nWidth;
  117. long height = pFrameInfo->nHeight;
  118. //识别尺寸发生变化
  119. thread->checkVideoSize(width, height);
  120. //thread->debug("回调视频", QString("宽高: %1x%2").arg(width).arg(height));
  121. //如果处于截图标志位则立即将图片保存
  122. if (thread->getIsSnap()) {
  123. QImage image(width, height, QImage::Format_RGB888);
  124. yv12ToRgb888(data, image.bits(), width, height);
  125. image.save(thread->getSnapName(), "jpg");
  126. QMetaObject::invokeMethod(thread, "snapFinsh");
  127. }
  128. //如果是绘制则转成图片否则转成yuv用opengl绘制
  129. if (thread->getVideoMode() == VideoMode_Opengl) {
  130. yv12toYuv(data, callbackData->dataY, callbackData->dataU, callbackData->dataV, width, height);
  131. thread->setYuv(width, height, callbackData->dataY, callbackData->dataU, callbackData->dataV);
  132. } else {
  133. QImage image(width, height, QImage::Format_RGB888);
  134. yv12ToRgb888(data, image.bits(), width, height);
  135. thread->setImage(image);
  136. }
  137. } else if (frameType == T_AUDIO16) {
  138. //thread->debug("回调音频", QString("采样: %1").arg(frameRate));
  139. }
  140. }