1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "VorbisComment" 19 #include <utils/Log.h> 20 21 #include "media/VorbisComment.h" 22 23 #include <media/stagefright/foundation/base64.h> 24 #include <media/stagefright/foundation/ABuffer.h> 25 #include <media/stagefright/foundation/AString.h> 26 #include <media/stagefright/foundation/ByteUtils.h> 27 #include <media/stagefright/MetaDataBase.h> 28 29 namespace android { 30 31 static void extractAlbumArt( 32 MetaDataBase *fileMeta, const void *data, size_t size) { 33 ALOGV("extractAlbumArt from '%s'", (const char *)data); 34 35 sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size)); 36 if (flacBuffer == NULL) { 37 ALOGE("malformed base64 encoded data."); 38 return; 39 } 40 41 size_t flacSize = flacBuffer->size(); 42 uint8_t *flac = flacBuffer->data(); 43 ALOGV("got flac of size %zu", flacSize); 44 45 uint32_t picType; 46 uint32_t typeLen; 47 uint32_t descLen; 48 uint32_t dataLen; 49 char type[128]; 50 51 if (flacSize < 8) { 52 return; 53 } 54 55 picType = U32_AT(flac); 56 57 if (picType != 3) { 58 // This is not a front cover. 59 return; 60 } 61 62 typeLen = U32_AT(&flac[4]); 63 if (typeLen > sizeof(type) - 1) { 64 return; 65 } 66 67 // we've already checked above that flacSize >= 8 68 if (flacSize - 8 < typeLen) { 69 return; 70 } 71 72 memcpy(type, &flac[8], typeLen); 73 type[typeLen] = '\0'; 74 75 ALOGV("picType = %d, type = '%s'", picType, type); 76 77 if (!strcmp(type, "-->")) { 78 // This is not inline cover art, but an external url instead. 79 return; 80 } 81 82 if (flacSize < 32 || flacSize - 32 < typeLen) { 83 return; 84 } 85 86 descLen = U32_AT(&flac[8 + typeLen]); 87 if (flacSize - 32 - typeLen < descLen) { 88 return; 89 } 90 91 dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]); 92 93 // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0 94 if (flacSize - 32 - typeLen - descLen < dataLen) { 95 return; 96 } 97 98 ALOGV("got image data, %zu trailing bytes", 99 flacSize - 32 - typeLen - descLen - dataLen); 100 101 fileMeta->setData( 102 kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen); 103 104 fileMeta->setCString(kKeyAlbumArtMIME, type); 105 } 106 107 void parseVorbisComment( 108 MetaDataBase *fileMeta, const char *comment, size_t commentLength) 109 { 110 struct { 111 const char *const mTag; 112 uint32_t mKey; 113 } kMap[] = { 114 { "TITLE", kKeyTitle }, 115 { "ARTIST", kKeyArtist }, 116 { "ALBUMARTIST", kKeyAlbumArtist }, 117 { "ALBUM ARTIST", kKeyAlbumArtist }, 118 { "COMPILATION", kKeyCompilation }, 119 { "ALBUM", kKeyAlbum }, 120 { "COMPOSER", kKeyComposer }, 121 { "GENRE", kKeyGenre }, 122 { "AUTHOR", kKeyAuthor }, 123 { "TRACKNUMBER", kKeyCDTrackNumber }, 124 { "DISCNUMBER", kKeyDiscNumber }, 125 { "DATE", kKeyDate }, 126 { "YEAR", kKeyYear }, 127 { "LYRICIST", kKeyWriter }, 128 { "METADATA_BLOCK_PICTURE", kKeyAlbumArt }, 129 { "ANDROID_LOOP", kKeyAutoLoop }, 130 }; 131 132 for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) { 133 size_t tagLen = strlen(kMap[j].mTag); 134 if (!strncasecmp(kMap[j].mTag, comment, tagLen) 135 && comment[tagLen] == '=') { 136 if (kMap[j].mKey == kKeyAlbumArt) { 137 extractAlbumArt( 138 fileMeta, 139 &comment[tagLen + 1], 140 commentLength - tagLen - 1); 141 } else if (kMap[j].mKey == kKeyAutoLoop) { 142 if (!strcasecmp(&comment[tagLen + 1], "true")) { 143 fileMeta->setInt32(kKeyAutoLoop, true); 144 } 145 } else { 146 fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]); 147 } 148 } 149 } 150 151 } 152 153 } // namespace android 154