Provider(5) - AdjustChannelsBufferProvider

AdjustChannelsBufferProvider

简介

和downmix、remix差不多,也是用于转换通道数据,但是控制精度没有前者那么精细,downmix和remix会根据src_mask和dst_mask做通道对应,然后在进行数据拷贝,而AdjustChannelsBufferProvider则不同,往下看就知道了

重点CopyFrames

void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
{
    if (mInChannelCount > mOutChannelCount) {
        // For case multi to mono, adjust_channels has special logic that will mix first two input
        // channels into a single output channel. In that case, use adjust_channels_non_destructive
        // to keep only one channel data even when contracting to mono.
        adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount,
                mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
        //if条件是处理contracted,也就是附加在out本来数据之后的数据;比如4通道转2通道,成功后的输出数据
        // |1|2|3|4| == >> |1|2|1|2|....|3|4||3|4|..;3、4开头的就是额外的数据
        if (mContractedFormat != AUDIO_FORMAT_INVALID
            && mContractedBuffer != nullptr) {
                //输出数据总大小
            const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
                //额外的数据拷贝到mContractedBuffer上去
            memcpy_by_audio_format(
                    (uint8_t*) mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
                    mContractedFormat, (uint8_t*) dst + contractedIdx, mFormat,
                    mContractedChannelCount * frames);
                //并记录
            mContractedWrittenFrames += frames;
        }
    } else {
        // Prefer expanding data from the end of each audio frame.
        //结果其实和上面的adjust_channels_non_destructive一样,但是他不要求src和dst的长度相同
        adjust_channels(src, mInChannelCount, dst, mOutChannelCount,
                mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
    }
}
  • adjust_channels_non_destructive 非破坏性的channels转换方法,它会要求音频数据src和dst的长度必须相等
  • adjust_channels 自适应channels转换,不要求输出前后数据长度相等

adjust_channels_non_destructive

/* 调用此函数的前提in_buff和out_buff长度必须一致
* channels_in < channels_out: in=2,out=4; |1|2|1|2| ===>>> |1|2|3|4|1|2|3|4|  3、4通道填充0
* channels_in > channels_out: in=4,out=2;|1|2|3|4| ==>>> |1|2|1|2|...|3|4|3|4|
*/
size_t adjust_channels_non_destructive(const void* in_buff, size_t in_buff_chans,
                       void* out_buff, size_t out_buff_chans,
                        //采样大小   num_in_bytes=采样大小*channels*frames
                       unsigned sample_size_in_bytes, size_t num_in_bytes)
{
        //输出通道数与输入通道数比较
    if (out_buff_chans > in_buff_chans) {
                //destructive翻译破坏性的
        return expand_channels_non_destructive(in_buff, in_buff_chans, out_buff, out_buff_chans,
                               sample_size_in_bytes, num_in_bytes);
    } else if (out_buff_chans < in_buff_chans) {
        return contract_channels_non_destructive(in_buff, in_buff_chans, out_buff, out_buff_chans,
                                 sample_size_in_bytes, num_in_bytes);
    } else if (in_buff != out_buff) {
        memcpy(out_buff, in_buff, num_in_bytes);
    }

    return num_in_bytes;
}

上面函数的注释写的很清楚,其文件在./system/media/audio_utils/channels.c,最后会在一个宏定义实现,如下:


/* Expand number of channels from an input buffer to an output buffer.
 * See expand_channels_non_destructive() function below for parameter definitions.
 *
 * Input channels are copied to the output buffer, with extra output
 * channels interleaved from back of input buffer.
 *
 * So for in_chans = 2, out_chans = 4: [1|2|1|2...|3|4|3|4] => [1|2|3|4|1|2|3|4...]
 *
 * NOTE: in_buff must be same size as out_buff and num_in_bytes must
 * be a multiple of in_buff_channels * in_buff_sample_size.
 *
 * Uses a temporary buffer so that the conversion can be done in-place
 * i.e. in_buff == out_buff
 *
 * Macro has a return statement.
 * typeof(A) B = (A);typeof是G++编译器的功能,创建B,类型和A相同,并把对象A赋值给B
 */
#define EXPAND_CHANNELS_NON_DESTRUCTIVE(in_buff, in_buff_chans, \
        out_buff, out_buff_chans, num_in_bytes) \
{ \
    size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
    size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
    typeof(out_buff) dst_ptr = (out_buff); \
    typeof(in_buff) src_ptr = (in_buff); \
    typeof(*out_buff) temp_buff[num_in_samples]; \
    typeof(out_buff) temp_ptr = temp_buff; \
    /* if in-place, copy input channels to a temp buffer if-else已经将in_buff里
        面的有效数据拷贝完了,后面src_ptr+=不会超过数组总长度,是因为此函数条件
        in_buf和out_buf必须长度一样*/ \
    if ((in_buff) == (out_buff)) { \
        memcpy(temp_buff, src_ptr, (num_in_bytes)); \
        src_ptr += num_in_samples; \
    } else { \
        temp_ptr = (typeof(out_buff)) src_ptr; \
        src_ptr += num_in_samples; \
    } \
    /* interleave channels from end of source buffer with those from front */ \
    size_t src_index; \
    for (src_index = 0; src_index < num_out_samples; src_index += (out_buff_chans)) { \
        size_t dst_offset; \
        for (dst_offset = 0; dst_offset < (in_buff_chans); dst_offset++) { \
                /* 拷贝in_buff里面的有效数据 */\
            *dst_ptr++ = *temp_ptr++; \
        } \
        for (;dst_offset < (out_buff_chans); dst_offset++) { \
                /*这里的src_ptr里面应该是0*/\
            *dst_ptr++ = *src_ptr++; \
        } \
    } \
    /* return number of *bytes* generated */ \
    return num_out_samples * sizeof(*(out_buff)); \
}

值得注意的是in_buff和out_buff长度必须一致;

adjust_channels

size_t adjust_channels(const void* in_buff, size_t in_buff_chans,
                       void* out_buff, size_t out_buff_chans,
                       unsigned sample_size_in_bytes, size_t num_in_bytes)
{
    if (out_buff_chans > in_buff_chans) {
        return expand_channels(in_buff, in_buff_chans, out_buff,  out_buff_chans,
                               sample_size_in_bytes, num_in_bytes);
    } else if (out_buff_chans < in_buff_chans) {
        return contract_channels(in_buff, in_buff_chans, out_buff,  out_buff_chans,
                                 sample_size_in_bytes, num_in_bytes);
    } else if (in_buff != out_buff) {
        memcpy(out_buff, in_buff, num_in_bytes);
    }

    return num_in_bytes;
}

最终也会执行到另一个宏定义:

/* Channel expands from a MONO input buffer to a MULTICHANNEL output buffer by duplicating the
 * single input channel to the first 2 output channels and 0-filling the remaining.
 * See expand_channels() function below for parameter definitions.
 *
 * in_buff_chans MUST be 1 and out_buff_chans MUST be >= 2
 *
 * Move from back to front so that the conversion can be done in-place
 * i.e. in_buff == out_buff
 * NOTE: num_in_bytes must be a multiple of in_buff_channels * in_buff_sample_size.
 * for example:1==>3: |1||1|.. ==>> |1|2|3||1|2|3|.... 2和3通道填充0
 * Macro has a return statement.
 */
#define EXPAND_MONO_TO_MULTI(in_buff, in_buff_chans, out_buff, out_buff_chans, num_in_bytes, zero) \
{ \
    size_t num_in_samples = (num_in_bytes) / sizeof(*(in_buff)); \
    size_t num_out_samples = (num_in_samples * (out_buff_chans)) / (in_buff_chans); \
        /*指向指针尾巴*/\
    typeof(out_buff) dst_ptr = (out_buff) + num_out_samples - 1; \
    size_t src_index; \
    typeof(in_buff) src_ptr = (in_buff) + num_in_samples - 1; \
        /*多余通道为0*/\
    size_t num_zero_chans = (out_buff_chans) - (in_buff_chans) - 1; \
    for (src_index = 0; src_index < num_in_samples; src_index += (in_buff_chans)) { \
        size_t dst_offset; \
        /*先补充0*/\
        for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { \
            *dst_ptr-- = zero; \
        } \
        for (; dst_offset < (out_buff_chans); dst_offset++) { \
            *dst_ptr-- = *src_ptr; \
        } \
        src_ptr--; \
    } \
    /* return number of *bytes* generated */ \
    return num_out_samples * sizeof(*(out_buff)); \
}

其实和adjust_channels_non_destructive一样,不同的是对src和dst的长度没有要求

总结

adjust Channels更新是为了满足dst的channels配置,强行进行映射和填充,没有去确认dst和src的通道是不是对应,举个其实现的例子就明白了:

channels_in < channels_out: in=2,out=4; |1|2|1|2| ===>>> |1|2|3|4|1|2|3|4| 3、4通道填充0

channels_in > channels_out: in=4,out=2;|1|2|3|4| ==>>> |1|2|1|2|…|3|4|3|4|,多余的3、4通道拼接到数据末尾

相关推荐

  1. Provider(5) - AdjustChannelsBufferProvider

    2024-07-20 13:56:02       17 阅读
  2. OpenSSL provider

    2024-07-20 13:56:02       58 阅读
  3. 设计模式 - Provider 模式

    2024-07-20 13:56:02       30 阅读
  4. nestjs之providerprovide取值的几种方式

    2024-07-20 13:56:02       41 阅读
  5. vue 依赖注入 provide() inject()

    2024-07-20 13:56:02       58 阅读
  6. 展开说说provide和inject

    2024-07-20 13:56:02       43 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-20 13:56:02       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-20 13:56:02       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-20 13:56:02       45 阅读
  4. Python语言-面向对象

    2024-07-20 13:56:02       55 阅读

热门阅读

  1. lua 游戏架构 之 SceneLoad场景加载(一)

    2024-07-20 13:56:02       19 阅读
  2. Thread类的基本用法

    2024-07-20 13:56:02       15 阅读
  3. C?C++?

    2024-07-20 13:56:02       16 阅读
  4. ArcGIS Pro SDK (九)几何 10 弧

    2024-07-20 13:56:02       15 阅读
  5. AB测试介绍

    2024-07-20 13:56:02       18 阅读
  6. MULESOFT

    MULESOFT

    2024-07-20 13:56:02      18 阅读
  7. libevent的事件分发相关接口

    2024-07-20 13:56:02       18 阅读