Home | History | Annotate | Download | only in libmediaextractor
      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