mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Pass through all ID3 internal data from udta
Also switch from using a CommentFrame to a new InternalFrame type for ID3 data stored with ID '----', to distinguish internal data from actual ID3 comments. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=201315254
This commit is contained in:
parent
d8a61aade7
commit
a75b5fb6a9
4 changed files with 114 additions and 10 deletions
|
|
@ -31,6 +31,8 @@
|
||||||
([#4360](https://github.com/google/ExoPlayer/issues/4360)).
|
([#4360](https://github.com/google/ExoPlayer/issues/4360)).
|
||||||
* Add `PlayerView.isControllerVisible`
|
* Add `PlayerView.isControllerVisible`
|
||||||
([#4385](https://github.com/google/ExoPlayer/issues/4385)).
|
([#4385](https://github.com/google/ExoPlayer/issues/4385)).
|
||||||
|
* Expose all internal ID3 data stored in MP4 udta boxes, and switch from using
|
||||||
|
CommentFrame to InternalFrame for frames with gapless metadata in MP4.
|
||||||
|
|
||||||
### 2.8.2 ###
|
### 2.8.2 ###
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.metadata.Metadata;
|
import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.metadata.id3.CommentFrame;
|
import com.google.android.exoplayer2.metadata.id3.CommentFrame;
|
||||||
import com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate;
|
import com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate;
|
||||||
|
import com.google.android.exoplayer2.metadata.id3.InternalFrame;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
@ -39,7 +40,8 @@ public final class GaplessInfoHolder {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String GAPLESS_COMMENT_ID = "iTunSMPB";
|
private static final String GAPLESS_DOMAIN = "com.apple.iTunes";
|
||||||
|
private static final String GAPLESS_DESCRIPTION = "iTunSMPB";
|
||||||
private static final Pattern GAPLESS_COMMENT_PATTERN =
|
private static final Pattern GAPLESS_COMMENT_PATTERN =
|
||||||
Pattern.compile("^ [0-9a-fA-F]{8} ([0-9a-fA-F]{8}) ([0-9a-fA-F]{8})");
|
Pattern.compile("^ [0-9a-fA-F]{8} ([0-9a-fA-F]{8}) ([0-9a-fA-F]{8})");
|
||||||
|
|
||||||
|
|
@ -91,7 +93,15 @@ public final class GaplessInfoHolder {
|
||||||
Metadata.Entry entry = metadata.get(i);
|
Metadata.Entry entry = metadata.get(i);
|
||||||
if (entry instanceof CommentFrame) {
|
if (entry instanceof CommentFrame) {
|
||||||
CommentFrame commentFrame = (CommentFrame) entry;
|
CommentFrame commentFrame = (CommentFrame) entry;
|
||||||
if (setFromComment(commentFrame.description, commentFrame.text)) {
|
if (GAPLESS_DESCRIPTION.equals(commentFrame.description)
|
||||||
|
&& setFromComment(commentFrame.text)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (entry instanceof InternalFrame) {
|
||||||
|
InternalFrame internalFrame = (InternalFrame) entry;
|
||||||
|
if (GAPLESS_DOMAIN.equals(internalFrame.domain)
|
||||||
|
&& GAPLESS_DESCRIPTION.equals(internalFrame.description)
|
||||||
|
&& setFromComment(internalFrame.text)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -103,14 +113,10 @@ public final class GaplessInfoHolder {
|
||||||
* Populates the holder with data parsed from a gapless playback comment (stored in an ID3 header
|
* Populates the holder with data parsed from a gapless playback comment (stored in an ID3 header
|
||||||
* or MPEG 4 user data), if valid and non-zero.
|
* or MPEG 4 user data), if valid and non-zero.
|
||||||
*
|
*
|
||||||
* @param name The comment's identifier.
|
|
||||||
* @param data The comment's payload data.
|
* @param data The comment's payload data.
|
||||||
* @return Whether the holder was populated.
|
* @return Whether the holder was populated.
|
||||||
*/
|
*/
|
||||||
private boolean setFromComment(String name, String data) {
|
private boolean setFromComment(String data) {
|
||||||
if (!GAPLESS_COMMENT_ID.equals(name)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Matcher matcher = GAPLESS_COMMENT_PATTERN.matcher(data);
|
Matcher matcher = GAPLESS_COMMENT_PATTERN.matcher(data);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer2.metadata.Metadata;
|
||||||
import com.google.android.exoplayer2.metadata.id3.ApicFrame;
|
import com.google.android.exoplayer2.metadata.id3.ApicFrame;
|
||||||
import com.google.android.exoplayer2.metadata.id3.CommentFrame;
|
import com.google.android.exoplayer2.metadata.id3.CommentFrame;
|
||||||
import com.google.android.exoplayer2.metadata.id3.Id3Frame;
|
import com.google.android.exoplayer2.metadata.id3.Id3Frame;
|
||||||
|
import com.google.android.exoplayer2.metadata.id3.InternalFrame;
|
||||||
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
|
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
@ -293,14 +294,13 @@ import com.google.android.exoplayer2.util.Util;
|
||||||
data.skipBytes(atomSize - 12);
|
data.skipBytes(atomSize - 12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!"com.apple.iTunes".equals(domain) || !"iTunSMPB".equals(name) || dataAtomPosition == -1) {
|
if (domain == null || name == null || dataAtomPosition == -1) {
|
||||||
// We're only interested in iTunSMPB.
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
data.setPosition(dataAtomPosition);
|
data.setPosition(dataAtomPosition);
|
||||||
data.skipBytes(16); // size (4), type (4), version (1), flags (3), empty (4)
|
data.skipBytes(16); // size (4), type (4), version (1), flags (3), empty (4)
|
||||||
String value = data.readNullTerminatedString(dataAtomSize - 16);
|
String value = data.readNullTerminatedString(dataAtomSize - 16);
|
||||||
return new CommentFrame(LANGUAGE_UNDEFINED, name, value);
|
return new InternalFrame(domain, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int parseUint8AttributeValue(ParsableByteArray data) {
|
private static int parseUint8AttributeValue(ParsableByteArray data) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.metadata.id3;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
|
||||||
|
/** Internal ID3 frame that is intended for use by the player. */
|
||||||
|
public final class InternalFrame extends Id3Frame {
|
||||||
|
|
||||||
|
public static final String ID = "----";
|
||||||
|
|
||||||
|
public final String domain;
|
||||||
|
public final String description;
|
||||||
|
public final String text;
|
||||||
|
|
||||||
|
public InternalFrame(String domain, String description, String text) {
|
||||||
|
super(ID);
|
||||||
|
this.domain = domain;
|
||||||
|
this.description = description;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ InternalFrame(Parcel in) {
|
||||||
|
super(ID);
|
||||||
|
domain = Assertions.checkNotNull(in.readString());
|
||||||
|
description = Assertions.checkNotNull(in.readString());
|
||||||
|
text = Assertions.checkNotNull(in.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
InternalFrame other = (InternalFrame) obj;
|
||||||
|
return Util.areEqual(description, other.description)
|
||||||
|
&& Util.areEqual(domain, other.domain)
|
||||||
|
&& Util.areEqual(text, other.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + (domain != null ? domain.hashCode() : 0);
|
||||||
|
result = 31 * result + (description != null ? description.hashCode() : 0);
|
||||||
|
result = 31 * result + (text != null ? text.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return id + ": domain=" + domain + ", description=" + description;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parcelable implementation.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(id);
|
||||||
|
dest.writeString(domain);
|
||||||
|
dest.writeString(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<InternalFrame> CREATOR =
|
||||||
|
new Creator<InternalFrame>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InternalFrame createFromParcel(Parcel in) {
|
||||||
|
return new InternalFrame(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InternalFrame[] newArray(int size) {
|
||||||
|
return new InternalFrame[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue