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

Commit bf37f336 authored by Andreas Huber's avatar Andreas Huber
Browse files

Recording/Export to .mp4/h.263 somewhat works on TI hardware.

parent fd6444c5
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -114,8 +114,8 @@ int main(int argc, char **argv) {
    assert(success);

    sp<MetaData> enc_meta = new MetaData;
    // enc_meta->setCString(kKeyMIMEType, "video/3gpp");
    enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
    enc_meta->setCString(kKeyMIMEType, "video/3gpp");
    // enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
    enc_meta->setInt32(kKeyWidth, width);
    enc_meta->setInt32(kKeyHeight, height);

@@ -129,7 +129,8 @@ int main(int argc, char **argv) {
    MPEG4Writer writer("/sdcard/output.mp4");
    writer.addSource(enc_meta, encoder);
    writer.start();
    sleep(120);
    sleep(20);
    printf("stopping now.\n");
    writer.stop();
#else
    encoder->start();
+4 −0
Original line number Diff line number Diff line
@@ -91,8 +91,10 @@ private:
    sp<IOMX> mOMX;
    IOMX::node_id mNode;
    char *mComponentName;
    char *mMIME;
    bool mIsMP3;
    bool mIsAVC;
    bool mIsEncoder;
    uint32_t mQuirks;

    MediaSource *mSource;
@@ -132,6 +134,7 @@ private:

    OMXDecoder(OMXClient *client, IOMX::node_id node,
               const char *mime, const char *codec,
               bool is_encoder,
               uint32_t quirks);

    void setPortStatus(OMX_U32 port_index, PortStatus status);
@@ -148,6 +151,7 @@ private:
            OMX_COLOR_FORMATTYPE colorFormat);

    void setVideoOutputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
    void setVideoInputFormat(const char *mime, OMX_U32 width, OMX_U32 height);
    void setup();
    void dumpPortDefinition(OMX_U32 port_index);

+6 −1
Original line number Diff line number Diff line
@@ -342,7 +342,12 @@ void MPEG4Writer::Track::threadEntry() {
                ++offset;
            }

            assert(offset + 3 < size);
            // assert(offset + 3 < size);
            if (offset + 3 >= size) {
                // XXX assume the entire first chunk of data is the codec specific
                // data.
                offset = size;
            }

            mCodecSpecificDataSize = offset;
            mCodecSpecificData = malloc(offset);
+112 −170
Original line number Diff line number Diff line
@@ -76,9 +76,12 @@ static const CodecInfo kEncoderInfo[] = {
    { "audio/3gpp", "OMX.PV.amrencnb" },
    { "audio/mp4a-latm", "OMX.PV.aacenc" },
    { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" },
    { "video/mp4v-es", "OMX.TI.Video.encoder" },
    { "video/mp4v-es", "OMX.PV.mpeg4enc" },
    { "video/3gpp", "OMX.qcom.video.encoder.h263" },
    { "video/3gpp", "OMX.TI.Video.encoder" },
    { "video/3gpp", "OMX.PV.h263enc" },
    { "video/avc", "OMX.TI.Video.encoder" },
    { "video/avc", "OMX.PV.avcenc" },
};

@@ -158,7 +161,8 @@ OMXDecoder *OMXDecoder::Create(
        quirks |= kMeasuresTimeInMilliseconds;
    }

    OMXDecoder *decoder = new OMXDecoder(client, node, mime, codec, quirks);
    OMXDecoder *decoder = new OMXDecoder(
            client, node, mime, codec, createEncoder, quirks);

    uint32_t type;
    const void *data;
@@ -211,13 +215,16 @@ OMXDecoder *OMXDecoder::Create(

OMXDecoder::OMXDecoder(OMXClient *client, IOMX::node_id node,
                       const char *mime, const char *codec,
                       bool is_encoder,
                       uint32_t quirks)
    : mClient(client),
      mOMX(mClient->interface()),
      mNode(node),
      mComponentName(strdup(codec)),
      mMIME(strdup(mime)),
      mIsMP3(!strcasecmp(mime, "audio/mpeg")),
      mIsAVC(!strcasecmp(mime, "video/avc")),
      mIsEncoder(is_encoder),
      mQuirks(quirks),
      mSource(NULL),
      mCodecSpecificDataIterator(mCodecSpecificData.begin()),
@@ -252,6 +259,9 @@ OMXDecoder::~OMXDecoder() {
    assert(err == OK);
    mNode = 0;

    free(mMIME);
    mMIME = NULL;

    free(mComponentName);
    mComponentName = NULL;
}
@@ -512,6 +522,27 @@ status_t OMXDecoder::setVideoPortFormatType(
        // The following assertion is violated by TI's video decoder.
        // assert(format.nIndex == index);

#if 1
        LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
             portIndex,
             index, format.eCompressionFormat, format.eColorFormat);
#endif

        if (!strcmp("OMX.TI.Video.encoder", mComponentName)) {
            if (portIndex == kPortIndexInput
                    && colorFormat == format.eColorFormat) {
                // eCompressionFormat does not seem right.
                found = true;
                break;
            }
            if (portIndex == kPortIndexOutput
                    && compressionFormat == format.eCompressionFormat) {
                // eColorFormat does not seem right.
                found = true;
                break;
            }
        }

        if (format.eCompressionFormat == compressionFormat
            && format.eColorFormat == colorFormat) {
            found = true;
@@ -525,6 +556,7 @@ status_t OMXDecoder::setVideoPortFormatType(
        return UNKNOWN_ERROR;
    }

    LOGI("found a match.");
    status_t err = mOMX->set_parameter(
            mNode, OMX_IndexParamVideoPortFormat,
            &format, sizeof(format));
@@ -532,103 +564,51 @@ status_t OMXDecoder::setVideoPortFormatType(
    return err;
}

#if 1
void OMXDecoder::setVideoOutputFormat(
void OMXDecoder::setVideoInputFormat(
        const char *mime, OMX_U32 width, OMX_U32 height) {
    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);

#if 1
    // Enabling this code appears to be the right thing(tm), but,...
    // the TI decoder then loses the ability to output YUV420 and only outputs
    // YCbYCr (16bit)
    if (!strcasecmp("video/avc", mime)) {
        OMX_PARAM_COMPONENTROLETYPE role;
        role.nSize = sizeof(role);
        role.nVersion.s.nVersionMajor = 1;
        role.nVersion.s.nVersionMinor = 1;
        strncpy((char *)role.cRole, "video_decoder.avc",
                OMX_MAX_STRINGNAME_SIZE - 1);
        role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';

        status_t err = mOMX->set_parameter(
                mNode, OMX_IndexParamStandardComponentRole,
                &role, sizeof(role));
        assert(err == OK);
    }
#endif
    LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);

    OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
    if (!strcasecmp("video/avc", mime)) {
    if (!strcasecmp("video/avc", mMIME)) {
        compressionFormat = OMX_VIDEO_CodingAVC;
    } else if (!strcasecmp("video/mp4v-es", mime)) {
    } else if (!strcasecmp("video/mp4v-es", mMIME)) {
        compressionFormat = OMX_VIDEO_CodingMPEG4;
    } else if (!strcasecmp("video/3gpp", mime)) {
    } else if (!strcasecmp("video/3gpp", mMIME)) {
        compressionFormat = OMX_VIDEO_CodingH263;
    } else {
        LOGE("Not a supported video mime type: %s", mime);
        assert(!"Should not be here. Not a supported video mime type.");
    }

    setVideoPortFormatType(
            kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);
    OMX_COLOR_FORMATTYPE colorFormat =
        0 ? OMX_COLOR_FormatYCbYCr : OMX_COLOR_FormatCbYCrY;

#if 1
    {
        OMX_VIDEO_PARAM_PORTFORMATTYPE format;
        format.nSize = sizeof(format);
        format.nVersion.s.nVersionMajor = 1;
        format.nVersion.s.nVersionMinor = 1;
        format.nPortIndex = kPortIndexOutput;
        format.nIndex = 0;

        status_t err = mOMX->get_parameter(
                mNode, OMX_IndexParamVideoPortFormat,
                &format, sizeof(format));
        assert(err == OK);

        assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);

        static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;

        assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
               || format.eColorFormat == OMX_COLOR_FormatCbYCrY
               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
    setVideoPortFormatType(
            kPortIndexInput, OMX_VIDEO_CodingUnused,
            colorFormat);

        err = mOMX->set_parameter(
                mNode, OMX_IndexParamVideoPortFormat,
                &format, sizeof(format));
        assert(err == OK);
    }
#endif
    setVideoPortFormatType(
            kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);

    OMX_PARAM_PORTDEFINITIONTYPE def;
    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;

    bool is_encoder = strstr(mComponentName, ".encoder.") != NULL;  // XXX

    def.nSize = sizeof(def);
    def.nVersion.s.nVersionMajor = 1;
    def.nVersion.s.nVersionMinor = 1;
    def.nPortIndex = is_encoder ? kPortIndexOutput : kPortIndexInput;
    def.nPortIndex = kPortIndexOutput;

    status_t err = mOMX->get_parameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));

    assert(err == NO_ERROR);

#if 1
    // XXX Need a (much) better heuristic to compute input buffer sizes.
    const size_t X = 64 * 1024;
    if (def.nBufferSize < X) {
        def.nBufferSize = X;
    }
#endif

    assert(def.eDomain == OMX_PortDomainVideo);

    video_def->nFrameWidth = width;
    video_def->nFrameHeight = height;

    video_def->eCompressionFormat = compressionFormat;
    video_def->eColorFormat = OMX_COLOR_FormatUnused;

    err = mOMX->set_parameter(
@@ -640,96 +620,37 @@ void OMXDecoder::setVideoOutputFormat(
    def.nSize = sizeof(def);
    def.nVersion.s.nVersionMajor = 1;
    def.nVersion.s.nVersionMinor = 1;
    def.nPortIndex = is_encoder ? kPortIndexInput : kPortIndexOutput;
    def.nPortIndex = kPortIndexInput;

    err = mOMX->get_parameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    assert(err == NO_ERROR);

    assert(def.eDomain == OMX_PortDomainVideo);
    def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
    LOGI("setting nBufferSize = %ld", def.nBufferSize);

#if 0
    def.nBufferSize =
        (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2;  // YUV420
#endif
    assert(def.eDomain == OMX_PortDomainVideo);

    video_def->nFrameWidth = width;
    video_def->nFrameHeight = height;
    video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
    video_def->eColorFormat = colorFormat;

    err = mOMX->set_parameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    assert(err == NO_ERROR);
}

#else
static void hexdump(const void *_data, size_t size) {
    char line[256];
    char tmp[16];

    const uint8_t *data = (const uint8_t *)_data;
    size_t offset = 0;
    while (offset < size) {
        sprintf(line, "0x%04x  ", offset);

        size_t n = size - offset;
        if (n > 16) {
            n = 16;
        }

        for (size_t i = 0; i < 16; ++i) {
            if (i == 8) {
                strcat(line, " ");
            }

            if (offset + i < size) {
                sprintf(tmp, "%02x ", data[offset + i]);
                strcat(line, tmp);
            } else {
                strcat(line, "   ");
            }
        }

        strcat(line, " ");

        for (size_t i = 0; i < n; ++i) {
            if (isprint(data[offset + i])) {
                sprintf(tmp, "%c", data[offset + i]);
                strcat(line, tmp);
            } else {
                strcat(line, ".");
            }
        }

        LOGI(line);

        offset += 16;
    }
}

static void DumpPortDefinitionType(const void *_param) {
    OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)_param;

    LOGI("nPortIndex=%ld eDir=%s nBufferCountActual=%ld nBufferCountMin=%ld nBufferSize=%ld", param->nPortIndex, param->eDir == OMX_DirInput ? "input" : "output",
        param->nBufferCountActual, param->nBufferCountMin, param->nBufferSize);

    if (param->eDomain == OMX_PortDomainVideo) {
        OMX_VIDEO_PORTDEFINITIONTYPE *video = &param->format.video;
        LOGI("nFrameWidth=%ld nFrameHeight=%ld nStride=%ld nSliceHeight=%ld nBitrate=%ld xFramerate=%ld eCompressionFormat=%d eColorFormat=%d",
            video->nFrameWidth, video->nFrameHeight, video->nStride, video->nSliceHeight, video->nBitrate, video->xFramerate, video->eCompressionFormat, video->eColorFormat);
    } else {
        hexdump(param, param->nSize);
    }
}

void OMXDecoder::setVideoOutputFormat(
        const char *mime, OMX_U32 width, OMX_U32 height) {
    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);

#if 0
#if 1
    // Enabling this code appears to be the right thing(tm), but,...
    // the decoder then loses the ability to output YUV420 and only outputs
    // the TI decoder then loses the ability to output YUV420 and only outputs
    // YCbYCr (16bit)
    {
    if (!strcmp("OMX.TI.Video.Decoder", mComponentName)
        && !strcasecmp("video/avc", mime)) {
        OMX_PARAM_COMPONENTROLETYPE role;
        role.nSize = sizeof(role);
        role.nVersion.s.nVersionMajor = 1;
@@ -745,8 +666,20 @@ void OMXDecoder::setVideoOutputFormat(
    }
#endif

    OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
    if (!strcasecmp("video/avc", mime)) {
        compressionFormat = OMX_VIDEO_CodingAVC;
    } else if (!strcasecmp("video/mp4v-es", mime)) {
        compressionFormat = OMX_VIDEO_CodingMPEG4;
    } else if (!strcasecmp("video/3gpp", mime)) {
        compressionFormat = OMX_VIDEO_CodingH263;
    } else {
        LOGE("Not a supported video mime type: %s", mime);
        assert(!"Should not be here. Not a supported video mime type.");
    }

    setVideoPortFormatType(
            kPortIndexInput, OMX_VIDEO_CodingAVC, OMX_COLOR_FormatUnused);
            kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused);

#if 1
    {
@@ -762,13 +695,14 @@ void OMXDecoder::setVideoOutputFormat(
                &format, sizeof(format));
        assert(err == OK);

        LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoPortFormat");
        hexdump(&format, format.nSize);

        assert(format.eCompressionFormat == OMX_VIDEO_CodingUnused);

        static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;

        assert(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
               || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
               || format.eColorFormat == OMX_COLOR_FormatCbYCrY);
               || format.eColorFormat == OMX_COLOR_FormatCbYCrY
               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);

        err = mOMX->set_parameter(
                mNode, OMX_IndexParamVideoPortFormat,
@@ -777,60 +711,64 @@ void OMXDecoder::setVideoOutputFormat(
    }
#endif

    OMX_PORT_PARAM_TYPE ptype;
    ptype.nSize = sizeof(ptype);
    ptype.nVersion.s.nVersionMajor = 1;
    ptype.nVersion.s.nVersionMinor = 1;

    status_t err = mOMX->get_parameter(
            mNode, OMX_IndexParamVideoInit, &ptype, sizeof(ptype));
    assert(err == OK);

    LOGI("XXX MyOMX_GetParameter OMX_IndexParamVideoInit");
    hexdump(&ptype, ptype.nSize);

    OMX_PARAM_PORTDEFINITIONTYPE def;
    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;

    def.nSize = sizeof(def);
    def.nVersion.s.nVersionMajor = 1;
    def.nVersion.s.nVersionMinor = 1;
    def.nPortIndex = kPortIndexInput;

    err = mOMX->get_parameter(
    status_t err = mOMX->get_parameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    assert(err == OK);

    LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
    DumpPortDefinitionType(&def);
    assert(err == NO_ERROR);

#if 1
    // XXX Need a (much) better heuristic to compute input buffer sizes.
    const size_t X = 64 * 1024;
    if (def.nBufferSize < X) {
        def.nBufferSize = X;
    }
#endif

    assert(def.eDomain == OMX_PortDomainVideo);

    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
    video_def->nFrameWidth = width;
    video_def->nFrameHeight = height;

    video_def->eColorFormat = OMX_COLOR_FormatUnused;

    err = mOMX->set_parameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    assert(err == OK);
    assert(err == NO_ERROR);

    ////////////////////////////////////////////////////////////////////////////

    def.nSize = sizeof(def);
    def.nVersion.s.nVersionMajor = 1;
    def.nVersion.s.nVersionMinor = 1;
    def.nPortIndex = kPortIndexOutput;

    err = mOMX->get_parameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    assert(err == OK);
    assert(err == NO_ERROR);

    assert(def.eDomain == OMX_PortDomainVideo);

    LOGI("XXX MyOMX_GetParameter OMX_IndexParamPortDefinition");
    DumpPortDefinitionType(&def);
#if 0
    def.nBufferSize =
        (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2;  // YUV420
#endif

    video_def->nFrameWidth = width;
    video_def->nFrameHeight = height;

    err = mOMX->set_parameter(
            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
    assert(err == OK);
    assert(err == NO_ERROR);
}

#endif

void OMXDecoder::setup() {
    const sp<MetaData> &meta = mSource->getFormat();

@@ -848,8 +786,12 @@ void OMXDecoder::setup() {
        success = success && meta->findInt32(kKeyHeight, &height);
        assert(success);

        if (mIsEncoder) {
            setVideoInputFormat(mime, width, height);
        } else {
            setVideoOutputFormat(mime, width, height);
        }
    }

    // dumpPortDefinition(0);
    // dumpPortDefinition(1);