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

Commit 987ab483 authored by James Dong's avatar James Dong
Browse files

Support for storing geo information in the recorded mp4/3gpp file.

o Geo data (latitude and longitude) is stored in udta box

Change-Id: I76e4aeb741c4b339f3753d3d28190151f3ea4919
related-to-bug: 4260295
parent ae7bc652
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -55,6 +55,8 @@ public:
    status_t setInterleaveDuration(uint32_t duration);
    status_t setInterleaveDuration(uint32_t duration);
    int32_t getTimeScale() const { return mTimeScale; }
    int32_t getTimeScale() const { return mTimeScale; }


    status_t setGeoData(int latitudex10000, int longitudex10000);

protected:
protected:
    virtual ~MPEG4Writer();
    virtual ~MPEG4Writer();


@@ -79,6 +81,9 @@ private:
    uint32_t mInterleaveDurationUs;
    uint32_t mInterleaveDurationUs;
    int32_t mTimeScale;
    int32_t mTimeScale;
    int64_t mStartTimestampUs;
    int64_t mStartTimestampUs;
    int mLatitudex10000;
    int mLongitudex10000;
    bool mAreGeoTagsAvailable;


    Mutex mLock;
    Mutex mLock;


@@ -169,6 +174,10 @@ private:
    void writeMvhdBox(int64_t durationUs);
    void writeMvhdBox(int64_t durationUs);
    void writeMoovBox(int64_t durationUs);
    void writeMoovBox(int64_t durationUs);
    void writeFtypBox(const MetaData *param);
    void writeFtypBox(const MetaData *param);
    void writeUdtaBox();
    void writeGeoDataBox();
    void writeLatitude(int degreex10000);
    void writeLongitude(int degreex10000);
    void sendSessionSummary();
    void sendSessionSummary();


    MPEG4Writer(const MPEG4Writer &);
    MPEG4Writer(const MPEG4Writer &);
+34 −0
Original line number Original line Diff line number Diff line
@@ -346,6 +346,40 @@ public class MediaRecorder
        setParameter("video-param-rotation-angle-degrees=" + degrees);
        setParameter("video-param-rotation-angle-degrees=" + degrees);
    }
    }


    /**
     * Store the geodata (latitude and longitude) in the output file.
     * This method should be called before prepare(). The geodata is
     * stored in udta box if the output format is OutputFormat.THREE_GPP
     * or OutputFormat.MPEG_4, and is ignored for other output formats.
     * The geodata is stored according to ISO-6709 standard.
     *
     * @param latitude latitude in degrees. Its value must be in the
     * range [-90, 90].
     * @param longitude longitude in degrees. Its value must be in the
     * range [-180, 180].
     *
     * @throws IllegalArgumentException if the given latitude or
     * longitude is out of range.
     *
     * {@hide}
     */
    public void setGeoData(float latitude, float longitude) {
        int latitudex10000  = (int) (latitude * 10000 + 0.5);
        int longitudex10000 = (int) (longitude * 10000 + 0.5);

        if (latitudex10000 > 900000 || latitudex10000 < -900000) {
            String msg = "Unsupported latitude: " + latitude;
            throw new IllegalArgumentException(msg);
        }
        if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
            String msg = "Unsupported longitude: " + longitude;
            throw new IllegalArgumentException(msg);
        }

        setParameter("param-geotag-latitude=" + latitudex10000);
        setParameter("param-geotag-longitude=" + longitudex10000);
    }

    /**
    /**
     * Sets the format of the output file produced during recording. Call this
     * Sets the format of the output file produced during recording. Call this
     * after setAudioSource()/setVideoSource() but before prepare().
     * after setAudioSource()/setVideoSource() but before prepare().
+36 −0
Original line number Original line Diff line number Diff line
@@ -593,6 +593,26 @@ status_t StagefrightRecorder::setParamAuxVideoEncodingBitRate(int32_t bitRate) {
    return OK;
    return OK;
}
}


status_t StagefrightRecorder::setParamGeoDataLongitude(
    int32_t longitudex10000) {

    if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
        return BAD_VALUE;
    }
    mLongitudex10000 = longitudex10000;
    return OK;
}

status_t StagefrightRecorder::setParamGeoDataLatitude(
    int32_t latitudex10000) {

    if (latitudex10000 > 900000 || latitudex10000 < -900000) {
        return BAD_VALUE;
    }
    mLatitudex10000 = latitudex10000;
    return OK;
}

status_t StagefrightRecorder::setParameter(
status_t StagefrightRecorder::setParameter(
        const String8 &key, const String8 &value) {
        const String8 &key, const String8 &value) {
    LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
    LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
@@ -621,6 +641,16 @@ status_t StagefrightRecorder::setParameter(
        if (safe_strtoi32(value.string(), &use64BitOffset)) {
        if (safe_strtoi32(value.string(), &use64BitOffset)) {
            return setParam64BitFileOffset(use64BitOffset != 0);
            return setParam64BitFileOffset(use64BitOffset != 0);
        }
        }
    } else if (key == "param-geotag-longitude") {
        int32_t longitudex10000;
        if (safe_strtoi32(value.string(), &longitudex10000)) {
            return setParamGeoDataLongitude(longitudex10000);
        }
    } else if (key == "param-geotag-latitude") {
        int32_t latitudex10000;
        if (safe_strtoi32(value.string(), &latitudex10000)) {
            return setParamGeoDataLatitude(latitudex10000);
        }
    } else if (key == "param-track-time-status") {
    } else if (key == "param-track-time-status") {
        int64_t timeDurationUs;
        int64_t timeDurationUs;
        if (safe_strtoi64(value.string(), &timeDurationUs)) {
        if (safe_strtoi64(value.string(), &timeDurationUs)) {
@@ -1412,6 +1442,10 @@ status_t StagefrightRecorder::setupMPEG4Recording(
        reinterpret_cast<MPEG4Writer *>(writer.get())->
        reinterpret_cast<MPEG4Writer *>(writer.get())->
            setInterleaveDuration(mInterleaveDurationUs);
            setInterleaveDuration(mInterleaveDurationUs);
    }
    }
    if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) {
        reinterpret_cast<MPEG4Writer *>(writer.get())->
            setGeoData(mLatitudex10000, mLongitudex10000);
    }
    if (mMaxFileDurationUs != 0) {
    if (mMaxFileDurationUs != 0) {
        writer->setMaxFileDuration(mMaxFileDurationUs);
        writer->setMaxFileDuration(mMaxFileDurationUs);
    }
    }
@@ -1638,6 +1672,8 @@ status_t StagefrightRecorder::reset() {
    mIsMetaDataStoredInVideoBuffers = false;
    mIsMetaDataStoredInVideoBuffers = false;
    mEncoderProfiles = MediaProfiles::getInstance();
    mEncoderProfiles = MediaProfiles::getInstance();
    mRotationDegrees = 0;
    mRotationDegrees = 0;
    mLatitudex10000 = -3600000;
    mLongitudex10000 = -3600000;


    mOutputFd = -1;
    mOutputFd = -1;
    mOutputFdAux = -1;
    mOutputFdAux = -1;
+4 −0
Original line number Original line Diff line number Diff line
@@ -97,6 +97,8 @@ private:
    int64_t mMaxFileDurationUs;
    int64_t mMaxFileDurationUs;
    int64_t mTrackEveryTimeDurationUs;
    int64_t mTrackEveryTimeDurationUs;
    int32_t mRotationDegrees;  // Clockwise
    int32_t mRotationDegrees;  // Clockwise
    int32_t mLatitudex10000;
    int32_t mLongitudex10000;


    bool mCaptureTimeLapse;
    bool mCaptureTimeLapse;
    int64_t mTimeBetweenTimeLapseFrameCaptureUs;
    int64_t mTimeBetweenTimeLapseFrameCaptureUs;
@@ -160,6 +162,8 @@ private:
    status_t setParamMaxFileDurationUs(int64_t timeUs);
    status_t setParamMaxFileDurationUs(int64_t timeUs);
    status_t setParamMaxFileSizeBytes(int64_t bytes);
    status_t setParamMaxFileSizeBytes(int64_t bytes);
    status_t setParamMovieTimeScale(int32_t timeScale);
    status_t setParamMovieTimeScale(int32_t timeScale);
    status_t setParamGeoDataLongitude(int32_t longitudex10000);
    status_t setParamGeoDataLatitude(int32_t latitudex10000);
    void clipVideoBitRate();
    void clipVideoBitRate();
    void clipVideoFrameRate();
    void clipVideoFrameRate();
    void clipVideoFrameWidth();
    void clipVideoFrameWidth();
+107 −2
Original line number Original line Diff line number Diff line
@@ -257,7 +257,10 @@ MPEG4Writer::MPEG4Writer(const char *filename)
      mOffset(0),
      mOffset(0),
      mMdatOffset(0),
      mMdatOffset(0),
      mEstimatedMoovBoxSize(0),
      mEstimatedMoovBoxSize(0),
      mInterleaveDurationUs(1000000) {
      mInterleaveDurationUs(1000000),
      mLatitudex10000(0),
      mLongitudex10000(0),
      mAreGeoTagsAvailable(false) {


    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
    if (mFd >= 0) {
    if (mFd >= 0) {
@@ -276,7 +279,10 @@ MPEG4Writer::MPEG4Writer(int fd)
      mOffset(0),
      mOffset(0),
      mMdatOffset(0),
      mMdatOffset(0),
      mEstimatedMoovBoxSize(0),
      mEstimatedMoovBoxSize(0),
      mInterleaveDurationUs(1000000) {
      mInterleaveDurationUs(1000000),
      mLatitudex10000(0),
      mLongitudex10000(0),
      mAreGeoTagsAvailable(false) {
}
}


MPEG4Writer::~MPEG4Writer() {
MPEG4Writer::~MPEG4Writer() {
@@ -724,6 +730,9 @@ void MPEG4Writer::writeMvhdBox(int64_t durationUs) {
void MPEG4Writer::writeMoovBox(int64_t durationUs) {
void MPEG4Writer::writeMoovBox(int64_t durationUs) {
    beginBox("moov");
    beginBox("moov");
    writeMvhdBox(durationUs);
    writeMvhdBox(durationUs);
    if (mAreGeoTagsAvailable) {
        writeUdtaBox();
    }
    int32_t id = 1;
    int32_t id = 1;
    for (List<Track *>::iterator it = mTracks.begin();
    for (List<Track *>::iterator it = mTracks.begin();
        it != mTracks.end(); ++it, ++id) {
        it != mTracks.end(); ++it, ++id) {
@@ -921,6 +930,77 @@ void MPEG4Writer::writeFourcc(const char *s) {
    write(s, 1, 4);
    write(s, 1, 4);
}
}



// Written in +/-DD.DDDD format
void MPEG4Writer::writeLatitude(int degreex10000) {
    bool isNegative = (degreex10000 < 0);
    char sign = isNegative? '-': '+';

    // Handle the whole part
    char str[9];
    int wholePart = degreex10000 / 10000;
    if (wholePart == 0) {
        snprintf(str, 5, "%c%.2d.", sign, wholePart);
    } else {
        snprintf(str, 5, "%+.2d.", wholePart);
    }

    // Handle the fractional part
    int fractionalPart = degreex10000 - (wholePart * 10000);
    if (fractionalPart < 0) {
        fractionalPart = -fractionalPart;
    }
    snprintf(&str[4], 5, "%.4d", fractionalPart);

    // Do not write the null terminator
    write(str, 1, 8);
}

// Written in +/- DDD.DDDD format
void MPEG4Writer::writeLongitude(int degreex10000) {
    bool isNegative = (degreex10000 < 0);
    char sign = isNegative? '-': '+';

    // Handle the whole part
    char str[10];
    int wholePart = degreex10000 / 10000;
    if (wholePart == 0) {
        snprintf(str, 6, "%c%.3d.", sign, wholePart);
    } else {
        snprintf(str, 6, "%+.3d.", wholePart);
    }

    // Handle the fractional part
    int fractionalPart = degreex10000 - (wholePart * 10000);
    if (fractionalPart < 0) {
        fractionalPart = -fractionalPart;
    }
    snprintf(&str[5], 5, "%.4d", fractionalPart);

    // Do not write the null terminator
    write(str, 1, 9);
}

/*
 * Geodata is stored according to ISO-6709 standard.
 * latitudex10000 is latitude in degrees times 10000, and
 * longitudex10000 is longitude in degrees times 10000.
 * The range for the latitude is in [-90, +90], and
 * The range for the longitude is in [-180, +180]
 */
status_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) {
    // Is latitude or longitude out of range?
    if (latitudex10000 < -900000 || latitudex10000 > 900000 ||
        longitudex10000 < -1800000 || longitudex10000 > 1800000) {
        return BAD_VALUE;
    }

    mLatitudex10000 = latitudex10000;
    mLongitudex10000 = longitudex10000;
    mAreGeoTagsAvailable = true;
    return OK;
}

void MPEG4Writer::write(const void *data, size_t size) {
void MPEG4Writer::write(const void *data, size_t size) {
    write(data, 1, size);
    write(data, 1, size);
}
}
@@ -2722,4 +2802,29 @@ void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
    mOwner->endBox();  // stco or co64
    mOwner->endBox();  // stco or co64
}
}


void MPEG4Writer::writeUdtaBox() {
    beginBox("udta");
    writeGeoDataBox();
    endBox();
}

/*
 * Geodata is stored according to ISO-6709 standard.
 */
void MPEG4Writer::writeGeoDataBox() {
    beginBox("\xA9xyz");
    /*
     * For historical reasons, any user data start
     * with "\0xA9", must be followed by its assoicated
     * language code.
     * 0x0012: locale en
     * 0x15c7: language 5575
     */
    writeInt32(0x001215c7);
    writeLatitude(mLatitudex10000);
    writeLongitude(mLongitudex10000);
    writeInt8(0x2F);
    endBox();
}

}  // namespace android
}  // namespace android