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

Commit de1d7b4b authored by James Dong's avatar James Dong Committed by Android (Google) Code Review
Browse files

Merge "Get rid of redundant media profiles"

parents 2704f2b0 797e4f1d
Loading
Loading
Loading
Loading
+69 −2
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@
namespace android {
namespace android {


enum camcorder_quality {
enum camcorder_quality {
    CAMCORDER_QUALITY_LIST_START = 0,
    CAMCORDER_QUALITY_LOW  = 0,
    CAMCORDER_QUALITY_LOW  = 0,
    CAMCORDER_QUALITY_HIGH = 1,
    CAMCORDER_QUALITY_HIGH = 1,
    CAMCORDER_QUALITY_QCIF = 2,
    CAMCORDER_QUALITY_QCIF = 2,
@@ -31,14 +32,17 @@ enum camcorder_quality {
    CAMCORDER_QUALITY_480P = 4,
    CAMCORDER_QUALITY_480P = 4,
    CAMCORDER_QUALITY_720P = 5,
    CAMCORDER_QUALITY_720P = 5,
    CAMCORDER_QUALITY_1080P = 6,
    CAMCORDER_QUALITY_1080P = 6,
    CAMCORDER_QUALITY_LIST_END = 6,


    CAMCORDER_QUALITY_TIME_LAPSE_LIST_START = 1000,
    CAMCORDER_QUALITY_TIME_LAPSE_LOW  = 1000,
    CAMCORDER_QUALITY_TIME_LAPSE_LOW  = 1000,
    CAMCORDER_QUALITY_TIME_LAPSE_HIGH = 1001,
    CAMCORDER_QUALITY_TIME_LAPSE_HIGH = 1001,
    CAMCORDER_QUALITY_TIME_LAPSE_QCIF = 1002,
    CAMCORDER_QUALITY_TIME_LAPSE_QCIF = 1002,
    CAMCORDER_QUALITY_TIME_LAPSE_CIF = 1003,
    CAMCORDER_QUALITY_TIME_LAPSE_CIF = 1003,
    CAMCORDER_QUALITY_TIME_LAPSE_480P = 1004,
    CAMCORDER_QUALITY_TIME_LAPSE_480P = 1004,
    CAMCORDER_QUALITY_TIME_LAPSE_720P = 1005,
    CAMCORDER_QUALITY_TIME_LAPSE_720P = 1005,
    CAMCORDER_QUALITY_TIME_LAPSE_1080P = 1006
    CAMCORDER_QUALITY_TIME_LAPSE_1080P = 1006,
    CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1006,
};
};


enum video_decoder {
enum video_decoder {
@@ -147,6 +151,11 @@ public:
    Vector<int> getImageEncodingQualityLevels(int cameraId) const;
    Vector<int> getImageEncodingQualityLevels(int cameraId) const;


private:
private:
    enum {
        // Camcorder profiles (high/low) and timelapse profiles (high/low)
        kNumRequiredProfiles = 4,
    };

    MediaProfiles& operator=(const MediaProfiles&);  // Don't call me
    MediaProfiles& operator=(const MediaProfiles&);  // Don't call me
    MediaProfiles(const MediaProfiles&);             // Don't call me
    MediaProfiles(const MediaProfiles&);             // Don't call me
    MediaProfiles() {}                               // Dummy default constructor
    MediaProfiles() {}                               // Dummy default constructor
@@ -160,6 +169,14 @@ private:
              mFrameHeight(frameHeight),
              mFrameHeight(frameHeight),
              mFrameRate(frameRate) {}
              mFrameRate(frameRate) {}


        VideoCodec(const VideoCodec& copy) {
            mCodec = copy.mCodec;
            mBitRate = copy.mBitRate;
            mFrameWidth = copy.mFrameWidth;
            mFrameHeight = copy.mFrameHeight;
            mFrameRate = copy.mFrameRate;
        }

        ~VideoCodec() {}
        ~VideoCodec() {}


        video_encoder mCodec;
        video_encoder mCodec;
@@ -176,6 +193,13 @@ private:
              mSampleRate(sampleRate),
              mSampleRate(sampleRate),
              mChannels(channels) {}
              mChannels(channels) {}


        AudioCodec(const AudioCodec& copy) {
            mCodec = copy.mCodec;
            mBitRate = copy.mBitRate;
            mSampleRate = copy.mSampleRate;
            mChannels = copy.mChannels;
        }

        ~AudioCodec() {}
        ~AudioCodec() {}


        audio_encoder mCodec;
        audio_encoder mCodec;
@@ -193,6 +217,15 @@ private:
              mVideoCodec(0),
              mVideoCodec(0),
              mAudioCodec(0) {}
              mAudioCodec(0) {}


        CamcorderProfile(const CamcorderProfile& copy) {
            mCameraId = copy.mCameraId;
            mFileFormat = copy.mFileFormat;
            mQuality = copy.mQuality;
            mDuration = copy.mDuration;
            mVideoCodec = new VideoCodec(*copy.mVideoCodec);
            mAudioCodec = new AudioCodec(*copy.mAudioCodec);
        }

        ~CamcorderProfile() {
        ~CamcorderProfile() {
            delete mVideoCodec;
            delete mVideoCodec;
            delete mAudioCodec;
            delete mAudioCodec;
@@ -272,6 +305,8 @@ private:
    };
    };


    int getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const;
    int getCamcorderProfileIndex(int cameraId, camcorder_quality quality) const;
    void initRequiredProfileRefs(const Vector<int>& cameraIds);
    int getRequiredProfileRefIndex(int cameraId);


    // Debug
    // Debug
    static void logVideoCodec(const VideoCodec& codec);
    static void logVideoCodec(const VideoCodec& codec);
@@ -291,7 +326,10 @@ private:
    static VideoDecoderCap* createVideoDecoderCap(const char **atts);
    static VideoDecoderCap* createVideoDecoderCap(const char **atts);
    static VideoEncoderCap* createVideoEncoderCap(const char **atts);
    static VideoEncoderCap* createVideoEncoderCap(const char **atts);
    static AudioEncoderCap* createAudioEncoderCap(const char **atts);
    static AudioEncoderCap* createAudioEncoderCap(const char **atts);
    static CamcorderProfile* createCamcorderProfile(int cameraId, const char **atts);

    static CamcorderProfile* createCamcorderProfile(
                int cameraId, const char **atts, Vector<int>& cameraIds);

    static int getCameraId(const char **atts);
    static int getCameraId(const char **atts);


    ImageEncodingQualityLevels* findImageEncodingQualityLevels(int cameraId) const;
    ImageEncodingQualityLevels* findImageEncodingQualityLevels(int cameraId) const;
@@ -335,6 +373,21 @@ private:


    static int findTagForName(const NameToTagMap *map, size_t nMappings, const char *name);
    static int findTagForName(const NameToTagMap *map, size_t nMappings, const char *name);


    /**
     * Check on existing profiles with the following criteria:
     * 1. Low quality profile must have the lowest video
     *    resolution product (width x height)
     * 2. High quality profile must have the highest video
     *    resolution product (width x height)
     *
     * and add required low/high quality camcorder/timelapse
     * profiles if they are not found. This allows to remove
     * duplicate profile definitions in the media_profiles.xml
     * file.
     */
    void checkAndAddRequiredProfilesIfNecessary();


    // Mappings from name (for instance, codec name) to enum value
    // Mappings from name (for instance, codec name) to enum value
    static const NameToTagMap sVideoEncoderNameMap[];
    static const NameToTagMap sVideoEncoderNameMap[];
    static const NameToTagMap sAudioEncoderNameMap[];
    static const NameToTagMap sAudioEncoderNameMap[];
@@ -355,6 +408,20 @@ private:
    Vector<VideoDecoderCap*>  mVideoDecoders;
    Vector<VideoDecoderCap*>  mVideoDecoders;
    Vector<output_format>     mEncoderOutputFileFormats;
    Vector<output_format>     mEncoderOutputFileFormats;
    Vector<ImageEncodingQualityLevels *>  mImageEncodingQualityLevels;
    Vector<ImageEncodingQualityLevels *>  mImageEncodingQualityLevels;

    typedef struct {
        bool mHasRefProfile;      // Refers to an existing profile
        int  mRefProfileIndex;    // Reference profile index
        int  mResolutionProduct;  // width x height
    } RequiredProfileRefInfo;     // Required low and high profiles

    typedef struct {
        RequiredProfileRefInfo mRefs[kNumRequiredProfiles];
        int mCameraId;
    } RequiredProfiles;

    RequiredProfiles *mRequiredProfileRefs;
    Vector<int>              mCameraIds;
};
};


}; // namespace android
}; // namespace android
+172 −6
Original line number Original line Diff line number Diff line
@@ -284,8 +284,17 @@ MediaProfiles::createEncoderOutputFileFormat(const char **atts)
    return static_cast<output_format>(format);
    return static_cast<output_format>(format);
}
}


static bool isCameraIdFound(int cameraId, const Vector<int>& cameraIds) {
    for (int i = 0, n = cameraIds.size(); i < n; ++i) {
        if (cameraId == cameraIds[i]) {
            return true;
        }
    }
    return false;
}

/*static*/ MediaProfiles::CamcorderProfile*
/*static*/ MediaProfiles::CamcorderProfile*
MediaProfiles::createCamcorderProfile(int cameraId, const char **atts)
MediaProfiles::createCamcorderProfile(int cameraId, const char **atts, Vector<int>& cameraIds)
{
{
    CHECK(!strcmp("quality",    atts[0]) &&
    CHECK(!strcmp("quality",    atts[0]) &&
          !strcmp("fileFormat", atts[2]) &&
          !strcmp("fileFormat", atts[2]) &&
@@ -301,6 +310,9 @@ MediaProfiles::createCamcorderProfile(int cameraId, const char **atts)


    MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
    MediaProfiles::CamcorderProfile *profile = new MediaProfiles::CamcorderProfile;
    profile->mCameraId = cameraId;
    profile->mCameraId = cameraId;
    if (!isCameraIdFound(cameraId, cameraIds)) {
        cameraIds.add(cameraId);
    }
    profile->mFileFormat = static_cast<output_format>(fileFormat);
    profile->mFileFormat = static_cast<output_format>(fileFormat);
    profile->mQuality = static_cast<camcorder_quality>(quality);
    profile->mQuality = static_cast<camcorder_quality>(quality);
    profile->mDuration = atoi(atts[5]);
    profile->mDuration = atoi(atts[5]);
@@ -370,12 +382,167 @@ MediaProfiles::startElementHandler(void *userData, const char *name, const char
        profiles->mCurrentCameraId = getCameraId(atts);
        profiles->mCurrentCameraId = getCameraId(atts);
    } else if (strcmp("EncoderProfile", name) == 0) {
    } else if (strcmp("EncoderProfile", name) == 0) {
        profiles->mCamcorderProfiles.add(
        profiles->mCamcorderProfiles.add(
            createCamcorderProfile(profiles->mCurrentCameraId, atts));
            createCamcorderProfile(profiles->mCurrentCameraId, atts, profiles->mCameraIds));
    } else if (strcmp("ImageEncoding", name) == 0) {
    } else if (strcmp("ImageEncoding", name) == 0) {
        profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
        profiles->addImageEncodingQualityLevel(profiles->mCurrentCameraId, atts);
    }
    }
}
}


static bool isCamcorderProfile(camcorder_quality quality) {
    return quality >= CAMCORDER_QUALITY_LIST_START &&
           quality <= CAMCORDER_QUALITY_LIST_END;
}

static bool isTimelapseProfile(camcorder_quality quality) {
    return quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START &&
           quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END;
}

void MediaProfiles::initRequiredProfileRefs(const Vector<int>& cameraIds) {
    LOGV("Number of camera ids: %d", cameraIds.size());
    CHECK(cameraIds.size() > 0);
    mRequiredProfileRefs = new RequiredProfiles[cameraIds.size()];
    for (size_t i = 0, n = cameraIds.size(); i < n; ++i) {
        mRequiredProfileRefs[i].mCameraId = cameraIds[i];
        for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
            mRequiredProfileRefs[i].mRefs[j].mHasRefProfile = false;
            mRequiredProfileRefs[i].mRefs[j].mRefProfileIndex = -1;
            if ((j & 1) == 0) {  // low resolution
                mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0x7FFFFFFF;
            } else {             // high resolution
                mRequiredProfileRefs[i].mRefs[j].mResolutionProduct = 0;
            }
        }
    }
}

int MediaProfiles::getRequiredProfileRefIndex(int cameraId) {
    for (size_t i = 0, n = mCameraIds.size(); i < n; ++i) {
        if (mCameraIds[i] == cameraId) {
            return i;
        }
    }
    return -1;
}

void MediaProfiles::checkAndAddRequiredProfilesIfNecessary() {
    if (sIsInitialized) {
        return;
    }

    initRequiredProfileRefs(mCameraIds);

    for (size_t i = 0, n = mCamcorderProfiles.size(); i < n; ++i) {
        int product = mCamcorderProfiles[i]->mVideoCodec->mFrameWidth *
                      mCamcorderProfiles[i]->mVideoCodec->mFrameHeight;

        camcorder_quality quality = mCamcorderProfiles[i]->mQuality;
        int cameraId = mCamcorderProfiles[i]->mCameraId;
        int index = -1;
        int refIndex = getRequiredProfileRefIndex(cameraId);
        CHECK(refIndex != -1);
        RequiredProfileRefInfo *info;
        camcorder_quality refQuality;
        VideoCodec *codec = NULL;

        // Check high and low from either camcorder profile or timelapse profile
        // but not both. Default, check camcorder profile
        size_t j = 0;
        size_t n = 2;
        if (isTimelapseProfile(quality)) {
            // Check timelapse profile instead.
            j = 2;
            n = kNumRequiredProfiles;
        } else {
            // Must be camcorder profile.
            CHECK(isCamcorderProfile(quality));
        }
        for (; j < n; ++j) {
            info = &(mRequiredProfileRefs[refIndex].mRefs[j]);
            if ((j % 2 == 0 && product > info->mResolutionProduct) ||  // low
                (j % 2 != 0 && product < info->mResolutionProduct)) {  // high
                continue;
            }
            switch (j) {
                case 0:
                   refQuality = CAMCORDER_QUALITY_LOW;
                   break;
                case 1:
                   refQuality = CAMCORDER_QUALITY_HIGH;
                   break;
                case 2:
                   refQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
                   break;
                case 3:
                   refQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
                   break;
                default:
                    CHECK(!"Should never reach here");
            }

            if (!info->mHasRefProfile) {
                index = getCamcorderProfileIndex(cameraId, refQuality);
            }
            if (index == -1) {
                // New high or low quality profile is found.
                // Update its reference.
                info->mHasRefProfile = true;
                info->mRefProfileIndex = i;
                info->mResolutionProduct = product;
            }
        }
    }

    for (size_t cameraId = 0; cameraId < mCameraIds.size(); ++cameraId) {
        for (size_t j = 0; j < kNumRequiredProfiles; ++j) {
            int refIndex = getRequiredProfileRefIndex(cameraId);
            CHECK(refIndex != -1);
            RequiredProfileRefInfo *info =
                    &mRequiredProfileRefs[refIndex].mRefs[j];

            if (info->mHasRefProfile) {

                CamcorderProfile *profile =
                    new CamcorderProfile(
                            *mCamcorderProfiles[info->mRefProfileIndex]);

                // Overwrite the quality
                switch (j % kNumRequiredProfiles) {
                    case 0:
                        profile->mQuality = CAMCORDER_QUALITY_LOW;
                        break;
                    case 1:
                        profile->mQuality = CAMCORDER_QUALITY_HIGH;
                        break;
                    case 2:
                        profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_LOW;
                        break;
                    case 3:
                        profile->mQuality = CAMCORDER_QUALITY_TIME_LAPSE_HIGH;
                        break;
                    default:
                        CHECK(!"Should never come here");
                }

                int index = getCamcorderProfileIndex(cameraId, profile->mQuality);
                if (index != -1) {
                    LOGV("Profile quality %d for camera %d already exists",
                        profile->mQuality, cameraId);
                    CHECK(index == refIndex);
                    continue;
                }

                // Insert the new profile
                LOGV("Add a profile: quality %d=>%d for camera %d",
                        mCamcorderProfiles[info->mRefProfileIndex]->mQuality,
                        profile->mQuality, cameraId);

                mCamcorderProfiles.add(profile);
            }
        }
    }
}

/*static*/ MediaProfiles*
/*static*/ MediaProfiles*
MediaProfiles::getInstance()
MediaProfiles::getInstance()
{
{
@@ -396,6 +563,9 @@ MediaProfiles::getInstance()
        } else {
        } else {
            sInstance = createInstanceFromXmlFile(value);
            sInstance = createInstanceFromXmlFile(value);
        }
        }
        CHECK(sInstance != NULL);
        sInstance->checkAndAddRequiredProfilesIfNecessary();
        sIsInitialized = true;
    }
    }


    return sInstance;
    return sInstance;
@@ -613,7 +783,6 @@ MediaProfiles::createDefaultInstance()
    createDefaultAudioDecoders(profiles);
    createDefaultAudioDecoders(profiles);
    createDefaultEncoderOutputFileFormats(profiles);
    createDefaultEncoderOutputFileFormats(profiles);
    createDefaultImageEncodingQualityLevels(profiles);
    createDefaultImageEncodingQualityLevels(profiles);
    sIsInitialized = true;
    return profiles;
    return profiles;
}
}


@@ -667,9 +836,6 @@ MediaProfiles::createInstanceFromXmlFile(const char *xml)
exit:
exit:
    ::XML_ParserFree(parser);
    ::XML_ParserFree(parser);
    ::fclose(fp);
    ::fclose(fp);
    if (profiles) {
        sIsInitialized = true;
    }
    return profiles;
    return profiles;
}
}