Merge pull request #10799 from OxygenCobalt:id3v2-multi-value

PiperOrigin-RevId: 491289028
This commit is contained in:
Rohit Singh 2022-11-29 18:35:59 +00:00
commit b81d5f304e
55 changed files with 248 additions and 112 deletions

View File

@ -17,6 +17,9 @@ Release notes
* Session: * Session:
* Add helper method to convert platform session token to Media3 * Add helper method to convert platform session token to Media3
`SessionToken` ([#171](https://github.com/androidx/media/issues/171)). `SessionToken` ([#171](https://github.com/androidx/media/issues/171)).
* Metadata:
* Parse multiple null-separated values from ID3 frames, as permitted by
ID3 v2.4.
* Remove deprecated symbols: * Remove deprecated symbols:
* Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder` * Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder`
instead. instead.

View File

@ -10408,7 +10408,9 @@ public final class ExoPlayerTest {
new Metadata( new Metadata(
new BinaryFrame(/* id= */ "", /* data= */ new byte[0]), new BinaryFrame(/* id= */ "", /* data= */ new byte[0]),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TT2", /* description= */ null, /* value= */ "title"))) /* id= */ "TT2",
/* description= */ null,
/* values= */ ImmutableList.of("title"))))
.build(); .build();
// Set multiple values together. // Set multiple values together.

View File

@ -108,7 +108,7 @@ public class MetadataRendererTest {
assertThat(metadata).hasSize(1); assertThat(metadata).hasSize(1);
assertThat(metadata.get(0).length()).isEqualTo(1); assertThat(metadata.get(0).length()).isEqualTo(1);
TextInformationFrame expectedId3Frame = TextInformationFrame expectedId3Frame =
new TextInformationFrame("TXXX", "Test description", "Test value"); new TextInformationFrame("TXXX", "Test description", ImmutableList.of("Test value"));
assertThat(metadata.get(0).get(0)).isEqualTo(expectedId3Frame); assertThat(metadata.get(0).get(0)).isEqualTo(expectedId3Frame);
} }

View File

@ -813,7 +813,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
if (entry instanceof TextInformationFrame) { if (entry instanceof TextInformationFrame) {
TextInformationFrame textFrame = (TextInformationFrame) entry; TextInformationFrame textFrame = (TextInformationFrame) entry;
if ("TXXX".equals(textFrame.id)) { if ("TXXX".equals(textFrame.id)) {
streamPlayer.triggerUserTextReceived(textFrame.value); streamPlayer.triggerUserTextReceived(textFrame.values.get(0));
} }
} else if (entry instanceof EventMessage) { } else if (entry instanceof EventMessage) {
EventMessage eventMessage = (EventMessage) entry; EventMessage eventMessage = (EventMessage) entry;

View File

@ -26,6 +26,7 @@ import androidx.media3.common.util.Util;
import androidx.media3.extractor.metadata.MetadataInputBuffer; import androidx.media3.extractor.metadata.MetadataInputBuffer;
import androidx.media3.extractor.metadata.SimpleMetadataDecoder; import androidx.media3.extractor.metadata.SimpleMetadataDecoder;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableList;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -457,14 +458,13 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
byte[] data = new byte[frameSize - 1]; byte[] data = new byte[frameSize - 1];
id3Data.readBytes(data, 0, frameSize - 1); id3Data.readBytes(data, 0, frameSize - 1);
int descriptionEndIndex = indexOfEos(data, 0, encoding); int descriptionEndIndex = indexOfTerminator(data, 0, encoding);
String description = new String(data, 0, descriptionEndIndex, charset); String description = new String(data, 0, descriptionEndIndex, charset);
int valueStartIndex = descriptionEndIndex + delimiterLength(encoding); ImmutableList<String> values =
int valueEndIndex = indexOfEos(data, valueStartIndex, encoding); decodeTextInformationFrameValues(
String value = decodeStringIfValid(data, valueStartIndex, valueEndIndex, charset); data, encoding, descriptionEndIndex + delimiterLength(encoding));
return new TextInformationFrame("TXXX", description, values);
return new TextInformationFrame("TXXX", description, value);
} }
@Nullable @Nullable
@ -476,15 +476,34 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
} }
int encoding = id3Data.readUnsignedByte(); int encoding = id3Data.readUnsignedByte();
String charset = getCharsetName(encoding);
byte[] data = new byte[frameSize - 1]; byte[] data = new byte[frameSize - 1];
id3Data.readBytes(data, 0, frameSize - 1); id3Data.readBytes(data, 0, frameSize - 1);
int valueEndIndex = indexOfEos(data, 0, encoding); ImmutableList<String> values = decodeTextInformationFrameValues(data, encoding, 0);
String value = new String(data, 0, valueEndIndex, charset); return new TextInformationFrame(id, null, values);
}
return new TextInformationFrame(id, null, value); private static ImmutableList<String> decodeTextInformationFrameValues(
byte[] data, final int encoding, final int index) throws UnsupportedEncodingException {
if (index >= data.length) {
return ImmutableList.of("");
}
ImmutableList.Builder<String> values = ImmutableList.builder();
String charset = getCharsetName(encoding);
int valueStartIndex = index;
int valueEndIndex = indexOfTerminator(data, valueStartIndex, encoding);
while (valueStartIndex < valueEndIndex) {
String value = new String(data, valueStartIndex, valueEndIndex - valueStartIndex, charset);
values.add(value);
valueStartIndex = valueEndIndex + delimiterLength(encoding);
valueEndIndex = indexOfTerminator(data, valueStartIndex, encoding);
}
ImmutableList<String> result = values.build();
return result.isEmpty() ? ImmutableList.of("") : result;
} }
@Nullable @Nullable
@ -501,7 +520,7 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
byte[] data = new byte[frameSize - 1]; byte[] data = new byte[frameSize - 1];
id3Data.readBytes(data, 0, frameSize - 1); id3Data.readBytes(data, 0, frameSize - 1);
int descriptionEndIndex = indexOfEos(data, 0, encoding); int descriptionEndIndex = indexOfTerminator(data, 0, encoding);
String description = new String(data, 0, descriptionEndIndex, charset); String description = new String(data, 0, descriptionEndIndex, charset);
int urlStartIndex = descriptionEndIndex + delimiterLength(encoding); int urlStartIndex = descriptionEndIndex + delimiterLength(encoding);
@ -548,11 +567,11 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
String mimeType = new String(data, 0, mimeTypeEndIndex, "ISO-8859-1"); String mimeType = new String(data, 0, mimeTypeEndIndex, "ISO-8859-1");
int filenameStartIndex = mimeTypeEndIndex + 1; int filenameStartIndex = mimeTypeEndIndex + 1;
int filenameEndIndex = indexOfEos(data, filenameStartIndex, encoding); int filenameEndIndex = indexOfTerminator(data, filenameStartIndex, encoding);
String filename = decodeStringIfValid(data, filenameStartIndex, filenameEndIndex, charset); String filename = decodeStringIfValid(data, filenameStartIndex, filenameEndIndex, charset);
int descriptionStartIndex = filenameEndIndex + delimiterLength(encoding); int descriptionStartIndex = filenameEndIndex + delimiterLength(encoding);
int descriptionEndIndex = indexOfEos(data, descriptionStartIndex, encoding); int descriptionEndIndex = indexOfTerminator(data, descriptionStartIndex, encoding);
String description = String description =
decodeStringIfValid(data, descriptionStartIndex, descriptionEndIndex, charset); decodeStringIfValid(data, descriptionStartIndex, descriptionEndIndex, charset);
@ -590,7 +609,7 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
int pictureType = data[mimeTypeEndIndex + 1] & 0xFF; int pictureType = data[mimeTypeEndIndex + 1] & 0xFF;
int descriptionStartIndex = mimeTypeEndIndex + 2; int descriptionStartIndex = mimeTypeEndIndex + 2;
int descriptionEndIndex = indexOfEos(data, descriptionStartIndex, encoding); int descriptionEndIndex = indexOfTerminator(data, descriptionStartIndex, encoding);
String description = String description =
new String( new String(
data, descriptionStartIndex, descriptionEndIndex - descriptionStartIndex, charset); data, descriptionStartIndex, descriptionEndIndex - descriptionStartIndex, charset);
@ -619,11 +638,11 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
data = new byte[frameSize - 4]; data = new byte[frameSize - 4];
id3Data.readBytes(data, 0, frameSize - 4); id3Data.readBytes(data, 0, frameSize - 4);
int descriptionEndIndex = indexOfEos(data, 0, encoding); int descriptionEndIndex = indexOfTerminator(data, 0, encoding);
String description = new String(data, 0, descriptionEndIndex, charset); String description = new String(data, 0, descriptionEndIndex, charset);
int textStartIndex = descriptionEndIndex + delimiterLength(encoding); int textStartIndex = descriptionEndIndex + delimiterLength(encoding);
int textEndIndex = indexOfEos(data, textStartIndex, encoding); int textEndIndex = indexOfTerminator(data, textStartIndex, encoding);
String text = decodeStringIfValid(data, textStartIndex, textEndIndex, charset); String text = decodeStringIfValid(data, textStartIndex, textEndIndex, charset);
return new CommentFrame(language, description, text); return new CommentFrame(language, description, text);
@ -800,7 +819,7 @@ public final class Id3Decoder extends SimpleMetadataDecoder {
: String.format(Locale.US, "%c%c%c%c", frameId0, frameId1, frameId2, frameId3); : String.format(Locale.US, "%c%c%c%c", frameId0, frameId1, frameId2, frameId3);
} }
private static int indexOfEos(byte[] data, int fromIndex, int encoding) { private static int indexOfTerminator(byte[] data, int fromIndex, int encoding) {
int terminationPos = indexOfZeroByte(data, fromIndex); int terminationPos = indexOfZeroByte(data, fromIndex);
// For single byte encoding charsets, we're done. // For single byte encoding charsets, we're done.

View File

@ -15,7 +15,8 @@
*/ */
package androidx.media3.extractor.metadata.id3; package androidx.media3.extractor.metadata.id3;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
@ -23,6 +24,8 @@ import androidx.annotation.Nullable;
import androidx.media3.common.MediaMetadata; import androidx.media3.common.MediaMetadata;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.InlineMe;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -31,42 +34,69 @@ import java.util.List;
public final class TextInformationFrame extends Id3Frame { public final class TextInformationFrame extends Id3Frame {
@Nullable public final String description; @Nullable public final String description;
public final String value;
public TextInformationFrame(String id, @Nullable String description, String value) { /**
* @deprecated Use the first element of {@link #values} instead.
*/
@Deprecated public final String value;
/** The text values of this frame. Will always have at least one element. */
public final ImmutableList<String> values;
public TextInformationFrame(String id, @Nullable String description, List<String> values) {
super(id); super(id);
checkArgument(!values.isEmpty());
this.description = description; this.description = description;
this.value = value; this.values = ImmutableList.copyOf(values);
this.value = this.values.get(0);
} }
/* package */ TextInformationFrame(Parcel in) { /**
super(castNonNull(in.readString())); * @deprecated Use {@code TextInformationFrame(String id, String description, String[] values}
description = in.readString(); * instead
value = castNonNull(in.readString()); */
@Deprecated
@InlineMe(
replacement = "this(id, description, ImmutableList.of(value))",
imports = "com.google.common.collect.ImmutableList")
public TextInformationFrame(String id, @Nullable String description, String value) {
this(id, description, ImmutableList.of(value));
} }
private TextInformationFrame(Parcel in) {
this(
checkNotNull(in.readString()),
in.readString(),
ImmutableList.copyOf(checkNotNull(in.createStringArray())));
}
/**
* Uses the first element in {@link #values} to set the relevant field in {@link MediaMetadata}
* (as determined by {@link #id}).
*/
@Override @Override
public void populateMediaMetadata(MediaMetadata.Builder builder) { public void populateMediaMetadata(MediaMetadata.Builder builder) {
switch (id) { switch (id) {
case "TT2": case "TT2":
case "TIT2": case "TIT2":
builder.setTitle(value); builder.setTitle(values.get(0));
break; break;
case "TP1": case "TP1":
case "TPE1": case "TPE1":
builder.setArtist(value); builder.setArtist(values.get(0));
break; break;
case "TP2": case "TP2":
case "TPE2": case "TPE2":
builder.setAlbumArtist(value); builder.setAlbumArtist(values.get(0));
break; break;
case "TAL": case "TAL":
case "TALB": case "TALB":
builder.setAlbumTitle(value); builder.setAlbumTitle(values.get(0));
break; break;
case "TRK": case "TRK":
case "TRCK": case "TRCK":
String[] trackNumbers = Util.split(value, "/"); String[] trackNumbers = Util.split(values.get(0), "/");
try { try {
int trackNumber = Integer.parseInt(trackNumbers[0]); int trackNumber = Integer.parseInt(trackNumbers[0]);
@Nullable @Nullable
@ -80,7 +110,7 @@ public final class TextInformationFrame extends Id3Frame {
case "TYE": case "TYE":
case "TYER": case "TYER":
try { try {
builder.setRecordingYear(Integer.parseInt(value)); builder.setRecordingYear(Integer.parseInt(values.get(0)));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// Do nothing, invalid input. // Do nothing, invalid input.
} }
@ -88,15 +118,16 @@ public final class TextInformationFrame extends Id3Frame {
case "TDA": case "TDA":
case "TDAT": case "TDAT":
try { try {
int month = Integer.parseInt(value.substring(2, 4)); String date = values.get(0);
int day = Integer.parseInt(value.substring(0, 2)); int month = Integer.parseInt(date.substring(2, 4));
int day = Integer.parseInt(date.substring(0, 2));
builder.setRecordingMonth(month).setRecordingDay(day); builder.setRecordingMonth(month).setRecordingDay(day);
} catch (NumberFormatException | StringIndexOutOfBoundsException e) { } catch (NumberFormatException | StringIndexOutOfBoundsException e) {
// Do nothing, invalid input. // Do nothing, invalid input.
} }
break; break;
case "TDRC": case "TDRC":
List<Integer> recordingDate = parseId3v2point4TimestampFrameForDate(value); List<Integer> recordingDate = parseId3v2point4TimestampFrameForDate(values.get(0));
switch (recordingDate.size()) { switch (recordingDate.size()) {
case 3: case 3:
builder.setRecordingDay(recordingDate.get(2)); builder.setRecordingDay(recordingDate.get(2));
@ -114,7 +145,7 @@ public final class TextInformationFrame extends Id3Frame {
} }
break; break;
case "TDRL": case "TDRL":
List<Integer> releaseDate = parseId3v2point4TimestampFrameForDate(value); List<Integer> releaseDate = parseId3v2point4TimestampFrameForDate(values.get(0));
switch (releaseDate.size()) { switch (releaseDate.size()) {
case 3: case 3:
builder.setReleaseDay(releaseDate.get(2)); builder.setReleaseDay(releaseDate.get(2));
@ -133,15 +164,15 @@ public final class TextInformationFrame extends Id3Frame {
break; break;
case "TCM": case "TCM":
case "TCOM": case "TCOM":
builder.setComposer(value); builder.setComposer(values.get(0));
break; break;
case "TP3": case "TP3":
case "TPE3": case "TPE3":
builder.setConductor(value); builder.setConductor(values.get(0));
break; break;
case "TXT": case "TXT":
case "TEXT": case "TEXT":
builder.setWriter(value); builder.setWriter(values.get(0));
break; break;
default: default:
break; break;
@ -159,7 +190,7 @@ public final class TextInformationFrame extends Id3Frame {
TextInformationFrame other = (TextInformationFrame) obj; TextInformationFrame other = (TextInformationFrame) obj;
return Util.areEqual(id, other.id) return Util.areEqual(id, other.id)
&& Util.areEqual(description, other.description) && Util.areEqual(description, other.description)
&& Util.areEqual(value, other.value); && values.equals(other.values);
} }
@Override @Override
@ -167,13 +198,13 @@ public final class TextInformationFrame extends Id3Frame {
int result = 17; int result = 17;
result = 31 * result + id.hashCode(); result = 31 * result + id.hashCode();
result = 31 * result + (description != null ? description.hashCode() : 0); result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (value != null ? value.hashCode() : 0); result = 31 * result + values.hashCode();
return result; return result;
} }
@Override @Override
public String toString() { public String toString() {
return id + ": description=" + description + ": value=" + value; return id + ": description=" + description + ": values=" + values;
} }
// Parcelable implementation. // Parcelable implementation.
@ -182,7 +213,7 @@ public final class TextInformationFrame extends Id3Frame {
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id); dest.writeString(id);
dest.writeString(description); dest.writeString(description);
dest.writeString(value); dest.writeStringArray(values.toArray(new String[0]));
} }
public static final Parcelable.Creator<TextInformationFrame> CREATOR = public static final Parcelable.Creator<TextInformationFrame> CREATOR =

View File

@ -594,7 +594,7 @@ public final class Mp3Extractor implements Extractor {
Metadata.Entry entry = metadata.get(i); Metadata.Entry entry = metadata.get(i);
if (entry instanceof TextInformationFrame if (entry instanceof TextInformationFrame
&& ((TextInformationFrame) entry).id.equals("TLEN")) { && ((TextInformationFrame) entry).id.equals("TLEN")) {
return Util.msToUs(Long.parseLong(((TextInformationFrame) entry).value)); return Util.msToUs(Long.parseLong(((TextInformationFrame) entry).values.get(0)));
} }
} }
} }

View File

@ -31,6 +31,7 @@ import androidx.media3.extractor.metadata.id3.Id3Frame;
import androidx.media3.extractor.metadata.id3.InternalFrame; import androidx.media3.extractor.metadata.id3.InternalFrame;
import androidx.media3.extractor.metadata.id3.TextInformationFrame; import androidx.media3.extractor.metadata.id3.TextInformationFrame;
import androidx.media3.extractor.metadata.mp4.MdtaMetadataEntry; import androidx.media3.extractor.metadata.mp4.MdtaMetadataEntry;
import com.google.common.collect.ImmutableList;
import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.compatqual.NullableType;
/** Utilities for handling metadata in MP4. */ /** Utilities for handling metadata in MP4. */
@ -452,7 +453,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
if (atomType == Atom.TYPE_data) { if (atomType == Atom.TYPE_data) {
data.skipBytes(8); // version (1), flags (3), empty (4) data.skipBytes(8); // version (1), flags (3), empty (4)
String value = data.readNullTerminatedString(atomSize - 16); String value = data.readNullTerminatedString(atomSize - 16);
return new TextInformationFrame(id, /* description= */ null, value); return new TextInformationFrame(id, /* description= */ null, ImmutableList.of(value));
} }
Log.w(TAG, "Failed to parse text attribute: " + Atom.getAtomTypeString(type)); Log.w(TAG, "Failed to parse text attribute: " + Atom.getAtomTypeString(type));
return null; return null;
@ -484,7 +485,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
} }
if (value >= 0) { if (value >= 0) {
return isTextInformationFrame return isTextInformationFrame
? new TextInformationFrame(id, /* description= */ null, Integer.toString(value)) ? new TextInformationFrame(
id, /* description= */ null, ImmutableList.of(Integer.toString(value)))
: new CommentFrame(C.LANGUAGE_UNDETERMINED, id, Integer.toString(value)); : new CommentFrame(C.LANGUAGE_UNDETERMINED, id, Integer.toString(value));
} }
Log.w(TAG, "Failed to parse uint8 attribute: " + Atom.getAtomTypeString(type)); Log.w(TAG, "Failed to parse uint8 attribute: " + Atom.getAtomTypeString(type));
@ -505,7 +507,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
if (count > 0) { if (count > 0) {
value += "/" + count; value += "/" + count;
} }
return new TextInformationFrame(attributeName, /* description= */ null, value); return new TextInformationFrame(
attributeName, /* description= */ null, ImmutableList.of(value));
} }
} }
Log.w(TAG, "Failed to parse index/count attribute: " + Atom.getAtomTypeString(type)); Log.w(TAG, "Failed to parse index/count attribute: " + Atom.getAtomTypeString(type));
@ -521,7 +524,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
? STANDARD_GENRES[genreCode - 1] ? STANDARD_GENRES[genreCode - 1]
: null; : null;
if (genreString != null) { if (genreString != null) {
return new TextInformationFrame("TCON", /* description= */ null, genreString); return new TextInformationFrame(
"TCON", /* description= */ null, ImmutableList.of(genreString));
} }
Log.w(TAG, "Failed to parse standard genre code"); Log.w(TAG, "Failed to parse standard genre code");
return null; return null;

View File

@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.os.Parcel; import android.os.Parcel;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -30,7 +31,7 @@ public final class ChapterFrameTest {
public void parcelable() { public void parcelable() {
Id3Frame[] subFrames = Id3Frame[] subFrames =
new Id3Frame[] { new Id3Frame[] {
new TextInformationFrame("TIT2", null, "title"), new TextInformationFrame("TIT2", null, ImmutableList.of("title")),
new UrlLinkFrame("WXXX", "description", "url") new UrlLinkFrame("WXXX", "description", "url")
}; };
ChapterFrame chapterFrameToParcel = new ChapterFrame("id", 0, 1, 2, 3, subFrames); ChapterFrame chapterFrameToParcel = new ChapterFrame("id", 0, 1, 2, 3, subFrames);

View File

@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.os.Parcel; import android.os.Parcel;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -31,7 +32,7 @@ public final class ChapterTocFrameTest {
String[] children = new String[] {"child0", "child1"}; String[] children = new String[] {"child0", "child1"};
Id3Frame[] subFrames = Id3Frame[] subFrames =
new Id3Frame[] { new Id3Frame[] {
new TextInformationFrame("TIT2", null, "title"), new TextInformationFrame("TIT2", null, ImmutableList.of("title")),
new UrlLinkFrame("WXXX", "description", "url") new UrlLinkFrame("WXXX", "description", "url")
}; };
ChapterTocFrame chapterTocFrameToParcel = ChapterTocFrame chapterTocFrameToParcel =

View File

@ -52,7 +52,7 @@ public final class Id3DecoderTest {
TextInformationFrame textInformationFrame = (TextInformationFrame) metadata.get(0); TextInformationFrame textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.id).isEqualTo("TXXX"); assertThat(textInformationFrame.id).isEqualTo("TXXX");
assertThat(textInformationFrame.description).isEmpty(); assertThat(textInformationFrame.description).isEmpty();
assertThat(textInformationFrame.value).isEqualTo("mdialog_VINDICO1527664_start"); assertThat(textInformationFrame.values.get(0)).isEqualTo("mdialog_VINDICO1527664_start");
// Test UTF-16. // Test UTF-16.
rawId3 = rawId3 =
@ -67,7 +67,21 @@ public final class Id3DecoderTest {
textInformationFrame = (TextInformationFrame) metadata.get(0); textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.id).isEqualTo("TXXX"); assertThat(textInformationFrame.id).isEqualTo("TXXX");
assertThat(textInformationFrame.description).isEqualTo("Hello World"); assertThat(textInformationFrame.description).isEqualTo("Hello World");
assertThat(textInformationFrame.value).isEmpty(); assertThat(textInformationFrame.values).containsExactly("");
// Test multiple values.
rawId3 =
buildSingleFrameTag(
"TXXX",
new byte[] {
1, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0,
100, 0, 0, 0, 70, 0, 111, 0, 111, 0, 0, 0, 66, 0, 97, 0, 114, 0, 0
});
metadata = decoder.decode(rawId3, rawId3.length);
assertThat(metadata.length()).isEqualTo(1);
textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.description).isEqualTo("Hello World");
assertThat(textInformationFrame.values).containsExactly("Foo", "Bar").inOrder();
// Test empty. // Test empty.
rawId3 = buildSingleFrameTag("TXXX", new byte[0]); rawId3 = buildSingleFrameTag("TXXX", new byte[0]);
@ -81,7 +95,7 @@ public final class Id3DecoderTest {
textInformationFrame = (TextInformationFrame) metadata.get(0); textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.id).isEqualTo("TXXX"); assertThat(textInformationFrame.id).isEqualTo("TXXX");
assertThat(textInformationFrame.description).isEmpty(); assertThat(textInformationFrame.description).isEmpty();
assertThat(textInformationFrame.value).isEmpty(); assertThat(textInformationFrame.values).containsExactly("");
} }
@Test @Test
@ -95,7 +109,15 @@ public final class Id3DecoderTest {
TextInformationFrame textInformationFrame = (TextInformationFrame) metadata.get(0); TextInformationFrame textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.id).isEqualTo("TIT2"); assertThat(textInformationFrame.id).isEqualTo("TIT2");
assertThat(textInformationFrame.description).isNull(); assertThat(textInformationFrame.description).isNull();
assertThat(textInformationFrame.value).isEqualTo("Hello World"); assertThat(textInformationFrame.values.size()).isEqualTo(1);
assertThat(textInformationFrame.values.get(0)).isEqualTo("Hello World");
// Test multiple values.
rawId3 = buildSingleFrameTag("TIT2", new byte[] {3, 70, 111, 111, 0, 66, 97, 114, 0});
metadata = decoder.decode(rawId3, rawId3.length);
assertThat(metadata.length()).isEqualTo(1);
textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.values).containsExactly("Foo", "Bar").inOrder();
// Test empty. // Test empty.
rawId3 = buildSingleFrameTag("TIT2", new byte[0]); rawId3 = buildSingleFrameTag("TIT2", new byte[0]);
@ -109,7 +131,7 @@ public final class Id3DecoderTest {
textInformationFrame = (TextInformationFrame) metadata.get(0); textInformationFrame = (TextInformationFrame) metadata.get(0);
assertThat(textInformationFrame.id).isEqualTo("TIT2"); assertThat(textInformationFrame.id).isEqualTo("TIT2");
assertThat(textInformationFrame.description).isNull(); assertThat(textInformationFrame.description).isNull();
assertThat(textInformationFrame.value).isEmpty(); assertThat(textInformationFrame.values).containsExactly("");
} }
@Test @Test

View File

@ -16,6 +16,7 @@
package androidx.media3.extractor.metadata.id3; package androidx.media3.extractor.metadata.id3;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import android.os.Parcel; import android.os.Parcel;
import androidx.media3.common.MediaMetadata; import androidx.media3.common.MediaMetadata;
@ -32,7 +33,8 @@ public class TextInformationFrameTest {
@Test @Test
public void parcelable() { public void parcelable() {
TextInformationFrame textInformationFrameToParcel = new TextInformationFrame("", "", ""); TextInformationFrame textInformationFrameToParcel =
new TextInformationFrame("", "", ImmutableList.of(""));
Parcel parcel = Parcel.obtain(); Parcel parcel = Parcel.obtain();
textInformationFrameToParcel.writeToParcel(parcel, 0); textInformationFrameToParcel.writeToParcel(parcel, 0);
@ -62,28 +64,42 @@ public class TextInformationFrameTest {
List<Metadata.Entry> entries = List<Metadata.Entry> entries =
ImmutableList.of( ImmutableList.of(
new TextInformationFrame(/* id= */ "TT2", /* description= */ null, /* value= */ title),
new TextInformationFrame(/* id= */ "TP1", /* description= */ null, /* value= */ artist),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TAL", /* description= */ null, /* value= */ albumTitle), /* id= */ "TT2", /* description= */ null, /* values= */ ImmutableList.of(title)),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TP2", /* description= */ null, /* value= */ albumArtist), /* id= */ "TP1", /* description= */ null, /* values= */ ImmutableList.of(artist)),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TRK", /* description= */ null, /* value= */ trackNumberInfo), /* id= */ "TAL",
/* description= */ null,
/* values= */ ImmutableList.of(albumTitle)),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TYE", /* description= */ null, /* value= */ recordingYear), /* id= */ "TP2",
/* description= */ null,
/* values= */ ImmutableList.of(albumArtist)),
new TextInformationFrame(
/* id= */ "TRK",
/* description= */ null,
/* values= */ ImmutableList.of(trackNumberInfo)),
new TextInformationFrame(
/* id= */ "TYE",
/* description= */ null,
/* values= */ ImmutableList.of(recordingYear)),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TDA", /* id= */ "TDA",
/* description= */ null, /* description= */ null,
/* value= */ recordingDay + recordingMonth), /* values= */ ImmutableList.of(recordingDay + recordingMonth)),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TDRL", /* description= */ null, /* value= */ releaseDate), /* id= */ "TDRL",
/* description= */ null,
/* values= */ ImmutableList.of(releaseDate)),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TCM", /* description= */ null, /* value= */ composer), /* id= */ "TCM", /* description= */ null, /* values= */ ImmutableList.of(composer)),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TP3", /* description= */ null, /* value= */ conductor), /* id= */ "TP3",
/* description= */ null,
/* values= */ ImmutableList.of(conductor)),
new TextInformationFrame( new TextInformationFrame(
/* id= */ "TXT", /* description= */ null, /* value= */ writer)); /* id= */ "TXT", /* description= */ null, /* values= */ ImmutableList.of(writer)));
MediaMetadata.Builder builder = MediaMetadata.EMPTY.buildUpon(); MediaMetadata.Builder builder = MediaMetadata.EMPTY.buildUpon();
for (Metadata.Entry entry : entries) { for (Metadata.Entry entry : entries) {
@ -108,4 +124,41 @@ public class TextInformationFrameTest {
assertThat(mediaMetadata.conductor.toString()).isEqualTo(conductor); assertThat(mediaMetadata.conductor.toString()).isEqualTo(conductor);
assertThat(mediaMetadata.writer.toString()).isEqualTo(writer); assertThat(mediaMetadata.writer.toString()).isEqualTo(writer);
} }
@Test
public void emptyValuesListThrowsException() {
assertThrows(
IllegalArgumentException.class,
() -> new TextInformationFrame("TXXX", "description", ImmutableList.of()));
}
@Test
@SuppressWarnings("deprecation") // Testing deprecated field
public void deprecatedValueStillPopulated() {
TextInformationFrame frame =
new TextInformationFrame("TXXX", "description", ImmutableList.of("value"));
assertThat(frame.value).isEqualTo("value");
assertThat(frame.values).containsExactly("value");
}
@Test
@SuppressWarnings({"deprecation", "InlineMeInliner"}) // Testing deprecated constructor
public void deprecatedConstructorPopulatesValuesList() {
TextInformationFrame frame = new TextInformationFrame("TXXX", "description", "value");
assertThat(frame.value).isEqualTo("value");
assertThat(frame.values).containsExactly("value");
}
@Test
@SuppressWarnings({"deprecation", "InlineMeInliner"}) // Testing deprecated constructor
public void deprecatedConstructorCreatesEqualInstance() {
TextInformationFrame frame1 = new TextInformationFrame("TXXX", "description", "value");
TextInformationFrame frame2 =
new TextInformationFrame("TXXX", "description", ImmutableList.of("value"));
assertThat(frame1).isEqualTo(frame2);
assertThat(frame1.hashCode()).isEqualTo(frame2.hashCode());
}
} }

View File

@ -14,7 +14,7 @@ track 0:
maxInputSize = 5776 maxInputSize = 5776
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
initializationData: initializationData:
data = length 42, hash 83F6895 data = length 42, hash 83F6895
sample 0: sample 0:

View File

@ -14,7 +14,7 @@ track 0:
maxInputSize = 5776 maxInputSize = 5776
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
initializationData: initializationData:
data = length 42, hash 83F6895 data = length 42, hash 83F6895
sample 0: sample 0:

View File

@ -14,7 +14,7 @@ track 0:
maxInputSize = 5776 maxInputSize = 5776
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
initializationData: initializationData:
data = length 42, hash 83F6895 data = length 42, hash 83F6895
sample 0: sample 0:

View File

@ -14,7 +14,7 @@ track 0:
maxInputSize = 5776 maxInputSize = 5776
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
initializationData: initializationData:
data = length 42, hash 83F6895 data = length 42, hash 83F6895
sample 0: sample 0:

View File

@ -14,7 +14,7 @@ track 0:
maxInputSize = 5776 maxInputSize = 5776
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
initializationData: initializationData:
data = length 42, hash 83F6895 data = length 42, hash 83F6895
sample 0: sample 0:

View File

@ -17,7 +17,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
pcmEncoding = 2 pcmEncoding = 2
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
sample 0: sample 0:
time = 0 time = 0
flags = 1 flags = 1

View File

@ -17,7 +17,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
pcmEncoding = 2 pcmEncoding = 2
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
sample 0: sample 0:
time = 853333 time = 853333
flags = 1 flags = 1

View File

@ -17,7 +17,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
pcmEncoding = 2 pcmEncoding = 2
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
sample 0: sample 0:
time = 1792000 time = 1792000
flags = 1 flags = 1

View File

@ -17,7 +17,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
pcmEncoding = 2 pcmEncoding = 2
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
sample 0: sample 0:
time = 2645333 time = 2645333
flags = 1 flags = 1

View File

@ -17,7 +17,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
pcmEncoding = 2 pcmEncoding = 2
metadata = entries=[TXXX: description=ID: value=105519843, TIT2: description=null: value=那么爱你为什么, TPE1: description=null: value=阿强, TALB: description=null: value=华丽的外衣, TXXX: description=ID: value=105519843, APIC: mimeType=image/jpeg, description=] metadata = entries=[TXXX: description=ID: values=[105519843], TIT2: description=null: values=[那么爱你为什么], TPE1: description=null: values=[阿强], TALB: description=null: values=[华丽的外衣], TXXX: description=ID: values=[105519843], APIC: mimeType=image/jpeg, description=]
sample 0: sample 0:
time = 0 time = 0
flags = 1 flags = 1

View File

@ -16,7 +16,7 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TIT2: description=null: value=Test title, TPE1: description=null: value=Test Artist, TALB: description=null: value=Test Album, TXXX: description=Test description: value=Test user info, COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: value=Lavf58.29.100, MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description] metadata = entries=[TIT2: description=null: values=[Test title], TPE1: description=null: values=[Test Artist], TALB: description=null: values=[Test Album], TXXX: description=Test description: values=[Test user info], COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: values=[Lavf58.29.100], MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description]
sample 0: sample 0:
time = 0 time = 0
flags = 1 flags = 1

View File

@ -16,7 +16,7 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TIT2: description=null: value=Test title, TPE1: description=null: value=Test Artist, TALB: description=null: value=Test Album, TXXX: description=Test description: value=Test user info, COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: value=Lavf58.29.100, MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description] metadata = entries=[TIT2: description=null: values=[Test title], TPE1: description=null: values=[Test Artist], TALB: description=null: values=[Test Album], TXXX: description=Test description: values=[Test user info], COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: values=[Lavf58.29.100], MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description]
sample 0: sample 0:
time = 943000 time = 943000
flags = 1 flags = 1

View File

@ -16,7 +16,7 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TIT2: description=null: value=Test title, TPE1: description=null: value=Test Artist, TALB: description=null: value=Test Album, TXXX: description=Test description: value=Test user info, COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: value=Lavf58.29.100, MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description] metadata = entries=[TIT2: description=null: values=[Test title], TPE1: description=null: values=[Test Artist], TALB: description=null: values=[Test Album], TXXX: description=Test description: values=[Test user info], COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: values=[Lavf58.29.100], MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description]
sample 0: sample 0:
time = 1879000 time = 1879000
flags = 1 flags = 1

View File

@ -16,5 +16,5 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TIT2: description=null: value=Test title, TPE1: description=null: value=Test Artist, TALB: description=null: value=Test Album, TXXX: description=Test description: value=Test user info, COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: value=Lavf58.29.100, MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description] metadata = entries=[TIT2: description=null: values=[Test title], TPE1: description=null: values=[Test Artist], TALB: description=null: values=[Test Album], TXXX: description=Test description: values=[Test user info], COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: values=[Lavf58.29.100], MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description]
tracksEnded = true tracksEnded = true

View File

@ -16,7 +16,7 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TIT2: description=null: value=Test title, TPE1: description=null: value=Test Artist, TALB: description=null: value=Test Album, TXXX: description=Test description: value=Test user info, COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: value=Lavf58.29.100, MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description] metadata = entries=[TIT2: description=null: values=[Test title], TPE1: description=null: values=[Test Artist], TALB: description=null: values=[Test Album], TXXX: description=Test description: values=[Test user info], COMM: language=eng, description=Test description, WXXX: url=Test URL, TSSE: description=null: values=[Lavf58.29.100], MLLT, PRIV: owner=test@gmail.com, UNKN, GEOB: mimeType=test/mime, filename=Testfilename.txt, description=Test description, CHAP, CHAP, CTOC, APIC: mimeType=image/jpeg, description=Test description]
sample 0: sample 0:
time = 0 time = 0
flags = 1 flags = 1

View File

@ -16,7 +16,7 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
sample 0: sample 0:
time = 0 time = 0
flags = 1 flags = 1

View File

@ -16,7 +16,7 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
sample 0: sample 0:
time = 958041 time = 958041
flags = 1 flags = 1

View File

@ -16,7 +16,7 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
sample 0: sample 0:
time = 1886772 time = 1886772
flags = 1 flags = 1

View File

@ -16,5 +16,5 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
tracksEnded = true tracksEnded = true

View File

@ -16,7 +16,7 @@ track 0:
sampleRate = 48000 sampleRate = 48000
encoderDelay = 576 encoderDelay = 576
encoderPadding = 576 encoderPadding = 576
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
sample 0: sample 0:
time = 0 time = 0
flags = 1 flags = 1

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -152,7 +152,7 @@ track 1:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample 0: sample 0:

View File

@ -16,7 +16,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
initializationData: initializationData:
data = length 19, hash 86852AE2 data = length 19, hash 86852AE2
data = length 8, hash 72CBCBF5 data = length 8, hash 72CBCBF5

View File

@ -16,7 +16,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
initializationData: initializationData:
data = length 19, hash 86852AE2 data = length 19, hash 86852AE2
data = length 8, hash 72CBCBF5 data = length 8, hash 72CBCBF5

View File

@ -16,7 +16,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
initializationData: initializationData:
data = length 19, hash 86852AE2 data = length 19, hash 86852AE2
data = length 8, hash 72CBCBF5 data = length 8, hash 72CBCBF5

View File

@ -16,7 +16,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
initializationData: initializationData:
data = length 19, hash 86852AE2 data = length 19, hash 86852AE2
data = length 8, hash 72CBCBF5 data = length 8, hash 72CBCBF5

View File

@ -16,7 +16,7 @@ track 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.29.100] metadata = entries=[TSSE: description=null: values=[Lavf58.29.100]]
initializationData: initializationData:
data = length 19, hash 86852AE2 data = length 19, hash 86852AE2
data = length 8, hash 72CBCBF5 data = length 8, hash 72CBCBF5

View File

@ -274,7 +274,7 @@ track 1:
channelCount = 2 channelCount = 2
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100] metadata = entries=[TSSE: description=null: values=[Lavf58.76.100]]
initializationData: initializationData:
data = length 16, hash CAA21BBF data = length 16, hash CAA21BBF
sample 0: sample 0:

View File

@ -274,7 +274,7 @@ track 1:
channelCount = 2 channelCount = 2
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100] metadata = entries=[TSSE: description=null: values=[Lavf58.76.100]]
initializationData: initializationData:
data = length 16, hash CAA21BBF data = length 16, hash CAA21BBF
sample 0: sample 0:

View File

@ -274,7 +274,7 @@ track 1:
channelCount = 2 channelCount = 2
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100] metadata = entries=[TSSE: description=null: values=[Lavf58.76.100]]
initializationData: initializationData:
data = length 16, hash CAA21BBF data = length 16, hash CAA21BBF
sample 0: sample 0:

View File

@ -274,7 +274,7 @@ track 1:
channelCount = 2 channelCount = 2
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100] metadata = entries=[TSSE: description=null: values=[Lavf58.76.100]]
initializationData: initializationData:
data = length 16, hash CAA21BBF data = length 16, hash CAA21BBF
sample 0: sample 0:

View File

@ -274,7 +274,7 @@ track 1:
channelCount = 2 channelCount = 2
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf58.76.100] metadata = entries=[TSSE: description=null: values=[Lavf58.76.100]]
initializationData: initializationData:
data = length 16, hash CAA21BBF data = length 16, hash CAA21BBF
sample 0: sample 0:

View File

@ -7,7 +7,7 @@ format 0:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
format 1: format 1:

View File

@ -7,7 +7,7 @@ format 0:
channelCount = 1 channelCount = 1
sampleRate = 44100 sampleRate = 44100
language = und language = und
metadata = entries=[TSSE: description=null: value=Lavf56.1.0] metadata = entries=[TSSE: description=null: values=[Lavf56.1.0]]
initializationData: initializationData:
data = length 2, hash 5F7 data = length 2, hash 5F7
sample: sample:

View File

@ -8,7 +8,7 @@ format 0:
channelCount = 2 channelCount = 2
sampleRate = 48000 sampleRate = 48000
language = en language = en
metadata = entries=[TSSE: description=null: value=Lavf58.76.100] metadata = entries=[TSSE: description=null: values=[Lavf58.76.100]]
initializationData: initializationData:
data = length 2, hash 560 data = length 2, hash 560
format 1: format 1: