Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1bf989e authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "MediaTesting: Add Mpeg4 H263 Encoder Test" am: 7bf3eff8 am: 0d431dd1

Change-Id: I2f782c4b4b864f76f1b6bcfea440c33a024f299b
parents 2d486a39 0d431dd1
Loading
Loading
Loading
Loading
+45 −0
Original line number Original line Diff line number Diff line
/*
 * 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.
 */

cc_test {
    name: "Mpeg4H263EncoderTest",
    gtest: true,

    srcs : [ "Mpeg4H263EncoderTest.cpp" ],

    shared_libs: [
        "libutils",
        "liblog",
    ],

    static_libs: [
        "libstagefright_m4vh263enc",
    ],

    cflags: [
        "-DOSCL_IMPORT_REF=",
        "-Wall",
        "-Werror",
    ],

    sanitize: {
        misc_undefined: [
            "signed-integer-overflow",
            "unsigned-integer-overflow",
        ],
        cfi: true,
    },
}
+31 −0
Original line number Original line Diff line number Diff line
<?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 MPEG4H263 encoder unit tests">
    <option name="test-suite-tag" value="Mpeg4H263EncoderTest" />
    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
        <option name="cleanup" value="true" />
        <option name="push" value="Mpeg4H263EncoderTest->/data/local/tmp/Mpeg4H263EncoderTest/" />
        <option name="push-file"
            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263Encoder.zip?unzip=true"
            value="/data/local/tmp/Mpeg4H263EncoderTestRes/" />
    </target_preparer>

    <test class="com.android.tradefed.testtype.GTest" >
        <option name="native-test-device-path" value="/data/local/tmp" />
        <option name="module-name" value="Mpeg4H263EncoderTest" />
        <option name="native-test-flag" value="-P /data/local/tmp/Mpeg4H263EncoderTestRes/" />
    </test>
</configuration>
 No newline at end of file
+250 −0
Original line number Original line Diff line number Diff line
/*
 * 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 "Mpeg4H263EncoderTest"
#include <utils/Log.h>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#include "mp4enc_api.h"

#include "Mpeg4H263EncoderTestEnvironment.h"

#define ENCODED_FILE "/data/local/tmp/Mpeg4H263Output"

// assuming a worst case compression of 2X
constexpr int16_t kCompressionRatio = 2;
constexpr int8_t kIDRFrameRefreshIntervalInSec = 1;

static Mpeg4H263EncoderTestEnvironment *gEnv = nullptr;

class Mpeg4H263EncoderTest
    : public ::testing::TestWithParam<tuple<string, bool, int32_t, int32_t, float, int32_t>> {
  private:
    void initEncoderParams();

  public:
    Mpeg4H263EncoderTest()
        : mInputBuffer(nullptr),
          mOutputBuffer(nullptr),
          mFpInput(nullptr),
          mFpOutput(nullptr),
          mEncodeHandle(nullptr),
          mEncodeControl(nullptr) {}

    ~Mpeg4H263EncoderTest() {
        if(mFpInput) {
            fclose(mFpInput);
        }
        if(mFpOutput) {
            fclose(mFpOutput);
        }
        if(mInputBuffer) free(mInputBuffer);
        if(mOutputBuffer) free(mOutputBuffer);
        if(mEncodeHandle) free(mEncodeHandle);
        if(mEncodeControl) free(mEncodeControl);
    }

    void SetUp() override {
        tuple<string /* fileName */, bool /* isMpeg4 */, int32_t /* frameWidth */,
          int32_t /* frameHeight */, float /* frameRate */, int32_t /* bitRate */>
            params = GetParam();
        mFileName = gEnv->getRes() + get<0>(params);
        mIsMpeg4 = get<1>(params);
        mFrameWidth = get<2>(params);
        mFrameHeight = get<3>(params);
        mFrameRate = get<4>(params);
        mBitRate = get<5>(params);

        ASSERT_TRUE(mFrameWidth % 16 == 0) << "Frame Width should be multiple of 16";
        ASSERT_TRUE(mFrameHeight % 16 == 0) << "Frame Height should be multiple of 16";
        ASSERT_LE(mFrameWidth, (mIsMpeg4 ? 720 : 352))
                << "Frame Width <= 720 for Mpeg4 and <= 352 for H263";
        ASSERT_LE(mFrameHeight, (mIsMpeg4 ? 480 : 288))
                << "Frame Height <= 480 for Mpeg4 and <= 288 for H263";
        ASSERT_LE(mFrameRate, 30) << "Frame rate less than or equal to 30";
        ASSERT_LE(mBitRate, 2048) << "Bit rate less than or equal to 2048 kbps";

        mOutputBufferSize = ( mFrameWidth * mFrameHeight * 3/2 ) / kCompressionRatio;
        mEncodeHandle = new VideoEncOptions;
        ASSERT_NE(mEncodeHandle, nullptr) << "Failed to get Video Encoding options object";
        memset(mEncodeHandle, 0, sizeof(VideoEncOptions));
        mEncodeControl = new VideoEncControls;
        ASSERT_NE(mEncodeControl, nullptr) << "Failed to get Video Encoding control object";
        memset(mEncodeControl, 0, sizeof(VideoEncControls));
        ASSERT_NO_FATAL_FAILURE(initEncoderParams())
                << "Failed to get the default Encoding parameters!";
    }

    int64_t getTotalFrames();
    void processEncoder(int32_t);
    bool mIsMpeg4;
    int32_t mFrameWidth, mFrameHeight, mBitRate;
    int64_t mOutputBufferSize;
    float mFrameRate;
    string mFileName;
    uint8_t *mInputBuffer, *mOutputBuffer;
    FILE *mFpInput, *mFpOutput;
    VideoEncOptions *mEncodeHandle;
    VideoEncControls *mEncodeControl;
};

void Mpeg4H263EncoderTest::initEncoderParams() {
    bool status = PVGetDefaultEncOption(mEncodeHandle, 0);
    ASSERT_TRUE(status);

    mEncodeHandle->rcType = VBR_1;
    mEncodeHandle->vbvDelay = 5.0f;
    mEncodeHandle->profile_level = CORE_PROFILE_LEVEL2;
    mEncodeHandle->packetSize = 32;
    mEncodeHandle->rvlcEnable = PV_OFF;
    mEncodeHandle->numLayers = 1;
    mEncodeHandle->timeIncRes = 1000;
    mEncodeHandle->iQuant[0] = 15;
    mEncodeHandle->pQuant[0] = 12;
    mEncodeHandle->quantType[0] = 0;
    mEncodeHandle->noFrameSkipped = PV_OFF;
    mEncodeHandle->numIntraMB = 0;
    mEncodeHandle->sceneDetect = PV_ON;
    mEncodeHandle->searchRange = 16;
    mEncodeHandle->mv8x8Enable = PV_OFF;
    mEncodeHandle->gobHeaderInterval = 0;
    mEncodeHandle->useACPred = PV_ON;
    mEncodeHandle->intraDCVlcTh = 0;
    if(!mIsMpeg4) {
        mEncodeHandle->encMode = H263_MODE;
    } else {
        mEncodeHandle->encMode = COMBINE_MODE_WITH_ERR_RES;
    }
    mEncodeHandle->encWidth[0] = mFrameWidth;
    mEncodeHandle->encHeight[0] = mFrameHeight;
    mEncodeHandle->encFrameRate[0] = mFrameRate;
    mEncodeHandle->bitRate[0] = mBitRate * 1024;
    mEncodeHandle->tickPerSrc = mEncodeHandle->timeIncRes / mFrameRate;
    if (kIDRFrameRefreshIntervalInSec == 0) {
        // All I frames.
        mEncodeHandle->intraPeriod = 1;
    } else {
        mEncodeHandle->intraPeriod = (kIDRFrameRefreshIntervalInSec * mFrameRate);
    }
}

int64_t Mpeg4H263EncoderTest::getTotalFrames() {
    int32_t frameSize = (mFrameWidth * mFrameHeight * 3) / 2;
    struct stat buf;
    stat(mFileName.c_str(), &buf);
    size_t fileSize = buf.st_size;
    int64_t totalFrames = (int64_t)(fileSize/frameSize);
    return totalFrames;
}

void Mpeg4H263EncoderTest::processEncoder(int32_t numFramesToEncode) {
    bool status;
    int64_t numEncodedFrames = 0;
    int32_t bytesRead;
    int32_t frameSize = (mFrameWidth * mFrameHeight * 3) / 2;
    while(numFramesToEncode != 0) {
        bytesRead = fread(mInputBuffer, 1, frameSize, mFpInput);
        // End of file.
        if (bytesRead != frameSize) {
            break;
        }

        VideoEncFrameIO videoIn, videoOut;
        videoIn.height = mFrameHeight;
        videoIn.pitch = mFrameWidth;
        videoIn.timestamp = (numEncodedFrames * 1000) / mFrameRate;  // in ms.
        videoIn.yChan = mInputBuffer;
        videoIn.uChan = videoIn.yChan + videoIn.height * videoIn.pitch;
        videoIn.vChan = videoIn.uChan + ((videoIn.height * videoIn.pitch) >> 2);
        uint32_t modTimeMs = 0;
        int32_t dataLength = mOutputBufferSize;
        int32_t nLayer = 0;
        status = PVEncodeVideoFrame(mEncodeControl, &videoIn, &videoOut, &modTimeMs, mOutputBuffer,
                                    &dataLength, &nLayer);
        ASSERT_TRUE(status) << "Failed to Encode: " << mFileName;

        MP4HintTrack hintTrack;
        status = PVGetHintTrack(mEncodeControl, &hintTrack);
        ASSERT_TRUE(status) << "Failed to get hint track!";
        UChar *overrunBuffer = PVGetOverrunBuffer(mEncodeControl);
        ASSERT_EQ(overrunBuffer, nullptr) << "Overrun of buffer!";

        int64_t numBytes = fwrite(mOutputBuffer, 1, dataLength, mFpOutput);
        ASSERT_EQ(numBytes, dataLength) << "Failed to write to the output file!";
        numEncodedFrames++;
        numFramesToEncode--;
    }
}

TEST_P(Mpeg4H263EncoderTest, EncodeTest) {
    mInputBuffer = (uint8_t *)malloc((mFrameWidth * mFrameWidth * 3) / 2);
    ASSERT_NE(mInputBuffer, nullptr) << "Failed to allocate the input buffer!";

    mOutputBuffer = (uint8_t *)malloc(mOutputBufferSize);
    ASSERT_NE(mOutputBuffer, nullptr) << "Failed to allocate the output buffer!";

    mFpInput = fopen(mFileName.c_str(), "rb");
    ASSERT_NE(mFpInput, nullptr) << "Failed to open the input file: " << mFileName;

    mFpOutput = fopen(ENCODED_FILE, "wb");
    ASSERT_NE(mFpOutput, nullptr) << "Failed to open the output file:" << ENCODED_FILE;

    bool status = PVInitVideoEncoder(mEncodeControl, mEncodeHandle);
    ASSERT_TRUE(status) << "Failed to initialize the encoder!";

    // Get VOL header.
    int32_t size = mOutputBufferSize;
    status = PVGetVolHeader(mEncodeControl, mOutputBuffer, &size, 0);
    ASSERT_TRUE(status) << "Failed to get the VOL header!";

    // Write the VOL header on the first frame.
    int32_t numBytes = fwrite(mOutputBuffer, 1, size, mFpOutput);
    ASSERT_EQ(numBytes, size) << "Failed to write the VOL header!";

    int64_t totalFrames = getTotalFrames();
    ASSERT_NO_FATAL_FAILURE(processEncoder(totalFrames)) << "Failed to Encode: " << mFileName;
    status = PVCleanUpVideoEncoder(mEncodeControl);
    ASSERT_TRUE(status) << "Failed to clean up the encoder resources!";
}

INSTANTIATE_TEST_SUITE_P(
        EncodeTest, Mpeg4H263EncoderTest,
        ::testing::Values(
                make_tuple("bbb_352x288_420p_30fps_32frames.yuv", false, 352, 288, 25, 1024),
                make_tuple("bbb_352x288_420p_30fps_32frames.yuv", true, 352, 288, 25, 1024),
                make_tuple("bbb_352x288_420p_30fps_32frames.yuv", false, 176, 144, 25, 1024),
                make_tuple("bbb_352x288_420p_30fps_32frames.yuv", true, 176, 144, 25, 1024),
                make_tuple("football_qvga.yuv", false, 352, 288, 25, 1024),
                make_tuple("football_qvga.yuv", true, 352, 288, 25, 1024),
                make_tuple("football_qvga.yuv", false, 176, 144, 30, 1024),
                make_tuple("football_qvga.yuv", true, 176, 144, 30, 1024)));

int32_t main(int argc, char **argv) {
    gEnv = new Mpeg4H263EncoderTestEnvironment();
    ::testing::AddGlobalTestEnvironment(gEnv);
    ::testing::InitGoogleTest(&argc, argv);
    uint8_t status = gEnv->initFromOptions(argc, argv);
    if (status == 0) {
        status = RUN_ALL_TESTS();
        ALOGI("Encoder Test Result = %d\n", status);
    }
    return status;
}
+73 −0
Original line number Original line Diff line number Diff line
/*
 * 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 __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__
#define __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__

#include <gtest/gtest.h>

#include <getopt.h>

using namespace std;

class Mpeg4H263EncoderTestEnvironment : public::testing::Environment {
  public:
    Mpeg4H263EncoderTestEnvironment() : res("/data/local/tmp/Mpeg4H263EncoderTest/") {}

    // 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 Mpeg4H263EncoderTestEnvironment::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  // __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__
+38 −0
Original line number Original line Diff line number Diff line
## Media Testing ##
---

#### Mpeg4H263Encoder :
The Mpeg4H263Encoder Test Suite validates the Mpeg4 and H263 encoder available in libstagefright.
Run the following steps to build the test suite:
```
m Mpeg4H263EncoderTest
```

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/Mpeg4H263EncoderTest/Mpeg4H263EncoderTest /data/local/tmp/
```

To test 32-bit binary push binaries from nativetest.
```
adb push ${OUT}/data/nativetest/Mpeg4H263EncoderTest/Mpeg4H263EncoderTest /data/local/tmp/
```

The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263Encoder.zip ) Download, unzip and push these files into device for testing.

```
adb push Mpeg4H263Encoder/. /data/local/tmp/
```

usage: Mpeg4H263EncoderTest -P \<path_to_folder\>
```
adb shell /data/local/tmp/Mpeg4H263EncoderTest -P /data/local/tmp/
```
Alternatively, the test can also be run using atest command.

```
atest Mpeg4H263EncoderTest -- --enable-module-dynamic-download=true
```