/* * Copyright (C) 2014 The CyanogenMod 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 "FFMPEGSoftCodec" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { enum MetaKeyType{ INT32, INT64, STRING, DATA, CSD }; struct MetaKeyEntry{ int MetaKey; const char* MsgKey; MetaKeyType KeyType; }; static const MetaKeyEntry MetaKeyTable[] { {kKeyAACAOT , "aac-profile" , INT32}, {kKeyArbitraryMode , "use-arbitrary-mode" , INT32}, {kKeyBitRate , "bitrate" , INT32}, {kKeyBitsPerSample , "bit-width" , INT32}, {kKeyBlockAlign , "block-align" , INT32}, {kKeyChannelCount , "channel-count" , INT32}, {kKeyCodecId , "codec-id" , INT32}, {kKeyCodedSampleBits , "coded-sample-bits" , INT32}, {kKeyRawCodecSpecificData , "raw-codec-specific-data", CSD}, {kKeyRVVersion , "rv-version" , INT32}, {kKeySampleFormat , "sample-format" , INT32}, {kKeySampleRate , "sample-rate" , INT32}, {kKeyWMAVersion , "wma-version" , INT32}, // int32_t {kKeyWMVVersion , "wmv-version" , INT32}, {kKeyPCMFormat , "pcm-format" , INT32}, }; const char* FFMPEGSoftCodec::getMsgKey(int key) { static const size_t numMetaKeys = sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]); size_t i; for (i = 0; i < numMetaKeys; ++i) { if (key == MetaKeyTable[i].MetaKey) { return MetaKeyTable[i].MsgKey; } } return "unknown"; } void FFMPEGSoftCodec::convertMetaDataToMessageFF( const sp &meta, sp *format) { const char * str_val; int32_t int32_val; int64_t int64_val; uint32_t data_type; const void * data; size_t size; static const size_t numMetaKeys = sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]); size_t i; for (i = 0; i < numMetaKeys; ++i) { if (MetaKeyTable[i].KeyType == INT32 && meta->findInt32(MetaKeyTable[i].MetaKey, &int32_val)) { ALOGV("found metakey %s of type int32", MetaKeyTable[i].MsgKey); format->get()->setInt32(MetaKeyTable[i].MsgKey, int32_val); } else if (MetaKeyTable[i].KeyType == INT64 && meta->findInt64(MetaKeyTable[i].MetaKey, &int64_val)) { ALOGV("found metakey %s of type int64", MetaKeyTable[i].MsgKey); format->get()->setInt64(MetaKeyTable[i].MsgKey, int64_val); } else if (MetaKeyTable[i].KeyType == STRING && meta->findCString(MetaKeyTable[i].MetaKey, &str_val)) { ALOGV("found metakey %s of type string", MetaKeyTable[i].MsgKey); format->get()->setString(MetaKeyTable[i].MsgKey, str_val); } else if ( (MetaKeyTable[i].KeyType == DATA || MetaKeyTable[i].KeyType == CSD) && meta->findData(MetaKeyTable[i].MetaKey, &data_type, &data, &size)) { ALOGV("found metakey %s of type data", MetaKeyTable[i].MsgKey); if (MetaKeyTable[i].KeyType == CSD) { const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { sp buffer = new ABuffer(size); memcpy(buffer->data(), data, size); buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); format->get()->setBuffer("csd-0", buffer); } else { const uint8_t *ptr = (const uint8_t *)data; CHECK(size >= 8); int seqLength = 0, picLength = 0; for (size_t i = 4; i < (size - 4); i++) { if ((*(ptr + i) == 0) && (*(ptr + i + 1) == 0) && (*(ptr + i + 2) == 0) && (*(ptr + i + 3) == 1)) seqLength = i; } sp buffer = new ABuffer(seqLength); memcpy(buffer->data(), data, seqLength); buffer->meta()->setInt32("csd", true); buffer->meta()->setInt64("timeUs", 0); format->get()->setBuffer("csd-0", buffer); picLength=size-seqLength; sp buffer1 = new ABuffer(picLength); memcpy(buffer1->data(), (const uint8_t *)data + seqLength, picLength); buffer1->meta()->setInt32("csd", true); buffer1->meta()->setInt64("timeUs", 0); format->get()->setBuffer("csd-1", buffer1); } } else { sp buffer = new ABuffer(size); memcpy(buffer->data(), data, size); format->get()->setBuffer(MetaKeyTable[i].MsgKey, buffer); } } } } void FFMPEGSoftCodec::convertMessageToMetaDataFF( const sp &msg, sp &meta) { AString str_val; int32_t int32_val; int64_t int64_val; static const size_t numMetaKeys = sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]); size_t i; for (i = 0; i < numMetaKeys; ++i) { if (MetaKeyTable[i].KeyType == INT32 && msg->findInt32(MetaKeyTable[i].MsgKey, &int32_val)) { ALOGV("found metakey %s of type int32", MetaKeyTable[i].MsgKey); meta->setInt32(MetaKeyTable[i].MetaKey, int32_val); } else if (MetaKeyTable[i].KeyType == INT64 && msg->findInt64(MetaKeyTable[i].MsgKey, &int64_val)) { ALOGV("found metakey %s of type int64", MetaKeyTable[i].MsgKey); meta->setInt64(MetaKeyTable[i].MetaKey, int64_val); } else if (MetaKeyTable[i].KeyType == STRING && msg->findString(MetaKeyTable[i].MsgKey, &str_val)) { ALOGV("found metakey %s of type string", MetaKeyTable[i].MsgKey); meta->setCString(MetaKeyTable[i].MetaKey, str_val.c_str()); } } } template static void InitOMXParams(T *params) { params->nSize = sizeof(T); params->nVersion.s.nVersionMajor = 1; params->nVersion.s.nVersionMinor = 0; params->nVersion.s.nRevision = 0; params->nVersion.s.nStep = 0; } void FFMPEGSoftCodec::overrideComponentName( uint32_t /*quirks*/, const sp &msg, AString* componentName, AString* mime, int32_t isEncoder) { int32_t wmvVersion = 0; if (!strncasecmp(mime->c_str(), MEDIA_MIMETYPE_VIDEO_WMV, strlen(MEDIA_MIMETYPE_VIDEO_WMV)) && msg->findInt32(getMsgKey(kKeyWMVVersion), &wmvVersion)) { ALOGD("Found WMV version key %d", wmvVersion); if (wmvVersion == 1) { ALOGD("Use FFMPEG for unsupported WMV track"); componentName->setTo("OMX.ffmpeg.wmv.decoder"); } } int32_t encodeOptions = 0; if (!isEncoder && !strncasecmp(mime->c_str(), MEDIA_MIMETYPE_AUDIO_WMA, strlen(MEDIA_MIMETYPE_AUDIO_WMA)) && !msg->findInt32(getMsgKey(kKeyWMAEncodeOpt), &encodeOptions)) { ALOGD("Use FFMPEG for unsupported WMA track"); componentName->setTo("OMX.ffmpeg.wma.decoder"); } // Google's decoder doesn't support MAIN profile int32_t aacProfile = 0; if (!isEncoder && !strncasecmp(mime->c_str(), MEDIA_MIMETYPE_AUDIO_AAC, strlen(MEDIA_MIMETYPE_AUDIO_AAC)) && msg->findInt32(getMsgKey(kKeyAACAOT), &aacProfile)) { if (aacProfile == OMX_AUDIO_AACObjectMain) { ALOGD("Use FFMPEG for AAC MAIN profile"); componentName->setTo("OMX.ffmpeg.aac.decoder"); } } } status_t FFMPEGSoftCodec::setVideoFormat( const sp &msg, const char* mime, sp OMXhandle, IOMX::node_id nodeID, bool isEncoder, OMX_VIDEO_CODINGTYPE *compressionFormat) { status_t err = OK; if (isEncoder) { ALOGE("Encoding not supported"); err = BAD_VALUE; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)) { err = setWMVFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setWMVFormat() failed (err = %d)", err); } else { *compressionFormat = OMX_VIDEO_CodingWMV; } } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_RV, mime)) { err = setRVFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setRVFormat() failed (err = %d)", err); } else { *compressionFormat = OMX_VIDEO_CodingRV; } } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VC1, mime)) { *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingVC1; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_FLV1, mime)) { *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingFLV1; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)) { *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingDIVX; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingHEVC; } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_FFMPEG, mime)) { ALOGV("Setting the OMX_VIDEO_PARAM_FFMPEGTYPE params"); err = setFFmpegVideoFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setFFmpegVideoFormat() failed (err = %d)", err); } else { *compressionFormat = OMX_VIDEO_CodingAutoDetect; } } else { err = BAD_TYPE; } return err; } status_t FFMPEGSoftCodec::getVideoPortFormat(OMX_U32 portIndex, int coding, sp ¬ify, sp OMXHandle, IOMX::node_id nodeId) { status_t err = BAD_TYPE; switch (coding) { case OMX_VIDEO_CodingWMV: { OMX_VIDEO_PARAM_WMVTYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, OMX_IndexParamVideoWmv, ¶ms, sizeof(params)); if (err != OK) { return err; } int32_t version; if (params.eFormat == OMX_VIDEO_WMVFormat7) { version = kTypeWMVVer_7; } else if (params.eFormat == OMX_VIDEO_WMVFormat8) { version = kTypeWMVVer_8; } else { version = kTypeWMVVer_9; } notify->setString("mime", MEDIA_MIMETYPE_VIDEO_WMV); notify->setInt32("wmv-version", version); break; } case OMX_VIDEO_CodingAutoDetect: { OMX_VIDEO_PARAM_FFMPEGTYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_VIDEO_FFMPEG); notify->setInt32("codec-id", params.eCodecId); break; } case OMX_VIDEO_CodingRV: { OMX_VIDEO_PARAM_RVTYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, (OMX_INDEXTYPE)OMX_IndexParamVideoRv, ¶ms, sizeof(params)); if (err != OK) { return err; } int32_t version; if (params.eFormat == OMX_VIDEO_RVFormatG2) { version = kTypeRVVer_G2; } else if (params.eFormat == OMX_VIDEO_RVFormat8) { version = kTypeRVVer_8; } else { version = kTypeRVVer_9; } notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RV); break; } } return err; } status_t FFMPEGSoftCodec::getAudioPortFormat(OMX_U32 portIndex, int coding, sp ¬ify, sp OMXHandle, IOMX::node_id nodeId) { status_t err = BAD_TYPE; switch (coding) { case OMX_AUDIO_CodingRA: { OMX_AUDIO_PARAM_RATYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, OMX_IndexParamAudioRa, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RA); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSamplingRate); break; } case OMX_AUDIO_CodingMP2: { OMX_AUDIO_PARAM_MP2TYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSampleRate); break; } case OMX_AUDIO_CodingWMA: { OMX_AUDIO_PARAM_WMATYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, OMX_IndexParamAudioWma, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_AUDIO_WMA); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSamplingRate); break; } case OMX_AUDIO_CodingAPE: { OMX_AUDIO_PARAM_APETYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_AUDIO_APE); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSamplingRate); notify->setInt32("bit-width", params.nBitsPerSample); break; } case OMX_AUDIO_CodingFLAC: { OMX_AUDIO_PARAM_FLACTYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioFlac, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_AUDIO_FLAC); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSampleRate); notify->setInt32("bit-width", params.nCompressionLevel); // piggyback break; } case OMX_AUDIO_CodingDTS: { OMX_AUDIO_PARAM_DTSTYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_AUDIO_DTS); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSamplingRate); break; } case OMX_AUDIO_CodingAC3: { OMX_AUDIO_PARAM_ANDROID_AC3TYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_AUDIO_AC3); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSampleRate); break; } case OMX_AUDIO_CodingAutoDetect: { OMX_AUDIO_PARAM_FFMPEGTYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; err = OMXHandle->getParameter( nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, ¶ms, sizeof(params)); if (err != OK) { return err; } notify->setString("mime", MEDIA_MIMETYPE_AUDIO_FFMPEG); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSampleRate); break; } } return err; } status_t FFMPEGSoftCodec::setAudioFormat( const sp &msg, const char* mime, sp OMXhandle, IOMX::node_id nodeID) { ALOGV("setAudioFormat called"); status_t err = OK; ALOGV("setAudioFormat: %s", msg->debugString(0).c_str()); if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_WMA, mime)) { err = setWMAFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setWMAFormat() failed (err = %d)", err); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_VORBIS, mime)) { err = setVORBISFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setVORBISFormat() failed (err = %d)", err); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RA, mime)) { err = setRAFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setRAFormat() failed (err = %d)", err); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_FLAC, mime)) { err = setFLACFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setFLACFormat() failed (err = %d)", err); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, mime)) { err = setMP2Format(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setMP2Format() failed (err = %d)", err); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mime)) { err = setAC3Format(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setAC3Format() failed (err = %d)", err); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_APE, mime)) { err = setAPEFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setAPEFormat() failed (err = %d)", err); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_DTS, mime)) { err = setDTSFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setDTSFormat() failed (err = %d)", err); } } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_FFMPEG, mime)) { err = setFFmpegAudioFormat(msg, OMXhandle, nodeID); if (err != OK) { ALOGE("setFFmpegAudioFormat() failed (err = %d)", err); } } return err; } status_t FFMPEGSoftCodec::setSupportedRole( const sp &omx, IOMX::node_id node, bool isEncoder, const char *mime) { ALOGV("setSupportedRole Called %s", mime); struct MimeToRole { const char *mime; const char *decoderRole; const char *encoderRole; }; static const MimeToRole kFFMPEGMimeToRole[] = { { MEDIA_MIMETYPE_AUDIO_AAC, "audio_decoder.aac", NULL }, { MEDIA_MIMETYPE_AUDIO_MPEG, "audio_decoder.mp3", NULL }, { MEDIA_MIMETYPE_AUDIO_VORBIS, "audio_decoder.vorbis", NULL }, { MEDIA_MIMETYPE_AUDIO_WMA, "audio_decoder.wma", NULL }, { MEDIA_MIMETYPE_AUDIO_RA, "audio_decoder.ra" , NULL }, { MEDIA_MIMETYPE_AUDIO_FLAC, "audio_decoder.flac", NULL }, { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, "audio_decoder.mp2", NULL }, { MEDIA_MIMETYPE_AUDIO_AC3, "audio_decoder.ac3", NULL }, { MEDIA_MIMETYPE_AUDIO_APE, "audio_decoder.ape", NULL }, { MEDIA_MIMETYPE_AUDIO_DTS, "audio_decoder.dts", NULL }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "video_decoder.mpeg2", NULL }, { MEDIA_MIMETYPE_VIDEO_DIVX, "video_decoder.divx", NULL }, { MEDIA_MIMETYPE_VIDEO_DIVX4, "video_decoder.divx", NULL }, { MEDIA_MIMETYPE_VIDEO_DIVX311, "video_decoder.divx", NULL }, { MEDIA_MIMETYPE_VIDEO_WMV, "video_decoder.wmv", NULL }, { MEDIA_MIMETYPE_VIDEO_VC1, "video_decoder.vc1", NULL }, { MEDIA_MIMETYPE_VIDEO_RV, "video_decoder.rv", NULL }, { MEDIA_MIMETYPE_VIDEO_FLV1, "video_decoder.flv1", NULL }, { MEDIA_MIMETYPE_VIDEO_HEVC, "video_decoder.hevc", NULL }, { MEDIA_MIMETYPE_AUDIO_FFMPEG, "audio_decoder.trial", NULL }, { MEDIA_MIMETYPE_VIDEO_FFMPEG, "video_decoder.trial", NULL }, }; static const size_t kNumMimeToRole = sizeof(kFFMPEGMimeToRole) / sizeof(kFFMPEGMimeToRole[0]); size_t i; for (i = 0; i < kNumMimeToRole; ++i) { if (!strcasecmp(mime, kFFMPEGMimeToRole[i].mime)) { break; } } if (i == kNumMimeToRole) { return ERROR_UNSUPPORTED; } const char *role = isEncoder ? kFFMPEGMimeToRole[i].encoderRole : kFFMPEGMimeToRole[i].decoderRole; if (role != NULL) { OMX_PARAM_COMPONENTROLETYPE roleParams; InitOMXParams(&roleParams); strncpy((char *)roleParams.cRole, role, OMX_MAX_STRINGNAME_SIZE - 1); roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0'; status_t err = omx->setParameter( node, OMX_IndexParamStandardComponentRole, &roleParams, sizeof(roleParams)); if (err != OK) { ALOGW("Failed to set standard component role '%s'.", role); return err; } } return OK; } //video status_t FFMPEGSoftCodec::setWMVFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t version = -1; OMX_VIDEO_PARAM_WMVTYPE paramWMV; if (!msg->findInt32(getMsgKey(kKeyWMVVersion), &version)) { ALOGE("WMV version not detected"); } InitOMXParams(¶mWMV); paramWMV.nPortIndex = kPortIndexInput; status_t err = OMXhandle->getParameter( nodeID, OMX_IndexParamVideoWmv, ¶mWMV, sizeof(paramWMV)); if (err != OK) { return err; } if (version == kTypeWMVVer_7) { paramWMV.eFormat = OMX_VIDEO_WMVFormat7; } else if (version == kTypeWMVVer_8) { paramWMV.eFormat = OMX_VIDEO_WMVFormat8; } else if (version == kTypeWMVVer_9) { paramWMV.eFormat = OMX_VIDEO_WMVFormat9; } err = OMXhandle->setParameter( nodeID, OMX_IndexParamVideoWmv, ¶mWMV, sizeof(paramWMV)); return err; } status_t FFMPEGSoftCodec::setRVFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t version = kTypeRVVer_G2; OMX_VIDEO_PARAM_RVTYPE paramRV; if (!msg->findInt32(getMsgKey(kKeyRVVersion), &version)) { ALOGE("RV version not detected"); } InitOMXParams(¶mRV); paramRV.nPortIndex = kPortIndexInput; status_t err = OMXhandle->getParameter( nodeID, OMX_IndexParamVideoRv, ¶mRV, sizeof(paramRV)); if (err != OK) return err; if (version == kTypeRVVer_G2) { paramRV.eFormat = OMX_VIDEO_RVFormatG2; } else if (version == kTypeRVVer_8) { paramRV.eFormat = OMX_VIDEO_RVFormat8; } else if (version == kTypeRVVer_9) { paramRV.eFormat = OMX_VIDEO_RVFormat9; } err = OMXhandle->setParameter( nodeID, OMX_IndexParamVideoRv, ¶mRV, sizeof(paramRV)); return err; } status_t FFMPEGSoftCodec::setFFmpegVideoFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t codec_id = 0; int32_t width = 0; int32_t height = 0; OMX_VIDEO_PARAM_FFMPEGTYPE param; ALOGD("setFFmpegVideoFormat"); if (msg->findInt32(getMsgKey(kKeyWidth), &width)) { ALOGE("No video width specified"); } if (msg->findInt32(getMsgKey(kKeyHeight), &height)) { ALOGE("No video height specified"); } if (!msg->findInt32(getMsgKey(kKeyCodecId), &codec_id)) { ALOGE("No codec id sent for FFMPEG catch-all codec!"); } InitOMXParams(¶m); param.nPortIndex = kPortIndexInput; status_t err = OMXhandle->getParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, ¶m, sizeof(param)); if (err != OK) return err; param.eCodecId = codec_id; param.nWidth = width; param.nHeight = height; err = OMXhandle->setParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, ¶m, sizeof(param)); return err; } //audio status_t FFMPEGSoftCodec::setRawAudioFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t numChannels = 0; int32_t sampleRate = 0; int32_t bitsPerSample = 16; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); if (!msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample)) { ALOGD("No PCM format specified, using 16 bit"); } OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); def.nPortIndex = kPortIndexOutput; status_t err = OMXhandle->getParameter( nodeID, OMX_IndexParamPortDefinition, &def, sizeof(def)); if (err != OK) { return err; } def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; err = OMXhandle->setParameter( nodeID, OMX_IndexParamPortDefinition, &def, sizeof(def)); if (err != OK) { return err; } OMX_AUDIO_PARAM_PCMMODETYPE pcmParams; InitOMXParams(&pcmParams); pcmParams.nPortIndex = kPortIndexOutput; err = OMXhandle->getParameter( nodeID, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); if (err != OK) { return err; } pcmParams.nChannels = numChannels; pcmParams.eNumData = OMX_NumericalDataSigned; pcmParams.bInterleaved = OMX_TRUE; pcmParams.nBitPerSample = bitsPerSample; pcmParams.nSamplingRate = sampleRate; pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear; if (getOMXChannelMapping(numChannels, pcmParams.eChannelMapping) != OK) { return OMX_ErrorNone; } return OMXhandle->setParameter( nodeID, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); } status_t FFMPEGSoftCodec::setWMAFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t version = 0; int32_t numChannels = 0; int32_t bitRate = 0; int32_t sampleRate = 0; int32_t blockAlign = 0; int32_t bitsPerSample = 0; OMX_AUDIO_PARAM_WMATYPE paramWMA; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); CHECK(msg->findInt32(getMsgKey(kKeyBitRate), &bitRate)); if (!msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign)) { // we should be last on the codec list, but another sniffer may // have handled it and there is no hardware codec. if (!msg->findInt32(getMsgKey(kKeyWMABlockAlign), &blockAlign)) { return ERROR_UNSUPPORTED; } } // mm-parser may want a different bit depth if (msg->findInt32(getMsgKey(kKeyWMABitspersample), &bitsPerSample)) { msg->setInt32("bit-width", bitsPerSample); } ALOGV("Channels: %d, SampleRate: %d, BitRate: %d, blockAlign: %d", numChannels, sampleRate, bitRate, blockAlign); CHECK(msg->findInt32(getMsgKey(kKeyWMAVersion), &version)); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶mWMA); paramWMA.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA)); if (err != OK) return err; paramWMA.nChannels = numChannels; paramWMA.nSamplingRate = sampleRate; paramWMA.nBitRate = bitRate; paramWMA.nBlockAlign = blockAlign; // http://msdn.microsoft.com/en-us/library/ff819498(v=vs.85).aspx if (version == kTypeWMA) { paramWMA.eFormat = OMX_AUDIO_WMAFormat7; } else if (version == kTypeWMAPro) { paramWMA.eFormat = OMX_AUDIO_WMAFormat8; } else if (version == kTypeWMALossLess) { paramWMA.eFormat = OMX_AUDIO_WMAFormat9; } return OMXhandle->setParameter( nodeID, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA)); } status_t FFMPEGSoftCodec::setVORBISFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t numChannels = 0; int32_t sampleRate = 0; OMX_AUDIO_PARAM_VORBISTYPE param; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); ALOGV("Channels: %d, SampleRate: %d", numChannels, sampleRate); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶m); param.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, OMX_IndexParamAudioVorbis, ¶m, sizeof(param)); if (err != OK) return err; param.nChannels = numChannels; param.nSampleRate = sampleRate; return OMXhandle->setParameter( nodeID, OMX_IndexParamAudioVorbis, ¶m, sizeof(param)); } status_t FFMPEGSoftCodec::setRAFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t numChannels = 0; int32_t bitRate = 0; int32_t sampleRate = 0; int32_t blockAlign = 0; OMX_AUDIO_PARAM_RATYPE paramRA; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); msg->findInt32(getMsgKey(kKeyBitRate), &bitRate); CHECK(msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign)); ALOGV("Channels: %d, SampleRate: %d, BitRate: %d, blockAlign: %d", numChannels, sampleRate, bitRate, blockAlign); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶mRA); paramRA.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, OMX_IndexParamAudioRa, ¶mRA, sizeof(paramRA)); if (err != OK) return err; paramRA.eFormat = OMX_AUDIO_RAFormatUnused; // FIXME, cook only??? paramRA.nChannels = numChannels; paramRA.nSamplingRate = sampleRate; // FIXME, HACK!!!, I use the nNumRegions parameter pass blockAlign!!! // the cook audio codec need blockAlign! paramRA.nNumRegions = blockAlign; return OMXhandle->setParameter( nodeID, OMX_IndexParamAudioRa, ¶mRA, sizeof(paramRA)); } status_t FFMPEGSoftCodec::setFLACFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t numChannels = 0; int32_t sampleRate = 0; int32_t bitsPerSample = 16; OMX_AUDIO_PARAM_FLACTYPE param; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); CHECK(msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample)); ALOGV("Channels: %d, SampleRate: %d BitsPerSample: %d", numChannels, sampleRate, bitsPerSample); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶m); param.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, OMX_IndexParamAudioFlac, ¶m, sizeof(param)); if (err != OK) return err; param.nChannels = numChannels; param.nSampleRate = sampleRate; param.nCompressionLevel = bitsPerSample; // piggyback hax! return OMXhandle->setParameter( nodeID, OMX_IndexParamAudioFlac, ¶m, sizeof(param)); } status_t FFMPEGSoftCodec::setMP2Format( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t numChannels = 0; int32_t sampleRate = 0; OMX_AUDIO_PARAM_MP2TYPE param; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); ALOGV("Channels: %d, SampleRate: %d", numChannels, sampleRate); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶m); param.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, ¶m, sizeof(param)); if (err != OK) return err; param.nChannels = numChannels; param.nSampleRate = sampleRate; return OMXhandle->setParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, ¶m, sizeof(param)); } status_t FFMPEGSoftCodec::setAC3Format( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t numChannels = 0; int32_t sampleRate = 0; OMX_AUDIO_PARAM_ANDROID_AC3TYPE param; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); ALOGV("Channels: %d, SampleRate: %d", numChannels, sampleRate); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶m); param.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, ¶m, sizeof(param)); if (err != OK) return err; param.nChannels = numChannels; param.nSampleRate = sampleRate; return OMXhandle->setParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, ¶m, sizeof(param)); } status_t FFMPEGSoftCodec::setAPEFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t numChannels = 0; int32_t sampleRate = 0; int32_t bitsPerSample = 0; OMX_AUDIO_PARAM_APETYPE param; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); CHECK(msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample)); ALOGV("Channels:%d, SampleRate:%d, bitsPerSample:%d", numChannels, sampleRate, bitsPerSample); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶m); param.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, ¶m, sizeof(param)); if (err != OK) return err; param.nChannels = numChannels; param.nSamplingRate = sampleRate; param.nBitsPerSample = bitsPerSample; return OMXhandle->setParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, ¶m, sizeof(param)); } status_t FFMPEGSoftCodec::setDTSFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t numChannels = 0; int32_t sampleRate = 0; OMX_AUDIO_PARAM_DTSTYPE param; CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); ALOGV("Channels: %d, SampleRate: %d", numChannels, sampleRate); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶m); param.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, ¶m, sizeof(param)); if (err != OK) return err; param.nChannels = numChannels; param.nSamplingRate = sampleRate; return OMXhandle->setParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, ¶m, sizeof(param)); } status_t FFMPEGSoftCodec::setFFmpegAudioFormat( const sp &msg, sp OMXhandle, IOMX::node_id nodeID) { int32_t codec_id = 0; int32_t numChannels = 0; int32_t bitRate = 0; int32_t bitsPerSample = 16; int32_t sampleRate = 0; int32_t blockAlign = 0; int32_t sampleFormat = 0; int32_t codedSampleBits = 0; OMX_AUDIO_PARAM_FFMPEGTYPE param; ALOGD("setFFmpegAudioFormat"); CHECK(msg->findInt32(getMsgKey(kKeyCodecId), &codec_id)); CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); CHECK(msg->findInt32(getMsgKey(kKeySampleFormat), &sampleFormat)); msg->findInt32(getMsgKey(kKeyBitRate), &bitRate); msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample); msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate); msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign); msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample); msg->findInt32(getMsgKey(kKeyCodedSampleBits), &codedSampleBits); status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); if (err != OK) return err; InitOMXParams(¶m); param.nPortIndex = kPortIndexInput; err = OMXhandle->getParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, ¶m, sizeof(param)); if (err != OK) return err; param.eCodecId = codec_id; param.nChannels = numChannels; param.nBitRate = bitRate; param.nBitsPerSample = codedSampleBits; param.nSampleRate = sampleRate; param.nBlockAlign = blockAlign; param.eSampleFormat = sampleFormat; return OMXhandle->setParameter( nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, ¶m, sizeof(param)); } }