Audio encoder specifies channel-range

Allow the audio encoder XML to specify ranges of channels instead
of just a max (which had implied min==1).

Bug: 156273760
Test: atest android.media.cts.MediaCodecTest#testPrependHeadersToSyncFrames
Change-Id: Ib862e09074ffc34874f2c7d1a9f074096cebc046
Merged-In: Ib862e09074ffc34874f2c7d1a9f074096cebc046
This commit is contained in:
Ray Essick
2020-10-13 20:04:11 -07:00
committed by Jean-Michel Trivi
parent 4f3e949354
commit 3acc244e52
2 changed files with 108 additions and 15 deletions

View File

@@ -21108,7 +21108,9 @@ package android.media {
public static final class MediaCodecInfo.AudioCapabilities {
method public android.util.Range<java.lang.Integer> getBitrateRange();
method @NonNull public android.util.Range<java.lang.Integer>[] getInputChannelCountRanges();
method public int getMaxInputChannelCount();
method public int getMinInputChannelCount();
method public android.util.Range<java.lang.Integer>[] getSupportedSampleRateRanges();
method public int[] getSupportedSampleRates();
method public boolean isSampleRateSupported(int);

View File

@@ -1089,7 +1089,7 @@ public final class MediaCodecInfo {
private int[] mSampleRates;
private Range<Integer>[] mSampleRateRanges;
private int mMaxInputChannelCount;
private Range<Integer>[] mInputChannelRanges;
private static final int MAX_INPUT_CHANNEL_COUNT = 30;
@@ -1119,11 +1119,61 @@ public final class MediaCodecInfo {
}
/**
* Returns the maximum number of input channels supported. The codec
* supports any number of channels between 1 and this maximum value.
* Returns the maximum number of input channels supported.
*
* Through {@link android.os.Build.VERSION_CODES#R}, this method indicated support
* for any number of input channels between 1 and this maximum value.
*
* As of {@link android.os.Build.VERSION_CODES#S},
* the implied lower limit of 1 channel is no longer valid.
* As of {@link android.os.Build.VERSION_CODES#S}, {@link #getMaxInputChannelCount} is
* superseded by {@link #getInputChannelCountRanges},
* which returns an array of ranges of channels.
* The {@link #getMaxInputChannelCount} method will return the highest value
* in the ranges returned by {@link #getInputChannelCountRanges}
*
*/
public int getMaxInputChannelCount() {
return mMaxInputChannelCount;
int overall_max = 0;
for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
int lmax = mInputChannelRanges[i].getUpper();
if (lmax > overall_max) {
overall_max = lmax;
}
}
return overall_max;
}
/**
* Returns the minimum number of input channels supported.
* This is often 1, but does vary for certain mime types.
*
* This returns the lowest channel count in the ranges returned by
* {@link #getInputChannelCountRanges}.
*/
public int getMinInputChannelCount() {
int overall_min = MAX_INPUT_CHANNEL_COUNT;
for (int i = mInputChannelRanges.length - 1; i >= 0; i--) {
int lmin = mInputChannelRanges[i].getLower();
if (lmin < overall_min) {
overall_min = lmin;
}
}
return overall_min;
}
/*
* Returns an array of ranges representing the number of input channels supported.
* The codec supports any number of input channels within this range.
*
* This supersedes the {@link #getMaxInputChannelCount} method.
*
* For many codecs, this will be a single range [1..N], for some N.
*/
@SuppressLint("ArrayReturn")
@NonNull
public Range<Integer>[] getInputChannelCountRanges() {
return Arrays.copyOf(mInputChannelRanges, mInputChannelRanges.length);
}
/* no public constructor */
@@ -1146,7 +1196,7 @@ public final class MediaCodecInfo {
private void initWithPlatformLimits() {
mBitrateRange = Range.create(0, Integer.MAX_VALUE);
mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT;
mInputChannelRanges = new Range[] {Range.create(1, MAX_INPUT_CHANNEL_COUNT)};
// mBitrateRange = Range.create(1, 320000);
final int minSampleRate = SystemProperties.
getInt("ro.mediacodec.min_sample_rate", 7350);
@@ -1158,9 +1208,12 @@ public final class MediaCodecInfo {
private boolean supports(Integer sampleRate, Integer inputChannels) {
// channels and sample rates are checked orthogonally
if (inputChannels != null &&
(inputChannels < 1 || inputChannels > mMaxInputChannelCount)) {
return false;
if (inputChannels != null) {
int ix = Utils.binarySearchDistinctRanges(
mInputChannelRanges, inputChannels);
if (ix < 0) {
return false;
}
}
if (sampleRate != null) {
int ix = Utils.binarySearchDistinctRanges(
@@ -1292,12 +1345,28 @@ public final class MediaCodecInfo {
} else if (sampleRateRange != null) {
limitSampleRates(new Range[] { sampleRateRange });
}
applyLimits(maxChannels, bitRates);
Range<Integer> channelRange = Range.create(1, maxChannels);
applyLimits(new Range[] { channelRange }, bitRates);
}
private void applyLimits(int maxInputChannels, Range<Integer> bitRates) {
mMaxInputChannelCount = Range.create(1, mMaxInputChannelCount)
.clamp(maxInputChannels);
private void applyLimits(Range<Integer>[] inputChannels, Range<Integer> bitRates) {
// clamp & make a local copy
Range<Integer>[] myInputChannels = new Range[inputChannels.length];
for (int i = 0; i < inputChannels.length; i++) {
int lower = inputChannels[i].clamp(1);
int upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT);
myInputChannels[i] = Range.create(lower, upper);
}
// sort, intersect with existing, & save channel list
sortDistinctRanges(myInputChannels);
Range<Integer>[] joinedChannelList =
intersectSortedDistinctRanges(myInputChannels, mInputChannelRanges);
mInputChannelRanges = joinedChannelList;
if (bitRates != null) {
mBitrateRange = mBitrateRange.intersect(bitRates);
}
@@ -1305,6 +1374,7 @@ public final class MediaCodecInfo {
private void parseFromInfo(MediaFormat info) {
int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
Range<Integer>[] channels = new Range[] { Range.create(1, maxInputChannels)};
Range<Integer> bitRates = POSITIVE_INTEGERS;
if (info.containsKey("sample-rate-ranges")) {
@@ -1315,17 +1385,38 @@ public final class MediaCodecInfo {
}
limitSampleRates(rateRanges);
}
if (info.containsKey("max-channel-count")) {
// we will prefer channel-ranges over max-channel-count
if (info.containsKey("channel-ranges")) {
String[] channelStrings = info.getString("channel-ranges").split(",");
Range<Integer>[] channelRanges = new Range[channelStrings.length];
for (int i = 0; i < channelStrings.length; i++) {
channelRanges[i] = Utils.parseIntRange(channelStrings[i], null);
}
channels = channelRanges;
} else if (info.containsKey("channel-range")) {
Range<Integer> oneRange = Utils.parseIntRange(info.getString("channel-range"),
null);
channels = new Range[] { oneRange };
} else if (info.containsKey("max-channel-count")) {
maxInputChannels = Utils.parseIntSafely(
info.getString("max-channel-count"), maxInputChannels);
if (maxInputChannels == 0) {
channels = new Range[] {Range.create(0, 0)};
} else {
channels = new Range[] {Range.create(1, maxInputChannels)};
}
} else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
maxInputChannels = 0;
channels = new Range[] {Range.create(0, 0)};
}
if (info.containsKey("bitrate-range")) {
bitRates = bitRates.intersect(
Utils.parseIntRange(info.getString("bitrate-range"), bitRates));
}
applyLimits(maxInputChannels, bitRates);
applyLimits(channels, bitRates);
}
/** @hide */
@@ -1334,7 +1425,7 @@ public final class MediaCodecInfo {
if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) {
format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower());
}
if (mMaxInputChannelCount == 1) {
if (getMaxInputChannelCount() == 1) {
// mono-only format
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
}