blob: 70b1e96a8c46659af6f9d13a642387b84f6706d8 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.audio;
import com.google.android.exoplayer2.C;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
/** Utility methods for handling Opus audio streams. */
public class OpusUtil {
/** Opus streams are always 48000 Hz. */
public static final int SAMPLE_RATE = 48_000;
private static final int DEFAULT_SEEK_PRE_ROLL_SAMPLES = 3840;
private static final int FULL_CODEC_INITIALIZATION_DATA_BUFFER_COUNT = 3;
private OpusUtil() {} // Prevents instantiation.
/**
* Parses the channel count from an Opus Identification Header.
*
* @param header An Opus Identification Header, as defined by RFC 7845.
* @return The parsed channel count.
*/
public static int getChannelCount(byte[] header) {
return header[9] & 0xFF;
}
/**
* Builds codec initialization data from an Opus Identification Header.
*
* @param header An Opus Identification Header, as defined by RFC 7845.
* @return Codec initialization data suitable for an Opus <a
* href="https://developer.android.com/reference/android/media/MediaCodec#initialization">MediaCodec</a>.
*/
public static List<byte[]> buildInitializationData(byte[] header) {
int preSkipSamples = getPreSkipSamples(header);
long preSkipNanos = sampleCountToNanoseconds(preSkipSamples);
long seekPreRollNanos = sampleCountToNanoseconds(DEFAULT_SEEK_PRE_ROLL_SAMPLES);
List<byte[]> initializationData = new ArrayList<>(FULL_CODEC_INITIALIZATION_DATA_BUFFER_COUNT);
initializationData.add(header);
initializationData.add(buildNativeOrderByteArray(preSkipNanos));
initializationData.add(buildNativeOrderByteArray(seekPreRollNanos));
return initializationData;
}
private static int getPreSkipSamples(byte[] header) {
return ((header[11] & 0xFF) << 8) | (header[10] & 0xFF);
}
private static byte[] buildNativeOrderByteArray(long value) {
return ByteBuffer.allocate(8).order(ByteOrder.nativeOrder()).putLong(value).array();
}
private static long sampleCountToNanoseconds(long sampleCount) {
return (sampleCount * C.NANOS_PER_SECOND) / SAMPLE_RATE;
}
}