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通道拼接到数据末尾