mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Standardize ALAC initialization data
Android considers ALAC initialization data to consider of the magic cookie only, where-as FFmpeg requires a full atom. Standardize around the Android definition, since it makes more sense (the magic cookie being contained within an atom is container specific, where-as the decoder shouldn't care what container the media stream is carried in) Issue: #5938 PiperOrigin-RevId: 261124155
This commit is contained in:
parent
95ed5ce65d
commit
cb8983afd1
2 changed files with 35 additions and 18 deletions
|
|
@ -172,28 +172,49 @@ import java.util.List;
|
||||||
private static @Nullable byte[] getExtraData(String mimeType, List<byte[]> initializationData) {
|
private static @Nullable byte[] getExtraData(String mimeType, List<byte[]> initializationData) {
|
||||||
switch (mimeType) {
|
switch (mimeType) {
|
||||||
case MimeTypes.AUDIO_AAC:
|
case MimeTypes.AUDIO_AAC:
|
||||||
case MimeTypes.AUDIO_ALAC:
|
|
||||||
case MimeTypes.AUDIO_OPUS:
|
case MimeTypes.AUDIO_OPUS:
|
||||||
return initializationData.get(0);
|
return initializationData.get(0);
|
||||||
|
case MimeTypes.AUDIO_ALAC:
|
||||||
|
return getAlacExtraData(initializationData);
|
||||||
case MimeTypes.AUDIO_VORBIS:
|
case MimeTypes.AUDIO_VORBIS:
|
||||||
byte[] header0 = initializationData.get(0);
|
return getVorbisExtraData(initializationData);
|
||||||
byte[] header1 = initializationData.get(1);
|
|
||||||
byte[] extraData = new byte[header0.length + header1.length + 6];
|
|
||||||
extraData[0] = (byte) (header0.length >> 8);
|
|
||||||
extraData[1] = (byte) (header0.length & 0xFF);
|
|
||||||
System.arraycopy(header0, 0, extraData, 2, header0.length);
|
|
||||||
extraData[header0.length + 2] = 0;
|
|
||||||
extraData[header0.length + 3] = 0;
|
|
||||||
extraData[header0.length + 4] = (byte) (header1.length >> 8);
|
|
||||||
extraData[header0.length + 5] = (byte) (header1.length & 0xFF);
|
|
||||||
System.arraycopy(header1, 0, extraData, header0.length + 6, header1.length);
|
|
||||||
return extraData;
|
|
||||||
default:
|
default:
|
||||||
// Other codecs do not require extra data.
|
// Other codecs do not require extra data.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] getAlacExtraData(List<byte[]> initializationData) {
|
||||||
|
// FFmpeg's ALAC decoder expects an ALAC atom, which contains the ALAC "magic cookie", as extra
|
||||||
|
// data. initializationData[0] contains only the magic cookie, and so we need to package it into
|
||||||
|
// an ALAC atom. See:
|
||||||
|
// https://ffmpeg.org/doxygen/0.6/alac_8c.html
|
||||||
|
// https://github.com/macosforge/alac/blob/master/ALACMagicCookieDescription.txt
|
||||||
|
byte[] magicCookie = initializationData.get(0);
|
||||||
|
int alacAtomLength = 12 + magicCookie.length;
|
||||||
|
ByteBuffer alacAtom = ByteBuffer.allocate(alacAtomLength);
|
||||||
|
alacAtom.putInt(alacAtomLength);
|
||||||
|
alacAtom.putInt(0x616c6163); // type=alac
|
||||||
|
alacAtom.putInt(0); // version=0, flags=0
|
||||||
|
alacAtom.put(magicCookie, /* offset= */ 0, magicCookie.length);
|
||||||
|
return alacAtom.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] getVorbisExtraData(List<byte[]> initializationData) {
|
||||||
|
byte[] header0 = initializationData.get(0);
|
||||||
|
byte[] header1 = initializationData.get(1);
|
||||||
|
byte[] extraData = new byte[header0.length + header1.length + 6];
|
||||||
|
extraData[0] = (byte) (header0.length >> 8);
|
||||||
|
extraData[1] = (byte) (header0.length & 0xFF);
|
||||||
|
System.arraycopy(header0, 0, extraData, 2, header0.length);
|
||||||
|
extraData[header0.length + 2] = 0;
|
||||||
|
extraData[header0.length + 3] = 0;
|
||||||
|
extraData[header0.length + 4] = (byte) (header1.length >> 8);
|
||||||
|
extraData[header0.length + 5] = (byte) (header1.length & 0xFF);
|
||||||
|
System.arraycopy(header1, 0, extraData, header0.length + 6, header1.length);
|
||||||
|
return extraData;
|
||||||
|
}
|
||||||
|
|
||||||
private native long ffmpegInitialize(
|
private native long ffmpegInitialize(
|
||||||
String codecName,
|
String codecName,
|
||||||
@Nullable byte[] extraData,
|
@Nullable byte[] extraData,
|
||||||
|
|
|
||||||
|
|
@ -1154,10 +1154,6 @@ import java.util.List;
|
||||||
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType, null,
|
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType, null,
|
||||||
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0,
|
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0,
|
||||||
language);
|
language);
|
||||||
} else if (childAtomType == Atom.TYPE_alac) {
|
|
||||||
initializationData = new byte[childAtomSize];
|
|
||||||
parent.setPosition(childPosition);
|
|
||||||
parent.readBytes(initializationData, /* offset= */ 0, childAtomSize);
|
|
||||||
} else if (childAtomType == Atom.TYPE_dOps) {
|
} else if (childAtomType == Atom.TYPE_dOps) {
|
||||||
// Build an Opus Identification Header (defined in RFC-7845) by concatenating the Opus Magic
|
// Build an Opus Identification Header (defined in RFC-7845) by concatenating the Opus Magic
|
||||||
// Signature and the body of the dOps atom.
|
// Signature and the body of the dOps atom.
|
||||||
|
|
@ -1166,7 +1162,7 @@ import java.util.List;
|
||||||
System.arraycopy(opusMagic, 0, initializationData, 0, opusMagic.length);
|
System.arraycopy(opusMagic, 0, initializationData, 0, opusMagic.length);
|
||||||
parent.setPosition(childPosition + Atom.HEADER_SIZE);
|
parent.setPosition(childPosition + Atom.HEADER_SIZE);
|
||||||
parent.readBytes(initializationData, opusMagic.length, childAtomBodySize);
|
parent.readBytes(initializationData, opusMagic.length, childAtomBodySize);
|
||||||
} else if (childAtomSize == Atom.TYPE_dfLa) {
|
} else if (childAtomSize == Atom.TYPE_dfLa || childAtomType == Atom.TYPE_alac) {
|
||||||
int childAtomBodySize = childAtomSize - Atom.FULL_HEADER_SIZE;
|
int childAtomBodySize = childAtomSize - Atom.FULL_HEADER_SIZE;
|
||||||
initializationData = new byte[childAtomBodySize];
|
initializationData = new byte[childAtomBodySize];
|
||||||
parent.setPosition(childPosition + Atom.FULL_HEADER_SIZE);
|
parent.setPosition(childPosition + Atom.FULL_HEADER_SIZE);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue