diff --git a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java index 151875c2c5..9f79f09117 100644 --- a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java +++ b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java @@ -229,8 +229,8 @@ public final class FlacExtractor implements Extractor { binarySearchSeeker = outputSeekMap(decoderJni, streamMetadata, input.getLength(), extractorOutput); Metadata metadata = id3MetadataDisabled ? null : id3Metadata; - if (streamMetadata.vorbisComments != null) { - metadata = streamMetadata.vorbisComments.copyWithAppendedEntriesFrom(metadata); + if (streamMetadata.flacMetadata != null) { + metadata = streamMetadata.flacMetadata.copyWithAppendedEntriesFrom(metadata); } outputFormat(streamMetadata, metadata, trackOutput); outputBuffer.reset(streamMetadata.maxDecodedFrameSize()); diff --git a/extensions/flac/src/main/jni/flac_jni.cc b/extensions/flac/src/main/jni/flac_jni.cc index 4ba071e1ca..4ccd24781b 100644 --- a/extensions/flac/src/main/jni/flac_jni.cc +++ b/extensions/flac/src/main/jni/flac_jni.cc @@ -102,10 +102,10 @@ DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) { jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "", "()V"); jobject commentList = env->NewObject(arrayListClass, arrayListConstructor); + jmethodID arrayListAddMethod = + env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); if (context->parser->isVorbisCommentsValid()) { - jmethodID arrayListAddMethod = - env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); std::vector vorbisComments = context->parser->getVorbisComments(); for (std::vector::const_iterator vorbisComment = @@ -117,6 +117,39 @@ DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) { } } + jobject pictureList = env->NewObject(arrayListClass, arrayListConstructor); + bool picValid = context->parser->isPicValid(); + if (picValid) { + std::vector pictures = context->parser->getPictures(); + jclass flacPictureFrameClass = env->FindClass( + "com/google/android/exoplayer2/metadata/flac/PictureFrame"); + jmethodID flacPictureFrameConstructor = env->GetMethodID( + flacPictureFrameClass, "", + "(ILjava/lang/String;Ljava/lang/String;IIII[B)V"); + for (std::vector::const_iterator picture = pictures.begin(); + picture != pictures.end(); ++picture) { + jstring mimeType = env->NewStringUTF(picture->mimeType.c_str()); + jstring description = env->NewStringUTF(picture->description.c_str()); + jbyteArray picArr = env->NewByteArray(picture->data.size()); + env->SetByteArrayRegion(picArr, 0, picture->data.size(), + (signed char *)&picture->data[0]); + jobject flacPictureFrame = env->NewObject(flacPictureFrameClass, + flacPictureFrameConstructor, + picture->type, + mimeType, + description, + picture->width, + picture->height, + picture->depth, + picture->colors, + picArr); + env->CallBooleanMethod(pictureList, arrayListAddMethod, flacPictureFrame); + env->DeleteLocalRef(mimeType); + env->DeleteLocalRef(description); + env->DeleteLocalRef(picArr); + } + } + const FLAC__StreamMetadata_StreamInfo &streamInfo = context->parser->getStreamInfo(); @@ -124,14 +157,21 @@ DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) { "com/google/android/exoplayer2/util/" "FlacStreamMetadata"); jmethodID flacStreamMetadataConstructor = env->GetMethodID( - flacStreamMetadataClass, "", "(IIIIIIIJLjava/util/List;)V"); + flacStreamMetadataClass, "", + "(IIIIIIIJLjava/util/List;Ljava/util/List;)V"); - return env->NewObject(flacStreamMetadataClass, flacStreamMetadataConstructor, - streamInfo.min_blocksize, streamInfo.max_blocksize, - streamInfo.min_framesize, streamInfo.max_framesize, - streamInfo.sample_rate, streamInfo.channels, - streamInfo.bits_per_sample, streamInfo.total_samples, - commentList); + jobject streamMetaData = env->NewObject(flacStreamMetadataClass, + flacStreamMetadataConstructor, + streamInfo.min_blocksize, + streamInfo.max_blocksize, + streamInfo.min_framesize, + streamInfo.max_framesize, + streamInfo.sample_rate, + streamInfo.channels, + streamInfo.bits_per_sample, + streamInfo.total_samples, + commentList, pictureList); + return streamMetaData; } DECODER_FUNC(jint, flacDecodeToBuffer, jlong jContext, jobject jOutputBuffer) { diff --git a/extensions/flac/src/main/jni/flac_parser.cc b/extensions/flac/src/main/jni/flac_parser.cc index b2d074252d..fafc254482 100644 --- a/extensions/flac/src/main/jni/flac_parser.cc +++ b/extensions/flac/src/main/jni/flac_parser.cc @@ -191,6 +191,22 @@ void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) { ALOGE("FLACParser::metadataCallback unexpected VORBISCOMMENT"); } break; + case FLAC__METADATA_TYPE_PICTURE: + { + const FLAC__StreamMetadata_Picture *pic = &metadata->data.picture; + flacPicture picture; + picture.mimeType.assign(std::string(pic->mime_type)); + picture.description.assign(std::string((char *)pic->description)); + picture.data.assign(pic->data, pic->data + pic->data_length); + picture.width = pic->width; + picture.height = pic->height; + picture.depth = pic->depth; + picture.colors = pic->colors; + picture.type = pic->type; + mPictures.push_back(picture); + mPicValid = true; + break; + } default: ALOGE("FLACParser::metadataCallback unexpected type %u", metadata->type); break; @@ -253,6 +269,7 @@ FLACParser::FLACParser(DataSource *source) mEOF(false), mStreamInfoValid(false), mVorbisCommentsValid(false), + mPicValid(false), mWriteRequested(false), mWriteCompleted(false), mWriteBuffer(NULL), @@ -288,6 +305,8 @@ bool FLACParser::init() { FLAC__METADATA_TYPE_SEEKTABLE); FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__stream_decoder_set_metadata_respond(mDecoder, + FLAC__METADATA_TYPE_PICTURE); FLAC__StreamDecoderInitStatus initStatus; initStatus = FLAC__stream_decoder_init_stream( mDecoder, read_callback, seek_callback, tell_callback, length_callback, diff --git a/extensions/flac/src/main/jni/include/flac_parser.h b/extensions/flac/src/main/jni/include/flac_parser.h index f09a22e951..f1d175b94f 100644 --- a/extensions/flac/src/main/jni/include/flac_parser.h +++ b/extensions/flac/src/main/jni/include/flac_parser.h @@ -30,6 +30,17 @@ typedef int status_t; +typedef struct { + int type; + std::string mimeType; + std::string description; + FLAC__uint32 width; + FLAC__uint32 height; + FLAC__uint32 depth; + FLAC__uint32 colors; + std::vector data; +} flacPicture; + class FLACParser { public: FLACParser(DataSource *source); @@ -54,6 +65,10 @@ class FLACParser { return mVorbisComments; } + bool isPicValid() const { return mPicValid; } + + const std::vector& getPictures() const { return mPictures; } + int64_t getLastFrameTimestamp() const { return (1000000LL * mWriteHeader.number.sample_number) / getSampleRate(); } @@ -82,7 +97,9 @@ class FLACParser { if (newPosition == 0) { mStreamInfoValid = false; mVorbisCommentsValid = false; + mPicValid = false; mVorbisComments.clear(); + mPictures.clear(); FLAC__stream_decoder_reset(mDecoder); } else { FLAC__stream_decoder_flush(mDecoder); @@ -132,6 +149,10 @@ class FLACParser { std::vector mVorbisComments; bool mVorbisCommentsValid; + // cached when the PICTURE metadata is parsed by libFLAC + std::vector mPictures; + bool mPicValid; + // cached when a decoded PCM block is "written" by libFLAC parser bool mWriteRequested; bool mWriteCompleted; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/flac/PictureFrame.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/flac/PictureFrame.java new file mode 100644 index 0000000000..fcf1fd6e58 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/flac/PictureFrame.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2019 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.flac; + +import static com.google.android.exoplayer2.util.Util.castNonNull; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.Nullable; +import com.google.android.exoplayer2.metadata.Metadata; +import java.util.Arrays; + +/** A Picture parsed in a FLAC file. */ +public final class PictureFrame implements Metadata.Entry { + + /** The type of the picture. */ + public final int pictureType; + /** The mime type of the picture. */ + public final String mimeType; + /** A description of the picture. */ + @Nullable public final String description; + /** The pixel width of the picture. */ + public final int width; + /** The pixel height of the picture. */ + public final int height; + /** The color depth of the picture in bits-per-pixel. */ + public final int depth; + /** + * For indexed-color pictures (e.g. GIF), the number of colors used, or 0 for non-indexed + * pictures. + */ + public final int colors; + /** The encoded picture data. */ + public final byte[] pictureData; + + public PictureFrame( + int pictureType, + String mimeType, + @Nullable String description, + int width, + int height, + int depth, + int colors, + byte[] pictureData) { + this.pictureType = pictureType; + this.mimeType = mimeType; + this.description = description; + this.width = width; + this.height = height; + this.depth = depth; + this.colors = colors; + this.pictureData = pictureData; + } + + /* package */ PictureFrame(Parcel in) { + this.pictureType = in.readInt(); + this.mimeType = castNonNull(in.readString()); + this.description = castNonNull(in.readString()); + this.width = in.readInt(); + this.height = in.readInt(); + this.depth = in.readInt(); + this.colors = in.readInt(); + this.pictureData = castNonNull(in.createByteArray()); + } + + @Override + public String toString() { + return "FLAC Picture" + + "\nType: " + pictureType + + "\nMime Type: " + mimeType + + "\nDescription: " + description + + "\nWidth: " + width + + "\nHeight: " + height + + "\nDepth: " + depth + + "\nColors: " + colors; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + PictureFrame other = (PictureFrame) obj; + return (pictureType == other.pictureType) + && mimeType.equals(other.mimeType) + && description.equals(other.description) + && (width == other.width) + && (height == other.height) + && (depth == other.depth) + && (colors == other.colors) + && Arrays.equals(pictureData, other.pictureData); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + pictureType; + result = 31 * result + (mimeType != null ? mimeType.hashCode() : 0); + result = 31 * result + (description != null ? description.hashCode() : 0); + result = 31 * result + width; + result = 31 * result + height; + result = 31 * result + depth; + result = 31 * result + colors; + result = 31 * result + Arrays.hashCode(pictureData); + return result; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(pictureType); + dest.writeString(mimeType); + dest.writeString(description); + dest.writeInt(width); + dest.writeInt(height); + dest.writeInt(depth); + dest.writeInt(colors); + dest.writeByteArray(pictureData); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + + @Override + public PictureFrame createFromParcel(Parcel in) { + return new PictureFrame(in); + } + + @Override + public PictureFrame[] newArray(int size) { + return new PictureFrame[size]; + } + }; +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/vorbis/VorbisComment.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/flac/VorbisComment.java similarity index 97% rename from library/core/src/main/java/com/google/android/exoplayer2/metadata/vorbis/VorbisComment.java rename to library/core/src/main/java/com/google/android/exoplayer2/metadata/flac/VorbisComment.java index b1951cbc13..9f44cdf393 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/vorbis/VorbisComment.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/flac/VorbisComment.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.metadata.vorbis; +package com.google.android.exoplayer2.metadata.flac; import static com.google.android.exoplayer2.util.Util.castNonNull; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamMetadata.java b/library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamMetadata.java index 43fdda367e..48680b5095 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamMetadata.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/FlacStreamMetadata.java @@ -18,7 +18,8 @@ package com.google.android.exoplayer2.util; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.metadata.Metadata; -import com.google.android.exoplayer2.metadata.vorbis.VorbisComment; +import com.google.android.exoplayer2.metadata.flac.PictureFrame; +import com.google.android.exoplayer2.metadata.flac.VorbisComment; import java.util.ArrayList; import java.util.List; @@ -35,7 +36,7 @@ public final class FlacStreamMetadata { public final int channels; public final int bitsPerSample; public final long totalSamples; - @Nullable public final Metadata vorbisComments; + @Nullable public final Metadata flacMetadata; private static final String SEPARATOR = "="; @@ -58,7 +59,7 @@ public final class FlacStreamMetadata { this.channels = scratch.readBits(3) + 1; this.bitsPerSample = scratch.readBits(5) + 1; this.totalSamples = ((scratch.readBits(4) & 0xFL) << 32) | (scratch.readBits(32) & 0xFFFFFFFFL); - this.vorbisComments = null; + this.flacMetadata = null; } /** @@ -71,10 +72,13 @@ public final class FlacStreamMetadata { * @param bitsPerSample Number of bits per sample of the FLAC stream. * @param totalSamples Total samples of the FLAC stream. * @param vorbisComments Vorbis comments. Each entry must be in key=value form. + * @param pictureList A list of pictures in the stream. * @see FLAC format * METADATA_BLOCK_STREAMINFO * @see FLAC format * METADATA_BLOCK_VORBIS_COMMENT + * @see FLAC format + * METADATA_BLOCK_PICTURE */ public FlacStreamMetadata( int minBlockSize, @@ -85,7 +89,8 @@ public final class FlacStreamMetadata { int channels, int bitsPerSample, long totalSamples, - List vorbisComments) { + List vorbisComments, + List pictureList) { this.minBlockSize = minBlockSize; this.maxBlockSize = maxBlockSize; this.minFrameSize = minFrameSize; @@ -94,7 +99,8 @@ public final class FlacStreamMetadata { this.channels = channels; this.bitsPerSample = bitsPerSample; this.totalSamples = totalSamples; - this.vorbisComments = parseVorbisComments(vorbisComments); + Metadata metadata = new Metadata(pictureList); + this.flacMetadata = metadata.copyWithAppendedEntriesFrom(parseVorbisComments(vorbisComments)); } /** Returns the maximum size for a decoded frame from the FLAC stream. */ diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/flac/PictureTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/flac/PictureTest.java new file mode 100644 index 0000000000..04a5b46e26 --- /dev/null +++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/flac/PictureTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 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.flac; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Parcel; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Test for {@link PictureFrame}. */ +@RunWith(AndroidJUnit4.class) +public class PictureTest { + + @Test + public void testParcelable() { + PictureFrame pictureFrameToParcel = + new PictureFrame(0, "", "", 0, 0, 0, 0, new byte[0]); + + Parcel parcel = Parcel.obtain(); + pictureFrameToParcel.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + PictureFrame pictureFrameFromParcel = PictureFrame.CREATOR.createFromParcel(parcel); + assertThat(pictureFrameFromParcel).isEqualTo(pictureFrameToParcel); + + parcel.recycle(); + } +} diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/vorbis/VorbisCommentTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/flac/VorbisCommentTest.java similarity index 96% rename from library/core/src/test/java/com/google/android/exoplayer2/metadata/vorbis/VorbisCommentTest.java rename to library/core/src/test/java/com/google/android/exoplayer2/metadata/flac/VorbisCommentTest.java index 868b28b0e1..bb118e381a 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/vorbis/VorbisCommentTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/flac/VorbisCommentTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.google.android.exoplayer2.metadata.vorbis; +package com.google.android.exoplayer2.metadata.flac; import static com.google.common.truth.Truth.assertThat; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/util/FlacStreamMetadataTest.java b/library/core/src/test/java/com/google/android/exoplayer2/util/FlacStreamMetadataTest.java index 325d9b19f6..c556282ca2 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/util/FlacStreamMetadataTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/util/FlacStreamMetadataTest.java @@ -19,7 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.metadata.Metadata; -import com.google.android.exoplayer2.metadata.vorbis.VorbisComment; +import com.google.android.exoplayer2.metadata.flac.VorbisComment; import java.util.ArrayList; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,7 +34,9 @@ public final class FlacStreamMetadataTest { commentsList.add("Title=Song"); commentsList.add("Artist=Singer"); - Metadata metadata = new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments; + Metadata metadata = + new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList, new ArrayList<>()) + .flacMetadata; assertThat(metadata.length()).isEqualTo(2); VorbisComment commentFrame = (VorbisComment) metadata.get(0); @@ -49,7 +51,9 @@ public final class FlacStreamMetadataTest { public void parseEmptyVorbisComments() { ArrayList commentsList = new ArrayList<>(); - Metadata metadata = new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments; + Metadata metadata = + new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList, new ArrayList<>()) + .flacMetadata; assertThat(metadata).isNull(); } @@ -59,7 +63,9 @@ public final class FlacStreamMetadataTest { ArrayList commentsList = new ArrayList<>(); commentsList.add("Title=So=ng"); - Metadata metadata = new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments; + Metadata metadata = + new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList, new ArrayList<>()) + .flacMetadata; assertThat(metadata.length()).isEqualTo(1); VorbisComment commentFrame = (VorbisComment) metadata.get(0); @@ -73,7 +79,9 @@ public final class FlacStreamMetadataTest { commentsList.add("TitleSong"); commentsList.add("Artist=Singer"); - Metadata metadata = new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList).vorbisComments; + Metadata metadata = + new FlacStreamMetadata(0, 0, 0, 0, 0, 0, 0, 0, commentsList, new ArrayList<>()) + .flacMetadata; assertThat(metadata.length()).isEqualTo(1); VorbisComment commentFrame = (VorbisComment) metadata.get(0); diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java index 269c48c282..4ac007fa55 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java @@ -49,6 +49,7 @@ import com.google.android.exoplayer2.PlaybackPreparer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.flac.PictureFrame; import com.google.android.exoplayer2.metadata.id3.ApicFrame; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.ads.AdsLoader; @@ -303,6 +304,7 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider private boolean controllerHideOnTouch; private int textureViewRotation; private boolean isTouching; + private static final int PICTURE_TYPE_FRONT_COVER = 3; public PlayerView(Context context) { this(context, null); @@ -1246,15 +1248,29 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider } private boolean setArtworkFromMetadata(Metadata metadata) { + boolean isArtworkSet = false; + int currentPicType = -1; for (int i = 0; i < metadata.length(); i++) { Metadata.Entry metadataEntry = metadata.get(i); + int picType; + byte[] bitmapData; if (metadataEntry instanceof ApicFrame) { - byte[] bitmapData = ((ApicFrame) metadataEntry).pictureData; + bitmapData = ((ApicFrame) metadataEntry).pictureData; + picType = ((ApicFrame) metadataEntry).pictureType; + } else if (metadataEntry instanceof PictureFrame) { + bitmapData = ((PictureFrame) metadataEntry).pictureData; + picType = ((PictureFrame) metadataEntry).pictureType; + } else { + continue; + } + /* Prefers the first front cover picture in the picture list */ + if (currentPicType != PICTURE_TYPE_FRONT_COVER) { Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length); - return setDrawableArtwork(new BitmapDrawable(getResources(), bitmap)); + isArtworkSet = setDrawableArtwork(new BitmapDrawable(getResources(), bitmap)); + currentPicType = picType; } } - return false; + return isArtworkSet; } private boolean setDrawableArtwork(@Nullable Drawable drawable) {