Collect configuration values in IamfDecoder
.
Instead of hard-coding values in multiple files, all default values are declared in `IamfDecoder`. Additionally, the max number of frames used for output buffer initialisation is fetched from `libiamf` native functions. PiperOrigin-RevId: 658772175
This commit is contained in:
parent
9ace81bf2f
commit
20df8b282a
@ -2315,19 +2315,30 @@ public final class Util {
|
|||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public static int getPcmFrameSize(@C.PcmEncoding int pcmEncoding, int channelCount) {
|
public static int getPcmFrameSize(@C.PcmEncoding int pcmEncoding, int channelCount) {
|
||||||
|
return getByteDepth(pcmEncoding) * channelCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the byte depth for audio with the specified encoding.
|
||||||
|
*
|
||||||
|
* @param pcmEncoding The encoding of the audio data.
|
||||||
|
* @return The byte depth of the audio.
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
public static int getByteDepth(@C.PcmEncoding int pcmEncoding) {
|
||||||
switch (pcmEncoding) {
|
switch (pcmEncoding) {
|
||||||
case C.ENCODING_PCM_8BIT:
|
case C.ENCODING_PCM_8BIT:
|
||||||
return channelCount;
|
return 1;
|
||||||
case C.ENCODING_PCM_16BIT:
|
case C.ENCODING_PCM_16BIT:
|
||||||
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
|
case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
|
||||||
return channelCount * 2;
|
return 2;
|
||||||
case C.ENCODING_PCM_24BIT:
|
case C.ENCODING_PCM_24BIT:
|
||||||
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
|
case C.ENCODING_PCM_24BIT_BIG_ENDIAN:
|
||||||
return channelCount * 3;
|
return 3;
|
||||||
case C.ENCODING_PCM_32BIT:
|
case C.ENCODING_PCM_32BIT:
|
||||||
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
|
case C.ENCODING_PCM_32BIT_BIG_ENDIAN:
|
||||||
case C.ENCODING_PCM_FLOAT:
|
case C.ENCODING_PCM_FLOAT:
|
||||||
return channelCount * 4;
|
return 4;
|
||||||
case C.ENCODING_INVALID:
|
case C.ENCODING_INVALID:
|
||||||
case Format.NO_VALUE:
|
case Format.NO_VALUE:
|
||||||
default:
|
default:
|
||||||
|
@ -18,6 +18,7 @@ package androidx.media3.decoder.iamf;
|
|||||||
import static android.support.annotation.VisibleForTesting.PACKAGE_PRIVATE;
|
import static android.support.annotation.VisibleForTesting.PACKAGE_PRIVATE;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.decoder.DecoderInputBuffer;
|
import androidx.media3.decoder.DecoderInputBuffer;
|
||||||
import androidx.media3.decoder.SimpleDecoder;
|
import androidx.media3.decoder.SimpleDecoder;
|
||||||
@ -30,9 +31,10 @@ import javax.annotation.Nullable;
|
|||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
||||||
public final class IamfDecoder
|
public final class IamfDecoder
|
||||||
extends SimpleDecoder<DecoderInputBuffer, SimpleDecoderOutputBuffer, IamfDecoderException> {
|
extends SimpleDecoder<DecoderInputBuffer, SimpleDecoderOutputBuffer, IamfDecoderException> {
|
||||||
|
// TODO(ktrajkovski): Fetch channel count from the device instead of hardcoding.
|
||||||
// TODO(ktrajkovski): Find the maximum acceptable output buffer size.
|
/* package */ static final int DEFAULT_CHANNEL_COUNT = 2;
|
||||||
private static final int DEFAULT_OUTPUT_BUFFER_SIZE = 4096;
|
/* package */ static final int DEFAULT_OUTPUT_SAMPLE_RATE = 48000;
|
||||||
|
/* package */ static final @C.PcmEncoding int DEFAULT_PCM_ENCODING = C.ENCODING_PCM_16BIT;
|
||||||
|
|
||||||
private final byte[] initializationData;
|
private final byte[] initializationData;
|
||||||
|
|
||||||
@ -48,7 +50,12 @@ public final class IamfDecoder
|
|||||||
throw new IamfDecoderException("Initialization data must contain a single element.");
|
throw new IamfDecoderException("Initialization data must contain a single element.");
|
||||||
}
|
}
|
||||||
this.initializationData = initializationData.get(0);
|
this.initializationData = initializationData.get(0);
|
||||||
int status = iamfConfigDecoder(this.initializationData);
|
int status =
|
||||||
|
iamfConfigDecoder(
|
||||||
|
this.initializationData,
|
||||||
|
Util.getByteDepth(DEFAULT_PCM_ENCODING) * C.BITS_PER_BYTE,
|
||||||
|
DEFAULT_OUTPUT_SAMPLE_RATE,
|
||||||
|
DEFAULT_CHANNEL_COUNT);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
throw new IamfDecoderException("Failed to configure decoder with returned status: " + status);
|
throw new IamfDecoderException("Failed to configure decoder with returned status: " + status);
|
||||||
}
|
}
|
||||||
@ -90,9 +97,15 @@ public final class IamfDecoder
|
|||||||
DecoderInputBuffer inputBuffer, SimpleDecoderOutputBuffer outputBuffer, boolean reset) {
|
DecoderInputBuffer inputBuffer, SimpleDecoderOutputBuffer outputBuffer, boolean reset) {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
iamfClose();
|
iamfClose();
|
||||||
iamfConfigDecoder(this.initializationData); // reconfigure
|
iamfConfigDecoder(
|
||||||
|
this.initializationData,
|
||||||
|
Util.getByteDepth(DEFAULT_PCM_ENCODING) * C.BITS_PER_BYTE,
|
||||||
|
DEFAULT_OUTPUT_SAMPLE_RATE,
|
||||||
|
DEFAULT_CHANNEL_COUNT); // reconfigure
|
||||||
}
|
}
|
||||||
outputBuffer.init(inputBuffer.timeUs, DEFAULT_OUTPUT_BUFFER_SIZE);
|
int bufferSize =
|
||||||
|
iamfGetMaxFrameSize() * DEFAULT_CHANNEL_COUNT * Util.getByteDepth(DEFAULT_PCM_ENCODING);
|
||||||
|
outputBuffer.init(inputBuffer.timeUs, bufferSize);
|
||||||
ByteBuffer outputData = Util.castNonNull(outputBuffer.data);
|
ByteBuffer outputData = Util.castNonNull(outputBuffer.data);
|
||||||
ByteBuffer inputData = Util.castNonNull(inputBuffer.data);
|
ByteBuffer inputData = Util.castNonNull(inputBuffer.data);
|
||||||
int ret = iamfDecode(inputData, inputData.limit(), outputData);
|
int ret = iamfDecode(inputData, inputData.limit(), outputData);
|
||||||
@ -100,17 +113,22 @@ public final class IamfDecoder
|
|||||||
return new IamfDecoderException("Failed to decode error= " + ret);
|
return new IamfDecoderException("Failed to decode error= " + ret);
|
||||||
}
|
}
|
||||||
outputData.position(0);
|
outputData.position(0);
|
||||||
// TODO(ktrajkovski): Extract the outputData limit from the iamfDecode return value, given
|
outputData.limit(ret * DEFAULT_CHANNEL_COUNT * Util.getByteDepth(DEFAULT_PCM_ENCODING));
|
||||||
// channel count, and given bit depth.
|
|
||||||
outputData.limit(ret * 4); // x2 for expected bit depth, x2 for channel count
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private native int iamfLayoutBinauralChannelsCount();
|
private native int iamfLayoutBinauralChannelsCount();
|
||||||
|
|
||||||
private native int iamfConfigDecoder(byte[] initializationData);
|
private native int iamfConfigDecoder(
|
||||||
|
byte[] initializationData, int bitDepth, int sampleRate, int channelCount);
|
||||||
|
|
||||||
private native void iamfClose();
|
private native void iamfClose();
|
||||||
|
|
||||||
private native int iamfDecode(ByteBuffer inputBuffer, int inputSize, ByteBuffer outputBuffer);
|
private native int iamfDecode(ByteBuffer inputBuffer, int inputSize, ByteBuffer outputBuffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum expected number of PCM samples per channel in a compressed audio frame.
|
||||||
|
* Used to initialize the output buffer.
|
||||||
|
*/
|
||||||
|
private native int iamfGetMaxFrameSize();
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,6 @@ import java.util.Objects;
|
|||||||
/** Decodes and renders audio using the native IAMF decoder. */
|
/** Decodes and renders audio using the native IAMF decoder. */
|
||||||
public class LibiamfAudioRenderer extends DecoderAudioRenderer<IamfDecoder> {
|
public class LibiamfAudioRenderer extends DecoderAudioRenderer<IamfDecoder> {
|
||||||
|
|
||||||
// TODO(ktrajkovski): Values need to be configured and must come from the same source of truth as
|
|
||||||
// in {@link IamfDecoder}.
|
|
||||||
private static final int BINAURAL_CHANNEL_COUNT = 2;
|
|
||||||
private static final int DEFAULT_OUTPUT_SAMPLE_RATE = 48000;
|
|
||||||
private static final int DEFAULT_PCM_ENCODING = C.ENCODING_PCM_16BIT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
*
|
*
|
||||||
@ -89,7 +83,9 @@ public class LibiamfAudioRenderer extends DecoderAudioRenderer<IamfDecoder> {
|
|||||||
@Override
|
@Override
|
||||||
protected Format getOutputFormat(IamfDecoder decoder) {
|
protected Format getOutputFormat(IamfDecoder decoder) {
|
||||||
return Util.getPcmFormat(
|
return Util.getPcmFormat(
|
||||||
DEFAULT_PCM_ENCODING, BINAURAL_CHANNEL_COUNT, DEFAULT_OUTPUT_SAMPLE_RATE);
|
IamfDecoder.DEFAULT_PCM_ENCODING,
|
||||||
|
IamfDecoder.DEFAULT_CHANNEL_COUNT,
|
||||||
|
IamfDecoder.DEFAULT_OUTPUT_SAMPLE_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,18 +56,17 @@ DECODER_FUNC(jint, iamfLayoutBinauralChannelsCount) {
|
|||||||
|
|
||||||
IAMF_DecoderHandle handle;
|
IAMF_DecoderHandle handle;
|
||||||
|
|
||||||
DECODER_FUNC(jint, iamfConfigDecoder, jbyteArray initializationDataArray) {
|
DECODER_FUNC(jint, iamfConfigDecoder, jbyteArray initializationDataArray,
|
||||||
|
jint bitDepth, jint sampleRate, jint channelCount) {
|
||||||
handle = IAMF_decoder_open();
|
handle = IAMF_decoder_open();
|
||||||
|
|
||||||
// TODO(ktrajkovski): Values need to be aligned with IamfDecoder and
|
|
||||||
// LibiamfAudioRenderer and/or extracted from ConfigOBUs.
|
|
||||||
IAMF_decoder_peak_limiter_enable(handle, 0);
|
IAMF_decoder_peak_limiter_enable(handle, 0);
|
||||||
IAMF_decoder_peak_limiter_set_threshold(handle, -1.0f);
|
IAMF_decoder_set_bit_depth(handle, bitDepth);
|
||||||
IAMF_decoder_set_normalization_loudness(handle, 0.0f);
|
IAMF_decoder_set_sampling_rate(handle, sampleRate);
|
||||||
IAMF_decoder_set_bit_depth(handle, 16);
|
if (channelCount == 2) {
|
||||||
IAMF_decoder_set_sampling_rate(handle, 48000);
|
IAMF_decoder_output_layout_set_binaural(handle);
|
||||||
IAMF_decoder_output_layout_set_binaural(handle);
|
} else {
|
||||||
IAMF_decoder_set_pts(handle, 0, 90000);
|
IAMF_decoder_output_layout_set_sound_system(handle, SOUND_SYSTEM_INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t* bytes_read = nullptr;
|
uint32_t* bytes_read = nullptr;
|
||||||
jbyte* initializationDataBytes =
|
jbyte* initializationDataBytes =
|
||||||
@ -92,4 +91,8 @@ DECODER_FUNC(jint, iamfDecode, jobject inputBuffer, jint inputSize,
|
|||||||
reinterpret_cast<void*>(env->GetDirectBufferAddress(outputBuffer)));
|
reinterpret_cast<void*>(env->GetDirectBufferAddress(outputBuffer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODER_FUNC(jint, iamfGetMaxFrameSize) {
|
||||||
|
return IAMF_decoder_get_stream_info(handle)->max_frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
DECODER_FUNC(void, iamfClose) { IAMF_decoder_close(handle); }
|
DECODER_FUNC(void, iamfClose) { IAMF_decoder_close(handle); }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user