record_audio_dshow.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. #include "record_audio_dshow.h"
  2. #include "headers_ffmpeg.h"
  3. #include "error_define.h"
  4. #include "log_helper.h"
  5. namespace am {
  6. record_audio_dshow::record_audio_dshow()
  7. {
  8. ffmpeg_register_all();
  9. ffmpeg_register_devices();
  10. _fmt_ctx = NULL;
  11. _input_fmt = NULL;
  12. _codec_ctx = NULL;
  13. _codec = NULL;
  14. _stream_index = -1;
  15. }
  16. record_audio_dshow::~record_audio_dshow()
  17. {
  18. stop();
  19. cleanup();
  20. }
  21. int record_audio_dshow::init(const std::string &device_name,
  22. const std::string &device_id,
  23. bool is_input)
  24. {
  25. int error = AE_NO;
  26. int ret = 0;
  27. if (_inited == true)
  28. return error;
  29. do {
  30. _device_name = device_name;
  31. _device_id = device_id;
  32. _is_input = is_input;
  33. _input_fmt = av_find_input_format("dshow");
  34. if (!_input_fmt) {
  35. error = AE_FFMPEG_FIND_INPUT_FMT_FAILED;
  36. break;
  37. }
  38. _fmt_ctx = avformat_alloc_context();
  39. ret = avformat_open_input(&_fmt_ctx, _device_name.c_str(), _input_fmt, NULL);
  40. if (ret != 0) {
  41. error = AE_FFMPEG_OPEN_INPUT_FAILED;
  42. break;
  43. }
  44. ret = avformat_find_stream_info(_fmt_ctx, NULL);
  45. if (ret < 0) {
  46. error = AE_FFMPEG_FIND_STREAM_FAILED;
  47. break;
  48. }
  49. int stream_index = -1;
  50. for (int i = 0; i < _fmt_ctx->nb_streams; i++) {
  51. if (ffmpeg_get_codec_type(_fmt_ctx->streams[i]) == AVMEDIA_TYPE_AUDIO) {
  52. stream_index = i;
  53. break;
  54. }
  55. }
  56. if (stream_index == -1) {
  57. error = AE_FFMPEG_FIND_STREAM_FAILED;
  58. break;
  59. }
  60. _stream_index = stream_index;
  61. _codec_ctx = ffmpeg_get_codec_context(_fmt_ctx->streams[stream_index]);
  62. _codec = (AVCodec*)avcodec_find_decoder(_codec_ctx->codec_id);
  63. if (_codec == NULL) {
  64. error = AE_FFMPEG_FIND_DECODER_FAILED;
  65. break;
  66. }
  67. ret = avcodec_open2(_codec_ctx, _codec, NULL);
  68. if (ret != 0) {
  69. error = AE_FFMPEG_OPEN_CODEC_FAILED;
  70. break;
  71. }
  72. _inited = true;
  73. _sample_rate = _codec_ctx->sample_rate;
  74. _bit_rate = _codec_ctx->bit_rate;
  75. _bit_per_sample = _codec_ctx->bits_per_coded_sample;
  76. _channel_num = ffmpeg_get_channels(_codec_ctx);
  77. _fmt = _codec_ctx->sample_fmt;
  78. _inited = true;
  79. } while (0);
  80. if (error != AE_NO) {
  81. al_debug("%s,error:%d", err2str(error), ret);
  82. cleanup();
  83. }
  84. return error;
  85. }
  86. int record_audio_dshow::start()
  87. {
  88. if (_running == true) {
  89. al_warn("record audio dshow is already running");
  90. return AE_NO;
  91. }
  92. if (_inited == false) {
  93. return AE_NEED_INIT;
  94. }
  95. _running = true;
  96. _thread = std::thread(std::bind(&record_audio_dshow::record_loop, this));
  97. return AE_NO;
  98. }
  99. int record_audio_dshow::pause()
  100. {
  101. return 0;
  102. }
  103. int record_audio_dshow::resume()
  104. {
  105. return 0;
  106. }
  107. int record_audio_dshow::stop()
  108. {
  109. _running = false;
  110. if (_thread.joinable())
  111. _thread.join();
  112. return AE_NO;
  113. }
  114. const AVRational record_audio_dshow::get_time_base()
  115. {
  116. if (_inited && _fmt_ctx && _stream_index != -1) {
  117. return _fmt_ctx->streams[_stream_index]->time_base;
  118. } else {
  119. return {1, AV_TIME_BASE};
  120. }
  121. }
  122. int64_t record_audio_dshow::get_start_time()
  123. {
  124. return _fmt_ctx->streams[_stream_index]->start_time;
  125. }
  126. int record_audio_dshow::decode(AVFrame *frame, AVPacket *packet)
  127. {
  128. int ret = avcodec_send_packet(_codec_ctx, packet);
  129. if (ret < 0) {
  130. al_error("avcodec_send_packet failed:%d", ret);
  131. return AE_FFMPEG_DECODE_FRAME_FAILED;
  132. }
  133. while (ret >= 0) {
  134. ret = avcodec_receive_frame(_codec_ctx, frame);
  135. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
  136. break;
  137. }
  138. if (ret < 0) {
  139. return AE_FFMPEG_READ_FRAME_FAILED;
  140. }
  141. if (ret == 0 && _on_data)
  142. _on_data(frame, _cb_extra_index);
  143. av_frame_unref(
  144. frame); //need to do this? avcodec_receive_frame said will call unref before receive
  145. }
  146. return AE_NO;
  147. }
  148. void record_audio_dshow::record_loop()
  149. {
  150. int ret = 0;
  151. AVPacket *packet = av_packet_alloc();
  152. AVFrame *frame = av_frame_alloc();
  153. while (_running == true) {
  154. av_init_packet(packet);
  155. ret = av_read_frame(_fmt_ctx, packet);
  156. if (ret < 0) {
  157. if (_on_error)
  158. _on_error(AE_FFMPEG_READ_FRAME_FAILED, _cb_extra_index);
  159. break;
  160. }
  161. if (packet->stream_index == _stream_index) {
  162. ret = decode(frame, packet);
  163. if (ret != AE_NO) {
  164. if (_on_error)
  165. _on_error(AE_FFMPEG_DECODE_FRAME_FAILED, _cb_extra_index);
  166. al_fatal("decode pcm packet failed:%d", ret);
  167. break;
  168. }
  169. }
  170. av_packet_unref(packet);
  171. }
  172. //flush packet left in decoder
  173. decode(frame, NULL);
  174. av_packet_free(&packet);
  175. av_frame_free(&frame);
  176. }
  177. void record_audio_dshow::cleanup()
  178. {
  179. if (_codec_ctx)
  180. avcodec_close(_codec_ctx);
  181. if (_fmt_ctx)
  182. avformat_close_input(&_fmt_ctx);
  183. _fmt_ctx = NULL;
  184. _input_fmt = NULL;
  185. _codec_ctx = NULL;
  186. _codec = NULL;
  187. _stream_index = -1;
  188. _inited = false;
  189. }
  190. } // namespace am