音频重采样

很多时候在播放音频时,音频的采样率、通道数等并不能满足我们播放得需求,这就需要我们对音频进行重采样。

FFmpeg提供的方法libswresample.a库为我们很好的解决重采样的问题,下面就对如何使用这个库进行具体说明。

#pragma mark -- 重采样
- (int)AudioResamplingWithAVCodecContext:(AVCodecContext *)audio_dec_ctx andAVFrame:(AVFrame *)pAudioDecodeFrame andOutfmt:(int)out_sample_fmt andOutchannels:(int)out_channels  andOutRate:(int)out_sample_rate  andOutbuf:(uint8_t *)out_buf
{
    //
    SwrContext * swr_ctx = NULL;
    int data_size = 0;
    int ret = 0;
    int64_t src_ch_layout = AV_CH_LAYOUT_STEREO; //初始化这样根据不同文件做调整
    int64_t dst_ch_layout = AV_CH_LAYOUT_STEREO; //这里设定ok
    int dst_nb_channels = 0;
    int dst_linesize = 0;
    int src_nb_samples = 0;
    int dst_nb_samples = 0;
    int max_dst_nb_samples = 0;
    uint8_t **dst_data = NULL;
    int resampled_data_size = 0;
    
    //重新采样
    if (swr_ctx)
    {
        swr_free(&swr_ctx);
    }
    swr_ctx = swr_alloc();//为重采样上下文申请空间
    if (!swr_ctx)
    {
        printf("swr_alloc error \n");
        return -1;
    }
    
    src_ch_layout = (audio_dec_ctx->channel_layout &&
                     audio_dec_ctx->channels ==
                     av_get_channel_layout_nb_channels(audio_dec_ctx->channel_layout)) ?
    audio_dec_ctx->channel_layout :
    av_get_default_channel_layout(audio_dec_ctx->channels);
    
    if (out_channels == 1)//输出单声道
    {
        dst_ch_layout = AV_CH_LAYOUT_MONO;
    }
    else if(out_channels == 2)//输出双声道
    {
        dst_ch_layout = AV_CH_LAYOUT_STEREO;
    }
    else
    {
        //可扩展
    }
    
    if (src_ch_layout <= 0)
    {
        printf("src_ch_layout error \n");
        return -1;
    }
//   src_nb_samples的值是固定的   aac:1024    opus:960   mp3:1152
    src_nb_samples = pAudioDecodeFrame->nb_samples;
    if (src_nb_samples <= 0)
    {
        printf("src_nb_samples error \n");
        return -1;
    }
    
    /* 设置参数 */
    av_opt_set_int(swr_ctx, "in_channel_layout",    src_ch_layout, 0);//设置输入源的通道布局
    av_opt_set_int(swr_ctx, "in_sample_rate",       audio_dec_ctx->sample_rate, 0);//设置输入源的采样率
    av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", audio_dec_ctx->sample_fmt, 0);//设置输入源的采样格式
    
    av_opt_set_int(swr_ctx, "out_channel_layout",    dst_ch_layout, 0);//设置输出源的通道布局
    av_opt_set_int(swr_ctx, "out_sample_rate",       out_sample_rate, 0);//设置输出源的采样率
    av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", (enum AVSampleFormat)out_sample_fmt, 0);//设置输出源的采样格式
    
    swr_init(swr_ctx);

    /**
     av_rescale_rnd作用:
     将以audio_dec_ctx->sample_rate表示的src_nb_samples转换成out_sample_rate。
     AV_ROUND_UP:取整方式选择趋于更大的整数
     */
    //计算转换后的采样数,要避免溢出
    max_dst_nb_samples = dst_nb_samples = (int)av_rescale_rnd(src_nb_samples, out_sample_rate, audio_dec_ctx->sample_rate, AV_ROUND_UP);
   
    if (max_dst_nb_samples <= 0)
    {
        printf("av_rescale_rnd error \n");
        return -1;
    }
    
    //分配目标采样存储空间
    dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
    ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,
                                             dst_nb_samples, (enum AVSampleFormat)out_sample_fmt, 0);
    if (ret < 0)
    {
        printf("av_samples_alloc_array_and_samples error \n");
        return -1;
    }
    //计算方式为:a*b/c ,先转换成64位再除y,避免溢出
    dst_nb_samples = (int)av_rescale_rnd(swr_get_delay(swr_ctx, audio_dec_ctx->sample_rate) +
                                    src_nb_samples, out_sample_rate, audio_dec_ctx->sample_rate,AV_ROUND_UP);
    if (dst_nb_samples <= 0)
    {
        printf("av_rescale_rnd error \n");
        return -1;
    }
    if (dst_nb_samples > max_dst_nb_samples)
        
    {
        av_free(dst_data[0]);
        ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
                               dst_nb_samples, (enum AVSampleFormat)out_sample_fmt, 1);
        max_dst_nb_samples = dst_nb_samples;
    }
    
    data_size = av_samples_get_buffer_size(NULL, audio_dec_ctx->channels,
                                           pAudioDecodeFrame->nb_samples,
                                           audio_dec_ctx->sample_fmt, 1);
    if (data_size <= 0)
    {
        printf("av_samples_get_buffer_size error \n");
        return -1;
    }
    resampled_data_size = data_size;
    
    if (swr_ctx)
    {
//        主要是将FLT和FLTP格式转换成S16或S16P格式
        ret = swr_convert(swr_ctx, dst_data, dst_nb_samples,
                          (const uint8_t **)pAudioDecodeFrame->data, pAudioDecodeFrame->nb_samples);
        if (ret <= 0)
        {
            printf("swr_convert error \n");
            return -1;
        }
//        获取重采样后的数据大小
        resampled_data_size = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,
                                                         ret, (enum AVSampleFormat)out_sample_fmt, 1);
        if (resampled_data_size <= 0)
        {
            printf("av_samples_get_buffer_size error \n");
            return -1;
        }
    }
    else
    {
        printf("swr_ctx null error \n");
        return -1;
    }
    
    //将值返回去
    memcpy(out_buf,dst_data[0],resampled_data_size);
    
    if (dst_data)  
    {
        av_freep(&dst_data[0]);  
    }  
    av_freep(&dst_data);  
    dst_data = NULL;  
    
    if (swr_ctx)  
    {  
        swr_free(&swr_ctx);  
    }  
    return resampled_data_size;  
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java音频重采样是指将音频信号的采样率进行修改或调整的过程。采样率是指在单位时间内对音频信号进行采样的次数,通常以赫兹(Hz)为单位。例如,CD音频采样率为44.1kHz,即每秒对音频信号采样44,100次。 音频重采样的目的是为了改变音频信号的采样率,以满足特定需求或要求。例如,当两个不同采样率的音频需要进行混合时,就需要进行重采样。另外,有些设备或平台只支持特定的采样率,那么我们也需要将音频重采样到符合其要求的采样率。 在Java中,可以使用一些库或框架来进行音频重采样。例如,可以使用Java Sound API提供的功能来进行音频重采样。通过Java Sound API,可以获取音频数据流的采样率,并使用线性插值或其他算法将其转换为目标采样率。 要进行音频重采样,我们需要注意一些关键点。首先,要选择合适的重采样算法,以保证音质不受损。其次,要平衡采样率变化对音频信号的影响,避免出现混叠或伪音等问题。最后,要对重采样后的音频进行适当的处理和校正,以确保音质的准确性和真实性。 总之,Java音频重采样是一项重要的音频处理技术,可以用于解决不同采样音频的兼容性问题,同时也能为我们提供更好的音频体验。通过选择合适的算法和处理方法,我们可以有效地进行音频重采样,并获得满足需求的音频信号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值