MediaSourceRtsp.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #include <thread>
  2. #include <windows.h>
  3. #include "MediaSourceRtsp.h"
  4. #pragma comment(lib, "avformat.lib")
  5. #pragma comment(lib, "avcodec.lib")
  6. #pragma comment(lib, "avdevice.lib")
  7. #pragma comment(lib, "avutil.lib")
  8. CMediaSourceRtsp::CMediaSourceRtsp()
  9. {
  10. outputContext = nullptr;
  11. inputContext = nullptr;
  12. m_nStartTime = 0;
  13. m_nWriteflag = false;
  14. m_timeout = 2;
  15. m_NetCount = 0;
  16. m_nVideoStream = -1;
  17. av_register_all();
  18. avformat_network_init();
  19. avcodec_register_all();
  20. avdevice_register_all();
  21. }
  22. CMediaSourceRtsp::~CMediaSourceRtsp()
  23. {
  24. CloseInput();
  25. CloseOutput();
  26. }
  27. void CMediaSourceRtsp::CloseInput()
  28. {
  29. if (inputContext) {
  30. avformat_close_input(&inputContext);
  31. inputContext = nullptr;
  32. }
  33. }
  34. void CMediaSourceRtsp::CloseOutput()
  35. {
  36. if (outputContext) {
  37. av_write_trailer(outputContext);
  38. for (int i = 0; i < outputContext->nb_streams; i++)
  39. {
  40. if (outputContext->streams[i]->codec)
  41. avcodec_close(outputContext->streams[i]->codec);
  42. }
  43. avformat_close_input(&outputContext);
  44. outputContext = nullptr;
  45. }
  46. }
  47. void CMediaSourceRtsp::ActionOpenInput()
  48. {
  49. while (1) {
  50. if (OpenInput(m_Input_rtsp, m_TcpOrudp))
  51. break;
  52. std::this_thread::sleep_for(std::chrono::milliseconds(2000));
  53. }
  54. }
  55. void CMediaSourceRtsp::ActionOpenOutput()
  56. {
  57. while (1) {
  58. if (OpenOutput(m_Output_rtsp))
  59. break;
  60. std::this_thread::sleep_for(std::chrono::milliseconds(5000));
  61. }
  62. }
  63. void CMediaSourceRtsp::CheckOutputNet()
  64. {
  65. m_NetCount++;
  66. if (m_NetCount > 500) {
  67. if (outputContext) {
  68. m_NetCount = 0;
  69. m_nWriteflag = false;
  70. CloseOutput();
  71. ActionOpenOutput();
  72. }
  73. }
  74. }
  75. void CMediaSourceRtsp::ResetConnect()
  76. {
  77. if (inputContext) {
  78. CloseInput();
  79. CloseOutput();
  80. }
  81. //这里会一直阻塞,知道视频源和输出源正常连接
  82. ActionOpenInput();
  83. ActionOpenOutput();
  84. }
  85. bool CMediaSourceRtsp::OpenInput(std::string inputUrl, std::string transport)
  86. {
  87. bool result = false;
  88. inputContext = avformat_alloc_context();
  89. AVDictionary* options = nullptr;
  90. if (transport == "tcp") {
  91. av_dict_set(&options, "rtsp_transport", "tcp", 0);
  92. av_dict_set(&options, "stimeout", "2000000", 0);
  93. if (0 > avformat_open_input(&inputContext, inputUrl.c_str(), nullptr, &options)) {
  94. OutputDebugStringA("failed open input file1");
  95. return result;
  96. }
  97. } else {
  98. av_dict_set(&options, "rtsp_transport", "udp", 0);
  99. av_dict_set(&options, "stimeout", "2000000", 0);
  100. if (0 > avformat_open_input(&inputContext, inputUrl.c_str(), nullptr, &options)) {
  101. OutputDebugStringA("failed open input file1");
  102. return result;
  103. }
  104. }
  105. int ret = avformat_find_stream_info(inputContext, nullptr);
  106. if (ret < 0)
  107. {
  108. OutputDebugStringA("Find input file stream inform failed");
  109. return result;
  110. }
  111. m_nVideoStream = av_find_best_stream(inputContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
  112. if (-1 == m_nVideoStream) {
  113. OutputDebugStringA("failed av_find_best_stream");
  114. return result;
  115. }
  116. return true;
  117. }
  118. int CMediaSourceRtsp::InterruptCb(void* ctx)
  119. {
  120. CMediaSourceRtsp* media_source = (CMediaSourceRtsp*)ctx;
  121. if (media_source->m_nWriteflag){
  122. return 0;
  123. }
  124. int64_t localTime = av_gettime();
  125. //1s = 1000*1000微妙
  126. int times = (localTime % (media_source->m_nStartTime))/(1000*1000);
  127. if (times > media_source->m_timeout)
  128. {
  129. return 1;
  130. }
  131. return 0;
  132. }
  133. int CMediaSourceRtsp::WritePacket(std::shared_ptr<AVPacket> packet)
  134. {
  135. auto inputStream = inputContext->streams[packet->stream_index];
  136. auto outputStream = outputContext->streams[packet->stream_index];
  137. av_packet_rescale_ts(packet.get(), inputStream->time_base, outputStream->time_base);
  138. return av_interleaved_write_frame(outputContext, packet.get());
  139. }
  140. std::shared_ptr<AVPacket> CMediaSourceRtsp::ReadPacket()
  141. {
  142. std::shared_ptr<AVPacket> packet(static_cast<AVPacket*>(av_malloc(sizeof(AVPacket))), [&](AVPacket* p) { av_packet_free(&p); av_freep(&p); });
  143. av_init_packet(packet.get());
  144. int ret = av_read_frame(inputContext, packet.get());
  145. if (ret >= 0)
  146. {
  147. return packet;
  148. }
  149. else
  150. {
  151. return nullptr;
  152. }
  153. }
  154. bool CMediaSourceRtsp::OpenOutput(std::string outUrl)
  155. {
  156. bool result = false;
  157. int ret = avformat_alloc_output_context2(&outputContext, nullptr, "rtsp", outUrl.c_str());
  158. if (ret < 0)
  159. {
  160. OutputDebugStringA("open output context failed");
  161. return result;
  162. }
  163. //设置超时回调
  164. outputContext->interrupt_callback.callback = InterruptCb; // 设置超时回调
  165. outputContext->interrupt_callback.opaque = this;
  166. //for (int i = 0; i < inputContext->nb_streams; i++)
  167. //{
  168. // AVStream* stream = avformat_new_stream(outputContext, inputContext->streams[i]->codec->codec);
  169. // ret = avcodec_copy_context(stream->codec, inputContext->streams[i]->codec);
  170. // if (ret < 0)
  171. // {
  172. // av_log(NULL, AV_LOG_ERROR, "copy coddec context failed");
  173. // return result;
  174. // }
  175. //}
  176. AVStream* stream = avformat_new_stream(outputContext, inputContext->streams[m_nVideoStream]->codec->codec);
  177. avcodec_copy_context(stream->codec, inputContext->streams[m_nVideoStream]->codec);
  178. if (ret < 0)
  179. {
  180. OutputDebugStringA("copy coddec context failed");
  181. return result;
  182. }
  183. //需要留意的是发输出是rtsp流时,是不需要调用avio_open,如果你调用了返回值是<0,所以这里m_pOutfmt_ctx->oformat->flags & AVFMT_NOFILE条件判断
  184. if (!(outputContext->oformat->flags & AVFMT_NOFILE)) {
  185. if (0 > avio_open(&outputContext->pb, outUrl.c_str(), AVIO_FLAG_WRITE)) {
  186. OutputDebugStringA("open avio failed");
  187. return result;
  188. }
  189. }
  190. m_nStartTime = av_gettime();
  191. ret = avformat_write_header(outputContext, nullptr);
  192. if (ret < 0)
  193. {
  194. OutputDebugStringA("format write header failed");
  195. return result;
  196. }
  197. m_nWriteflag = true;
  198. return true;
  199. }