video_parser.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*************************************************************************
  2. * Copyright (C) [2020] by Cambricon, Inc. All rights reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  13. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  15. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. * THE SOFTWARE.
  19. *************************************************************************/
  20. #include "video_parser.h"
  21. #include <atomic>
  22. #include <chrono>
  23. #include <thread>
  24. #include "cxxutil/log.h"
  25. #include "easycodec/easy_decode.h"
  26. #ifdef __cplusplus
  27. extern "C" {
  28. #endif
  29. #include <libavcodec/avcodec.h>
  30. #include <libavformat/avformat.h>
  31. #include <libavutil/avutil.h>
  32. #include <libavutil/imgutils.h>
  33. #ifdef __cplusplus
  34. }
  35. #endif
  36. #ifdef __GNUC__
  37. #pragma GCC diagnostic push
  38. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  39. #endif
  40. #define FFMPEG_VERSION_3_1 AV_VERSION_INT(57, 40, 100)
  41. namespace detail {
  42. static int InterruptCallBack(void* ctx) {
  43. VideoParser* parser = reinterpret_cast<VideoParser*>(ctx);
  44. if (parser->CheckTimeout()) {
  45. LOGD(SAMPLES) << "[RTSP] Get interrupt and timeout";
  46. return 1;
  47. }
  48. return 0;
  49. }
  50. } // namespace detail
  51. bool VideoParser::CheckTimeout() {
  52. std::chrono::duration<float, std::milli> dura = std::chrono::steady_clock::now() - last_receive_frame_time_;
  53. if (dura.count() > max_receive_timeout_) {
  54. return true;
  55. }
  56. return false;
  57. }
  58. bool VideoParser::Open(const char *url, bool save_file) {
  59. static struct _InitFFmpeg {
  60. _InitFFmpeg() {
  61. // init ffmpeg
  62. avcodec_register_all();
  63. av_register_all();
  64. avformat_network_init();
  65. }
  66. } _init_ffmpeg;
  67. is_rtsp_ = ::IsRtsp(url);
  68. if (have_video_source_.load()) return false;
  69. // format context
  70. p_format_ctx_ = avformat_alloc_context();
  71. if (!p_format_ctx_) return false;
  72. if (is_rtsp_) {
  73. AVIOInterruptCB intrpt_callback = {detail::InterruptCallBack, this};
  74. p_format_ctx_->interrupt_callback = intrpt_callback;
  75. last_receive_frame_time_ = std::chrono::steady_clock::now();
  76. // options
  77. av_dict_set(&options_, "buffer_size", "1024000", 0);
  78. av_dict_set(&options_, "max_delay", "500000", 0);
  79. av_dict_set(&options_, "stimeout", "20000000", 0);
  80. av_dict_set(&options_, "rtsp_flags", "prefer_tcp", 0);
  81. } else {
  82. av_dict_set(&options_, "buffer_size", "1024000", 0);
  83. av_dict_set(&options_, "stimeout", "200000", 0);
  84. }
  85. // open input
  86. int ret_code = avformat_open_input(&p_format_ctx_, url, NULL, &options_);
  87. if (0 != ret_code) {
  88. LOGE(SAMPLES) << "couldn't open input stream: " << url;
  89. return false;
  90. }
  91. // find video stream information
  92. ret_code = avformat_find_stream_info(p_format_ctx_, NULL);
  93. if (ret_code < 0) {
  94. LOGE(SAMPLES) << "couldn't find stream information.";
  95. return false;
  96. }
  97. video_index_ = -1;
  98. AVStream *vstream = nullptr;
  99. for (uint32_t iloop = 0; iloop < p_format_ctx_->nb_streams; iloop++) {
  100. vstream = p_format_ctx_->streams[iloop];
  101. #if LIBAVFORMAT_VERSION_INT >= FFMPEG_VERSION_3_1
  102. if (vstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  103. #else
  104. if (vstream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  105. #endif
  106. video_index_ = iloop;
  107. break;
  108. }
  109. }
  110. if (video_index_ == -1) {
  111. LOGE(SAMPLES) << "didn't find a video stream.";
  112. return false;
  113. }
  114. info_.width = vstream->codec->width;
  115. info_.height = vstream->codec->height;
  116. // Get codec id, check progressive
  117. #if LIBAVFORMAT_VERSION_INT >= FFMPEG_VERSION_3_1
  118. auto codec_id = vstream->codecpar->codec_id;
  119. int field_order = vstream->codecpar->field_order;
  120. #else
  121. auto codec_id = vstream->codec->codec_id;
  122. int field_order = vstream->codec->field_order;
  123. #endif
  124. /*
  125. * At this moment, if the demuxer does not set this value (avctx->field_order == UNKNOWN),
  126. * the input stream will be assumed as progressive one.
  127. */
  128. switch (field_order) {
  129. case AV_FIELD_TT:
  130. case AV_FIELD_BB:
  131. case AV_FIELD_TB:
  132. case AV_FIELD_BT:
  133. info_.progressive = 0;
  134. break;
  135. case AV_FIELD_PROGRESSIVE: // fall through
  136. default:
  137. info_.progressive = 1;
  138. break;
  139. }
  140. // get extra data
  141. #if LIBAVFORMAT_VERSION_INT >= FFMPEG_VERSION_3_1
  142. uint8_t* extradata = vstream->codecpar->extradata;
  143. int extradata_size = vstream->codecpar->extradata_size;
  144. #else
  145. uint8_t* extradata = vstream->codec->extradata;
  146. int extradata_size = vstream->codec->extradata_size;
  147. #endif
  148. info_.extra_data = std::vector<uint8_t>(extradata, extradata + extradata_size);
  149. // bitstream filter
  150. p_bsfc_ = nullptr;
  151. LOGI(SAMPLES) << p_format_ctx_->iformat->name;
  152. if (strstr(p_format_ctx_->iformat->name, "mp4") || strstr(p_format_ctx_->iformat->name, "flv") ||
  153. strstr(p_format_ctx_->iformat->name, "matroska") || strstr(p_format_ctx_->iformat->name, "h264") ||
  154. strstr(p_format_ctx_->iformat->name, "rtsp")) {
  155. if (AV_CODEC_ID_H264 == codec_id) {
  156. p_bsfc_ = av_bitstream_filter_init("h264_mp4toannexb");
  157. info_.codec_type = edk::CodecType::H264;
  158. if (save_file) saver_.reset(new detail::FileSaver("out.h264"));
  159. } else if (AV_CODEC_ID_HEVC == codec_id) {
  160. p_bsfc_ = av_bitstream_filter_init("hevc_mp4toannexb");
  161. info_.codec_type = edk::CodecType::H265;
  162. if (save_file) saver_.reset(new detail::FileSaver("out.h265"));
  163. } else {
  164. LOGE(SAMPLES) << "nonsupport codec id.";
  165. return false;
  166. }
  167. }
  168. have_video_source_.store(true);
  169. first_frame_ = true;
  170. return true;
  171. }
  172. void VideoParser::Close() {
  173. if (!have_video_source_.load()) return;
  174. LOGI(SAMPLES) << "Close ffmpeg resources";
  175. if (p_format_ctx_) {
  176. avformat_close_input(&p_format_ctx_);
  177. avformat_free_context(p_format_ctx_);
  178. av_dict_free(&options_);
  179. p_format_ctx_ = nullptr;
  180. options_ = nullptr;
  181. }
  182. if (p_bsfc_) {
  183. av_bitstream_filter_close(p_bsfc_);
  184. p_bsfc_ = nullptr;
  185. }
  186. have_video_source_.store(false);
  187. frame_index_ = 0;
  188. saver_.reset();
  189. }
  190. int VideoParser::ParseLoop(uint32_t frame_interval) {
  191. if (!info_.extra_data.empty()) {
  192. edk::CnPacket pkt;
  193. pkt.data = const_cast<void*>(reinterpret_cast<const void*>(info_.extra_data.data()));
  194. pkt.length = info_.extra_data.size();
  195. pkt.pts = 0;
  196. if (!handler_->OnPacket(pkt)) {
  197. THROW_EXCEPTION(edk::Exception::INTERNAL, "send stream extra data failed");
  198. }
  199. }
  200. auto now_time = std::chrono::steady_clock::now();
  201. auto last_time = std::chrono::steady_clock::now();
  202. std::chrono::duration<double, std::milli> dura;
  203. while (handler_->Running()) {
  204. if (!have_video_source_.load()) {
  205. LOGE(SAMPLES) << "video source have not been init";
  206. return -1;
  207. }
  208. if (av_read_frame(p_format_ctx_, &packet_) < 0) {
  209. // EOS
  210. handler_->OnEos();
  211. return 1;
  212. }
  213. // update receive frame time
  214. last_receive_frame_time_ = std::chrono::steady_clock::now();
  215. // skip unmatched stream
  216. if (packet_.stream_index != video_index_) {
  217. av_packet_unref(&packet_);
  218. continue;
  219. }
  220. // filter non-key-frame in head
  221. if (first_frame_) {
  222. LOGI(SAMPLES) << "check first frame";
  223. if (packet_.flags & AV_PKT_FLAG_KEY) {
  224. first_frame_ = false;
  225. } else {
  226. LOGW(SAMPLES) << "skip first not-key-frame";
  227. av_packet_unref(&packet_);
  228. continue;
  229. }
  230. }
  231. // parse data from packet
  232. edk::CnPacket pkt;
  233. auto vstream = p_format_ctx_->streams[video_index_];
  234. if (p_bsfc_) {
  235. av_bitstream_filter_filter(p_bsfc_, vstream->codec, NULL, reinterpret_cast<uint8_t **>(&pkt.data),
  236. reinterpret_cast<int *>(&pkt.length), packet_.data, packet_.size, 0);
  237. } else {
  238. pkt.data = packet_.data;
  239. pkt.length = packet_.size;
  240. }
  241. // find pts information
  242. if (AV_NOPTS_VALUE == packet_.pts) {
  243. LOGI(SAMPLES) << "Didn't find pts informations, use ordered numbers instead. ";
  244. pkt.pts = frame_index_++;
  245. } else if (AV_NOPTS_VALUE != packet_.pts) {
  246. packet_.pts = av_rescale_q(packet_.pts, vstream->time_base, {1, 90000});
  247. pkt.pts = packet_.pts;
  248. }
  249. if (saver_) {
  250. saver_->Write(reinterpret_cast<char *>(pkt.data), pkt.length);
  251. }
  252. if (!handler_->OnPacket(pkt)) return -1;
  253. // free packet
  254. if (p_bsfc_) {
  255. av_freep(&pkt.data);
  256. }
  257. av_packet_unref(&packet_);
  258. // frame rate control
  259. if (frame_interval) {
  260. now_time = std::chrono::steady_clock::now();
  261. dura = now_time - last_time;
  262. if (frame_interval > dura.count()) {
  263. std::this_thread::sleep_for(std::chrono::duration<double, std::milli>(frame_interval - dura.count()));
  264. }
  265. last_time = std::chrono::steady_clock::now();
  266. }
  267. } // while (true)
  268. return 1;
  269. }