FFmpeg(11)-基于FFmpeg进行音频重采样(swr_init(), swr_convert())

一.包含头文件和库文件

修改CMakeLists

# swresample
add_library(swresample SHARED IMPORTED)
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${FF}/libswresample.so)

更新target_link_libraries

复制代码
target_link_libraries( # Specifies the target library.
                       native-lib
                       avcodec
                       avformat
                       avutil
                       swscale
                       swresample

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )
复制代码

在代码中包含头文件 #include <libswresample/swresample.h> 

二.相关函数说明

a)

SwrContext *swr_alloc(void);  // 分配重采样的上下文。

SwrContext *swr_alloc_set_opts(struct SwrContext *s, int64_t out_ch_layout, AVSampleFormat out_sample_fmt, int out_sample_rate

, int64_t in_ch_layout, AVSampleFormat in_sample_fmt, int in_sample_rate, int log_offset, void *log_ctx

);

参数1:重采样上下文

参数2:输出的layout, 如:5.1声道…

参数3:输出的样本格式。Float, S16, S24

参数4:输出的样本率。可以不变。

参数5:输入的layout。

参数6:输入的样本格式。

参数7:输入的样本率。

参数8,参数9,日志,不用管,可直接传0

针对音频的播放速度,可以通过样本率的改变而改变。

 

int swr_init(struct SwrContext *s);                       // 初始化上下文

void swr_free(struct SwrContext **s);                  // 释放上下文空间。

 

b) 

swr_convert()

针对每一帧音频的处理。把一帧帧的音频作相应的重采样

int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, const uint8_t **in, int in_count);

参数1:音频重采样的上下文

参数2:输出的指针。传递的输出的数组

参数3:输出的样本数量,不是字节数。单通道的样本数量。

参数4:输入的数组,AVFrame解码出来的DATA

参数5:输入的单通道的样本数量。

三.示例代码

复制代码
// 初始化像素格式转换上下文
    SwsContext *vctx = NULL;
    int outWidth = 1280;
    int outHeight = 720;
    char *rgb = new char[1920*1080*4];
    char *pcm = new char[48000*4*2];

    // 初始化音频重采样上下文
    SwrContext *actx = swr_alloc();
    actx = swr_alloc_set_opts(
            actx,
            av_get_default_channel_layout(2),
            AV_SAMPLE_FMT_S16,
            ac->sample_rate,
            av_get_default_channel_layout(ac->channels),
            ac->sample_fmt,
            ac->sample_rate,
            0, 0
    );

    ret = swr_init(actx);
    if (ret != 0) {
        LOGE("swr_init failed");
    } else {
        LOGI("swr_init success");
    }

    for (;;) {

        if (getNowMs() - start >= 3000) {
            LOGI("now decoder fps is: %d", frameCount / 3);
            start = getNowMs();
            frameCount = 0;
        }
        int ret = av_read_frame(ic, packet);
        if (ret != 0) {
            LOGE("读取到结尾处");
            int pos = 20 * r2d(ic->streams[videoStream]->time_base);
            // 改变播放进度
            av_seek_frame(ic, videoStream, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
            continue;
        }

//        LOGI("Read a Packet. streamIndex=%d, size=%d, pts=%lld, flag=%d",
//             packet->stream_index,
//             packet->size,
//             packet->pts,
//             packet->flags
//        );

        AVCodecContext *cc = vc;
        if (packet->stream_index == audioStream) cc = ac;
        // 发送到线程中去解码(将packet写入到解码队列当中去)
        ret = avcodec_send_packet(cc, packet);
        // 清理
        int p = packet->pts;
        av_packet_unref(packet);
        if (ret != 0) {
            // LOGE("avcodec_send_packet failed.");
            continue;
        }

        for(;;) {
            // 从已解码成功的数据当中取出一个frame, 要注意send一次,receive不一定是一次
            ret = avcodec_receive_frame(cc, frame);
            if (ret != 0) {
                break;
            }
            if (cc == vc) {
                frameCount++;
                vctx = sws_getCachedContext(
                        vctx,
                        frame->width,
                        frame->height,
                        (AVPixelFormat)frame->format,
                        outWidth,
                        outHeight,
                        AV_PIX_FMT_RGBA,
                        SWS_FAST_BILINEAR,
                        0, 0, 0
                );
                if (!vctx) {
                    LOGE("sws_getCachedContext failed!");
                } else {
                    // 开始像素格式转换
                    uint8_t  *data[AV_NUM_DATA_POINTERS] = {0};
                    data[0] = (uint8_t *)rgb;
                    int lines[AV_NUM_DATA_POINTERS] = {0};
                    lines[0] = outWidth * 4;
                    int h = sws_scale(
                            vctx,
                            (const uint8_t **)frame->data,
                            frame->linesize,
                            0,
                            frame->height,
                            data, lines
                    );
                    LOGI("sws_scale = %d", h);
                }
            } else { // 音频部分
                uint8_t *out[2] = {0};
                out[0] = (uint8_t *)pcm;
                // 音频重采样
                int len = swr_convert(
                        actx,
                        out,
                        frame->nb_samples,
                        (const uint8_t **)frame->data,
                        frame->nb_samples
                );
                LOGI("swr_convert = %d", len);
            }
            // LOGI("Receive a frame.........");
        }
    }

    delete rgb;
    delete pcm;
复制代码

 



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   夜行过客  阅读(10635)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
历史上的今天:
2016-10-22 新浪微博客户端(10)-切换多个fragment
点击右上角即可分享
微信分享提示