Android FFmpeg音频重采样

FFmpeg :音频重采样 所谓的重采样,就是改变⾳频的采样率、sample format、声道数等参数,使之按照我们期望的参数输出。 阅读详情

自己有个需求,要把采样率为44100的PCM重采样为16000的PCM,经过1天的探索,终于成功了!!

网上的资料比较少,找到的都是比较零碎的知识点,只能慢慢摸索,想到这个,还是觉得有团队好,个人学习总是慢一点的,比较曲折,不过也能锻炼个人的学习能力!

基本原理

进入正题,所谓音频重采样,简单来说,就是在原来的PCM进行插值(低采样率到高采样率)或抽取(高采样率到低采样),但是如果我们只是线性插值或者抽取,抽取可能产生混叠,内插可能产生镜像,因此需要在抽取前进行抗混叠滤波,在内插后进行抗镜像滤波。抗混叠滤波和抗镜像滤波都是使用低通滤波器实现。

音频基础

采样率:

自然界的声音都是模拟信号,采样就是从这些模拟信号按一定的间隔采集数据,而1秒采集多少个,称之为采样率。

采样精度:

采集的数据得给他一个值,以多少计算好呢?此时就需要一个精度!如果最大的值为255,最小的值为0,那么采样的数值就得在0-255之间,精度为1/256,精度位数为8BIT;如果最大的值为65535,最小的值为0,那么采样的数值就得在0-65535之间,精度为1/65535,精度位数为16BIT;采样精度是采样所能达到的最小的精度。采样的精度越小,精度位数越大,采集的数据值就越接近模拟时的值。

声道:

顾名思义,就是声道数,一般有单声道,双声道,3声道等等。

音频帧:

一般音频帧有1024样品,那么一帧音频的数据量大小 = 声道数 * 样品数 * 每个样本占用的字节数。

这个概念对下面理解FFmpeg进行重采样很重要!

PCM格式

由于我们是对PCM进行重采样,因此我们对PCM格式有个基本了解!

PCM数据格式有2种:分片(plane)和打包(packed);

目前我遇到的都是packed格式,如下图:
PCM格式

一般我们会使用精度较高的16位,一个PCM由2Byte组成,低位在前,高位在后:

 short pcm1 = array[0];
 short pcm2 = origin[1];
 short pcm = (short) ((pcm1 & 0xff) | (pcm2 << 8));

重采样

直接上码:

/**
 * 重采样
 * @param env 
 * @param clazz 
 * @param sourcePath 源PCM文件
 * @param targetPath 目标PCM文件
 * @param sourceSampleRate 源采样率 
 * @param targetSampleRate 目标采样率
 * @param sourceChannels 源声道数
 * @param targetChannels 目标声道数
 * @return 
 */
static jint jniResample(JNIEnv *env, jclass clazz,
                        jstring sourcePath, jstring targetPath,
                        jint sourceSampleRate, jint targetSampleRate,
                        jint sourceChannels, jint targetChannels) {
    int result = -1;
    FILE *source;
    FILE *target;
    SwrContext *context;
    int sourceChannelLayout;
    int targetChannelLayout;
    AVSampleFormat sampleFormat;
    int sourceLineSize;
    int sourceBufferSize;
    int sourceSamples;
    uint8_t **sourceData;
    int targetLineSize;
    int targetBufferSize;
    int targetSamples;
    int targetMaxSamples;
    uint8_t **targetData;
    int read;
    const char *_sourcePath = env->GetStringUTFChars(sourcePath, 0);
    const char *_targetPath = env->GetStringUTFChars(targetPath, 0);
    // 打开文件
    source = fopen(_sourcePath, "rb");
    if (!source) {
        result = -1;
        goto R2;
    }
    target = fopen(_targetPath, "wb");
    if (!target) {
        fclose(source);
        goto R2;
    }
    // 重采样上下文
    context = swr_alloc();
    if (!context) {
        goto R1;
    }
    // 声道类型
    sourceChannelLayout = getChannelLayout(sourceChannels);
    targetChannelLayout = getChannelLayout(targetChannels);
    // 16BIT交叉存放PCM数据格式
    sampleFormat = AV_SAMPLE_FMT_S16;
    // 配置
    av_opt_set_int(context, "in_channel_layout", sourceChannelLayout, 0);
    av_opt_set_int(context, "in_sample_rate", sourceSampleRate, 0);
    av_opt_set_sample_fmt(context, "in_sample_fmt", sampleFormat, 0);
    av_opt_set_int(context, "out_channel_layout", targetChannelLayout, 0);
    av_opt_set_int(context, "out_sample_rate", targetSampleRate, 0);
    av_opt_set_sample_fmt(context, "out_sample_fmt", sampleFormat, 0);
    // 初始化
    if (swr_init(context) < 0) {
        result = -1;
        goto R1;
    }
    // 输入
    // 输入样品数 一帧1024样品数
    sourceSamples = 1024;
    // 输入大小 计算一帧样品数据量大小 = 声道数 * 样品数 * 每个样品所占字节 
    sourceBufferSize = av_samples_get_buffer_size(&sourceLineSize, sourceChannels, sourceSamples, sampleFormat, 1);
    // 分配输入空间
    result = av_samples_alloc_array_and_samples(&sourceData, &sourceLineSize, sourceChannels,
                                       sourceSamples, sampleFormat, 0);
    if (result < 0) {
        result = -1;
        goto R1;
    }
    // 输出
    // 计算(最大)输出样品数
    targetMaxSamples = targetSamples = (int) av_rescale_rnd(sourceSamples, targetSampleRate, sourceSampleRate, AV_ROUND_UP);
    // 分配输出空间
    result = av_samples_alloc_array_and_samples(&targetData, &targetLineSize, targetChannels,
                                                targetSamples, sampleFormat, 0);
    if (result < 0) {
        result = -1;
        goto R1;
    }
    // 循环读取文件
    // 每次读取一帧数据量大小
    read = fread(sourceData[0], 1, sourceBufferSize, source);
    while (read > 0) {
        // 计算输出样品数
        targetSamples = (int) av_rescale_rnd(swr_get_delay(context, sourceSampleRate) + sourceSamples, targetSampleRate, sourceSampleRate, AV_ROUND_UP);
        if (targetSamples > targetMaxSamples) {
            av_freep(&targetData[0]);
            result = av_samples_alloc(targetData, &targetLineSize, targetChannels, targetSamples, sampleFormat, 1);
            if (result < 0) {
                break;
            }
            targetMaxSamples = targetSamples;
        }
        // 重采样
        result = swr_convert(context, targetData, targetSamples,
                                 (const uint8_t **) sourceData, sourceSamples);
        if (result < 0) {
            break;
        }
        // 计算输出大小 result为一帧重采样数
        targetBufferSize = av_samples_get_buffer_size(&targetLineSize, targetChannels, result, sampleFormat, 1);
        if (targetBufferSize < 0) {
            break;
        }
        // 写入文件
        fwrite(targetData[0], 1, targetBufferSize, target);
        // 每次读取一帧数据量大小
        read = fread(sourceData[0], 1, sourceBufferSize, source);
    }
R1:
    // 关闭文件
    fclose(source);
    fclose(target);
R2:
    // 释放
    swr_free(&context);
    env->ReleaseStringUTFChars(sourcePath, _sourcePath);
    env->ReleaseStringUTFChars(targetPath, _targetPath);
    return result;
}

参考

FFMpeg笔记(三) 音频处理基本概念及音频重采样
PCM音频格式的深入理解

Android原生采集音频数据,ffmpeg进行重采样 第一步读数据 从AudioRecord提供的API读取pcm数据包 获取音频数据包size int minBufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT); 参数 44100 采样频率 AudioFormat.CHANNEL_IN_STEREO 声道布局设置,可以得出通道数 AudioFormat.ENCODING_PCM_ 阅读详情

相关推荐

音视频开发系列(63) -FFmpeg + AudioTrack 实现音频解码和播放

上一篇我们了解了FFmpeg解码流程、关键函数和结构体,实现了视频解码器。这篇我们来实现下音频的解码器。解码流程和视频的基本一致。FFmpeg解码的音频裸数据是PCM格式,android上播放PCM音频数据可以通过AudioTrack和OpenSL ES来实现。 下面我们下来看下解码的流程 一、音频解码流程 和上一篇的视频解码流程基本一致。需要注意的是音频对音频的重采样,以及不同样本格式的数据的排列方式 1.1 音频解码流程 avformat_open_input 打开媒体文件

yinshipin007的博客 764

Android音视频开发,详说PCM音频重采样、PCM编码

计算机采集大于40khz 就可以采集 就可以还原出现实世界的声音,这就是我们常见的采样率 44.1khz 48khz 怎么来的,就是根据人的耳朵的极限,有一点冗余 后面就开始定义44.1khz 48khz最经典的,看到无损这一些格式,96khz 192khz 这些采样率 这些是不是我的采样率越高 他越能还原出现实世界,就是有些人可以听的频率高一点,这个采样率越高 音质就会更好一些,高频率的 人的耳朵大概能听到20khz 超过就听不到了,不同的编码格式他是有区别的, 比如说我们最常见的编码格式,acc。

chezabo6116的博客 2065

Android Audio基础——音频流重采样(十三)

在音频处理过程中,音频流重采样是一个常见的需求,尤其是在不同设备之间进行音频传输或播放时。重采样就是将不同采样率的音频统一到相同的采样率(例如,将 44.1 kHz 的音频转换为 48 kHz 的音频),主要用于解决输入音频流的采样率与输出设备支持的采样率不匹配的问题。

小旭的专栏 1464

android 音频重采样_音频重采样的坑 - Clean Code - OSCHINA - 中文开源技术交流社区...

背景使用webrtc进行语音通话,网络正常的情况下,延迟比较大。进行过如下分析:(1)从socket收包到webrtc处理完音频没有耗时长的操作,排除了webrtc处理音频引入的延迟(2)与其他终端进行通话无延迟通过以上的分析,最终确认跟设备有关。分析发现Android设备存在重采用的问题。重采样的原因音频系统中可能存在多个音轨,而每个音轨的原始采样率可能是不一致的。比如在播放音乐的过程中,来了一...

weixin_39653766的博客 514

Android14实战:打破音频默认重采样的限制(五十二)

本篇目的:Android14实战:打破音频默认重采样的限制。

Android系统攻城狮 1702

ROS应用之如何配置RTOS满足机器人系统中的实时要求

实时操作系统(RTOS)基本概念实时操作系统(RTOS)是设计用于实时应用的操作系统,其主要目标是在确定的时间内完成任务。RTOS的任务调度算法和优先级控制机制能够确保高优先级任务按时完成。精确的传感器数据采集:传感器数据需要在规定时间内采集并传输给控制系统。快速响应外部事件:对于控制系统,需要确保指令在最短的时间内得到响应。任务的调度周期:任务的周期可以通过公式计算,其中 ftask 是任务的调度频率。优先级分配。

weixin_68094467的博客 1008

[Cmake-Android音视频]ffmpeg3.4音频重采样

[Cmake-Android]音视频总结: [Cmake-Android音视频]SDK,NDK基本介绍 [Cmake-Android音视频]NDK-r14b编译ffmpeg3.4支持neon,硬解码 [Cmake-Android音视频]创建支持ffmpeg3.4的项目 [Cmake-Android音视频]ffmpeg3.4实现解封装 [Cmake-An...

adolph_lu的博客 1969

从零到一:基于Blazor和Elsa Workflows的工作流系统开发实战

本文详细介绍了如何利用Blazor和Elsa Workflows构建高效的工作流系统,从技术选型到生产环境部署,涵盖动态工作流建模、Blazor前端集成及性能优化等核心内容。通过实战案例,展示如何实现订单处理系统的自动化与灵活性,提升企业流程效率。

weixin_26875109的博客 428

android 音频重采样_[Cmake-Android音视频]ffmpeg3.4音频重采样

[Cmake-Android]音视频总结:音频重采样流程图函数介绍swr_alloc()分配音频重采样的上下文swr_alloc_set_opts(...)设置音频重采样参数,可以通过音频的样本率来改变播放速度,但声音一般会失真struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,int64_t out_ch_layout,enum ...

weixin_36475420的博客 230

SpringBoot + MyBatis-Plus 高效实现数据变更记录:从注解到通用审计方案(附源码)

*** 数据变更审计插件* 拦截增删改操作,自动记录变更日志*/@Component@Resource/*** 拦截SQL执行*/@Override/*** 数据变更审计插件* 拦截增删改操作,自动记录变更日志/*** 拦截SQL执行。

2601_94871597的博客 559

YOLO26改进策略【卷积层】| SPD-Conv 针对小目标和低分辨率图像的检测任务

SPD-Conv是一种新的 CNN 构建模块,用于替代传统 CNN 架构中使用的步长卷积(strided convolution)和池化(pooling)层,它由空间到深度(Space-to-depth,SPD)层和非步长卷积(non - strided convolution)层组成。

Limiiiing的博客 357

【Android FFMPEG 开发】FFMPEG 音频重采样 ( 初始化音频重采样上下文 SwrContext | 计算音频延迟 | 计算输出样本个数 | 音频重采样 swr_convert )

I . FFMPEG 播放视频流程 II . FFMPEG 音频重采样流程 III . FFMPEG 音频重采样 IV . FFMPEG 初始化音频重采样上下文 SwrContext V . FFMPEG 计算音频延迟样本数 VI . FFMPEG 计算音频重采样输出样本个数 VII . FFMPEG 输出样本缓冲区初始化 VIII . FFMPEG 音频重采样 IX . FFMPEG 音频重采样输出的重采样数据字节数计算 X . FFMPEG 音频重采样部分代码总结

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 3401

SAP MD09 事务码中的物料需求追溯详解

物料需求追溯是指在物料需求计划中,追踪特定物料的需求来源和满足方式的过程。它帮助企业确定每个需求(如销售订单、独立需求、预留等)是由哪些供应元素(如库存、生产订单、采购订单等)来满足的。通过这种追溯,企业可以了解需求和供应之间的关系,从而优化生产和采购计划,减少库存积压,提升供应链效率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1193

【Android音视频开发】FFmpeg对音频数据重采样生成PCM数据

基本概念: 采样率:每秒对音频数据采样的个数(44100hz) 采样位数:存储采样数据的位数(16bit 2字节) 输出声道:单声道、立体声(左右声道)等 重采样: 就是把目标音频按照一定的格式重新采样编码成新的音频数据, 方便统一处理,一般的采样标准是:44100HZ、16bit、双声道 FFmpeg重采样 采样对象:解码出来的音频帧(AVframe) 使用函数:SwrContext swr_ctx = swr_alloc_set_opts( struct SwrCon...

乔培宸的博客 884

小程序设计中的区块链应用:数字藏品实现

本文旨在为开发者提供在小程序中实现区块链数字藏品功能的完整技术方案。区块链与数字藏品的基础概念智能合约的设计与实现小程序与区块链的交互方式数字藏品的完整实现流程文章将从基础概念入手,逐步深入到技术实现层面,最后通过完整项目案例展示数字藏品在小程序中的实现方式。每个技术点都会配合代码示例和架构图进行说明。区块链:一种分布式数据库技术,通过加密算法保证数据不可篡改数字藏品:基于区块链技术的数字资产,具有唯一性和可验证性NFT。

小程序开发 1351

dy创作者平台上传并发布视频

整体上来说不是很难,就是过程有点复杂。因为这个是别人给的单子,所以这里不放源码了。细致一点就可以搞定。如果要Signature算法,可私信,不免费。

记录一些web逆向的过程 1515

Android使用FFmpeg(四)--ffmpeg实现音频播放(使用AudioTrack进行播放)

关于 Android使用FFmpeg(一)--编译ffmpeg Android使用FFmpeg(二)--Android Studio配置ffmpeg Android使用FFmpeg(三)--ffmpeg实现视频播放 Android使用FFmpeg(四)--ffmpeg实现音频播放(使用Au...

测试0901-1 919

玩转 InternVL3.5 轻量级实战:从部署到优化的全记录

玩转 InternVL3.5 轻量级实战:从部署到优化的全记录

jacke121的专栏 626

Android FFmpeg视频播放器三 音频封装格式解码播放

Android FFmpeg视频播放器一解封装Android Android FFmpeg视频播放器二 视频封装格式解码播放视频解封装之后就会得到音频流和视频流,解封状得到的数据是AVPackage类型数据,需要进一步解码成AVFrame一帧一帧数据才能进行播放。 pthread_create:AVPackage解码得到AVFrame耗时操作,创建线程 getQueueAndDel:从AVPackage队列获取数据,阻塞队列,如果队列为空会进行wait阻塞 avcodec_send_packet:将获取到

风的轨迹 1325

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

pcm格式android播放器,Android万能音频播放器03--FFmpeg音频数据重采样后生成pcm文件...

1、基本概念采样率:每秒对音频数据采样的个数(44100hz)采样位数:存储采样数据的位数(16bit 2字节)输出声道(声道布局):单声道、立体声(左右声道)等2、重采样就是把目标音频按照一定的格式重新采样编码成新的音频数据,方便统一处理,一般的采样标准是:44100HZ、16bit、双声道3、采样对象:解码出来的音频帧(AVframe)使用函数:SwrContextswr_ctx = swr_...

weixin_39687786的博客 546

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

ffmpeg学习笔记-音频播放

前文讲到音频解码,将音频解码,并且输入到PCM文件,这里将音频通过AudioTrack直接输出 音频播放说明 在Android中自带的MediaPlayer也可以对音频播放,但其支持格式太少 使用ffmpeg可以支持更多格式 常用的音频播放有很多种方式,但播放PCM就只有OpenSL和AudioTrack 这里使用AudioTrack进行实现 在上文...

weixin_30455365的博客 86

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

ffmpeg 音乐循环_Android使用FFmpeg(四)--ffmpeg实现音频播放(使用AudioTrack进行播放)

关于准备工作正文 和视频播放一样我们依照流程图来实现,从这个流程图可以看出,音频播放和视频播放的大概流程并没有多大差别,只是细节之处需要处理。依照流程来实现1.注册组件,打开音频文件并获取内容,找到音频流:av_register_all();AVFormatContext *pFormatCtx = avformat_alloc_context();//openif (avformat_open_...

weixin_42492215的博客 430

android 音频采集、FLTP重采样与AAC编码推流

相比较视频编码,音频编码要简单很多,主要就是将采集到的音频源数据PCM编码AAC.MediaPlus中FFmpeg使用的是libfdk-aac编码器,这里有个问题需要注意下:FFmpeg已经废弃了AV_SAMPLE_FMT_S16格式PCM编码AAC,也就是说如果使用FFmpeg自带的AAC编码器,必须做音频的重采样(重采样为:AV_SAMPLE_FMT_FLTP),否则AAC编码是失败的。 ...

weixin_34274029的博客 799

Android 万能音频播放器 三 ffmpeg + opensl 实现声音的播放

Android 万能音频播放器三 ffmpeg + OpenSL 实现声音的播放 前言 在上几篇的文章中已经讲到了如何用OpenSL播放PCM数据,本篇文章主要讲解如何使用FFmepg 解码和重采样出PCM数据,并使用OpenSL 进行播放, 主要知识点 采样率:每秒对音频数据采样的个数(44100) 采样位数:存储采样数据的位数(16bit 2字节) 输出声道:单声道,立体声等 重...

yangyasong的博客 1156

Android PCM数据重采样与位宽修改实战指南:从原理到代码实现

PCM(脉冲编码调制)是数字音频最基础的表示形式,它直接记录声音波形采样点的数值。在Android开发中,我们经常需要处理来自麦克风、音频文件或网络流的PCM数据。PCM三要素:采样率(如44.1kHz)、位宽(如16bit)和声道数(如单声道),这三个参数决定了音频质量和数据大小Android中的PCM:AudioRecord采集、AudioTrack播放、MediaCodec编解码等底层操作都直接处理PCM数据为什么需要处理。

2600_94959839的博客 870

Ffmpeg + OpenSL ES + Android 播放音频

一 拿到音频的路径 ,然后根据 jni 发送数据到C语言的方法 然后,开始解析 avcodec_register_all(); avformat_network_init(); pPlayer->pFormatContext = avformat_alloc_context(); int openInput = avformat_open_input(&pPlayer->pFormatContext, url, NULL, NULL); .

sinat_40387150的博客 207
上一篇: JNI 同一个Module生成多个so
下一篇: PS 一键生成Android各个尺寸的图标
JohanMan
博客等级 码龄10年 72粉丝 131原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值