CVideoSource.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #include "CVideoSource.h"
  2. #include <process.h>
  3. #include <iostream>
  4. #include <windows.h>
  5. extern "C"
  6. {
  7. #include "libavcodec/avcodec.h"
  8. #include "libavformat/avformat.h"
  9. #include "libavutil/frame.h"
  10. #include "libavcodec/bsf.h"
  11. };
  12. #include "CSyncProc.h"
  13. #include "CVideoDataManager.h"
  14. #pragma comment(lib, "avcodec.lib")
  15. #pragma comment(lib, "avformat.lib")
  16. #pragma comment(lib, "avutil.lib")
  17. #pragma comment(lib, "avdevice.lib")
  18. #pragma comment(lib, "avfilter.lib")
  19. #pragma comment(lib, "postproc.lib")
  20. #pragma comment(lib, "swresample.lib")
  21. #pragma comment(lib, "swscale.lib")
  22. AVHWDeviceType CVideoSource::m_HardType = AV_HWDEVICE_TYPE_NONE;
  23. AVPixelFormat CVideoSource::m_pixelFormat = AV_PIX_FMT_NONE;
  24. bool CVideoSource::m_bUseHardDecode = true;
  25. CVideoSource::CVideoSource()
  26. {
  27. }
  28. CVideoSource::~CVideoSource()
  29. {
  30. Clear();
  31. }
  32. bool CVideoSource::IsHardDecode()
  33. {
  34. //return false;
  35. if (!m_bUseHardDecode)
  36. {
  37. return false;
  38. }
  39. //已经检测过
  40. if (m_HardType != AV_HWDEVICE_TYPE_NONE)
  41. {
  42. return true;
  43. }
  44. m_HardType = av_hwdevice_find_type_by_name("cuda");
  45. if (m_HardType != AV_HWDEVICE_TYPE_NONE)
  46. {
  47. return true;
  48. }
  49. while ((m_HardType = av_hwdevice_iterate_types(m_HardType)) != AV_HWDEVICE_TYPE_NONE)
  50. {
  51. return true;
  52. }
  53. //m_HardType = AV_HWDEVICE_TYPE_VULKAN;
  54. /*AV_HWDEVICE_TYPE_VDPAU,
  55. AV_HWDEVICE_TYPE_CUDA,
  56. AV_HWDEVICE_TYPE_VAAPI,
  57. AV_HWDEVICE_TYPE_DXVA2,
  58. AV_HWDEVICE_TYPE_QSV,
  59. AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
  60. AV_HWDEVICE_TYPE_D3D11VA,
  61. AV_HWDEVICE_TYPE_DRM,
  62. AV_HWDEVICE_TYPE_OPENCL,
  63. AV_HWDEVICE_TYPE_MEDIACODEC,
  64. AV_HWDEVICE_TYPE_VULKAN,*/
  65. return false;
  66. }
  67. AVPixelFormat CVideoSource::GetpPixelFormat(AVCodecContext* ctx, const enum AVPixelFormat* fmts)
  68. {
  69. const enum AVPixelFormat* p;
  70. for (p = fmts; *p != AV_PIX_FMT_NONE; p++) {
  71. if (*p == m_pixelFormat) {
  72. return *p;
  73. }
  74. }
  75. return AV_PIX_FMT_NONE;
  76. }
  77. bool CVideoSource::Init(const char * szUrl, CVideoDataManager * pDataManager)
  78. {
  79. m_pDataManager = pDataManager;
  80. auto memberFunc1 = std::bind(&CVideoDataManager::AlignRecvData, m_pDataManager);
  81. CSyncProc::getInstance().AddFun(this, memberFunc1);
  82. int ret;
  83. AVDictionary* options = NULL;
  84. av_dict_set(&options, "rtsp_transport", "tcp", 0);
  85. av_dict_set(&options, "probesize", "10240", 0);
  86. if (avformat_open_input(&m_pFormatCtx, szUrl, NULL, &options) != 0)
  87. {
  88. return false;
  89. }
  90. if ((ret = avformat_find_stream_info(m_pFormatCtx, NULL)) < 0)
  91. {
  92. return false;
  93. }
  94. // 最后一个参数目前未定义,填写0 即可
  95. // 找到指定流类型的流信息,并且初始化codec(如果codec没有值)
  96. AVCodec *decoder = nullptr;
  97. if ((ret = av_find_best_stream(m_pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, (const AVCodec **)&decoder, 0)) < 0)
  98. {
  99. return false;
  100. }
  101. m_nVideoIndex = ret;
  102. AVCodec* decoderVideo = nullptr;
  103. AVBufferRef* hw_device_ctx = NULL;
  104. if (IsHardDecode())
  105. {
  106. // 根据解码器获取支持此解码方式的硬件加速计
  107. /** 所有支持的硬件解码器保存在AVCodec的hw_configs变量中。对于硬件编码器来说又是单独的AVCodec
  108. */
  109. if (m_pixelFormat == AV_PIX_FMT_NONE)
  110. {
  111. for (int i = 0;; i++)
  112. {
  113. const AVCodecHWConfig* hwcodec = avcodec_get_hw_config(decoder, i);
  114. if (hwcodec == NULL) break;
  115. // 可能一个解码器对应着多个硬件加速方式,所以这里将其挑选出来
  116. if (hwcodec->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && hwcodec->device_type == m_HardType)
  117. {
  118. m_pixelFormat = hwcodec->pix_fmt;
  119. break;
  120. }
  121. }
  122. }
  123. if ((m_pCodecContextVideo = avcodec_alloc_context3(decoder)) == NULL)
  124. {
  125. return false;
  126. }
  127. AVStream* video_stream = m_pFormatCtx->streams[m_nVideoIndex];
  128. // 给解码器赋值解码相关参数
  129. if (avcodec_parameters_to_context(m_pCodecContextVideo, video_stream->codecpar) < 0) {
  130. return false;
  131. }
  132. // 配置获取硬件加速器像素格式的函数;该函数实际上就是将AVCodec中AVHWCodecConfig中的pix_fmt返回
  133. //m_pCodecContext->get_format = &CFfmpegProc::GetpPixelFormat;
  134. // 创建硬件加速器的缓冲区
  135. if (ret = av_hwdevice_ctx_create(&hw_device_ctx, m_HardType, NULL, NULL, 0) < 0) {
  136. return false;
  137. }
  138. /** 如果使用软解码则默认有一个软解码的缓冲区(获取AVFrame的),而硬解码则需要额外创建硬件解码的缓冲区
  139. * 这个缓冲区变量为hw_frames_ctx,不手动创建,则在调用avcodec_send_packet()函数内部自动创建一个
  140. * 但是必须手动赋值硬件解码缓冲区引用hw_device_ctx(它是一个AVBufferRef变量)
  141. */
  142. // 即hw_device_ctx有值则使用硬件解码
  143. m_pCodecContextVideo->hw_device_ctx = av_buffer_ref(hw_device_ctx);
  144. av_buffer_unref(&hw_device_ctx);
  145. // 初始化并打开解码器上下文
  146. if (avcodec_open2(m_pCodecContextVideo, decoder, NULL) < 0)
  147. {
  148. return false;
  149. }
  150. }
  151. else
  152. {
  153. decoderVideo = (AVCodec*)avcodec_find_decoder(m_pFormatCtx->streams[m_nVideoIndex]->codecpar->codec_id);
  154. if (decoderVideo == nullptr)
  155. {
  156. return false;
  157. }
  158. m_pCodecContextVideo = avcodec_alloc_context3(decoderVideo);
  159. //AV_CODEC_ID_PCM_ALAW
  160. avcodec_parameters_to_context(m_pCodecContextVideo, m_pFormatCtx->streams[m_nVideoIndex]->codecpar);
  161. //打开解码器
  162. if (avcodec_open2(m_pCodecContextVideo, 0, 0) < 0)
  163. {
  164. return false;
  165. }
  166. }
  167. m_nWidth = m_pFormatCtx->streams[m_nVideoIndex]->codecpar->width;
  168. m_nHeight = m_pFormatCtx->streams[m_nVideoIndex]->codecpar->height ;
  169. m_eVideoCodec = m_pFormatCtx->streams[m_nVideoIndex]->codecpar->codec_id;
  170. InitAudio();
  171. _beginthreadex(nullptr, 0, &CVideoSource::RecvThread, this, 0, 0);
  172. }
  173. void CVideoSource::Clear()
  174. {
  175. if (m_pFormatCtx!=nullptr)
  176. {
  177. avformat_close_input(&m_pFormatCtx);
  178. m_pFormatCtx = nullptr;
  179. }
  180. if (m_pCodecContextAudio != nullptr)
  181. {
  182. avcodec_close(m_pCodecContextAudio);
  183. m_pCodecContextAudio = nullptr;
  184. }
  185. }
  186. unsigned __stdcall CVideoSource::RecvThread(void * param)
  187. {
  188. CVideoSource* p = (CVideoSource*)param;
  189. p->RecvThreadProcessor();
  190. return 0;
  191. }
  192. void CVideoSource::RecvThreadProcessor()
  193. {
  194. while (true)
  195. {
  196. RecvFrameSync();
  197. }
  198. }
  199. bool CVideoSource::InitAudio()
  200. {
  201. int ret;
  202. AVCodec *decoderAudio = nullptr;
  203. if ((ret = av_find_best_stream(m_pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, (const AVCodec **)&decoderAudio, 0)) < 0)
  204. {
  205. return false;
  206. }
  207. m_nAudioIndex = ret;
  208. decoderAudio = (AVCodec *)avcodec_find_decoder(m_pFormatCtx->streams[m_nAudioIndex]->codecpar->codec_id);
  209. if (decoderAudio == nullptr)
  210. {
  211. return false;
  212. }
  213. m_pCodecContextAudio = avcodec_alloc_context3(decoderAudio);
  214. //AV_CODEC_ID_PCM_ALAW
  215. avcodec_parameters_to_context(m_pCodecContextAudio, m_pFormatCtx->streams[m_nAudioIndex]->codecpar);
  216. //打开解码器
  217. if (avcodec_open2(m_pCodecContextAudio, 0, 0) < 0)
  218. {
  219. return false;
  220. }
  221. }
  222. int CVideoSource::RecvFrameSync()
  223. {
  224. int nRet = 0;
  225. AVPacket *packet = av_packet_alloc();
  226. nRet = av_read_frame(m_pFormatCtx, packet);
  227. if (nRet < 0)
  228. {
  229. return RECV_FAILED;
  230. }
  231. if (packet->stream_index != m_nVideoIndex)
  232. {
  233. AudioProc(packet);
  234. av_packet_free(&packet);
  235. return RECV_SUCCESS_NOTPROC;
  236. }
  237. m_pDataManager->AddRecvData(packet->pts, packet, packet->flags&AV_PKT_FLAG_KEY );
  238. //av_packet_free(&packet);
  239. return RECV_SUCCESS;
  240. }
  241. int CVideoSource::AudioProc(AVPacket * pktAudio)
  242. {
  243. int nRet = 0;
  244. avcodec_send_packet(m_pCodecContextAudio, pktAudio);
  245. AVFrame * pFramAudio = av_frame_alloc();
  246. nRet = avcodec_receive_frame(m_pCodecContextAudio, pFramAudio);
  247. if (nRet < 0)
  248. {
  249. return RECV_FAILED;
  250. }
  251. int32_t nSum = 0;
  252. for (int i = 0; i < pFramAudio->linesize[0] * pFramAudio->channels; i = i + 2)
  253. {
  254. int16_t word16 = 0;
  255. word16 = (int16_t)(pFramAudio->data[0][i+1] << 8);
  256. word16 +=(pFramAudio->data[0][i]);
  257. if (word16<0)
  258. {
  259. word16 = abs(word16);
  260. word16 = ~word16 + 1;
  261. //word16 |= 0x8000;
  262. }
  263. //OutputDebugPrintf("VideoPlayer AudioProc word16 1--- %d", word16);
  264. //word16 = bit_reverse(word16);
  265. nSum += abs(word16);
  266. }
  267. av_frame_free(&pFramAudio);
  268. //通过多次数据采集分析,能量值大于80000 确保是有同步信号
  269. if (nSum < 80000)
  270. {
  271. return RECV_SUCCESS;
  272. }
  273. double pts = 0;
  274. pts = av_q2d(m_pCodecContextAudio->time_base)* pktAudio->pts;
  275. //出现 音频的同步信号,3秒以内认为是同一个信号,认为无效
  276. if (pts - m_curAutdioPts < 3)
  277. {
  278. return RECV_SUCCESS;
  279. }
  280. m_curAutdioPts = pts;
  281. m_pDataManager->SetAutdioPts(m_curAutdioPts);
  282. CSyncProc::getInstance().UpdateTimeQueue(m_pDataManager, m_curAutdioPts);
  283. }