mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
Merge pull request #324 from jeoliva/id3
Add support for GEOB and PRIV ID3 frames.
This commit is contained in:
commit
2bb2e2c44f
4 changed files with 142 additions and 12 deletions
|
|
@ -123,6 +123,9 @@ import java.util.Locale;
|
|||
new Sample("Apple AAC media playlist",
|
||||
"https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear0/"
|
||||
+ "prog_index.m3u8", DemoUtil.TYPE_HLS),
|
||||
new Sample("Apple ID3 metadata",
|
||||
"http://devimages.apple.com/samplecode/adDemo/"
|
||||
+ "ad.m3u8", DemoUtil.TYPE_HLS),
|
||||
};
|
||||
|
||||
public static final Sample[] MISC = new Sample[] {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.exoplayer.metadata;
|
||||
|
||||
/**
|
||||
* A metadata that contains parsed ID3 GEOB (General Encapsulated Object) frame data associated
|
||||
* with time indices.
|
||||
*/
|
||||
public class GeobMetadata {
|
||||
|
||||
public static final String TYPE = "GEOB";
|
||||
|
||||
public final String mimeType;
|
||||
public final String filename;
|
||||
public final String description;
|
||||
public final byte[] data;
|
||||
|
||||
public GeobMetadata(String mimeType, String filename, String description, byte[] data) {
|
||||
this.mimeType = mimeType;
|
||||
this.filename = filename;
|
||||
this.description = description;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,6 +29,11 @@ import java.util.Map;
|
|||
*/
|
||||
public class Id3Parser implements MetadataParser<Map<String, Object>> {
|
||||
|
||||
private static final int ID3_TEXT_ENCODING_ISO_8859_1 = 0;
|
||||
private static final int ID3_TEXT_ENCODING_UTF_16 = 1;
|
||||
private static final int ID3_TEXT_ENCODING_UTF_16BE = 2;
|
||||
private static final int ID3_TEXT_ENCODING_UTF_8 = 3;
|
||||
|
||||
@Override
|
||||
public boolean canParse(String mimeType) {
|
||||
return mimeType.equals(MimeTypes.APPLICATION_ID3);
|
||||
|
|
@ -60,13 +65,48 @@ public class Id3Parser implements MetadataParser<Map<String, Object>> {
|
|||
byte[] frame = new byte[frameSize - 1];
|
||||
id3Data.readBytes(frame, 0, frameSize - 1);
|
||||
|
||||
int firstZeroIndex = indexOf(frame, 0, (byte) 0);
|
||||
int firstZeroIndex = indexOfEOS(frame, 0, encoding);
|
||||
String description = new String(frame, 0, firstZeroIndex, charset);
|
||||
int valueStartIndex = indexOfNot(frame, firstZeroIndex, (byte) 0);
|
||||
int valueEndIndex = indexOf(frame, valueStartIndex, (byte) 0);
|
||||
int valueStartIndex = firstZeroIndex + delimiterLength(encoding);
|
||||
int valueEndIndex = indexOfEOS(frame, valueStartIndex, encoding);
|
||||
String value = new String(frame, valueStartIndex, valueEndIndex - valueStartIndex,
|
||||
charset);
|
||||
metadata.put(TxxxMetadata.TYPE, new TxxxMetadata(description, value));
|
||||
} else if (frameId0 == 'P' && frameId1 == 'R' && frameId2 == 'I' && frameId3 == 'V') {
|
||||
// Check frame ID == PRIV
|
||||
byte[] frame = new byte[frameSize];
|
||||
id3Data.readBytes(frame, 0, frameSize);
|
||||
|
||||
int firstZeroIndex = indexOf(frame, 0, (byte) 0);
|
||||
String owner = new String(frame, 0, firstZeroIndex, "ISO-8859-1");
|
||||
byte[] privateData = new byte[frameSize - firstZeroIndex - 1];
|
||||
System.arraycopy(frame, firstZeroIndex + 1, privateData, 0, frameSize - firstZeroIndex - 1);
|
||||
metadata.put(PrivMetadata.TYPE, new PrivMetadata(owner, privateData));
|
||||
} else if (frameId0 == 'G' && frameId1 == 'E' && frameId2 == 'O' && frameId3 == 'B') {
|
||||
// Check frame ID == GEOB
|
||||
int encoding = id3Data.readUnsignedByte();
|
||||
String charset = getCharsetName(encoding);
|
||||
byte[] frame = new byte[frameSize - 1];
|
||||
id3Data.readBytes(frame, 0, frameSize - 1);
|
||||
|
||||
int firstZeroIndex = indexOf(frame, 0, (byte) 0);
|
||||
String mimeType = new String(frame, 0, firstZeroIndex, "ISO-8859-1");
|
||||
int filenameStartIndex = firstZeroIndex + 1;
|
||||
int filenameEndIndex = indexOfEOS(frame, filenameStartIndex, encoding);
|
||||
String filename = new String(frame, filenameStartIndex,
|
||||
filenameEndIndex - filenameStartIndex, charset);
|
||||
int descriptionStartIndex = filenameEndIndex + delimiterLength(encoding);
|
||||
int descriptionEndIndex = indexOfEOS(frame, descriptionStartIndex, encoding);
|
||||
String description = new String(frame, descriptionStartIndex,
|
||||
descriptionEndIndex - descriptionStartIndex, charset);
|
||||
|
||||
int objectDataSize = frameSize - 1 /* encoding byte */ - descriptionEndIndex -
|
||||
delimiterLength(encoding);
|
||||
byte[] objectData = new byte[objectDataSize];
|
||||
System.arraycopy(frame, descriptionEndIndex + delimiterLength(encoding), objectData, 0,
|
||||
objectDataSize);
|
||||
metadata.put(GeobMetadata.TYPE, new GeobMetadata(mimeType, filename,
|
||||
description, objectData));
|
||||
} else {
|
||||
String type = String.format("%c%c%c%c", frameId0, frameId1, frameId2, frameId3);
|
||||
byte[] frame = new byte[frameSize];
|
||||
|
|
@ -89,15 +129,30 @@ public class Id3Parser implements MetadataParser<Map<String, Object>> {
|
|||
return data.length;
|
||||
}
|
||||
|
||||
private static int indexOfNot(byte[] data, int fromIndex, byte key) {
|
||||
for (int i = fromIndex; i < data.length; i++) {
|
||||
if (data[i] != key) {
|
||||
return i;
|
||||
}
|
||||
private static int indexOfEOS(byte[] data, int fromIndex, int encodingByte) {
|
||||
int terminationPos = indexOf(data, fromIndex, (byte) 0);
|
||||
|
||||
// For single byte encoding charsets, we are done
|
||||
if(encodingByte == ID3_TEXT_ENCODING_ISO_8859_1 || encodingByte == ID3_TEXT_ENCODING_UTF_8) {
|
||||
return terminationPos;
|
||||
}
|
||||
|
||||
// Otherwise, look for a two zero bytes
|
||||
while(terminationPos < data.length - 1) {
|
||||
if(data[terminationPos + 1] == (byte) 0) {
|
||||
return terminationPos;
|
||||
}
|
||||
terminationPos = indexOf(data, terminationPos + 1, (byte) 0);
|
||||
}
|
||||
|
||||
return data.length;
|
||||
}
|
||||
|
||||
private static int delimiterLength(int encodingByte) {
|
||||
return (encodingByte == ID3_TEXT_ENCODING_ISO_8859_1 ||
|
||||
encodingByte == ID3_TEXT_ENCODING_UTF_8) ? 1 : 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ID3 header.
|
||||
*
|
||||
|
|
@ -142,13 +197,13 @@ public class Id3Parser implements MetadataParser<Map<String, Object>> {
|
|||
*/
|
||||
private static String getCharsetName(int encodingByte) {
|
||||
switch (encodingByte) {
|
||||
case 0:
|
||||
case ID3_TEXT_ENCODING_ISO_8859_1:
|
||||
return "ISO-8859-1";
|
||||
case 1:
|
||||
case ID3_TEXT_ENCODING_UTF_16:
|
||||
return "UTF-16";
|
||||
case 2:
|
||||
case ID3_TEXT_ENCODING_UTF_16BE:
|
||||
return "UTF-16BE";
|
||||
case 3:
|
||||
case ID3_TEXT_ENCODING_UTF_8:
|
||||
return "UTF-8";
|
||||
default:
|
||||
return "ISO-8859-1";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.exoplayer.metadata;
|
||||
|
||||
/**
|
||||
* A metadata that contains parsed ID3 PRIV (Private) frame data associated
|
||||
* with time indices.
|
||||
*/
|
||||
public class PrivMetadata {
|
||||
|
||||
public static final String TYPE = "PRIV";
|
||||
|
||||
public final String owner;
|
||||
public final byte[] privateData;
|
||||
|
||||
public PrivMetadata(String owner, byte[] privateData) {
|
||||
this.owner = owner;
|
||||
this.privateData = privateData;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue