ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

音视频之播放PCM(七)

2021-11-01 16:04:28  阅读:351  来源: 互联网

标签:buffer len 音视频 PCM SDL 播放 spec


使用命令行播放-ffplay

可以使用ffplay播放我们在上面博客中录制好的PCm文件,测试一下是否录制成功。
播放PCM需要指定相关参数: 

  • ar: 采样率
  • ac: 声道数
  • f: 采样格式
    • s16le: PCM signed 16-bit little-endian
    • 更多PCM的采样格式可以使用命令查看
      • Windows: ffmpeg -formats | findstr OCM
      • Mac: ffmpeg -formats | grep PCM

播放命令如下:

ffplay -ar 44100 -ac 2 -f s16le /Users/muzi/Desktop/out.pcm 

借助SDL使用代码播放

简介

SDL全称 Simple DirectMedia Layer,是一个跨平台的C语言多媒体开发库。 

  • 支持Windows、Mac OSX、Linux、iOS、Android
  • 提供对音频、键盘、鼠标、游戏操纵杆、图形硬件的底层访问
  • 很多的视频播放软件、模拟器、受欢迎的游戏都在使用它
  • 目前最新的稳定版本是: 2.0.16
  • API文档: wiki

安装环境

brew官网可以看的出来:之前执行 brew install ffmpeg时,已经顺带安装了SDL,安装目录是: /usr/local/Cellar/sdl2。如果没有这个目录,就执行brew install sdl2进行安装即可。

配置

.pro文件

win32 {
    SDL_HOME = /muzi
}

mac {
    SDL_HOME = /usr/local/Cellar/sdl2/2.0.16
}

INCLUDEPATH += $${SDL_HOME}/include

LIBS += -L $${SDL_HOME}/lib \
        -lSDL2

播放PCM

初始化子系统

SDL分成好多个子系统: 

  • Video: 显示和窗口管理
  • Audio: 音频设备管理
  • Joystick: 游戏摇杆控制
  • Timers: 定时器
  • ...

目前只用到了音频功能,所以只需要通过SDL_init函数初始化Audio子系统即可。

打开音频设备

// 音频参数
    SDL_AudioSpec spec;
    // 采样率
    spec.freq = SAMPLE_RATE;
    // 采样格式 (s16le)
    spec.format = AUDIO_S16LSB;
    // 声道数
    spec.channels = CHANNELS;
    // 音频缓冲区的样本数量(这个值必须是2的幂)
    spec.samples = 1024;
    // 回调
    spec.callback = pull_audio_data;
    AudioBuffer buffer;
    spec.userdata = &buffer;

    // 打开设备
    if (SDL_OpenAudio(&spec, nullptr)) {
        qDebug() << "SDL_OpenAudio error" << SDL_GetError();
        // 清除所有的子系统
        SDL_Quit();
        return;
    }

打开文件

// 打开文件
    QFile file(FILENAME);
    if (!file.open(QFile::ReadOnly)) {
        qDebug() << "file open error" << FILENAME;
        // 关闭设备
        SDL_CloseAudio();
        // 清除所有的子系统
        SDL_Quit();
        return;
    }

开始播放

// 开始播放 (0是取消暂停)
    SDL_PauseAudio(0);
    qDebug() << BUFFER_SIZE << "BUFFER_SIZE";
    // 存放从文件中读取的数据
        Uint8 data[BUFFER_SIZE];
        while (!isInterruptionRequested()) {
            // 只要从文件中读取的音频数据,还没有填充完毕,就跳过
            if (buffer.len > 0) continue;

            buffer.len = file.read((char *) data, BUFFER_SIZE);

            // 文件数据已经读取完毕
            if (buffer.len <= 0) {
                // 剩余的样本数量
                int samples = buffer.pullLen / BYTES_PER_SAMPLE;
                int ms = samples * 1000 / SAMPLE_RATE;
                SDL_Delay(ms);
                break;
            }

            // 读取到了文件数据
            buffer.data = data;
        }

回调函数

// 等待音频设备回调(会回调多次)
void pull_audio_data(void *userdata,
                     Uint8 *stream, // 需要往stream中填充PCM数据
                     int len) { // 希望填充的大小(samples * format * channels / 8)
    qDebug() << "pull_audio_data" << len;

    // 清空stream (静音处理)
    SDL_memset(stream, 0 , len);

    // 取出AudioBuffer
    AudioBuffer *buffer = (AudioBuffer *)userdata;

    // 文件数据还没准备好
    if (buffer->len <= 0) return;

    // 取len、bufferLen的最小值(为了保证数据安全,防止指针越界)
    buffer->pullLen = (len > buffer->len) ? buffer->len : len;

    // 填充数据
    SDL_MixAudio(stream, buffer->data, buffer->pullLen, SDL_MIX_MAXVOLUME);
    buffer->data += buffer->pullLen;
    buffer->len -= buffer->pullLen;
}

释放资源

 // 关闭文件
    file.close();

    // 关闭设备
    SDL_CloseAudio();

    // 清除所有的子系统
    SDL_Quit();

标签:buffer,len,音视频,PCM,SDL,播放,spec
来源: https://www.cnblogs.com/muzichenyu/p/15494111.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有