record_audio_dshow.cpp 4.5 KB

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