/** * Parses a udta atom. * * @param udtaAtom The udta (user data) atom to decode. * @param isQuickTime True for QuickTime media. False otherwise. * @return Parsed metadata, or null. */ public static Metadata parseUdta(Atom.LeafAtom udtaAtom, boolean isQuickTime) { if (isQuickTime) { // Meta boxes are regular boxes rather than full boxes in QuickTime. For now, don't try and // decode one. return null; } ParsableByteArray udtaData = udtaAtom.data; udtaData.setPosition(Atom.HEADER_SIZE); while (udtaData.bytesLeft() >= Atom.HEADER_SIZE) { int atomPosition = udtaData.getPosition(); int atomSize = udtaData.readInt(); int atomType = udtaData.readInt(); if (atomType == Atom.TYPE_meta) { udtaData.setPosition(atomPosition); return parseMetaAtom(udtaData, atomPosition + atomSize); } udtaData.skipBytes(atomSize - Atom.HEADER_SIZE); } return null; }
@Test public void testDecodeEventMessage() { byte[] rawEmsgBody = new byte[] { 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test" 49, 50, 51, 0, // value = "123" 0, 0, -69, -128, // timescale = 48000 0, 0, 0, 0, // presentation_time_delta (ignored) = 0 0, 2, 50, -128, // event_duration = 144000 0, 15, 67, -45, // id = 1000403 0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4} EventMessageDecoder decoder = new EventMessageDecoder(); MetadataInputBuffer buffer = new MetadataInputBuffer(); buffer.data = ByteBuffer.allocate(rawEmsgBody.length).put(rawEmsgBody); Metadata metadata = decoder.decode(buffer); assertThat(metadata.length()).isEqualTo(1); EventMessage eventMessage = (EventMessage) metadata.get(0); assertThat(eventMessage.schemeIdUri).isEqualTo("urn:test"); assertThat(eventMessage.value).isEqualTo("123"); assertThat(eventMessage.durationMs).isEqualTo(3000); assertThat(eventMessage.id).isEqualTo(1000403); assertThat(eventMessage.messageData).isEqualTo(new byte[]{0, 1, 2, 3, 4}); }
@Test public void testDecodeTxxxFrame() throws MetadataDecoderException { byte[] rawId3 = buildSingleFrameTag("TXXX", new byte[] {3, 0, 109, 100, 105, 97, 108, 111, 103, 95, 86, 73, 78, 68, 73, 67, 79, 49, 53, 50, 55, 54, 54, 52, 95, 115, 116, 97, 114, 116, 0}); Id3Decoder decoder = new Id3Decoder(); Metadata metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); TextInformationFrame textInformationFrame = (TextInformationFrame) metadata.get(0); assertThat(textInformationFrame.id).isEqualTo("TXXX"); assertThat(textInformationFrame.description).isEmpty(); assertThat(textInformationFrame.value).isEqualTo("mdialog_VINDICO1527664_start"); // Test empty. rawId3 = buildSingleFrameTag("TXXX", new byte[0]); metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(0); // Test encoding byte only. rawId3 = buildSingleFrameTag("TXXX", new byte[] {ID3_TEXT_ENCODING_UTF_8}); metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); textInformationFrame = (TextInformationFrame) metadata.get(0); assertThat(textInformationFrame.id).isEqualTo("TXXX"); assertThat(textInformationFrame.description).isEmpty(); assertThat(textInformationFrame.value).isEmpty(); }
@Test public void testDecodeTextInformationFrame() throws MetadataDecoderException { byte[] rawId3 = buildSingleFrameTag("TIT2", new byte[] {3, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 0}); Id3Decoder decoder = new Id3Decoder(); Metadata metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); TextInformationFrame textInformationFrame = (TextInformationFrame) metadata.get(0); assertThat(textInformationFrame.id).isEqualTo("TIT2"); assertThat(textInformationFrame.description).isNull(); assertThat(textInformationFrame.value).isEqualTo("Hello World"); // Test empty. rawId3 = buildSingleFrameTag("TIT2", new byte[0]); metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(0); // Test encoding byte only. rawId3 = buildSingleFrameTag("TIT2", new byte[] {ID3_TEXT_ENCODING_UTF_8}); metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); textInformationFrame = (TextInformationFrame) metadata.get(0); assertThat(textInformationFrame.id).isEqualTo("TIT2"); assertThat(textInformationFrame.description).isNull(); assertThat(textInformationFrame.value).isEmpty(); }
@Test public void testDecodeUrlLinkFrame() throws MetadataDecoderException { byte[] rawId3 = buildSingleFrameTag("WCOM", new byte[] {104, 116, 116, 112, 115, 58, 47, 47, 116, 101, 115, 116, 46, 99, 111, 109, 47, 97, 98, 99, 63, 100, 101, 102}); Id3Decoder decoder = new Id3Decoder(); Metadata metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); UrlLinkFrame urlLinkFrame = (UrlLinkFrame) metadata.get(0); assertThat(urlLinkFrame.id).isEqualTo("WCOM"); assertThat(urlLinkFrame.description).isNull(); assertThat(urlLinkFrame.url).isEqualTo("https://test.com/abc?def"); // Test empty. rawId3 = buildSingleFrameTag("WCOM", new byte[0]); metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); urlLinkFrame = (UrlLinkFrame) metadata.get(0); assertThat(urlLinkFrame.id).isEqualTo("WCOM"); assertThat(urlLinkFrame.description).isNull(); assertThat(urlLinkFrame.url).isEmpty(); }
@Test public void testDecodePrivFrame() throws MetadataDecoderException { byte[] rawId3 = buildSingleFrameTag("PRIV", new byte[] {116, 101, 115, 116, 0, 1, 2, 3, 4}); Id3Decoder decoder = new Id3Decoder(); Metadata metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); PrivFrame privFrame = (PrivFrame) metadata.get(0); assertThat(privFrame.owner).isEqualTo("test"); assertThat(privFrame.privateData).isEqualTo(new byte[]{1, 2, 3, 4}); // Test empty. rawId3 = buildSingleFrameTag("PRIV", new byte[0]); metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); privFrame = (PrivFrame) metadata.get(0); assertThat(privFrame.owner).isEmpty(); assertThat(privFrame.privateData).isEqualTo(new byte[0]); }
@Test public void testDecodeCommentFrame() throws MetadataDecoderException { byte[] rawId3 = buildSingleFrameTag("COMM", new byte[] {ID3_TEXT_ENCODING_UTF_8, 101, 110, 103, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 0, 116, 101, 120, 116, 0}); Id3Decoder decoder = new Id3Decoder(); Metadata metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); CommentFrame commentFrame = (CommentFrame) metadata.get(0); assertThat(commentFrame.language).isEqualTo("eng"); assertThat(commentFrame.description).isEqualTo("description"); assertThat(commentFrame.text).isEqualTo("text"); // Test empty. rawId3 = buildSingleFrameTag("COMM", new byte[0]); metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(0); // Test language only. rawId3 = buildSingleFrameTag("COMM", new byte[] {ID3_TEXT_ENCODING_UTF_8, 101, 110, 103}); metadata = decoder.decode(rawId3, rawId3.length); assertThat(metadata.length()).isEqualTo(1); commentFrame = (CommentFrame) metadata.get(0); assertThat(commentFrame.language).isEqualTo("eng"); assertThat(commentFrame.description).isEmpty(); assertThat(commentFrame.text).isEmpty(); }
@Test public void testWrappedAroundTimeSignalCommand() throws MetadataDecoderException { byte[] rawTimeSignalSection = new byte[] { 0, // table_id. (byte) 0x80, // section_syntax_indicator, private_indicator, reserved, section_length(4). 0x14, // section_length(8). 0x00, // protocol_version. 0x00, // encrypted_packet, encryption_algorithm, pts_adjustment(1). 0x00, 0x00, 0x00, 0x00, // pts_adjustment(32). 0x00, // cw_index. 0x00, // tier(8). 0x00, // tier(4), splice_command_length(4). 0x05, // splice_command_length(8). 0x06, // splice_command_type = time_signal. // Start of splice_time(). (byte) 0x80, // time_specified_flag, reserved, pts_time(1). 0x52, 0x03, 0x02, (byte) 0x8f, // pts_time(32). PTS for a second after playback position. 0x00, 0x00, 0x00, 0x00}; // CRC_32 (ignored, check happens at extraction). // The playback position is 57:15:58.43 approximately. // With this offset, the playback position pts before wrapping is 0x451ebf851. Metadata metadata = feedInputBuffer(rawTimeSignalSection, 0x3000000000L, -0x50000L); assertThat(metadata.length()).isEqualTo(1); assertThat(((TimeSignalCommand) metadata.get(0)).playbackPositionUs) .isEqualTo(removePtsConversionPrecisionError(0x3001000000L, inputBuffer.subsampleOffsetUs)); }
private void updateForCurrentTrackSelections() { if (player == null) { return; } TrackSelectionArray selections = player.getCurrentTrackSelections(); for (int i = 0; i < selections.length; i++) { if (player.getRendererType(i) == C.TRACK_TYPE_VIDEO && selections.get(i) != null) { // Video enabled so artwork must be hidden. If the shutter is closed, it will be opened in // onRenderedFirstFrame(). hideArtwork(); return; } } // Video disabled so the shutter must be closed. if (shutterView != null) { shutterView.setVisibility(VISIBLE); } // Display artwork if enabled and available, else hide it. if (useArtwork) { for (int i = 0; i < selections.length; i++) { TrackSelection selection = selections.get(i); if (selection != null) { for (int j = 0; j < selection.length(); j++) { Metadata metadata = selection.getFormat(j).metadata; if (metadata != null && setArtworkFromMetadata(metadata)) { return; } } } } if (setArtworkFromBitmap(null)) { return; } } // Artwork disabled or unavailable. hideArtwork(); }
private boolean setArtworkFromMetadata(Metadata metadata) { for (int i = 0; i < metadata.length(); i++) { Metadata.Entry metadataEntry = metadata.get(i); if (metadataEntry instanceof ApicFrame) { byte[] bitmapData = ((ApicFrame) metadataEntry).pictureData; Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length); return setArtworkFromBitmap(bitmap); } } return false; }
private void updateForCurrentTrackSelections() { if (player == null) { return; } TrackSelectionArray selections = player.getCurrentTrackSelections(); for (int i = 0; i < selections.length; i++) { if (player.getRendererType(i) == C.TRACK_TYPE_VIDEO && selections.get(i) != null) { // Video enabled so artwork must be hidden. If the shutter is closed, it will be opened in // onRenderedFirstFrame(). hideArtwork(); return; } } // Video disabled so the shutter must be closed. if (shutterView != null) { shutterView.setVisibility(VISIBLE); } // Display artwork if enabled and available, else hide it. if (useArtwork) { for (int i = 0; i < selections.length; i++) { TrackSelection selection = selections.get(i); if (selection != null) { for (int j = 0; j < selection.length(); j++) { Metadata metadata = selection.getFormat(j).metadata; if (metadata != null && setArtworkFromMetadata(metadata)) { return; } } } } if (setArtworkFromBitmap(defaultArtwork)) { return; } } // Artwork disabled or unavailable. hideArtwork(); }
private void printMetadata(Metadata metadata, String prefix) { for (int i = 0; i < metadata.length(); i++) { Metadata.Entry entry = metadata.get(i); if (entry instanceof TextInformationFrame) { TextInformationFrame textInformationFrame = (TextInformationFrame) entry; Log.d(TAG, prefix + String.format("%s: value=%s", textInformationFrame.id, textInformationFrame.value)); } else if (entry instanceof UrlLinkFrame) { UrlLinkFrame urlLinkFrame = (UrlLinkFrame) entry; Log.d(TAG, prefix + String.format("%s: url=%s", urlLinkFrame.id, urlLinkFrame.url)); } else if (entry instanceof PrivFrame) { PrivFrame privFrame = (PrivFrame) entry; Log.d(TAG, prefix + String.format("%s: owner=%s", privFrame.id, privFrame.owner)); } else if (entry instanceof GeobFrame) { GeobFrame geobFrame = (GeobFrame) entry; Log.d(TAG, prefix + String.format("%s: mimeType=%s, filename=%s, description=%s", geobFrame.id, geobFrame.mimeType, geobFrame.filename, geobFrame.description)); } else if (entry instanceof ApicFrame) { ApicFrame apicFrame = (ApicFrame) entry; Log.d(TAG, prefix + String.format("%s: mimeType=%s, description=%s", apicFrame.id, apicFrame.mimeType, apicFrame.description)); } else if (entry instanceof CommentFrame) { CommentFrame commentFrame = (CommentFrame) entry; Log.d(TAG, prefix + String.format("%s: language=%s, description=%s", commentFrame.id, commentFrame.language, commentFrame.description)); } else if (entry instanceof Id3Frame) { Id3Frame id3Frame = (Id3Frame) entry; Log.d(TAG, prefix + String.format("%s", id3Frame.id)); } else if (entry instanceof EventMessage) { EventMessage eventMessage = (EventMessage) entry; Log.d(TAG, prefix + String.format("EMSG: scheme=%s, id=%d, value=%s", eventMessage.schemeIdUri, eventMessage.id, eventMessage.value)); } } }
public static Format createAudioSampleFormat(String id, String sampleMimeType, String codecs, int bitrate, int maxInputSize, int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, int encoderDelay, int encoderPadding, List<byte[]> initializationData, DrmInitData drmInitData, @C.SelectionFlags int selectionFlags, String language, Metadata metadata) { return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, null, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, metadata); }
Format(String id, String containerMimeType, String sampleMimeType, String codecs, int bitrate, int maxInputSize, int width, int height, float frameRate, int rotationDegrees, float pixelWidthHeightRatio, byte[] projectionData, @C.StereoMode int stereoMode, ColorInfo colorInfo, int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, int encoderDelay, int encoderPadding, @C.SelectionFlags int selectionFlags, String language, int accessibilityChannel, long subsampleOffsetUs, List<byte[]> initializationData, DrmInitData drmInitData, Metadata metadata) { this.id = id; this.containerMimeType = containerMimeType; this.sampleMimeType = sampleMimeType; this.codecs = codecs; this.bitrate = bitrate; this.maxInputSize = maxInputSize; this.width = width; this.height = height; this.frameRate = frameRate; this.rotationDegrees = rotationDegrees; this.pixelWidthHeightRatio = pixelWidthHeightRatio; this.projectionData = projectionData; this.stereoMode = stereoMode; this.colorInfo = colorInfo; this.channelCount = channelCount; this.sampleRate = sampleRate; this.pcmEncoding = pcmEncoding; this.encoderDelay = encoderDelay; this.encoderPadding = encoderPadding; this.selectionFlags = selectionFlags; this.language = language; this.accessibilityChannel = accessibilityChannel; this.subsampleOffsetUs = subsampleOffsetUs; this.initializationData = initializationData == null ? Collections.<byte[]>emptyList() : initializationData; this.drmInitData = drmInitData; this.metadata = metadata; }
@SuppressWarnings("ResourceType") /* package */ Format(Parcel in) { id = in.readString(); containerMimeType = in.readString(); sampleMimeType = in.readString(); codecs = in.readString(); bitrate = in.readInt(); maxInputSize = in.readInt(); width = in.readInt(); height = in.readInt(); frameRate = in.readFloat(); rotationDegrees = in.readInt(); pixelWidthHeightRatio = in.readFloat(); boolean hasProjectionData = in.readInt() != 0; projectionData = hasProjectionData ? in.createByteArray() : null; stereoMode = in.readInt(); colorInfo = in.readParcelable(ColorInfo.class.getClassLoader()); channelCount = in.readInt(); sampleRate = in.readInt(); pcmEncoding = in.readInt(); encoderDelay = in.readInt(); encoderPadding = in.readInt(); selectionFlags = in.readInt(); language = in.readString(); accessibilityChannel = in.readInt(); subsampleOffsetUs = in.readLong(); int initializationDataSize = in.readInt(); initializationData = new ArrayList<>(initializationDataSize); for (int i = 0; i < initializationDataSize; i++) { initializationData.add(in.createByteArray()); } drmInitData = in.readParcelable(DrmInitData.class.getClassLoader()); metadata = in.readParcelable(Metadata.class.getClassLoader()); }
public Format copyWithMetadata(Metadata metadata) { return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, colorInfo, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); }
private static Metadata parseMetaAtom(ParsableByteArray meta, int limit) { meta.skipBytes(Atom.FULL_HEADER_SIZE); while (meta.getPosition() < limit) { int atomPosition = meta.getPosition(); int atomSize = meta.readInt(); int atomType = meta.readInt(); if (atomType == Atom.TYPE_ilst) { meta.setPosition(atomPosition); return parseIlst(meta, atomPosition + atomSize); } meta.skipBytes(atomSize - Atom.HEADER_SIZE); } return null; }
private static Metadata parseIlst(ParsableByteArray ilst, int limit) { ilst.skipBytes(Atom.HEADER_SIZE); ArrayList<Metadata.Entry> entries = new ArrayList<>(); while (ilst.getPosition() < limit) { Metadata.Entry entry = MetadataUtil.parseIlstElement(ilst); if (entry != null) { entries.add(entry); } } return entries.isEmpty() ? null : new Metadata(entries); }
/** * Populates the holder with data parsed from ID3 {@link Metadata}. * * @param metadata The metadata from which to parse the gapless information. * @return Whether the holder was populated. */ public boolean setFromMetadata(Metadata metadata) { for (int i = 0; i < metadata.length(); i++) { Metadata.Entry entry = metadata.get(i); if (entry instanceof CommentFrame) { CommentFrame commentFrame = (CommentFrame) entry; if (setFromComment(commentFrame.description, commentFrame.text)) { return true; } } } return false; }
/** * Decodes ID3 tags. * * @param data The bytes to decode ID3 tags from. * @param size Amount of bytes in {@code data} to read. * @return A {@link Metadata} object containing the decoded ID3 tags. */ public Metadata decode(byte[] data, int size) { List<Id3Frame> id3Frames = new ArrayList<>(); ParsableByteArray id3Data = new ParsableByteArray(data, size); Id3Header id3Header = decodeHeader(id3Data); if (id3Header == null) { return null; } int startPosition = id3Data.getPosition(); int frameHeaderSize = id3Header.majorVersion == 2 ? 6 : 10; int framesSize = id3Header.framesSize; if (id3Header.isUnsynchronized) { framesSize = removeUnsynchronization(id3Data, id3Header.framesSize); } id3Data.setLimit(startPosition + framesSize); boolean unsignedIntFrameSizeHack = false; if (!validateFrames(id3Data, id3Header.majorVersion, frameHeaderSize, false)) { if (id3Header.majorVersion == 4 && validateFrames(id3Data, 4, frameHeaderSize, true)) { unsignedIntFrameSizeHack = true; } else { Log.w(TAG, "Failed to validate ID3 tag with majorVersion=" + id3Header.majorVersion); return null; } } while (id3Data.bytesLeft() >= frameHeaderSize) { Id3Frame frame = decodeFrame(id3Header.majorVersion, id3Data, unsignedIntFrameSizeHack, frameHeaderSize, framePredicate); if (frame != null) { id3Frames.add(frame); } } return new Metadata(id3Frames); }
public static Format createAudioSampleFormat(String id, String sampleMimeType, String codecs, int bitrate, int maxInputSize, int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, int encoderDelay, int encoderPadding, List<byte[]> initializationData, DrmInitData drmInitData, @C.SelectionFlags int selectionFlags, String language, Metadata metadata) { return new Format(id, null, sampleMimeType, codecs, bitrate, maxInputSize, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, NO_VALUE, null, NO_VALUE, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, NO_VALUE, OFFSET_SAMPLE_RELATIVE, initializationData, drmInitData, metadata); }
Format(String id, String containerMimeType, String sampleMimeType, String codecs, int bitrate, int maxInputSize, int width, int height, float frameRate, int rotationDegrees, float pixelWidthHeightRatio, byte[] projectionData, @C.StereoMode int stereoMode, int channelCount, int sampleRate, @C.PcmEncoding int pcmEncoding, int encoderDelay, int encoderPadding, @C.SelectionFlags int selectionFlags, String language, int accessibilityChannel, long subsampleOffsetUs, List<byte[]> initializationData, DrmInitData drmInitData, Metadata metadata) { this.id = id; this.containerMimeType = containerMimeType; this.sampleMimeType = sampleMimeType; this.codecs = codecs; this.bitrate = bitrate; this.maxInputSize = maxInputSize; this.width = width; this.height = height; this.frameRate = frameRate; this.rotationDegrees = rotationDegrees; this.pixelWidthHeightRatio = pixelWidthHeightRatio; this.projectionData = projectionData; this.stereoMode = stereoMode; this.channelCount = channelCount; this.sampleRate = sampleRate; this.pcmEncoding = pcmEncoding; this.encoderDelay = encoderDelay; this.encoderPadding = encoderPadding; this.selectionFlags = selectionFlags; this.language = language; this.accessibilityChannel = accessibilityChannel; this.subsampleOffsetUs = subsampleOffsetUs; this.initializationData = initializationData == null ? Collections.<byte[]>emptyList() : initializationData; this.drmInitData = drmInitData; this.metadata = metadata; }
@SuppressWarnings("ResourceType") /* package */ Format(Parcel in) { id = in.readString(); containerMimeType = in.readString(); sampleMimeType = in.readString(); codecs = in.readString(); bitrate = in.readInt(); maxInputSize = in.readInt(); width = in.readInt(); height = in.readInt(); frameRate = in.readFloat(); rotationDegrees = in.readInt(); pixelWidthHeightRatio = in.readFloat(); boolean hasProjectionData = in.readInt() != 0; projectionData = hasProjectionData ? in.createByteArray() : null; stereoMode = in.readInt(); channelCount = in.readInt(); sampleRate = in.readInt(); pcmEncoding = in.readInt(); encoderDelay = in.readInt(); encoderPadding = in.readInt(); selectionFlags = in.readInt(); language = in.readString(); accessibilityChannel = in.readInt(); subsampleOffsetUs = in.readLong(); int initializationDataSize = in.readInt(); initializationData = new ArrayList<>(initializationDataSize); for (int i = 0; i < initializationDataSize; i++) { initializationData.add(in.createByteArray()); } drmInitData = in.readParcelable(DrmInitData.class.getClassLoader()); metadata = in.readParcelable(Metadata.class.getClassLoader()); }
public Format copyWithMetadata(Metadata metadata) { return new Format(id, containerMimeType, sampleMimeType, codecs, bitrate, maxInputSize, width, height, frameRate, rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, channelCount, sampleRate, pcmEncoding, encoderDelay, encoderPadding, selectionFlags, language, accessibilityChannel, subsampleOffsetUs, initializationData, drmInitData, metadata); }
/** * Decodes ID3 tags. * * @param data The bytes to decode ID3 tags from. * @param size Amount of bytes in {@code data} to read. * @return A {@link Metadata} object containing the decoded ID3 tags. */ public Metadata decode(byte[] data, int size) { List<Id3Frame> id3Frames = new ArrayList<>(); ParsableByteArray id3Data = new ParsableByteArray(data, size); Id3Header id3Header = decodeHeader(id3Data); if (id3Header == null) { return null; } int startPosition = id3Data.getPosition(); int framesSize = id3Header.framesSize; if (id3Header.isUnsynchronized) { framesSize = removeUnsynchronization(id3Data, id3Header.framesSize); } id3Data.setLimit(startPosition + framesSize); boolean unsignedIntFrameSizeHack = false; if (id3Header.majorVersion == 4) { if (!validateV4Frames(id3Data, false)) { if (validateV4Frames(id3Data, true)) { unsignedIntFrameSizeHack = true; } else { Log.w(TAG, "Failed to validate V4 ID3 tag"); return null; } } } int frameHeaderSize = id3Header.majorVersion == 2 ? 6 : 10; while (id3Data.bytesLeft() >= frameHeaderSize) { Id3Frame frame = decodeFrame(id3Header.majorVersion, id3Data, unsignedIntFrameSizeHack, frameHeaderSize, framePredicate); if (frame != null) { id3Frames.add(frame); } } return new Metadata(id3Frames); }
private void printMetadata(Metadata metadata, String prefix) { for (int i = 0; i < metadata.length(); i++) { Metadata.Entry entry = metadata.get(i); if (entry instanceof TxxxFrame) { TxxxFrame txxxFrame = (TxxxFrame) entry; Log.d(TAG, prefix + String.format("%s: description=%s, value=%s", txxxFrame.id, txxxFrame.description, txxxFrame.value)); } else if (entry instanceof PrivFrame) { PrivFrame privFrame = (PrivFrame) entry; Log.d(TAG, prefix + String.format("%s: owner=%s", privFrame.id, privFrame.owner)); } else if (entry instanceof GeobFrame) { GeobFrame geobFrame = (GeobFrame) entry; Log.d(TAG, prefix + String.format("%s: mimeType=%s, filename=%s, description=%s", geobFrame.id, geobFrame.mimeType, geobFrame.filename, geobFrame.description)); } else if (entry instanceof ApicFrame) { ApicFrame apicFrame = (ApicFrame) entry; Log.d(TAG, prefix + String.format("%s: mimeType=%s, description=%s", apicFrame.id, apicFrame.mimeType, apicFrame.description)); } else if (entry instanceof TextInformationFrame) { TextInformationFrame textInformationFrame = (TextInformationFrame) entry; Log.d(TAG, prefix + String.format("%s: description=%s", textInformationFrame.id, textInformationFrame.description)); } else if (entry instanceof CommentFrame) { CommentFrame commentFrame = (CommentFrame) entry; Log.d(TAG, prefix + String.format("%s: language=%s description=%s", commentFrame.id, commentFrame.language, commentFrame.description)); } else if (entry instanceof Id3Frame) { Id3Frame id3Frame = (Id3Frame) entry; Log.d(TAG, prefix + String.format("%s", id3Frame.id)); } } }