audio.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. #include "player.h"
  2. #include "packet.h"
  3. #include "frame.h"
  4. static void sdl_audio_callback(void *opaque, Uint8 *stream, int len);
  5. // 从packet_queue中取一个packet,解码生成frame
  6. static int audio_decode_frame(AVCodecContext *p_codec_ctx, packet_queue_t *p_pkt_queue, AVFrame *frame, play_logfun rvclog)
  7. {
  8. int ret;
  9. while (1)
  10. {
  11. AVPacket pkt;
  12. while (1)
  13. {
  14. //if (d->queue->abort_request)
  15. // return -1;
  16. // 3.2 一个音频packet含一至多个音频frame,每次avcodec_receive_frame()返回一个frame,此函数返回。
  17. // 下次进来此函数,继续获取一个frame,直到avcodec_receive_frame()返回AVERROR(EAGAIN),
  18. // 表示解码器需要填入新的音频packet
  19. ret = avcodec_receive_frame(p_codec_ctx, frame);
  20. if (ret >= 0)
  21. {
  22. // 时基转换,从d->avctx->pkt_timebase时基转换到1/frame->sample_rate时基
  23. AVRational tb{ 1, frame->sample_rate };
  24. if (frame->pts != AV_NOPTS_VALUE)
  25. {
  26. frame->pts = av_rescale_q(frame->pts, p_codec_ctx->pkt_timebase, tb);
  27. }
  28. else
  29. {
  30. //av_log(NULL, AV_LOG_WARNING, "frame->pts no.\n");
  31. //rvclog("frame->pts no.");
  32. }
  33. return 1;
  34. }
  35. else if (ret == AVERROR_EOF)
  36. {
  37. //av_log(NULL, AV_LOG_INFO, "audio avcodec_receive_frame(): the decoder has been flushed.\n");
  38. //rvclog("audio avcodec_receive_frame(): the decoder has been flushed.");
  39. avcodec_flush_buffers(p_codec_ctx);
  40. return 0;
  41. }
  42. else if (ret == AVERROR(EAGAIN))
  43. {
  44. //av_log(NULL, AV_LOG_INFO, "audio avcodec_receive_frame(): input is not accepted in the current state.\n");
  45. //rvclog("audio avcodec_receive_frame(): input is not accepted in the current state.");
  46. break;
  47. }
  48. else
  49. {
  50. //av_log(NULL, AV_LOG_ERROR, "audio avcodec_receive_frame(): other errors.\n");
  51. //rvclog( "audio avcodec_receive_frame(): other errors.");
  52. continue;
  53. }
  54. }
  55. // 1. 取出一个packet。使用pkt对应的serial赋值给d->pkt_serial
  56. if (packet_queue_get(p_pkt_queue, &pkt, true) < 0)
  57. {
  58. return -1;
  59. }
  60. // packet_queue中第一个总是flush_pkt。每次seek操作会插入flush_pkt,更新serial,开启新的播放序列
  61. if (pkt.data == NULL)
  62. {
  63. // 复位解码器内部状态/刷新内部缓冲区。当seek操作或切换流时应调用此函数。
  64. avcodec_flush_buffers(p_codec_ctx);
  65. }
  66. else
  67. {
  68. // 2. 将packet发送给解码器
  69. // 发送packet的顺序是按dts递增的顺序,如IPBBPBB
  70. // pkt.pos变量可以标识当前packet在视频文件中的地址偏移
  71. if (avcodec_send_packet(p_codec_ctx, &pkt) == AVERROR(EAGAIN))
  72. {
  73. //av_log(NULL, AV_LOG_ERROR, "receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
  74. //rvclog("receive_frame and send_packet both returned EAGAIN, which is an API violation.");
  75. }
  76. av_packet_unref(&pkt);
  77. }
  78. }
  79. }
  80. // 音频解码线程:从音频packet_queue中取数据,解码后放入音频frame_queue
  81. static int audio_decode_thread(void *arg)
  82. {
  83. player_stat_t *is = (player_stat_t *)arg;
  84. AVFrame *p_frame = av_frame_alloc();
  85. frame_t *af;
  86. int got_frame = 0;
  87. AVRational tb;
  88. int ret = 0;
  89. if (p_frame == NULL)
  90. {
  91. return AVERROR(ENOMEM);
  92. }
  93. //is->rvc_log("audio_decode_thread is->abort_request == %d.", is->abort_request);
  94. while (0 == is->abort_request)
  95. {
  96. got_frame = audio_decode_frame(is->p_acodec_ctx, &is->audio_pkt_queue, p_frame, is->rvc_log);
  97. if (got_frame < 0)
  98. {
  99. goto the_end;
  100. }
  101. if (got_frame)
  102. {
  103. tb = { 1, p_frame->sample_rate };
  104. if (!(af = frame_queue_peek_writable(&is->audio_frm_queue)))
  105. goto the_end;
  106. af->pts = (p_frame->pts == AV_NOPTS_VALUE) ? NAN : p_frame->pts * av_q2d(tb);
  107. af->pos = p_frame->pkt_pos;
  108. //-af->serial = is->auddec.pkt_serial;
  109. // 当前帧包含的(单个声道)采样数/采样率就是当前帧的播放时长
  110. AVRational tbdata{ p_frame->nb_samples, p_frame->sample_rate };
  111. //af->duration = av_q2d((AVRational) { p_frame->nb_samples, p_frame->sample_rate });
  112. af->duration = av_q2d(tbdata);
  113. // 将frame数据拷入af->frame,af->frame指向音频frame队列尾部
  114. av_frame_move_ref(af->frame, p_frame);
  115. // 更新音频frame队列大小及写指针
  116. frame_queue_push(&is->audio_frm_queue);
  117. }
  118. }
  119. the_end:
  120. av_frame_free(&p_frame);
  121. return ret;
  122. }
  123. int open_audio_stream(player_stat_t *is)
  124. {
  125. AVCodecContext *p_codec_ctx;
  126. AVCodecParameters *p_codec_par = NULL;
  127. AVCodec* p_codec = NULL;
  128. int ret;
  129. // 1. 为音频流构建解码器AVCodecContext
  130. // 1.1 获取解码器参数AVCodecParameters
  131. p_codec_par = is->p_audio_stream->codecpar;
  132. // 1.2 获取解码器
  133. p_codec = avcodec_find_decoder(p_codec_par->codec_id);
  134. if (p_codec == NULL)
  135. {
  136. //av_log(NULL, AV_LOG_ERROR, "Cann't find codec!\n");
  137. //is->rvc_log("Cann't find codec!");
  138. return -1;
  139. }
  140. // 1.3 构建解码器AVCodecContext
  141. // 1.3.1 p_codec_ctx初始化:分配结构体,使用p_codec初始化相应成员为默认值
  142. p_codec_ctx = avcodec_alloc_context3(p_codec);
  143. if (p_codec_ctx == NULL)
  144. {
  145. //av_log(NULL, AV_LOG_ERROR, "avcodec_alloc_context3() failed\n");
  146. //is->rvc_log("avcodec_alloc_context3() failed.");
  147. return -1;
  148. }
  149. // 1.3.2 p_codec_ctx初始化:p_codec_par ==> p_codec_ctx,初始化相应成员
  150. ret = avcodec_parameters_to_context(p_codec_ctx, p_codec_par);
  151. if (ret < 0)
  152. {
  153. //av_log(NULL, AV_LOG_ERROR, "avcodec_parameters_to_context() failed %d\n", ret);
  154. //is->rvc_log("avcodec_parameters_to_context() failed %d.", ret);
  155. return -1;
  156. }
  157. // 1.3.3 p_codec_ctx初始化:使用p_codec初始化p_codec_ctx,初始化完成
  158. ret = avcodec_open2(p_codec_ctx, p_codec, NULL);
  159. if (ret < 0)
  160. {
  161. //av_log(NULL, AV_LOG_ERROR, "avcodec_open2() failed %d\n", ret);
  162. //is->rvc_log("avcodec_open2() failed %d.", ret);
  163. return -1;
  164. }
  165. p_codec_ctx->pkt_timebase = is->p_audio_stream->time_base;
  166. is->p_acodec_ctx = p_codec_ctx;
  167. // 2. 创建音频解码线程
  168. SDL_CreateThread(audio_decode_thread, "audio decode thread", is);
  169. return 0;
  170. }
  171. static int audio_resample(player_stat_t *is, int64_t audio_callback_time)
  172. {
  173. int data_size, resampled_data_size;
  174. int64_t dec_channel_layout;
  175. av_unused double audio_clock0;
  176. int wanted_nb_samples;
  177. frame_t *af;
  178. #if defined(_WIN32)
  179. while (frame_queue_nb_remaining(&is->audio_frm_queue) == 0)
  180. {
  181. if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_param_tgt.bytes_per_sec / 2)
  182. return -1;
  183. av_usleep(1000);
  184. }
  185. #endif
  186. // 若队列头部可读,则由af指向可读帧
  187. if (!(af = frame_queue_peek_readable(&is->audio_frm_queue)))
  188. return -1;
  189. frame_queue_next(&is->audio_frm_queue);
  190. // 根据frame中指定的音频参数获取缓冲区的大小
  191. data_size = av_samples_get_buffer_size(NULL, af->frame->channels, // 本行两参数:linesize,声道数
  192. af->frame->nb_samples, // 本行一参数:本帧中包含的单个声道中的样本数
  193. (AVSampleFormat)af->frame->format, 1); // 本行两参数:采样格式,不对齐
  194. // 获取声道布局
  195. dec_channel_layout =
  196. (af->frame->channel_layout && af->frame->channels == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ?
  197. af->frame->channel_layout : av_get_default_channel_layout(af->frame->channels);
  198. wanted_nb_samples = af->frame->nb_samples;
  199. // is->audio_param_tgt是SDL可接受的音频帧数,是audio_open()中取得的参数
  200. // 在audio_open()函数中又有“is->audio_src = is->audio_param_tgt”
  201. // 此处表示:如果frame中的音频参数 == is->audio_src == is->audio_param_tgt,那音频重采样的过程就免了(因此时is->swr_ctr是NULL)
  202. //      否则使用frame(源)和is->audio_param_tgt(目标)中的音频参数来设置is->swr_ctx,并使用frame中的音频参数来赋值is->audio_src
  203. if (af->frame->format != is->audio_param_src.fmt ||
  204. dec_channel_layout != is->audio_param_src.channel_layout ||
  205. af->frame->sample_rate != is->audio_param_src.freq)
  206. {
  207. swr_free(&is->audio_swr_ctx);
  208. // 使用frame(源)和is->audio_param_tgt(目标)中的音频参数来设置is->audio_swr_ctx
  209. is->audio_swr_ctx = swr_alloc_set_opts(NULL,
  210. is->audio_param_tgt.channel_layout, is->audio_param_tgt.fmt, is->audio_param_tgt.freq,
  211. dec_channel_layout, (AVSampleFormat)af->frame->format, af->frame->sample_rate,
  212. 0, NULL);
  213. if (!is->audio_swr_ctx || swr_init(is->audio_swr_ctx) < 0)
  214. {
  215. //av_log(NULL, AV_LOG_ERROR,
  216. // "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
  217. // af->frame->sample_rate, av_get_sample_fmt_name((AVSampleFormat)af->frame->format), af->frame->channels,
  218. // is->audio_param_tgt.freq, av_get_sample_fmt_name(is->audio_param_tgt.fmt), is->audio_param_tgt.channels);
  219. is->rvc_log("Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
  220. af->frame->sample_rate, av_get_sample_fmt_name((AVSampleFormat)af->frame->format), af->frame->channels,
  221. is->audio_param_tgt.freq, av_get_sample_fmt_name(is->audio_param_tgt.fmt), is->audio_param_tgt.channels);
  222. swr_free(&is->audio_swr_ctx);
  223. return -1;
  224. }
  225. // 使用frame中的参数更新is->audio_src,第一次更新后后面基本不用执行此if分支了,因为一个音频流中各frame通用参数一样
  226. is->audio_param_src.channel_layout = dec_channel_layout;
  227. is->audio_param_src.channels = af->frame->channels;
  228. is->audio_param_src.freq = af->frame->sample_rate;
  229. is->audio_param_src.fmt = (AVSampleFormat)af->frame->format;
  230. }
  231. if (is->audio_swr_ctx)
  232. {
  233. // 重采样输入参数1:输入音频样本数是af->frame->nb_samples
  234. // 重采样输入参数2:输入音频缓冲区
  235. const uint8_t **in = (const uint8_t **)af->frame->extended_data;
  236. // 重采样输出参数1:输出音频缓冲区尺寸
  237. // 重采样输出参数2:输出音频缓冲区
  238. uint8_t **out = &is->audio_frm_rwr;
  239. // 重采样输出参数:输出音频样本数(多加了256个样本)
  240. int out_count = (int64_t)wanted_nb_samples * is->audio_param_tgt.freq / af->frame->sample_rate + 256;
  241. // 重采样输出参数:输出音频缓冲区尺寸(以字节为单位)
  242. int out_size = av_samples_get_buffer_size(NULL, is->audio_param_tgt.channels, out_count, is->audio_param_tgt.fmt, 0);
  243. int len2;
  244. if (out_size < 0)
  245. {
  246. //av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n");
  247. //is->rvc_log("av_samples_get_buffer_size() failed.");
  248. return -1;
  249. }
  250. av_fast_malloc(&is->audio_frm_rwr, &is->audio_frm_rwr_size, out_size);
  251. if (!is->audio_frm_rwr)
  252. return AVERROR(ENOMEM);
  253. // 音频重采样:返回值是重采样后得到的音频数据中单个声道的样本数
  254. len2 = swr_convert(is->audio_swr_ctx, out, out_count, in, af->frame->nb_samples);
  255. if (len2 < 0)
  256. {
  257. //av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n");
  258. //is->rvc_log("swr_convert() failed.");
  259. return -1;
  260. }
  261. if (len2 == out_count)
  262. {
  263. //av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n");
  264. //is->rvc_log("audio buffer is probably too small.");
  265. if (swr_init(is->audio_swr_ctx) < 0)
  266. swr_free(&is->audio_swr_ctx);
  267. }
  268. is->p_audio_frm = is->audio_frm_rwr;
  269. // 重采样返回的一帧音频数据大小(以字节为单位)
  270. resampled_data_size = len2 * is->audio_param_tgt.channels * av_get_bytes_per_sample(is->audio_param_tgt.fmt);
  271. }
  272. else
  273. {
  274. // 未经重采样,则将指针指向frame中的音频数据
  275. is->p_audio_frm = af->frame->data[0];
  276. resampled_data_size = data_size;
  277. }
  278. audio_clock0 = is->audio_clock;
  279. /* update the audio clock with the pts */
  280. if (!isnan(af->pts))
  281. {
  282. is->audio_clock = af->pts + (double)af->frame->nb_samples / af->frame->sample_rate;
  283. }
  284. else
  285. {
  286. is->audio_clock = NAN;
  287. }
  288. is->audio_clock_serial = af->serial;
  289. #ifdef DEBUG
  290. {
  291. static double last_clock;
  292. //printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
  293. // is->audio_clock - last_clock,
  294. // is->audio_clock, audio_clock0);
  295. //is->rvc_log("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
  296. // is->audio_clock - last_clock,
  297. // is->audio_clock, audio_clock0);
  298. last_clock = is->audio_clock;
  299. }
  300. #endif
  301. return resampled_data_size;
  302. }
  303. static int open_audio_playing(void *arg)
  304. {
  305. player_stat_t *is = (player_stat_t *)arg;
  306. SDL_AudioSpec wanted_spec;
  307. SDL_AudioSpec actual_spec;
  308. // 2. 打开音频设备并创建音频处理线程
  309. // 2.1 打开音频设备,获取SDL设备支持的音频参数actual_spec(期望的参数是wanted_spec,实际得到actual_spec)
  310. // 1) SDL提供两种使音频设备取得音频数据方法:
  311. // a. push,SDL以特定的频率调用回调函数,在回调函数中取得音频数据
  312. // b. pull,用户程序以特定的频率调用SDL_QueueAudio(),向音频设备提供数据。此种情况wanted_spec.callback=NULL
  313. // 2) 音频设备打开后播放静音,不启动回调,调用SDL_PauseAudio(0)后启动回调,开始正常播放音频
  314. wanted_spec.freq = is->p_acodec_ctx->sample_rate; // 采样率
  315. wanted_spec.format = AUDIO_S16SYS; // S表带符号,16是采样深度,SYS表采用系统字节序
  316. wanted_spec.channels = is->p_acodec_ctx->channels; // 声音通道数
  317. wanted_spec.silence = 0; // 静音值
  318. // wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; // SDL声音缓冲区尺寸,单位是单声道采样点尺寸x通道数
  319. // SDL声音缓冲区尺寸,单位是单声道采样点尺寸x声道数
  320. wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));
  321. wanted_spec.callback = sdl_audio_callback; // 回调函数,若为NULL,则应使用SDL_QueueAudio()机制
  322. wanted_spec.userdata = is; // 提供给回调函数的参数
  323. if (SDL_OpenAudio(&wanted_spec, &actual_spec) < 0)
  324. {
  325. //av_log(NULL, AV_LOG_ERROR, "SDL_OpenAudio() failed: %s\n", SDL_GetError());
  326. //is->rvc_log("SDL_OpenAudio() failed: %s.", SDL_GetError());
  327. return -1;
  328. }
  329. // 2.2 根据SDL音频参数构建音频重采样参数
  330. // wanted_spec是期望的参数,actual_spec是实际的参数,wanted_spec和auctual_spec都是SDL中的参数。
  331. // 此处audio_param是FFmpeg中的参数,此参数应保证是SDL播放支持的参数,后面重采样要用到此参数
  332. // 音频帧解码后得到的frame中的音频格式未必被SDL支持,比如frame可能是planar格式,但SDL2.0并不支持planar格式,
  333. // 若将解码后的frame直接送入SDL音频缓冲区,声音将无法正常播放。所以需要先将frame重采样(转换格式)为SDL支持的模式,
  334. // 然后送再写入SDL音频缓冲区
  335. is->audio_param_tgt.fmt = AV_SAMPLE_FMT_S16;
  336. is->audio_param_tgt.freq = actual_spec.freq;
  337. is->audio_param_tgt.channel_layout = av_get_default_channel_layout(actual_spec.channels);
  338. is->audio_param_tgt.channels = actual_spec.channels;
  339. is->audio_param_tgt.frame_size = av_samples_get_buffer_size(NULL, actual_spec.channels, 1, is->audio_param_tgt.fmt, 1);
  340. is->audio_param_tgt.bytes_per_sec = av_samples_get_buffer_size(NULL, actual_spec.channels, actual_spec.freq, is->audio_param_tgt.fmt, 1);
  341. if (is->audio_param_tgt.bytes_per_sec <= 0 || is->audio_param_tgt.frame_size <= 0)
  342. {
  343. //av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");
  344. //is->rvc_log("av_samples_get_buffer_size failed.");
  345. return -1;
  346. }
  347. is->audio_param_src = is->audio_param_tgt;
  348. is->audio_hw_buf_size = actual_spec.size; // SDL音频缓冲区大小
  349. is->audio_frm_size = 0;
  350. is->audio_cp_index = 0;
  351. // 3. 暂停/继续音频回调处理。参数1表暂停,0表继续。
  352. // 打开音频设备后默认未启动回调处理,通过调用SDL_PauseAudio(0)来启动回调处理。
  353. // 这样就可以在打开音频设备后先为回调函数安全初始化数据,一切就绪后再启动音频回调。
  354. // 在暂停期间,会将静音值往音频设备写。
  355. SDL_PauseAudio(0);
  356. }
  357. // 音频处理回调函数。读队列获取音频包,解码,播放
  358. // 此函数被SDL按需调用,此函数不在用户主线程中,因此数据需要保护
  359. // \param[in] opaque 用户在注册回调函数时指定的参数
  360. // \param[out] stream 音频数据缓冲区地址,将解码后的音频数据填入此缓冲区
  361. // \param[out] len 音频数据缓冲区大小,单位字节
  362. // 回调函数返回后,stream指向的音频缓冲区将变为无效
  363. // 双声道采样点的顺序为LRLRLR
  364. static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
  365. {
  366. player_stat_t *is = (player_stat_t *)opaque;
  367. int audio_size, len1;
  368. int64_t audio_callback_time = av_gettime_relative();
  369. //av_log(NULL, AV_LOG_INFO, "sdl_audio_callback audo len is %d.\n", len);
  370. //is->rvc_log("sdl_audio_callback audo len is %d.", len);
  371. while (len > 0 && 0 == is->abort_request) // 输入参数len等于is->audio_hw_buf_size,是audio_open()中申请到的SDL音频缓冲区大小
  372. {
  373. if (is->audio_cp_index >= (int)is->audio_frm_size)
  374. {
  375. // 1. 从音频frame队列中取出一个frame,转换为音频设备支持的格式,返回值是重采样音频帧的大小
  376. audio_size = audio_resample(is, audio_callback_time);
  377. //av_log(NULL, AV_LOG_INFO, "audio_resample audio_size is %d.\n", audio_size);
  378. //is->rvc_log("audio_resample audio_size is %d.", audio_size);
  379. if (audio_size < 0)
  380. {
  381. /* if error, just output silence */
  382. is->p_audio_frm = NULL;
  383. is->audio_frm_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_param_tgt.frame_size * is->audio_param_tgt.frame_size;
  384. }
  385. else
  386. {
  387. is->audio_frm_size = audio_size;
  388. }
  389. is->audio_cp_index = 0;
  390. }
  391. // 引入is->audio_cp_index的作用:防止一帧音频数据大小超过SDL音频缓冲区大小,这样一帧数据需要经过多次拷贝
  392. // 用is->audio_cp_index标识重采样帧中已拷入SDL音频缓冲区的数据位置索引,len1表示本次拷贝的数据量
  393. len1 = is->audio_frm_size - is->audio_cp_index;
  394. if (len1 > len)
  395. {
  396. len1 = len;
  397. }
  398. // 2. 将转换后的音频数据拷贝到音频缓冲区stream中,之后的播放就是音频设备驱动程序的工作了
  399. if (is->p_audio_frm != NULL)
  400. {
  401. //memcpy(stream, (uint8_t *)is->p_audio_frm + is->audio_cp_index, len1);
  402. SDL_memset(stream, 0, len1);
  403. SDL_MixAudio(stream, (uint8_t*)is->p_audio_frm + is->audio_cp_index, len1, /*SDL_MIX_MAXVOLUME*/is->uVolume);
  404. }
  405. else
  406. {
  407. //memset(stream, 0, len1);
  408. SDL_memset(stream, 0, len1);
  409. }
  410. len -= len1;
  411. stream += len1;
  412. is->audio_cp_index += len1;
  413. }
  414. // is->audio_write_buf_size是本帧中尚未拷入SDL音频缓冲区的数据量
  415. is->audio_write_buf_size = is->audio_frm_size - is->audio_cp_index;
  416. //is->rvc_log("audio_write_buf_size == %d.", is->audio_write_buf_size);
  417. /* Let's assume the audio driver that is used by SDL has two periods. */
  418. // 3. 更新时钟
  419. if (!isnan(is->audio_clock))
  420. {
  421. // 更新音频时钟,更新时刻:每次往声卡缓冲区拷入数据后
  422. // 前面audio_decode_frame中更新的is->audio_clock是以音频帧为单位,所以此处第二个参数要减去未拷贝数据量占用的时间
  423. set_clock_at(&is->audio_clk,
  424. is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_param_tgt.bytes_per_sec,
  425. is->audio_clock_serial,
  426. audio_callback_time / 1000000.0);
  427. }
  428. }
  429. int open_audio(player_stat_t *is)
  430. {
  431. open_audio_stream(is);
  432. open_audio_playing(is);
  433. return 0;
  434. }