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

Commit 71c27d99 authored by Andreas Huber's avatar Andreas Huber
Browse files

Various fixes to enable recording on passion and nexus1.

Change-Id: I75a461c9882e2449082ad754ee7b231c1ceec039
parent ab88ea95
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -147,7 +147,7 @@ int main(int argc, char **argv) {
    OMXClient client;
    CHECK_EQ(client.connect(), OK);

#if 1
#if 0
    sp<MediaSource> source = createSource(argv[1]);

    if (source == NULL) {
@@ -165,14 +165,15 @@ int main(int argc, char **argv) {
    success = success && meta->findInt32(kKeyHeight, &height);
    CHECK(success);
#else
    int width = 800;
    int width = 720;
    int height = 480;
    sp<MediaSource> decoder = new DummySource(width, height);
#endif

    sp<MetaData> enc_meta = new MetaData;
    // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
    // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
    enc_meta->setInt32(kKeyWidth, width);
    enc_meta->setInt32(kKeyHeight, height);

@@ -213,6 +214,8 @@ int main(int argc, char **argv) {

#if 0
    CameraSource *source = CameraSource::Create();
    source->start();

    printf("source = %p\n", source);

    for (int i = 0; i < 100; ++i) {
@@ -227,6 +230,8 @@ int main(int argc, char **argv) {
        buffer = NULL;
    }

    source->stop();

    delete source;
    source = NULL;
#endif
+0 −7
Original line number Diff line number Diff line
@@ -142,13 +142,6 @@ CameraSource::CameraSource(const sp<Camera> &camera)
      mFirstFrameTimeUs(0),
      mNumFrames(0),
      mStarted(false) {
    char value[PROPERTY_VALUE_MAX];
    if (property_get("ro.hardware", value, NULL) && !strcmp(value, "sholes")) {
        // The hardware encoder(s) do not support yuv420, but only YCbYCr,
        // fortunately the camera also supports this, so we needn't transcode.
        mCamera->setParameters(String8("preview-format=yuv422i-yuyv"));
    }

    String8 s = mCamera->getParameters();
    printf("params: \"%s\"\n", s.string());

+185 −40
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h>

@@ -65,10 +66,15 @@ private:
    static void *ThreadWrapper(void *me);
    void threadEntry();

    status_t makeAVCCodecSpecificData(
            const uint8_t *data, size_t size);

    Track(const Track &);
    Track &operator=(const Track &);
};

#define USE_NALLEN_FOUR         1

MPEG4Writer::MPEG4Writer(const char *filename)
    : mFile(fopen(filename, "wb")),
      mOffset(0),
@@ -213,23 +219,55 @@ off_t MPEG4Writer::addSample(MediaBuffer *buffer) {
    return old_offset;
}

static void StripStartcode(MediaBuffer *buffer) {
    if (buffer->range_length() < 4) {
        return;
    }

    const uint8_t *ptr =
        (const uint8_t *)buffer->data() + buffer->range_offset();

    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
        buffer->set_range(
                buffer->range_offset() + 4, buffer->range_length() - 4);
    }
}

off_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) {
    Mutex::Autolock autoLock(mLock);

    StripStartcode(buffer);

    off_t old_offset = mOffset;

    size_t length = buffer->range_length();

#if USE_NALLEN_FOUR
    uint8_t x = length >> 24;
    fwrite(&x, 1, 1, mFile);
    x = (length >> 16) & 0xff;
    fwrite(&x, 1, 1, mFile);
    x = (length >> 8) & 0xff;
    fwrite(&x, 1, 1, mFile);
    x = length & 0xff;
    fwrite(&x, 1, 1, mFile);
#else
    CHECK(length < 65536);

    uint8_t x = length >> 8;
    fwrite(&x, 1, 1, mFile);
    x = length & 0xff;
    fwrite(&x, 1, 1, mFile);
#endif

    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
           1, length, mFile);

#if USE_NALLEN_FOUR
    mOffset += length + 4;
#else
    mOffset += length + 2;
#endif

    return old_offset;
}
@@ -380,6 +418,60 @@ void *MPEG4Writer::Track::ThreadWrapper(void *me) {
    return NULL;
}

status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
        const uint8_t *data, size_t size) {
    if (mCodecSpecificData != NULL) {
        return ERROR_MALFORMED;
    }

    if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
        // Must start with a start-code.
        return ERROR_MALFORMED;
    }

    size_t picParamOffset = 4;
    while (picParamOffset + 3 < size
            && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
        ++picParamOffset;
    }

    if (picParamOffset + 3 >= size) {
        // Could not find start-code for pictureParameterSet.
        return ERROR_MALFORMED;
    }

    size_t seqParamSetLength = picParamOffset - 4;
    size_t picParamSetLength = size - picParamOffset - 4;

    mCodecSpecificDataSize =
        6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;

    mCodecSpecificData = malloc(mCodecSpecificDataSize);
    uint8_t *header = (uint8_t *)mCodecSpecificData;
    header[0] = 1;
    header[1] = 0x42;  // profile
    header[2] = 0x80;
    header[3] = 0x1e;  // level

#if USE_NALLEN_FOUR
    header[4] = 0xfc | 3;  // length size == 4 bytes
#else
    header[4] = 0xfc | 1;  // length size == 2 bytes
#endif

    header[5] = 0xe0 | 1;
    header[6] = seqParamSetLength >> 8;
    header[7] = seqParamSetLength & 0xff;
    memcpy(&header[8], &data[4], seqParamSetLength);
    header += 8 + seqParamSetLength;
    header[0] = 1;
    header[1] = picParamSetLength >> 8;
    header[2] = picParamSetLength & 0xff;
    memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);

    return OK;
}

void MPEG4Writer::Track::threadEntry() {
    sp<MetaData> meta = mSource->getFormat();
    const char *mime;
@@ -399,54 +491,40 @@ void MPEG4Writer::Track::threadEntry() {

        ++count;

        if (is_avc && count < 3) {
            size_t size = buffer->range_length();

            switch (count) {
                case 1:
                {
                    CHECK_EQ(mCodecSpecificData, NULL);
                    mCodecSpecificData = malloc(size + 8);
                    uint8_t *header = (uint8_t *)mCodecSpecificData;
                    header[0] = 1;
                    header[1] = 0x42;  // profile
                    header[2] = 0x80;
                    header[3] = 0x1e;  // level
                    header[4] = 0xfc | 3;
                    header[5] = 0xe0 | 1;
                    header[6] = size >> 8;
                    header[7] = size & 0xff;
                    memcpy(&header[8],
                            (const uint8_t *)buffer->data() + buffer->range_offset(),
                            size);
        int32_t isCodecConfig;
        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
                && isCodecConfig) {
            if (is_avc) {
                status_t err = makeAVCCodecSpecificData(
                        (const uint8_t *)buffer->data()
                            + buffer->range_offset(),
                        buffer->range_length());

                    mCodecSpecificDataSize = size + 8;
                if (err != OK) {
                    LOGE("failed to parse avc codec specific data.");
                    break;
                }

                case 2:
                {
                    size_t offset = mCodecSpecificDataSize;
                    mCodecSpecificDataSize += size + 3;
                    mCodecSpecificData = realloc(mCodecSpecificData, mCodecSpecificDataSize);
                    uint8_t *header = (uint8_t *)mCodecSpecificData;
                    header[offset] = 1;
                    header[offset + 1] = size >> 8;
                    header[offset + 2] = size & 0xff;
                    memcpy(&header[offset + 3],
                            (const uint8_t *)buffer->data() + buffer->range_offset(),
                            size);
            } else if (is_mpeg4) {
                if (mCodecSpecificData != NULL) {
                    break;
                }

                mCodecSpecificDataSize = buffer->range_length();
                mCodecSpecificData = malloc(mCodecSpecificDataSize);
                memcpy(mCodecSpecificData,
                        (const uint8_t *)buffer->data()
                            + buffer->range_offset(),
                       buffer->range_length());
            }

            buffer->release();
            buffer = NULL;

            continue;
        }
        } else if (count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
            // The TI mpeg4 encoder does not properly set the
            // codec-specific-data flag.

        if (mCodecSpecificData == NULL && is_mpeg4) {
            const uint8_t *data =
                (const uint8_t *)buffer->data() + buffer->range_offset();

@@ -474,13 +552,70 @@ void MPEG4Writer::Track::threadEntry() {
            memcpy(mCodecSpecificData, data, offset);

            buffer->set_range(buffer->range_offset() + offset, size - offset);

            if (size == offset) {
                buffer->release();
                buffer = NULL;

                continue;
            }
        } else if (is_avc && count < 3) {
            // The TI video encoder does not flag codec specific data
            // as such and also splits up SPS and PPS across two buffers.

            const uint8_t *data =
                (const uint8_t *)buffer->data() + buffer->range_offset();

            size_t size = buffer->range_length();

            CHECK(count == 2 || mCodecSpecificData == NULL);

            size_t offset = mCodecSpecificDataSize;
            mCodecSpecificDataSize += size + 4;
            mCodecSpecificData =
                realloc(mCodecSpecificData, mCodecSpecificDataSize);

            memcpy((uint8_t *)mCodecSpecificData + offset,
                   "\x00\x00\x00\x01", 4);

            memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);

            buffer->release();
            buffer = NULL;

            if (count == 2) {
                void *tmp = mCodecSpecificData;
                size = mCodecSpecificDataSize;
                mCodecSpecificData = NULL;
                mCodecSpecificDataSize = 0;

                status_t err = makeAVCCodecSpecificData(
                        (const uint8_t *)tmp, size);

                free(tmp);
                tmp = NULL;

                if (err != OK) {
                    LOGE("failed to parse avc codec specific data.");
                    break;
                }
            }

            continue;
        }

        off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer)
                              : mOwner->addSample(buffer);

        SampleInfo info;
        info.size = is_avc ? buffer->range_length() + 2 : buffer->range_length();
        info.size = is_avc
#if USE_NALLEN_FOUR
            ? buffer->range_length() + 4
#else
            ? buffer->range_length() + 2
#endif
            : buffer->range_length();

        info.offset = offset;

        int64_t timestampUs;
@@ -733,19 +868,29 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {

          mOwner->beginBox("stts");
            mOwner->writeInt32(0);  // version=0, flags=0
            mOwner->writeInt32(mSampleInfos.size() - 1);
            mOwner->writeInt32(mSampleInfos.size());

            List<SampleInfo>::iterator it = mSampleInfos.begin();
            int64_t last = (*it).timestamp;
            int64_t lastDuration = 1;

            ++it;
            while (it != mSampleInfos.end()) {
                mOwner->writeInt32(1);
                mOwner->writeInt32((*it).timestamp - last);
                lastDuration = (*it).timestamp - last;
                mOwner->writeInt32(lastDuration);

                last = (*it).timestamp;

                ++it;
            }

            // We don't really know how long the last frame lasts, since
            // there is no frame time after it, just repeat the previous
            // frame's duration.
            mOwner->writeInt32(1);
            mOwner->writeInt32(lastDuration);

          mOwner->endBox();  // stts

          mOwner->beginBox("stsz");
+12 −2
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ static const CodecInfo kEncoderInfo[] = {
    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
};
@@ -679,6 +680,7 @@ static size_t getFrameSize(
        case OMX_COLOR_FormatCbYCrY:
            return width * height * 2;

        case OMX_COLOR_FormatYUV420Planar:
        case OMX_COLOR_FormatYUV420SemiPlanar:
            return (width * height * 3) / 2;

@@ -706,7 +708,7 @@ void OMXCodec::setVideoInputFormat(

    OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
    if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
        colorFormat = OMX_COLOR_FormatYCbYCr;
        colorFormat = OMX_COLOR_FormatYUV420Planar;
    }

    CHECK_EQ(setVideoPortFormatType(
@@ -764,6 +766,14 @@ void OMXCodec::setVideoInputFormat(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    CHECK_EQ(err, OK);

    err = mOMX->getParameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    CHECK_EQ(err, OK);

    err = mOMX->setParameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    CHECK_EQ(err, OK);

    switch (compressionFormat) {
        case OMX_VIDEO_CodingMPEG4:
        {
@@ -911,7 +921,7 @@ status_t OMXCodec::setupAVCEncoderParameters() {
    CHECK_EQ(err, OK);

    bitrateType.eControlRate = OMX_Video_ControlRateVariable;
    bitrateType.nTargetBitrate = 1000000;
    bitrateType.nTargetBitrate = 3000000;

    err = mOMX->setParameter(
            mNode, OMX_IndexParamVideoBitrate,
+6 −0
Original line number Diff line number Diff line
@@ -264,6 +264,8 @@ status_t OMXNodeInstance::useBuffer(
        return UNKNOWN_ERROR;
    }

    CHECK_EQ(header->pAppPrivate, buffer_meta);

    *buffer = header;

    addActiveBuffer(portIndex, *buffer);
@@ -294,6 +296,8 @@ status_t OMXNodeInstance::allocateBuffer(
        return UNKNOWN_ERROR;
    }

    CHECK_EQ(header->pAppPrivate, buffer_meta);

    *buffer = header;
    *buffer_data = header->pBuffer;

@@ -325,6 +329,8 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
        return UNKNOWN_ERROR;
    }

    CHECK_EQ(header->pAppPrivate, buffer_meta);

    *buffer = header;

    addActiveBuffer(portIndex, *buffer);