ffmpeg_outputer.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #pragma once
  2. #include <iostream>
  3. #include <thread>
  4. #include <chrono>
  5. #include <assert.h>
  6. #include <list>
  7. #include <mutex>
  8. #ifdef __cplusplus
  9. extern "C" {
  10. #include "libavcodec/avcodec.h"
  11. #include "libavformat/avformat.h"
  12. #include "libavutil/avutil.h"
  13. #include "libavutil/time.h"
  14. }
  15. #endif
  16. class FfmpegOutputer {
  17. enum State {INIT=0, SERVICE, DOWN};
  18. AVFormatContext *m_ofmt_ctx {nullptr};
  19. std::string m_url;
  20. std::thread *m_thread_output {nullptr};
  21. bool m_thread_output_is_running {false};
  22. State m_output_state;
  23. std::mutex m_list_packets_lock;
  24. std::list<AVPacket*> m_list_packets;
  25. bool m_repeat {true};
  26. bool string_start_with(const std::string& s, const std::string& prefix){
  27. return (s.compare(0, prefix.size(), prefix) == 0);
  28. }
  29. int output_initialize(){
  30. std::cout<<"init. "<<std::endl;
  31. int ret = 0;
  32. if (!(m_ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
  33. ret = avio_open(&m_ofmt_ctx->pb, m_url.c_str(), AVIO_FLAG_WRITE);
  34. if (ret < 0) {
  35. printf("Could not open output URL '%s'", m_url.c_str());
  36. return -1;
  37. }
  38. }
  39. AVDictionary *opts = NULL;
  40. if (string_start_with(m_url, "rtsp://")) {
  41. av_dict_set(&opts, "rtsp_transport", "tcp", 0);
  42. av_dict_set(&opts, "muxdelay", "0.1", 0);
  43. // av_dict_set(&opts, "fps", "30", 0);
  44. }
  45. assert(opts!= NULL);
  46. assert(m_ofmt_ctx != NULL);
  47. //Write file header
  48. ret = avformat_write_header(m_ofmt_ctx, &opts);
  49. // std::cout<<" run hear. "<<std::endl;
  50. if (ret < 0) {
  51. printf("Error occurred when opening output URL\n");
  52. return -1;
  53. }
  54. m_output_state = SERVICE;
  55. std::cout<<"init "<<m_url<<" ok.service."<<std::endl;
  56. m_list_packets.clear();
  57. return 0;
  58. }
  59. void output_service() {
  60. int ret = 0;
  61. if(m_list_packets.size() == 0)
  62. {
  63. std::this_thread::sleep_for(std::chrono::microseconds(3000));
  64. return;
  65. }
  66. while(m_list_packets.size() > 0) {
  67. AVPacket *pkt = m_list_packets.front();
  68. // std::cout<<"send "<<std::endl;
  69. m_list_packets.pop_front();
  70. ret = av_interleaved_write_frame(m_ofmt_ctx, pkt);
  71. av_packet_free(&pkt);
  72. if (ret != 0) {
  73. std::cout << "av_interleaved_write_frame err" << ret << std::endl;
  74. m_output_state = DOWN;
  75. break;
  76. }
  77. else
  78. {
  79. #ifdef SHOWINFO
  80. int64_t now = std::chrono::system_clock::now().time_since_epoch().count()/1000000;
  81. std::cout<<now<<" "<<m_url<<" up a frame. "<<std::endl;
  82. #endif
  83. }
  84. }
  85. }
  86. void output_down() {
  87. if (m_repeat) {
  88. m_output_state = INIT;
  89. }else{
  90. av_write_trailer(m_ofmt_ctx);
  91. if (!(m_ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
  92. avio_closep(&m_ofmt_ctx->pb);
  93. }
  94. // Set exit flag
  95. m_thread_output_is_running = false;
  96. }
  97. }
  98. void output_process_thread_proc() {
  99. m_thread_output_is_running = true;
  100. while(m_thread_output_is_running) {
  101. switch(m_output_state) {
  102. case INIT:
  103. if (output_initialize() < 0) m_output_state = DOWN;
  104. break;
  105. case SERVICE:
  106. output_service();
  107. break;
  108. case DOWN:
  109. output_down();
  110. break;
  111. }
  112. }
  113. std::cout << "output thread exit!" << std::endl;
  114. }
  115. public:
  116. FfmpegOutputer():m_ofmt_ctx(NULL){
  117. }
  118. virtual ~FfmpegOutputer()
  119. {
  120. CloseOutputStream();
  121. }
  122. int OpenOutputStream(const std::string& url, AVFormatContext *ifmt_ctx)
  123. {
  124. int ret = 0;
  125. const char* format_name = NULL;
  126. m_url = url;
  127. if (string_start_with(m_url, "rtsp://")) {
  128. format_name = "rtsp";
  129. }else if(string_start_with(m_url, "udp://") || string_start_with(m_url, "tcp://")) {
  130. format_name = "h264";
  131. }else if(string_start_with(m_url, "rtp://")) {
  132. format_name = "rtp";
  133. }else if(string_start_with(m_url, "rtmp://")) {
  134. format_name = "flv";
  135. }
  136. else{
  137. std::cout << "Not support this Url:" << m_url << std::endl;
  138. return -1;
  139. }
  140. if (nullptr == m_ofmt_ctx) {
  141. ret = avformat_alloc_output_context2(&m_ofmt_ctx, NULL, format_name, m_url.c_str());
  142. if (ret < 0 || m_ofmt_ctx == NULL) {
  143. std::cout << "avformat_alloc_output_context2() err=" << ret << std::endl;
  144. return -1;
  145. }
  146. for(int i = 0;i < ifmt_ctx->nb_streams; ++i) {
  147. AVStream *ostream = avformat_new_stream(m_ofmt_ctx, NULL);
  148. if (NULL == ostream) {
  149. std::cout << "Can't create new stream!" << std::endl;
  150. return -1;
  151. }
  152. #if LIBAVCODEC_VERSION_MAJOR > 56
  153. ret = avcodec_parameters_copy(ostream->codecpar, ifmt_ctx->streams[i]->codecpar);
  154. if (ret < 0) {
  155. std::cout << "avcodec_parameters_copy() err=" << ret << std::endl;
  156. return -1;
  157. }
  158. #else
  159. ret = avcodec_copy_context(ostream->codec, ifmt_ctx->streams[i]->codec);
  160. if (ret < 0){
  161. flog(LOG_ERROR, "avcodec_copy_context() err=%d", ret);
  162. return -1;
  163. }
  164. #endif
  165. m_ofmt_ctx->oformat->flags |= AVFMT_TS_NONSTRICT;
  166. if (m_ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
  167. ostream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  168. }
  169. }
  170. }
  171. if (!m_ofmt_ctx) {
  172. printf("Could not create output context\n");
  173. return -1;
  174. }
  175. av_dump_format(m_ofmt_ctx, 0, m_url.c_str(), 1);
  176. ret = output_initialize();
  177. if (ret != 0) {
  178. return -1;
  179. }
  180. m_thread_output = new std::thread(&FfmpegOutputer::output_process_thread_proc, this);
  181. return 0;
  182. }
  183. int InputPacket(AVPacket *pkt) {
  184. if(m_list_packets.size()>90)
  185. {
  186. int64_t now = std::chrono::system_clock::now().time_since_epoch().count()/1000000;
  187. std::cout<<now<<" ignore packete. buffer full."<<std::endl;
  188. return -1;
  189. }
  190. AVPacket *pkt1 = av_packet_alloc();
  191. av_packet_ref(pkt1, pkt);
  192. m_list_packets.push_back(pkt1);
  193. return 0;
  194. }
  195. int CloseOutputStream() {
  196. std::cout << "call CloseOutputStream()" << std::endl;
  197. m_repeat = false;
  198. m_output_state = DOWN;
  199. if (m_thread_output) {
  200. m_thread_output->join();
  201. delete m_thread_output;
  202. m_thread_output = nullptr;
  203. }
  204. if (m_ofmt_ctx) {
  205. avformat_free_context(m_ofmt_ctx);
  206. m_ofmt_ctx = NULL;
  207. }
  208. return 0;
  209. }
  210. };