separate metadatautils from rest of stagefright

metadatautils is used in mainline+framework. This gives us better
encapsulation for that code.

Bug: 245354160
Test: build and boot
Change-Id: I8e6aa7a1b11b52696263b271674936f3f752714c
diff --git a/media/module/metadatautils/Android.bp b/media/module/metadatautils/Android.bp
new file mode 100644
index 0000000..1f98f32
--- /dev/null
+++ b/media/module/metadatautils/Android.bp
@@ -0,0 +1,37 @@
+cc_library_static {
+    name: "libstagefright_metadatautils",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+    ],
+    min_sdk_version: "29",
+
+    srcs: ["MetaDataUtils.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+
+    header_libs: [
+        "libaudioclient_headers",
+        "libstagefright_headers",
+        "libstagefright_foundation_headers",
+        "media_ndk_headers",
+    ],
+
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+
+    export_include_dirs: ["include"],
+}
diff --git a/media/module/metadatautils/MetaDataUtils.cpp b/media/module/metadatautils/MetaDataUtils.cpp
new file mode 100644
index 0000000..db60f04
--- /dev/null
+++ b/media/module/metadatautils/MetaDataUtils.cpp
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2018 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MetaDataUtils"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/foundation/ABitReader.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaDataUtils.h>
+#include <media/NdkMediaFormat.h>
+
+namespace android {
+
+bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
+    if (data == nullptr || size == 0) {
+        return false;
+    }
+
+    int32_t width;
+    int32_t height;
+    int32_t sarWidth;
+    int32_t sarHeight;
+    sp<ABuffer> accessUnit = new ABuffer((void*)data,  size);
+    sp<ABuffer> csd = MakeAVCCodecSpecificData(accessUnit, &width, &height, &sarWidth, &sarHeight);
+    if (csd == nullptr) {
+        return false;
+    }
+    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+
+    meta.setData(kKeyAVCC, kTypeAVCC, csd->data(), csd->size());
+    meta.setInt32(kKeyWidth, width);
+    meta.setInt32(kKeyHeight, height);
+    if (sarWidth > 0 && sarHeight > 0) {
+        meta.setInt32(kKeySARWidth, sarWidth);
+        meta.setInt32(kKeySARHeight, sarHeight);
+    }
+    return true;
+}
+
+bool MakeAVCCodecSpecificData(AMediaFormat *meta, const uint8_t *data, size_t size) {
+    if (meta == nullptr || data == nullptr || size == 0) {
+        return false;
+    }
+
+    int32_t width;
+    int32_t height;
+    int32_t sarWidth;
+    int32_t sarHeight;
+    sp<ABuffer> accessUnit = new ABuffer((void*)data,  size);
+    sp<ABuffer> csd = MakeAVCCodecSpecificData(accessUnit, &width, &height, &sarWidth, &sarHeight);
+    if (csd == nullptr) {
+        return false;
+    }
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
+
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_AVC, csd->data(), csd->size());
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_WIDTH, width);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_HEIGHT, height);
+    if (sarWidth > 0 && sarHeight > 0) {
+        AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAR_WIDTH, sarWidth);
+        AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAR_HEIGHT, sarHeight);
+    }
+    return true;
+}
+
+bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
+    if (data == nullptr || size < 7) {
+        return false;
+    }
+
+    ABitReader bits(data, size);
+
+    // adts_fixed_header
+
+    if (bits.getBits(12) != 0xfffu) {
+        ALOGE("Wrong atds_fixed_header");
+        return false;
+    }
+
+    bits.skipBits(4);  // ID, layer, protection_absent
+
+    unsigned profile = bits.getBits(2);
+    if (profile == 3u) {
+        ALOGE("profile should not be 3");
+        return false;
+    }
+    unsigned sampling_freq_index = bits.getBits(4);
+    bits.getBits(1);  // private_bit
+    unsigned channel_configuration = bits.getBits(3);
+    if (channel_configuration == 0u) {
+        ALOGE("channel_config should not be 0");
+        return false;
+    }
+
+    if (!MakeAACCodecSpecificData(
+            meta, profile, sampling_freq_index, channel_configuration)) {
+        return false;
+    }
+
+    meta.setInt32(kKeyIsADTS, true);
+    return true;
+}
+
+bool MakeAACCodecSpecificData(
+        uint8_t *csd, /* out */
+        size_t *esds_size, /* in/out */
+        unsigned profile, /* in */
+        unsigned sampling_freq_index, /* in */
+        unsigned channel_configuration, /* in */
+        int32_t *sampling_rate /* out */
+) {
+    if(sampling_freq_index > 11u) {
+        return false;
+    }
+    static const int32_t kSamplingFreq[] = {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000
+    };
+    *sampling_rate = kSamplingFreq[sampling_freq_index];
+
+    static const uint8_t kStaticESDS[] = {
+        0x03, 22,
+        0x00, 0x00,     // ES_ID
+        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+        0x04, 17,
+        0x40,                       // Audio ISO/IEC 14496-3
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x05, 2,
+        // AudioSpecificInfo follows
+
+        // oooo offf fccc c000
+        // o - audioObjectType
+        // f - samplingFreqIndex
+        // c - channelConfig
+    };
+
+    size_t csdSize = sizeof(kStaticESDS) + 2;
+    if (csdSize > *esds_size) {
+        return false;
+    }
+    memcpy(csd, kStaticESDS, sizeof(kStaticESDS));
+
+    csd[sizeof(kStaticESDS)] =
+        ((profile + 1) << 3) | (sampling_freq_index >> 1);
+
+    csd[sizeof(kStaticESDS) + 1] =
+        ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+    *esds_size = csdSize;
+    return true;
+}
+
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration) {
+
+    if(sampling_freq_index > 11u) {
+        return false;
+    }
+
+    uint8_t csd[2];
+    csd[0] = ((profile + 1) << 3) | (sampling_freq_index >> 1);
+    csd[1] = ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+    static const int32_t kSamplingFreq[] = {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000
+    };
+    int32_t sampleRate = kSamplingFreq[sampling_freq_index];
+
+    AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd, sizeof(csd));
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampleRate);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channel_configuration);
+
+    return true;
+}
+
+bool MakeAACCodecSpecificData(
+        MetaDataBase &meta,
+        unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration) {
+
+    uint8_t csd[24];
+    size_t csdSize = sizeof(csd);
+    int32_t sampleRate;
+
+    if (!MakeAACCodecSpecificData(csd, &csdSize, profile, sampling_freq_index,
+            channel_configuration, &sampleRate)) {
+        return false;
+    }
+
+    meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+    meta.setInt32(kKeySampleRate, sampleRate);
+    meta.setInt32(kKeyChannelCount, channel_configuration);
+    meta.setData(kKeyESDS, 0, csd, csdSize);
+    return true;
+}
+
+
+static void extractAlbumArt(
+        AMediaFormat *fileMeta, const void *data, size_t size) {
+    ALOGV("extractAlbumArt from '%s'", (const char *)data);
+
+    size_t inLen = strnlen((const char *)data, size);
+    size_t flacSize = inLen / 4 * 3;
+    uint8_t *flac = new uint8_t[flacSize];
+    if (!decodeBase64(flac, &flacSize, (const char*)data)) {
+        ALOGE("malformed base64 encoded data.");
+        delete[] flac;
+        return;
+    }
+
+    ALOGV("got flac of size %zu", flacSize);
+
+    uint32_t picType;
+    uint32_t typeLen;
+    uint32_t descLen;
+    uint32_t dataLen;
+    char type[128];
+
+    if (flacSize < 8) {
+        delete[] flac;
+        return;
+    }
+
+    picType = U32_AT(flac);
+
+    if (picType != 3) {
+        // This is not a front cover.
+        delete[] flac;
+        return;
+    }
+
+    typeLen = U32_AT(&flac[4]);
+    if (typeLen > sizeof(type) - 1) {
+        delete[] flac;
+        return;
+    }
+
+    // we've already checked above that flacSize >= 8
+    if (flacSize - 8 < typeLen) {
+        delete[] flac;
+        return;
+    }
+
+    memcpy(type, &flac[8], typeLen);
+    type[typeLen] = '\0';
+
+    ALOGV("picType = %d, type = '%s'", picType, type);
+
+    if (!strcmp(type, "-->")) {
+        // This is not inline cover art, but an external url instead.
+        delete[] flac;
+        return;
+    }
+
+    if (flacSize < 32 || flacSize - 32 < typeLen) {
+        delete[] flac;
+        return;
+    }
+
+    descLen = U32_AT(&flac[8 + typeLen]);
+    if (flacSize - 32 - typeLen < descLen) {
+        delete[] flac;
+        return;
+    }
+
+    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
+    if (flacSize - 32 - typeLen - descLen < dataLen) {
+        delete[] flac;
+        return;
+    }
+
+    ALOGV("got image data, %zu trailing bytes",
+         flacSize - 32 - typeLen - descLen - dataLen);
+
+    AMediaFormat_setBuffer(fileMeta, AMEDIAFORMAT_KEY_ALBUMART,
+            &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+    delete[] flac;
+}
+
+void parseVorbisComment(
+        AMediaFormat *fileMeta, const char *comment, size_t commentLength) {
+    // Haptic tag is only kept here as it will only be used in extractor to generate channel mask.
+    struct {
+        const char *const mTag;
+        const char *mKey;
+    } kMap[] = {
+        { "TITLE", AMEDIAFORMAT_KEY_TITLE },
+        { "ARTIST", AMEDIAFORMAT_KEY_ARTIST },
+        { "ALBUMARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+        { "ALBUM ARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+        { "COMPILATION", AMEDIAFORMAT_KEY_COMPILATION },
+        { "ALBUM", AMEDIAFORMAT_KEY_ALBUM },
+        { "COMPOSER", AMEDIAFORMAT_KEY_COMPOSER },
+        { "GENRE", AMEDIAFORMAT_KEY_GENRE },
+        { "AUTHOR", AMEDIAFORMAT_KEY_AUTHOR },
+        { "TRACKNUMBER", AMEDIAFORMAT_KEY_CDTRACKNUMBER },
+        { "DISCNUMBER", AMEDIAFORMAT_KEY_DISCNUMBER },
+        { "DATE", AMEDIAFORMAT_KEY_DATE },
+        { "YEAR", AMEDIAFORMAT_KEY_YEAR },
+        { "LYRICIST", AMEDIAFORMAT_KEY_LYRICIST },
+        { "METADATA_BLOCK_PICTURE", AMEDIAFORMAT_KEY_ALBUMART },
+        { "ANDROID_LOOP", AMEDIAFORMAT_KEY_LOOP },
+        { "ANDROID_HAPTIC", AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT },
+    };
+
+        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+            size_t tagLen = strlen(kMap[j].mTag);
+            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+                    && comment[tagLen] == '=') {
+                if (kMap[j].mKey == AMEDIAFORMAT_KEY_ALBUMART) {
+                    extractAlbumArt(
+                            fileMeta,
+                            &comment[tagLen + 1],
+                            commentLength - tagLen - 1);
+                } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_LOOP) {
+                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
+                        AMediaFormat_setInt32(fileMeta, AMEDIAFORMAT_KEY_LOOP, 1);
+                    }
+                } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_HAPTIC_CHANNEL_COUNT) {
+                    char *end;
+                    errno = 0;
+                    const int hapticChannelCount = strtol(&comment[tagLen + 1], &end, 10);
+                    if (errno == 0) {
+                        AMediaFormat_setInt32(fileMeta, kMap[j].mKey, hapticChannelCount);
+                    } else {
+                        ALOGE("Error(%d) when parsing haptic channel count", errno);
+                    }
+                } else {
+                    AMediaFormat_setString(fileMeta, kMap[j].mKey, &comment[tagLen + 1]);
+                }
+            }
+        }
+
+}
+
+}  // namespace android
diff --git a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
new file mode 100644
index 0000000..dcaf27f
--- /dev/null
+++ b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef META_DATA_UTILS_H_
+
+#define META_DATA_UTILS_H_
+
+#include <media/stagefright/MetaData.h>
+
+struct AMediaFormat;
+
+namespace android {
+
+struct ABuffer;
+bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+bool MakeAVCCodecSpecificData(AMediaFormat *meta, const uint8_t *data, size_t size);
+
+bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration);
+
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration);
+
+void parseVorbisComment(
+        AMediaFormat *fileMeta, const char *comment, size_t commentLength);
+
+}  // namespace android
+
+#endif  // META_DATA_UTILS_H_
diff --git a/media/module/metadatautils/test/Android.bp b/media/module/metadatautils/test/Android.bp
new file mode 100644
index 0000000..21f38f6
--- /dev/null
+++ b/media/module/metadatautils/test/Android.bp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_av_media_libstagefright_tests_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+}
+
+cc_test {
+    name: "MetaDataUtilsTest",
+    gtest: true,
+
+    srcs: [
+        "MetaDataUtilsTest.cpp",
+    ],
+
+    static_libs: [
+        "libstagefright_metadatautils",
+        "libstagefright_esds",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libmediandk",
+        "libstagefright",
+        "libstagefright_foundation",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/module/metadatautils/test/AndroidTest.xml b/media/module/metadatautils/test/AndroidTest.xml
new file mode 100644
index 0000000..d6497f3
--- /dev/null
+++ b/media/module/metadatautils/test/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Test module config for MetaDataUtils unit test">
+    <option name="test-suite-tag" value="MetaDataUtilsTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="false" />
+        <option name="push" value="MetaDataUtilsTest->/data/local/tmp/MetaDataUtilsTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/metadatautils/MetaDataUtilsTestRes-1.0.zip?unzip=true"
+            value="/data/local/tmp/MetaDataUtilsTestRes/" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="MetaDataUtilsTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/MetaDataUtilsTestRes/" />
+    </test>
+</configuration>
diff --git a/media/module/metadatautils/test/MetaDataUtilsTest.cpp b/media/module/metadatautils/test/MetaDataUtilsTest.cpp
new file mode 100644
index 0000000..08c9284
--- /dev/null
+++ b/media/module/metadatautils/test/MetaDataUtilsTest.cpp
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MetaDataUtilsTest"
+#include <utils/Log.h>
+
+#include <fstream>
+#include <string>
+
+#include <media/esds/ESDS.h>
+#include <media/NdkMediaFormat.h>
+#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/foundation/ABitReader.h>
+
+#include "MetaDataUtilsTestEnvironment.h"
+
+constexpr uint8_t kAdtsCsdSize = 7;
+// from AAC specs: https://www.iso.org/standard/43345.html
+constexpr int32_t kSamplingFreq[] = {96000, 88200, 64000, 48000, 44100, 32000,
+                                     24000, 22050, 16000, 12000, 11025, 8000};
+constexpr uint8_t kMaxSamplingFreqIndex = sizeof(kSamplingFreq) / sizeof(kSamplingFreq[0]);
+
+static MetaDataUtilsTestEnvironment *gEnv = nullptr;
+
+using namespace android;
+
+class MetaDataValidate {
+  public:
+    MetaDataValidate() : mInputBuffer(nullptr) {}
+
+    ~MetaDataValidate() {
+        if (mInputBuffer) {
+            delete[] mInputBuffer;
+            mInputBuffer = nullptr;
+        }
+    }
+
+    void SetUpMetaDataValidate(string fileName) {
+        struct stat buf;
+        int8_t err = stat(fileName.c_str(), &buf);
+        ASSERT_EQ(err, 0) << "Failed to get file information for file: " << fileName;
+
+        mInputBufferSize = buf.st_size;
+        FILE *inputFilePtr = fopen(fileName.c_str(), "rb+");
+        ASSERT_NE(inputFilePtr, nullptr) << "Failed to open file: " << fileName;
+
+        mInputBuffer = new uint8_t[mInputBufferSize];
+        ASSERT_NE(mInputBuffer, nullptr)
+                << "Failed to allocate memory of size: " << mInputBufferSize;
+
+        int32_t numBytes =
+                fread((char *)mInputBuffer, sizeof(uint8_t), mInputBufferSize, inputFilePtr);
+        ASSERT_EQ(numBytes, mInputBufferSize) << numBytes << " of " << mInputBufferSize << " read";
+
+        fclose(inputFilePtr);
+    }
+
+    size_t mInputBufferSize;
+    const uint8_t *mInputBuffer;
+};
+
+class AvcCSDTest : public ::testing::TestWithParam<
+                           tuple<string /*inputFile*/, size_t /*avcWidth*/, size_t /*avcHeight*/>> {
+  public:
+    AvcCSDTest() : mInputBuffer(nullptr) {}
+
+    ~AvcCSDTest() {
+        if (mInputBuffer) {
+            delete[] mInputBuffer;
+            mInputBuffer = nullptr;
+        }
+    }
+    virtual void SetUp() override {
+        tuple<string, size_t, size_t> params = GetParam();
+        string inputFile = gEnv->getRes() + get<0>(params);
+        mFrameWidth = get<1>(params);
+        mFrameHeight = get<2>(params);
+
+        struct stat buf;
+        int8_t err = stat(inputFile.c_str(), &buf);
+        ASSERT_EQ(err, 0) << "Failed to get information for file: " << inputFile;
+
+        mInputBufferSize = buf.st_size;
+        FILE *inputFilePtr = fopen(inputFile.c_str(), "rb+");
+        ASSERT_NE(inputFilePtr, nullptr) << "Failed to open file: " << inputFile;
+
+        mInputBuffer = new uint8_t[mInputBufferSize];
+        ASSERT_NE(mInputBuffer, nullptr)
+                << "Failed to create a buffer of size: " << mInputBufferSize;
+
+        int32_t numBytes =
+                fread((char *)mInputBuffer, sizeof(uint8_t), mInputBufferSize, inputFilePtr);
+        ASSERT_EQ(numBytes, mInputBufferSize) << numBytes << " of " << mInputBufferSize << " read";
+
+        fclose(inputFilePtr);
+    }
+
+    size_t mFrameWidth;
+    size_t mFrameHeight;
+    size_t mInputBufferSize;
+    const uint8_t *mInputBuffer;
+};
+
+class AvcCSDValidateTest : public MetaDataValidate,
+                           public ::testing::TestWithParam<string /*inputFile*/> {
+  public:
+    virtual void SetUp() override {
+        string inputFile = gEnv->getRes() + GetParam();
+
+        ASSERT_NO_FATAL_FAILURE(SetUpMetaDataValidate(inputFile));
+    }
+};
+
+class AacCSDTest
+    : public ::testing::TestWithParam<tuple<uint32_t /*profile*/, uint32_t /*samplingFreqIndex*/,
+                                            uint32_t /*channelConfig*/>> {
+  public:
+    virtual void SetUp() override {
+        tuple<uint32_t, uint32_t, uint32_t> params = GetParam();
+        mAacProfile = get<0>(params);
+        mAacSamplingFreqIndex = get<1>(params);
+        mAacChannelConfig = get<2>(params);
+    }
+
+    uint32_t mAacProfile;
+    uint32_t mAacSamplingFreqIndex;
+    uint32_t mAacChannelConfig;
+};
+
+class AacADTSTest
+    : public ::testing::TestWithParam<
+              tuple<string /*adtsFile*/, uint32_t /*channelCount*/, uint32_t /*sampleRate*/>> {
+  public:
+    AacADTSTest() : mInputBuffer(nullptr) {}
+
+    virtual void SetUp() override {
+        tuple<string, uint32_t, uint32_t> params = GetParam();
+        string fileName = gEnv->getRes() + get<0>(params);
+        mAacChannelCount = get<1>(params);
+        mAacSampleRate = get<2>(params);
+
+        FILE *filePtr = fopen(fileName.c_str(), "r");
+        ASSERT_NE(filePtr, nullptr) << "Failed to open file: " << fileName;
+
+        mInputBuffer = new uint8_t[kAdtsCsdSize];
+        ASSERT_NE(mInputBuffer, nullptr) << "Failed to allocate a memory of size: " << kAdtsCsdSize;
+
+        int32_t numBytes = fread((void *)mInputBuffer, sizeof(uint8_t), kAdtsCsdSize, filePtr);
+        ASSERT_EQ(numBytes, kAdtsCsdSize)
+                << "Failed to read complete file, bytes read: " << numBytes;
+
+        fclose(filePtr);
+    }
+    int32_t mAacChannelCount;
+    int32_t mAacSampleRate;
+    const uint8_t *mInputBuffer;
+};
+
+class AacCSDValidateTest : public MetaDataValidate,
+                           public ::testing::TestWithParam<string /*inputFile*/> {
+  public:
+    virtual void SetUp() override {
+        string inputFile = gEnv->getRes() + GetParam();
+
+        ASSERT_NO_FATAL_FAILURE(SetUpMetaDataValidate(inputFile));
+    }
+};
+
+class VorbisTest : public ::testing::TestWithParam<pair<string /*fileName*/, string /*infoFile*/>> {
+  public:
+    virtual void SetUp() override {
+        pair<string, string> params = GetParam();
+        string inputMediaFile = gEnv->getRes() + params.first;
+        mInputFileStream.open(inputMediaFile, ifstream::in);
+        ASSERT_TRUE(mInputFileStream.is_open()) << "Failed to open data file: " << inputMediaFile;
+
+        string inputInfoFile = gEnv->getRes() + params.second;
+        mInfoFileStream.open(inputInfoFile, ifstream::in);
+        ASSERT_TRUE(mInputFileStream.is_open()) << "Failed to open data file: " << inputInfoFile;
+        ASSERT_FALSE(inputInfoFile.empty()) << "Empty info file: " << inputInfoFile;
+    }
+
+    ~VorbisTest() {
+        if (mInputFileStream.is_open()) mInputFileStream.close();
+        if (mInfoFileStream.is_open()) mInfoFileStream.close();
+    }
+
+    ifstream mInputFileStream;
+    ifstream mInfoFileStream;
+};
+
+TEST_P(AvcCSDTest, AvcCSDValidationTest) {
+    AMediaFormat *csdData = AMediaFormat_new();
+    ASSERT_NE(csdData, nullptr) << "Failed to create AMedia format";
+
+    bool status = MakeAVCCodecSpecificData(csdData, mInputBuffer, mInputBufferSize);
+    ASSERT_TRUE(status) << "Failed to make AVC CSD from AMediaFormat";
+
+    int32_t avcWidth = -1;
+    status = AMediaFormat_getInt32(csdData, AMEDIAFORMAT_KEY_WIDTH, &avcWidth);
+    ASSERT_TRUE(status) << "Failed to get avc width";
+    ASSERT_EQ(avcWidth, mFrameWidth);
+
+    int32_t avcHeight = -1;
+    status = AMediaFormat_getInt32(csdData, AMEDIAFORMAT_KEY_HEIGHT, &avcHeight);
+    ASSERT_TRUE(status) << "Failed to get avc height";
+    ASSERT_EQ(avcHeight, mFrameHeight);
+
+    const char *mimeType = "";
+    status = AMediaFormat_getString(csdData, AMEDIAFORMAT_KEY_MIME, &mimeType);
+    ASSERT_TRUE(status) << "Failed to get the mime type";
+    ASSERT_STREQ(mimeType, MEDIA_MIMETYPE_VIDEO_AVC);
+
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create MetaData Base";
+
+    status = MakeAVCCodecSpecificData(*metaData, mInputBuffer, mInputBufferSize);
+    ASSERT_TRUE(status) << "Failed to make AVC CSD from MetaDataBase";
+
+    avcWidth = -1;
+    status = metaData->findInt32(kKeyWidth, &avcWidth);
+    ASSERT_TRUE(status) << "Failed to find the width";
+    ASSERT_EQ(avcWidth, mFrameWidth);
+
+    avcHeight = -1;
+    status = metaData->findInt32(kKeyHeight, &avcHeight);
+    ASSERT_TRUE(status) << "Failed to find the height";
+    ASSERT_EQ(avcHeight, mFrameHeight);
+
+    void *csdAMediaFormatBuffer = nullptr;
+    size_t csdAMediaFormatSize;
+    status = AMediaFormat_getBuffer(csdData, AMEDIAFORMAT_KEY_CSD_AVC, &csdAMediaFormatBuffer,
+                                    &csdAMediaFormatSize);
+    ASSERT_TRUE(status) << "Failed to get the CSD from AMediaFormat";
+    ASSERT_NE(csdAMediaFormatBuffer, nullptr) << "Invalid CSD from AMediaFormat";
+
+    const void *csdMetaDataBaseBuffer = nullptr;
+    size_t csdMetaDataBaseSize = 0;
+    uint32_t mediaType;
+    status = metaData->findData(kKeyAVCC, &mediaType, &csdMetaDataBaseBuffer, &csdMetaDataBaseSize);
+    ASSERT_TRUE(status) << "Failed to get the CSD from MetaDataBase";
+    ASSERT_NE(csdMetaDataBaseBuffer, nullptr) << "Invalid CSD from MetaDataBase";
+    ASSERT_GT(csdMetaDataBaseSize, 0) << "CSD size must be greater than 0";
+    ASSERT_EQ(csdMetaDataBaseSize, csdAMediaFormatSize)
+            << "CSD size of MetaData type and AMediaFormat type must be same";
+
+    int32_t result = memcmp(csdAMediaFormatBuffer, csdMetaDataBaseBuffer, csdAMediaFormatSize);
+    ASSERT_EQ(result, 0) << "CSD from AMediaFormat and MetaDataBase do not match";
+
+    delete metaData;
+    AMediaFormat_delete(csdData);
+}
+
+TEST_P(AvcCSDValidateTest, AvcValidateTest) {
+    AMediaFormat *csdData = AMediaFormat_new();
+    ASSERT_NE(csdData, nullptr) << "Failed to create AMedia format";
+
+    bool status = MakeAVCCodecSpecificData(csdData, mInputBuffer, mInputBufferSize);
+    ASSERT_FALSE(status) << "MakeAVCCodecSpecificData with AMediaFormat succeeds with invalid data";
+
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create MetaData Base";
+
+    status = MakeAVCCodecSpecificData(*metaData, mInputBuffer, mInputBufferSize);
+    ASSERT_FALSE(status) << "MakeAVCCodecSpecificData with MetaDataBase succeeds with invalid data";
+}
+
+TEST_P(AacCSDTest, AacCSDValidationTest) {
+    AMediaFormat *csdData = AMediaFormat_new();
+    ASSERT_NE(csdData, nullptr) << "Failed to create AMedia format";
+
+    ASSERT_GE(mAacSamplingFreqIndex, 0);
+    ASSERT_LT(mAacSamplingFreqIndex, kMaxSamplingFreqIndex);
+    bool status = MakeAACCodecSpecificData(csdData, mAacProfile, mAacSamplingFreqIndex,
+                                           mAacChannelConfig);
+    ASSERT_TRUE(status) << "Failed to make AAC CSD from AMediaFormat";
+
+    int32_t sampleRate = -1;
+    status = AMediaFormat_getInt32(csdData, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sampleRate);
+    ASSERT_TRUE(status) << "Failed to get sample rate";
+    ASSERT_EQ(kSamplingFreq[mAacSamplingFreqIndex], sampleRate);
+
+    int32_t channelCount = -1;
+    status = AMediaFormat_getInt32(csdData, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &channelCount);
+    ASSERT_TRUE(status) << "Failed to get channel count";
+    ASSERT_EQ(channelCount, mAacChannelConfig);
+
+    const char *mimeType = "";
+    status = AMediaFormat_getString(csdData, AMEDIAFORMAT_KEY_MIME, &mimeType);
+    ASSERT_TRUE(status) << "Failed to get the mime type";
+    ASSERT_STREQ(mimeType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create MetaData Base";
+
+    status = MakeAACCodecSpecificData(*metaData, mAacProfile, mAacSamplingFreqIndex,
+                                      mAacChannelConfig);
+    ASSERT_TRUE(status) << "Failed to make AAC CSD from MetaDataBase";
+
+    sampleRate = -1;
+    status = metaData->findInt32(kKeySampleRate, &sampleRate);
+    ASSERT_TRUE(status) << "Failed to get sampling rate";
+    ASSERT_EQ(kSamplingFreq[mAacSamplingFreqIndex], sampleRate);
+
+    channelCount = -1;
+    status = metaData->findInt32(kKeyChannelCount, &channelCount);
+    ASSERT_TRUE(status) << "Failed to get channel count";
+    ASSERT_EQ(channelCount, mAacChannelConfig);
+
+    mimeType = "";
+    status = metaData->findCString(kKeyMIMEType, &mimeType);
+    ASSERT_TRUE(status) << "Failed to get mime type";
+    ASSERT_STREQ(mimeType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+    void *csdAMediaFormatBuffer = nullptr;
+    size_t csdAMediaFormatSize = 0;
+    status = AMediaFormat_getBuffer(csdData, AMEDIAFORMAT_KEY_CSD_0, &csdAMediaFormatBuffer,
+                                    &csdAMediaFormatSize);
+    ASSERT_TRUE(status) << "Failed to get the AMediaFormat CSD";
+    ASSERT_GT(csdAMediaFormatSize, 0) << "CSD size must be greater than 0";
+    ASSERT_NE(csdAMediaFormatBuffer, nullptr) << "Invalid CSD found";
+
+    const void *csdMetaDataBaseBuffer;
+    size_t csdMetaDataBaseSize = 0;
+    uint32_t mediaType;
+    status = metaData->findData(kKeyESDS, &mediaType, &csdMetaDataBaseBuffer, &csdMetaDataBaseSize);
+    ASSERT_TRUE(status) << "Failed to get the ESDS data from MetaDataBase";
+    ASSERT_GT(csdMetaDataBaseSize, 0) << "CSD size must be greater than 0";
+
+    ESDS esds(csdMetaDataBaseBuffer, csdMetaDataBaseSize);
+    status_t result = esds.getCodecSpecificInfo(&csdMetaDataBaseBuffer, &csdMetaDataBaseSize);
+    ASSERT_EQ(result, (status_t)OK) << "Failed to get CSD from ESDS data";
+    ASSERT_NE(csdMetaDataBaseBuffer, nullptr) << "Invalid CSD found";
+    ASSERT_EQ(csdAMediaFormatSize, csdMetaDataBaseSize)
+            << "CSD size do not match between AMediaFormat type and MetaDataBase type";
+
+    int32_t memcmpResult =
+            memcmp(csdAMediaFormatBuffer, csdMetaDataBaseBuffer, csdAMediaFormatSize);
+    ASSERT_EQ(memcmpResult, 0) << "AMediaFormat and MetaDataBase CSDs do not match";
+
+    AMediaFormat_delete(csdData);
+    delete metaData;
+}
+
+TEST_P(AacADTSTest, AacADTSValidationTest) {
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create meta data";
+
+    bool status = MakeAACCodecSpecificData(*metaData, mInputBuffer, kAdtsCsdSize);
+    ASSERT_TRUE(status) << "Failed to make AAC CSD from MetaDataBase";
+
+    int32_t sampleRate = -1;
+    status = metaData->findInt32(kKeySampleRate, &sampleRate);
+    ASSERT_TRUE(status) << "Failed to get sampling rate";
+    ASSERT_EQ(sampleRate, mAacSampleRate);
+
+    int32_t channelCount = -1;
+    status = metaData->findInt32(kKeyChannelCount, &channelCount);
+    ASSERT_TRUE(status) << "Failed to get channel count";
+    ASSERT_EQ(channelCount, mAacChannelCount);
+
+    const char *mimeType = "";
+    status = metaData->findCString(kKeyMIMEType, &mimeType);
+    ASSERT_TRUE(status) << "Failed to get mime type";
+    ASSERT_STREQ(mimeType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+    delete metaData;
+}
+
+TEST_P(AacCSDValidateTest, AacInvalidInputTest) {
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create meta data";
+
+    bool status = MakeAACCodecSpecificData(*metaData, mInputBuffer, kAdtsCsdSize);
+    ASSERT_FALSE(status) << "MakeAACCodecSpecificData succeeds with invalid data";
+}
+
+TEST_P(VorbisTest, VorbisCommentTest) {
+    string line;
+    string tag;
+    string key;
+    string value;
+    size_t commentLength;
+    bool status;
+
+    while (getline(mInfoFileStream, line)) {
+        istringstream stringLine(line);
+        stringLine >> tag >> key >> value >> commentLength;
+        ASSERT_GT(commentLength, 0) << "Vorbis comment size must be greater than 0";
+
+        string comment;
+        string dataLine;
+
+        getline(mInputFileStream, dataLine);
+        istringstream dataStringLine(dataLine);
+        dataStringLine >> comment;
+
+        char *buffer = strndup(comment.c_str(), commentLength);
+        ASSERT_NE(buffer, nullptr) << "Failed to allocate buffer of size: " << commentLength;
+
+        AMediaFormat *fileMeta = AMediaFormat_new();
+        ASSERT_NE(fileMeta, nullptr) << "Failed to create AMedia format";
+
+        parseVorbisComment(fileMeta, buffer, commentLength);
+        free(buffer);
+
+        if (!strncasecmp(tag.c_str(), "ANDROID_HAPTIC", sizeof(tag))) {
+            int32_t numChannelExpected = stoi(value);
+            int32_t numChannelFound = -1;
+            status = AMediaFormat_getInt32(fileMeta, key.c_str(), &numChannelFound);
+            ASSERT_TRUE(status) << "Failed to get the channel count";
+            ASSERT_EQ(numChannelExpected, numChannelFound);
+        } else if (!strncasecmp(tag.c_str(), "ANDROID_LOOP", sizeof(tag))) {
+            int32_t loopExpected = !value.compare("true");
+            int32_t loopFound = -1;
+
+            status = AMediaFormat_getInt32(fileMeta, "loop", &loopFound);
+            ASSERT_TRUE(status) << "Failed to get the loop count";
+            ASSERT_EQ(loopExpected, loopFound);
+        } else {
+            const char *tagValue = "";
+            status = AMediaFormat_getString(fileMeta, key.c_str(), &tagValue);
+            ASSERT_TRUE(status) << "Failed to get the tag value";
+            ASSERT_STREQ(value.c_str(), tagValue);
+        }
+        AMediaFormat_delete(fileMeta);
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(MetaDataUtilsTestAll, AvcCSDTest,
+                         ::testing::Values(make_tuple("sps_pps_userdata.h264", 8, 8),
+                                           make_tuple("sps_userdata_pps.h264", 8, 8),
+                                           make_tuple("sps_pps_sps_pps.h264", 8, 8)));
+
+// TODO(b/158067691): Add invalid test vectors with incomplete PPS or no PPS
+INSTANTIATE_TEST_SUITE_P(MetaDataUtilsTestAll, AvcCSDValidateTest,
+                         ::testing::Values("sps_pps_only_startcode.h264",
+                                           "sps_incomplete_pps.h264",
+                                           // TODO(b/158067691) "sps_pps_incomplete.h264",
+                                           "randomdata.h264",
+                                           // TODO(b/158067691) "sps.h264",
+                                           "pps.h264"));
+
+INSTANTIATE_TEST_SUITE_P(MetaDataUtilsTestAll, AacCSDTest,
+                         ::testing::Values(make_tuple(AACObjectMain, 1, 1)));
+
+INSTANTIATE_TEST_SUITE_P(MetaDataUtilsTestAll, AacADTSTest,
+                         ::testing::Values(make_tuple("loudsoftaacadts", 1, 44100)));
+
+INSTANTIATE_TEST_SUITE_P(MetaDataUtilsTestAll, AacCSDValidateTest,
+                         ::testing::Values("loudsoftaacadts_invalidheader",
+                                           "loudsoftaacadts_invalidprofile",
+                                           "loudsoftaacadts_invalidchannelconfig"));
+
+// TODO(b/157974508) Add test vector for vorbis thumbnail tag
+// Info file contains TAG, Key, Value and size of the vorbis comment
+INSTANTIATE_TEST_SUITE_P(
+        MetaDataUtilsTestAll, VorbisTest,
+        ::testing::Values(make_pair("vorbiscomment_sintel.dat", "vorbiscomment_sintel.info"),
+                          make_pair("vorbiscomment_album.dat", "vorbiscomment_album.info"),
+                          make_pair("vorbiscomment_loop.dat", "vorbiscomment_loop.info")));
+
+int main(int argc, char **argv) {
+    gEnv = new MetaDataUtilsTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/module/metadatautils/test/MetaDataUtilsTestEnvironment.h b/media/module/metadatautils/test/MetaDataUtilsTestEnvironment.h
new file mode 100644
index 0000000..4d642bc
--- /dev/null
+++ b/media/module/metadatautils/test/MetaDataUtilsTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef __METADATA_UTILS_TEST_ENVIRONMENT_H__
+#define __METADATA_UTILS_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class MetaDataUtilsTestEnvironment : public::testing::Environment {
+  public:
+    MetaDataUtilsTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int MetaDataUtilsTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P': {
+                setRes(optarg);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __METADATA_UTILS_TEST_ENVIRONMENT_H__
diff --git a/media/module/metadatautils/test/README.md b/media/module/metadatautils/test/README.md
new file mode 100644
index 0000000..0862a07
--- /dev/null
+++ b/media/module/metadatautils/test/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### MetaDataUtils Test
+The MetaDataUtils Unit Test Suite validates the libstagefright_metadatautils library available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m MetaDataUtilsTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/MetaDataUtilsTest/MetaDataUtilsTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/MetaDataUtilsTest/MetaDataUtilsTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/metadatautils/MetaDataUtilsTestRes-1.0.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push MetaDataUtilsTestRes-1.0 /data/local/tmp/
+```
+
+usage: MetaDataUtilsTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/MetaDataUtilsTest -P /data/local/tmp/MetaDataUtilsTestRes-1.0/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest MetaDataUtilsTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/module/mpeg2ts/Android.bp b/media/module/mpeg2ts/Android.bp
index 283df1e..bf762c6 100644
--- a/media/module/mpeg2ts/Android.bp
+++ b/media/module/mpeg2ts/Android.bp
@@ -51,6 +51,7 @@
         "libmedia_datasource_headers",
         "libaudioclient_headers",
         "media_ndk_headers",
+        "libstagefright_headers",
         "libstagefright_foundation_headers",
     ],