直播软件源码如何实现音视频同步(四)

tech2023-08-28  90

2.4.4 音频播放过程

音频时钟是同步主时钟,音频按照自己的节奏进行播放即可。视频播放时则要参考音频时钟。音频播放函数由 SDL 音频播放线程回调,回调函数实现如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 // 音频处理回调函数。读队列获取音频包,解码,播放 // 此函数被SDL按需调用,此函数不在用户主线程中,因此数据需要保护 // \param[in] opaque 用户在注册回调函数时指定的参数 // \param[out] stream 音频数据缓冲区地址,将解码后的音频数据填入此缓冲区 // \param[out] len 音频数据缓冲区大小,单位字节 // 回调函数返回后,stream指向的音频缓冲区将变为无效 // 双声道采样点的顺序为LRLRLR static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) { player_stat_t *is = (player_stat_t *)opaque; int audio_size, len1; int64_t audio_callback_time = av_gettime_relative(); while (len > 0) // 输入参数len等于is->audio_hw_buf_size,是audio_open()中申请到的SDL音频缓冲区大小 { if (is->audio_cp_index >= (int)is->audio_frm_size) { // 1. 从音频frame队列中取出一个frame,转换为音频设备支持的格式,返回值是重采样音频帧的大小 audio_size = audio_resample(is, audio_callback_time); if (audio_size < 0) { /* if error, just output silence */ is->p_audio_frm = NULL; is->audio_frm_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_param_tgt.frame_size * is->audio_param_tgt.frame_size; } else { is->audio_frm_size = audio_size; } is->audio_cp_index = 0; } // 引入is->audio_cp_index的作用:防止一帧音频数据大小超过SDL音频缓冲区大小,这样一帧数据需要经过多次拷贝 // 用is->audio_cp_index标识重采样帧中已拷入SDL音频缓冲区的数据位置索引,len1表示本次拷贝的数据量 len1 = is->audio_frm_size - is->audio_cp_index; if (len1 > len) { len1 = len; } // 2. 将转换后的音频数据拷贝到音频缓冲区stream中,之后的播放就是音频设备驱动程序的工作了 if (is->p_audio_frm != NULL) { memcpy(stream, (uint8_t *)is->p_audio_frm + is->audio_cp_index, len1); } else { memset(stream, 0, len1); } len -= len1; stream += len1; is->audio_cp_index += len1; } // is->audio_write_buf_size是本帧中尚未拷入SDL音频缓冲区的数据量 is->audio_write_buf_size = is->audio_frm_size - is->audio_cp_index; /* Let's assume the audio driver that is used by SDL has two periods. */ // 3. 更新时钟 if (!isnan(is->audio_clock)) { // 更新音频时钟,更新时刻:每次往声卡缓冲区拷入数据后 // 前面audio_decode_frame中更新的is->audio_clock是以音频帧为单位,所以此处第二个参数要减去未拷贝数据量占用的时间 set_clock_at(&is->audio_clk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_param_tgt.bytes_per_sec, is->audio_clock_serial, audio_callback_time / 1000000.0); } }

3. 编译与验证

3.1 编译

gcc -o ffplayer ffplayer.c -lavutil -lavformat -lavcodec -lavutil -lswscale -lswresample -lSDL2

3.2 验证

选用 clock.avi 测试文件,下载工程后,测试文件在 resources 子目录下

查看视频文件格式信息:

ffprobe clock.avi

打印视频文件信息如下:

1 2 3 4 5 [avi @ 0x9286c0] non-interleaved AVI Input #0, avi, from 'clock.avi': Duration: 00:00:12.00, start: 0.000000, bitrate: 42 kb/s Stream #0:0: Video: msrle ([1][0][0][0] / 0x0001), pal8, 320x320, 1 fps, 1 tbr, 1 tbn, 1 tbc Stream #0:1: Audio: truespeech ([34][0][0][0] / 0x0022), 8000 Hz, mono, s16, 8 kb/s

运行测试命令:

./ffplayer clock.avi

可以听到每隔 1 秒播放一次 “嘀” 声,声音播放 12 次。时针每隔 1 秒跳动一格,跳动 12 次。声音播放正常,画面播放也正常,声音与画面基本同步。

4. 问题记录

[1] 在Windows平台上有些电脑无法播放出声音异常现象: 在一台电脑上声音能正常播放,在另一台电脑上无法正常播放原因分析: 原因不清楚解决方法: 环境一个变量 SDL_AUDIODRIVER=directsound(或 winmm) 即可。 参考资料 “[12] FFplay: WASAPI can't initialize audio client”

[2] 音频播放过程中持续卡顿异常现象: 音频播放过程中持续卡顿,类似播一下停一下原因分析: SDL 音频缓冲区设置过小。缓冲区小可缓存数据量少,实时性要求高,缓冲区数据被取完,又无新数据送入时,会出现播放停顿现象。解决方法: 增大 SDL 音频缓冲区

5. 遗留问题

[1]. 启动播放瞬间,视频画面未及时播放 [2]. 点击关闭按钮关闭播放器会引起内存异常报错

6. 参考资料

[1] 雷霄骅,视音频编解码技术零基础学习方法 [2] 视频编解码基础概念, https://www.cnblogs.com/leisure_chn/p/10285829.html [3] FFmpeg基础概念, https://www.cnblogs.com/leisure_chn/p/10297002.html [4] 零基础读懂视频播放器控制原理:ffplay播放器源代码分析, https://cloud.tencent.com/developer/article/1004559 [5] An ffmpeg and SDL Tutorial, Tutorial 05: Synching Video [6] 视频同步音频, https://zhuanlan.zhihu.com/p/44615401 [7] 音频同步视频, https://zhuanlan.zhihu.com/p/44680734 [8] 音视频同步(播放)原理, https://blog.csdn.net/zhuweigangzwg/article/details/25815851 [9] 对ffmpeg的时间戳的理解笔记, https://blog.csdn.net/topsluo/article/details/76239136 [10] ffmpeg音视频同步---视频同步到音频时钟, https://my.oschina.net/u/735973/blog/806117 [11] FFmpeg音视频同步原理与实现, https://www.jianshu.com/p/3578e794f6b5 [12] FFplay: WASAPI can't initialize audio client, https://stackoverflow.com/questions/46835811/ffplay-wasapi-cant-initialize-audio-client-ffmpeg-3-4-binaries [13] WASAPI can't initialize audio client, https://blog.csdn.net/A694543965/article/details/78786230

 

本文转载自网络,感谢原作者的分享,转载仅为分享干货知识,如有侵权欢迎联系作者进行删除处理

最新回复(0)