summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/stagefright/OMXCodec.h1
-rw-r--r--include/media/stagefright/openmax/OMX_Video.h1
-rw-r--r--media/libstagefright/ACodec.cpp2
-rw-r--r--media/libstagefright/Android.mk36
-rw-r--r--media/libstagefright/AwesomePlayer.cpp4
-rw-r--r--media/libstagefright/OMXCodec.cpp134
-rw-r--r--media/libstagefright/WAVExtractor.cpp2
-rw-r--r--media/libstagefright/codecs/aacdec/Android.mk29
-rw-r--r--media/libstagefright/codecs/aacdec/SoftAAC.cpp449
-rw-r--r--media/libstagefright/codecs/aacdec/SoftAAC.h76
-rw-r--r--media/libstagefright/codecs/amrnb/dec/Android.mk30
-rw-r--r--media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp434
-rw-r--r--media/libstagefright/codecs/amrnb/dec/SoftAMR.h87
-rw-r--r--media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp2
-rw-r--r--media/libstagefright/codecs/amrwb/src/mime_io.cpp2
-rw-r--r--media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.h4
-rw-r--r--media/libstagefright/codecs/avc/dec/Android.mk55
-rw-r--r--media/libstagefright/codecs/avc/dec/SoftAVC.cpp690
-rw-r--r--media/libstagefright/codecs/avc/dec/SoftAVC.h109
-rw-r--r--media/libstagefright/codecs/g711/dec/Android.mk19
-rw-r--r--media/libstagefright/codecs/g711/dec/SoftG711.cpp302
-rw-r--r--media/libstagefright/codecs/g711/dec/SoftG711.h63
-rw-r--r--media/libstagefright/codecs/m4v_h263/dec/Android.mk26
-rw-r--r--media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp528
-rw-r--r--media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h92
-rw-r--r--media/libstagefright/codecs/mp3dec/Android.mk23
-rw-r--r--media/libstagefright/codecs/mp3dec/SoftMP3.cpp325
-rw-r--r--media/libstagefright/codecs/mp3dec/SoftMP3.h80
-rw-r--r--media/libstagefright/codecs/on2/dec/Android.mk31
-rw-r--r--media/libstagefright/codecs/on2/dec/SoftVPX.cpp366
-rw-r--r--media/libstagefright/codecs/on2/dec/SoftVPX.h70
-rw-r--r--media/libstagefright/codecs/vorbis/dec/Android.mk27
-rw-r--r--media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp445
-rw-r--r--media/libstagefright/codecs/vorbis/dec/SoftVorbis.h78
-rw-r--r--media/libstagefright/include/SimpleSoftOMXComponent.h143
-rw-r--r--media/libstagefright/include/SoftOMXComponent.h171
-rw-r--r--media/libstagefright/omx/Android.mk50
-rw-r--r--media/libstagefright/omx/OMXMaster.cpp17
-rw-r--r--media/libstagefright/omx/OMXMaster.h1
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp1
-rw-r--r--media/libstagefright/omx/OMXPVCodecsPlugin.cpp101
-rw-r--r--media/libstagefright/omx/SimpleSoftOMXComponent.cpp640
-rw-r--r--media/libstagefright/omx/SoftOMXComponent.cpp326
-rw-r--r--media/libstagefright/omx/SoftOMXPlugin.cpp170
-rw-r--r--media/libstagefright/omx/SoftOMXPlugin.h (renamed from media/libstagefright/omx/OMXPVCodecsPlugin.h)17
-rw-r--r--media/libstagefright/omx/tests/OMXHarness.cpp21
46 files changed, 6062 insertions, 218 deletions
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 93b5d24..70daafa 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -214,6 +214,7 @@ private:
void setAMRFormat(bool isWAMR, int32_t bitRate);
void setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate);
+ void setG711Format(int32_t numChannels);
status_t setVideoPortFormatType(
OMX_U32 portIndex,
diff --git a/include/media/stagefright/openmax/OMX_Video.h b/include/media/stagefright/openmax/OMX_Video.h
index 2738bdc..4f8485d 100644
--- a/include/media/stagefright/openmax/OMX_Video.h
+++ b/include/media/stagefright/openmax/OMX_Video.h
@@ -85,6 +85,7 @@ typedef enum OMX_VIDEO_CODINGTYPE {
OMX_VIDEO_CodingRV, /**< all versions of Real Video */
OMX_VIDEO_CodingAVC, /**< H.264/AVC */
OMX_VIDEO_CodingMJPEG, /**< Motion JPEG */
+ OMX_VIDEO_CodingVPX, /**< Google VPX, formerly known as On2 VP8 */
OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
OMX_VIDEO_CodingMax = 0x7FFFFFFF
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e52f6d1..4189354 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1644,7 +1644,7 @@ void ACodec::UninitializedState::onSetup(
if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
componentName = "OMX.Nvidia.h264.decode";
} else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) {
- componentName = "OMX.Nvidia.aac.decoder";
+ componentName = "OMX.google.aac.decoder";
} else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_MPEG)) {
componentName = "OMX.Nvidia.mp3.decoder";
} else {
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 10ce00c..d8cf810 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -3,6 +3,8 @@ include $(CLEAR_VARS)
include frameworks/base/media/libstagefright/codecs/common/Config.mk
+BUILD_WITH_SOFTWARE_DECODERS := true
+
LOCAL_SRC_FILES:= \
ACodec.cpp \
AACExtractor.cpp \
@@ -45,7 +47,6 @@ LOCAL_SRC_FILES:= \
ShoutcastSource.cpp \
StagefrightMediaScanner.cpp \
StagefrightMetadataRetriever.cpp \
- ThreadedSource.cpp \
ThrottledSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
@@ -82,28 +83,39 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
- libstagefright_aacdec \
libstagefright_aacenc \
- libstagefright_amrnbdec \
libstagefright_amrnbenc \
- libstagefright_amrwbdec \
libstagefright_amrwbenc \
- libstagefright_avcdec \
libstagefright_avcenc \
- libstagefright_m4vh263dec \
libstagefright_m4vh263enc \
- libstagefright_mp3dec \
- libstagefright_vorbisdec \
libstagefright_matroska \
- libstagefright_vpxdec \
libvpx \
libstagefright_mpeg2ts \
libstagefright_httplive \
libstagefright_rtsp \
libstagefright_id3 \
- libstagefright_g711dec \
libFLAC \
+ifeq ($(BUILD_WITH_SOFTWARE_DECODERS),true)
+
+LOCAL_SRC_FILES += \
+ ThreadedSource.cpp \
+
+LOCAL_STATIC_LIBRARIES += \
+ libstagefright_aacdec \
+ libstagefright_amrnbdec \
+ libstagefright_amrwbdec \
+ libstagefright_avcdec \
+ libstagefright_g711dec \
+ libstagefright_mp3dec \
+ libstagefright_m4vh263dec \
+ libstagefright_vorbisdec \
+ libstagefright_vpxdec \
+ libvpx \
+
+endif
+
+
################################################################################
# The following was shamelessly copied from external/webkit/Android.mk and
@@ -180,6 +192,10 @@ endif
LOCAL_CFLAGS += -Wno-multichar
+ifeq ($(BUILD_WITH_SOFTWARE_DECODERS),true)
+ LOCAL_CFLAGS += -DHAVE_SOFTWARE_DECODERS
+endif
+
LOCAL_MODULE:= libstagefright
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index dcc268f..b45e5d3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -942,7 +942,9 @@ void AwesomePlayer::initRenderer_l() {
// before creating a new one.
IPCThreadState::self()->flushCommands();
- if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) {
+ if (USE_SURFACE_ALLOC
+ && !strncmp(component, "OMX.", 4)
+ && strncmp(component, "OMX.google.", 11)) {
// Hardware decoders avoid the CPU color conversion by decoding
// directly to ANativeBuffers, so we must use a renderer that
// just pushes those buffers to the ANativeWindow.
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 78d13b2..cd5bdfb 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -53,7 +53,10 @@
#include <OMX_Audio.h>
#include <OMX_Component.h>
+#if HAVE_SOFTWARE_DECODERS
#include "include/ThreadedSource.h"
+#endif
+
#include "include/avc_utils.h"
namespace android {
@@ -65,11 +68,6 @@ struct CodecInfo {
const char *codec;
};
-#define FACTORY_CREATE(name) \
-static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \
- return new name(source); \
-}
-
#define FACTORY_CREATE_ENCODER(name) \
static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \
return new name(source, meta); \
@@ -77,20 +75,29 @@ static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaDa
#define FACTORY_REF(name) { #name, Make##name },
-FACTORY_CREATE(MP3Decoder)
+FACTORY_CREATE_ENCODER(AMRNBEncoder)
+FACTORY_CREATE_ENCODER(AMRWBEncoder)
+FACTORY_CREATE_ENCODER(AACEncoder)
+FACTORY_CREATE_ENCODER(AVCEncoder)
+FACTORY_CREATE_ENCODER(M4vH263Encoder)
+
+#if HAVE_SOFTWARE_DECODERS
+
+#define FACTORY_CREATE(name) \
+static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \
+ return new name(source); \
+}
+
FACTORY_CREATE(AMRNBDecoder)
FACTORY_CREATE(AMRWBDecoder)
FACTORY_CREATE(AACDecoder)
FACTORY_CREATE(AVCDecoder)
FACTORY_CREATE(G711Decoder)
+FACTORY_CREATE(MP3Decoder)
FACTORY_CREATE(M4vH263Decoder)
FACTORY_CREATE(VorbisDecoder)
FACTORY_CREATE(VPXDecoder)
-FACTORY_CREATE_ENCODER(AMRNBEncoder)
-FACTORY_CREATE_ENCODER(AMRWBEncoder)
-FACTORY_CREATE_ENCODER(AACEncoder)
-FACTORY_CREATE_ENCODER(AVCEncoder)
-FACTORY_CREATE_ENCODER(M4vH263Encoder)
+#endif
static sp<MediaSource> InstantiateSoftwareEncoder(
const char *name, const sp<MediaSource> &source,
@@ -119,18 +126,19 @@ static sp<MediaSource> InstantiateSoftwareEncoder(
static sp<MediaSource> InstantiateSoftwareCodec(
const char *name, const sp<MediaSource> &source) {
+#if HAVE_SOFTWARE_DECODERS
struct FactoryInfo {
const char *name;
sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &);
};
static const FactoryInfo kFactoryInfo[] = {
- FACTORY_REF(MP3Decoder)
FACTORY_REF(AMRNBDecoder)
FACTORY_REF(AMRWBDecoder)
FACTORY_REF(AACDecoder)
FACTORY_REF(AVCDecoder)
FACTORY_REF(G711Decoder)
+ FACTORY_REF(MP3Decoder)
FACTORY_REF(M4vH263Decoder)
FACTORY_REF(VorbisDecoder)
FACTORY_REF(VPXDecoder)
@@ -145,6 +153,7 @@ static sp<MediaSource> InstantiateSoftwareCodec(
return (*kFactoryInfo[i].CreateFunc)(source);
}
}
+#endif
return NULL;
}
@@ -156,36 +165,47 @@ static const CodecInfo kDecoderInfo[] = {
{ MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.Nvidia.mp3.decoder" },
// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" },
{ MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
+ { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amrwb.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
+ { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder" },
// { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.Nvidia.aac.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
+ { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" },
+ { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "OMX.google.g711.alaw.decoder" },
{ MEDIA_MIMETYPE_AUDIO_G711_ALAW, "G711Decoder" },
+ { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "OMX.google.g711.mlaw.decoder" },
{ MEDIA_MIMETYPE_AUDIO_G711_MLAW, "G711Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.decode" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Decoder" },
+ { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.google.mpeg4.decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.decode" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Decoder" },
+ { MEDIA_MIMETYPE_VIDEO_H263, "OMX.google.h263.decoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.decode" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Decoder" },
+ { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.avc.decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" },
+ { MEDIA_MIMETYPE_AUDIO_VORBIS, "OMX.google.vorbis.decoder" },
{ MEDIA_MIMETYPE_AUDIO_VORBIS, "VorbisDecoder" },
+ { MEDIA_MIMETYPE_VIDEO_VPX, "OMX.google.vpx.decoder" },
{ MEDIA_MIMETYPE_VIDEO_VPX, "VPXDecoder" },
};
@@ -277,6 +297,10 @@ static void InitOMXParams(T *params) {
}
static bool IsSoftwareCodec(const char *componentName) {
+ if (!strncmp("OMX.google.", componentName, 11)) {
+ return true;
+ }
+
if (!strncmp("OMX.", componentName, 4)) {
return false;
}
@@ -284,26 +308,29 @@ static bool IsSoftwareCodec(const char *componentName) {
return true;
}
-// A sort order in which non-OMX components are first,
-// followed by software codecs, and followed by all the others.
+// A sort order in which OMX software codecs are first, followed
+// by other (non-OMX) software codecs, followed by everything else.
static int CompareSoftwareCodecsFirst(
const String8 *elem1, const String8 *elem2) {
- bool isNotOMX1 = strncmp(elem1->string(), "OMX.", 4);
- bool isNotOMX2 = strncmp(elem2->string(), "OMX.", 4);
-
- if (isNotOMX1) {
- if (isNotOMX2) { return 0; }
- return -1;
- }
- if (isNotOMX2) {
- return 1;
- }
+ bool isOMX1 = !strncmp(elem1->string(), "OMX.", 4);
+ bool isOMX2 = !strncmp(elem2->string(), "OMX.", 4);
bool isSoftwareCodec1 = IsSoftwareCodec(elem1->string());
bool isSoftwareCodec2 = IsSoftwareCodec(elem2->string());
if (isSoftwareCodec1) {
- if (isSoftwareCodec2) { return 0; }
+ if (!isSoftwareCodec2) { return -1; }
+
+ if (isOMX1) {
+ if (isOMX2) { return 0; }
+
+ return -1;
+ } else {
+ if (isOMX2) { return 0; }
+
+ return 1;
+ }
+
return -1;
}
@@ -622,6 +649,11 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
LOGE("Profile and/or level exceed the decoder's capabilities.");
return ERROR_UNSUPPORTED;
}
+ } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
+ addCodecSpecificData(data, size);
+
+ CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
+ addCodecSpecificData(data, size);
}
}
@@ -631,16 +663,23 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
}
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mMIME)) {
setAMRFormat(false /* isWAMR */, bitRate);
- }
- if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mMIME)) {
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mMIME)) {
setAMRFormat(true /* isWAMR */, bitRate);
- }
- if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mMIME)) {
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mMIME)) {
int32_t numChannels, sampleRate;
CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
setAACFormat(numChannels, sampleRate, bitRate);
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME)
+ || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) {
+ // These are PCM-like formats with a fixed sample rate but
+ // a variable number of channels.
+
+ int32_t numChannels;
+ CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+
+ setG711Format(numChannels);
}
if (!strncasecmp(mMIME, "video/", 6)) {
@@ -1316,6 +1355,8 @@ status_t OMXCodec::setVideoOutputFormat(
compressionFormat = OMX_VIDEO_CodingMPEG4;
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
compressionFormat = OMX_VIDEO_CodingH263;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VPX, mime)) {
+ compressionFormat = OMX_VIDEO_CodingVPX;
} else {
LOGE("Not a supported video mime type: %s", mime);
CHECK(!"Should not be here. Not a supported video mime type.");
@@ -1443,7 +1484,8 @@ OMXCodec::OMXCodec(
mOutputPortSettingsChangedPending(false),
mLeftOverBuffer(NULL),
mPaused(false),
- mNativeWindow(nativeWindow) {
+ mNativeWindow(!strncmp(componentName, "OMX.google.", 11)
+ ? NULL : nativeWindow) {
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
@@ -2899,6 +2941,23 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {
offset += srcBuffer->range_length();
+ if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_VORBIS, mMIME)) {
+ CHECK(!(mQuirks & kSupportsMultipleFramesPerInputBuffer));
+ CHECK_GE(info->mSize, offset + sizeof(int32_t));
+
+ int32_t numPageSamples;
+ if (!srcBuffer->meta_data()->findInt32(
+ kKeyValidSamples, &numPageSamples)) {
+ numPageSamples = -1;
+ }
+
+ memcpy((uint8_t *)info->mData + offset,
+ &numPageSamples,
+ sizeof(numPageSamples));
+
+ offset += sizeof(numPageSamples);
+ }
+
if (releaseBuffer) {
srcBuffer->release();
srcBuffer = NULL;
@@ -3224,6 +3283,11 @@ void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bit
}
}
+void OMXCodec::setG711Format(int32_t numChannels) {
+ CHECK(!mIsEncoder);
+ setRawAudioFormat(kPortIndexInput, 8000, numChannels);
+}
+
void OMXCodec::setImageOutputFormat(
OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
@@ -4013,6 +4077,13 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
numChannels, params.nChannels);
}
+ if (sampleRate != params.nSamplingRate) {
+ LOGW("Codec outputs at different sampling rate than "
+ "what the input stream contains (contains data at "
+ "%d Hz, codec outputs %d Hz)",
+ sampleRate, params.nSamplingRate);
+ }
+
mOutputFormat->setCString(
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
@@ -4025,8 +4096,7 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
(mQuirks & kDecoderLiesAboutNumberOfChannels)
? numChannels : params.nChannels);
- // The codec-reported sampleRate is not reliable...
- mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+ mOutputFormat->setInt32(kKeySampleRate, params.nSamplingRate);
} else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
OMX_AUDIO_PARAM_AMRTYPE amr;
InitOMXParams(&amr);
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 76f47f7..bf978d7 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -264,6 +264,8 @@ WAVSource::WAVSource(
mGroup(NULL) {
CHECK(mMeta->findInt32(kKeySampleRate, &mSampleRate));
CHECK(mMeta->findInt32(kKeyChannelCount, &mNumChannels));
+
+ mMeta->setInt32(kKeyMaxInputSize, kMaxFrameSize);
}
WAVSource::~WAVSource() {
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index 69e331f..5ef54fd 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -143,14 +143,39 @@ LOCAL_SRC_FILES := \
unpack_idx.cpp \
window_tables_fxp.cpp \
pvmp4setaudioconfig.cpp \
- AACDecoder.cpp
+ AACDecoder.cpp \
LOCAL_CFLAGS := -DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF= -DOSCL_UNUSED_ARG=
-LOCAL_C_INCLUDES := frameworks/base/media/libstagefright/include
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
LOCAL_ARM_MODE := arm
LOCAL_MODULE := libstagefright_aacdec
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftAAC.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+
+LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_aacdec
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_omx libstagefright_foundation libutils
+
+LOCAL_MODULE := libstagefright_soft_aacdec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
new file mode 100644
index 0000000..7ce6128
--- /dev/null
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftAAC"
+#include <utils/Log.h>
+
+#include "SoftAAC.h"
+
+#include "pvmp4audiodecoder_api.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+template<class T>
+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;
+}
+
+SoftAAC::SoftAAC(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mConfig(new tPVMP4AudioDecoderExternal),
+ mDecoderBuf(NULL),
+ mInputBufferCount(0),
+ mUpsamplingFactor(2),
+ mAnchorTimeUs(0),
+ mNumSamplesOutput(0),
+ mSignalledError(false),
+ mOutputPortSettingsChange(NONE) {
+ initPorts();
+ CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftAAC::~SoftAAC() {
+ free(mDecoderBuf);
+ mDecoderBuf = NULL;
+
+ delete mConfig;
+ mConfig = NULL;
+}
+
+void SoftAAC::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/aac");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+ addPort(def);
+}
+
+status_t SoftAAC::initDecoder() {
+ memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
+ mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
+ mConfig->aacPlusEnabled = 1;
+
+ // The software decoder doesn't properly support mono output on
+ // AACplus files. Always output stereo.
+ mConfig->desiredChannels = 2;
+
+ UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
+ mDecoderBuf = malloc(memRequirements);
+
+ Int err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
+ if (err != MP4AUDEC_SUCCESS) {
+ LOGE("Failed to initialize MP4 audio decoder");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+OMX_ERRORTYPE SoftAAC::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioAac:
+ {
+ OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
+ (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+ if (aacParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ aacParams->nBitRate = 0;
+ aacParams->nAudioBandWidth = 0;
+ aacParams->nAACtools = 0;
+ aacParams->nAACERtools = 0;
+ aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
+ aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+ aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+
+ if (!isConfigured()) {
+ aacParams->nChannels = 1;
+ aacParams->nSampleRate = 44100;
+ aacParams->nFrameLength = 0;
+ } else {
+ aacParams->nChannels = mConfig->encodedChannels;
+ aacParams->nSampleRate = mConfig->samplingRate;
+ aacParams->nFrameLength = mConfig->frameLength;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eEndian = OMX_EndianBig;
+ pcmParams->bInterleaved = OMX_TRUE;
+ pcmParams->nBitPerSample = 16;
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+ if (!isConfigured()) {
+ pcmParams->nChannels = 1;
+ pcmParams->nSamplingRate = 44100;
+ } else {
+ pcmParams->nChannels = mConfig->desiredChannels;
+ pcmParams->nSamplingRate = mConfig->samplingRate;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftAAC::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.aac",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAac:
+ {
+ const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
+ (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+ if (aacParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+bool SoftAAC::isConfigured() const {
+ return mInputBufferCount > 0;
+}
+
+void SoftAAC::onQueueFilled(OMX_U32 portIndex) {
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ if (portIndex == 0 && mInputBufferCount == 0) {
+ ++mInputBufferCount;
+
+ BufferInfo *info = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *header = info->mHeader;
+
+ mConfig->pInputBuffer = header->pBuffer + header->nOffset;
+ mConfig->inputBufferCurrentLength = header->nFilledLen;
+ mConfig->inputBufferMaxLength = 0;
+
+ Int err = PVMP4AudioDecoderConfig(mConfig, mDecoderBuf);
+ if (err != MP4AUDEC_SUCCESS) {
+ mSignalledError = true;
+ notify(OMX_EventError, OMX_ErrorUndefined, err, NULL);
+ return;
+ }
+
+ inQueue.erase(inQueue.begin());
+ info->mOwnedByUs = false;
+ notifyEmptyBufferDone(header);
+
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ return;
+ }
+
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
+ }
+
+ if (inHeader->nOffset == 0) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumSamplesOutput = 0;
+ }
+
+ mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset;
+ mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+ mConfig->inputBufferMaxLength = 0;
+ mConfig->inputBufferUsedLength = 0;
+ mConfig->remainderBits = 0;
+
+ mConfig->pOutputBuffer =
+ reinterpret_cast<Int16 *>(outHeader->pBuffer + outHeader->nOffset);
+
+ mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
+ mConfig->repositionFlag = false;
+
+ Int32 prevSamplingRate = mConfig->samplingRate;
+ Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
+
+ /*
+ * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+ * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+ * rate system and the sampling rate in the final output is actually
+ * doubled compared with the core AAC decoder sampling rate.
+ *
+ * Explicit signalling is done by explicitly defining SBR audio object
+ * type in the bitstream. Implicit signalling is done by embedding
+ * SBR content in AAC extension payload specific to SBR, and hence
+ * requires an AAC decoder to perform pre-checks on actual audio frames.
+ *
+ * Thus, we could not say for sure whether a stream is
+ * AAC+/eAAC+ until the first data frame is decoded.
+ */
+ if (mInputBufferCount <= 2) {
+ LOGV("audio/extended audio object type: %d + %d",
+ mConfig->audioObjectType, mConfig->extendedAudioObjectType);
+ LOGV("aac+ upsampling factor: %d desired channels: %d",
+ mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels);
+
+ if (mInputBufferCount == 1) {
+ mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor;
+ // Check on the sampling rate to see whether it is changed.
+ if (mConfig->samplingRate != prevSamplingRate) {
+ LOGW("Sample rate was %d Hz, but now is %d Hz",
+ prevSamplingRate, mConfig->samplingRate);
+
+ // We'll hold onto the input buffer and will decode
+ // it again once the output port has been reconfigured.
+
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ return;
+ }
+ } else { // mInputBufferCount == 2
+ if (mConfig->extendedAudioObjectType == MP4AUDIO_AAC_LC ||
+ mConfig->extendedAudioObjectType == MP4AUDIO_LTP) {
+ if (mUpsamplingFactor == 2) {
+ // The stream turns out to be not aacPlus mode anyway
+ LOGW("Disable AAC+/eAAC+ since extended audio object "
+ "type is %d",
+ mConfig->extendedAudioObjectType);
+ mConfig->aacPlusEnabled = 0;
+ }
+ } else {
+ if (mUpsamplingFactor == 1) {
+ // aacPlus mode does not buy us anything, but to cause
+ // 1. CPU load to increase, and
+ // 2. a half speed of decoding
+ LOGW("Disable AAC+/eAAC+ since upsampling factor is 1");
+ mConfig->aacPlusEnabled = 0;
+ }
+ }
+ }
+ }
+
+ size_t numOutBytes =
+ mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
+
+ if (decoderErr == MP4AUDEC_SUCCESS) {
+ CHECK_LE(mConfig->inputBufferUsedLength, inHeader->nFilledLen);
+
+ inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
+ inHeader->nOffset += mConfig->inputBufferUsedLength;
+ } else {
+ memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
+ }
+
+ if (mUpsamplingFactor == 2) {
+ if (mConfig->desiredChannels == 1) {
+ memcpy(&mConfig->pOutputBuffer[1024],
+ &mConfig->pOutputBuffer[2048],
+ numOutBytes * 2);
+ }
+ numOutBytes *= 2;
+ }
+
+ outHeader->nFilledLen = numOutBytes;
+ outHeader->nFlags = 0;
+
+ outHeader->nTimeStamp =
+ mAnchorTimeUs
+ + (mNumSamplesOutput * 1000000ll) / mConfig->samplingRate;
+
+ mNumSamplesOutput += mConfig->frameLength * mUpsamplingFactor;
+
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
+
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+
+ ++mInputBufferCount;
+ }
+}
+
+void SoftAAC::onPortFlushCompleted(OMX_U32 portIndex) {
+ if (portIndex == 0) {
+ // Make sure that the next buffer output does not still
+ // depend on fragments from the last one decoded.
+ PVMP4AudioDecoderResetBuffer(mDecoderBuf);
+ }
+}
+
+void SoftAAC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+ if (portIndex != 1) {
+ return;
+ }
+
+ switch (mOutputPortSettingsChange) {
+ case NONE:
+ break;
+
+ case AWAITING_DISABLED:
+ {
+ CHECK(!enabled);
+ mOutputPortSettingsChange = AWAITING_ENABLED;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+ CHECK(enabled);
+ mOutputPortSettingsChange = NONE;
+ break;
+ }
+ }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftAAC(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.h b/media/libstagefright/codecs/aacdec/SoftAAC.h
new file mode 100644
index 0000000..963fd27
--- /dev/null
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_AAC_H_
+
+#define SOFT_AAC_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct tPVMP4AudioDecoderExternal;
+
+namespace android {
+
+struct SoftAAC : public SimpleSoftOMXComponent {
+ SoftAAC(const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftAAC();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+private:
+ enum {
+ kNumBuffers = 4
+ };
+
+ tPVMP4AudioDecoderExternal *mConfig;
+ void *mDecoderBuf;
+
+ size_t mInputBufferCount;
+ size_t mUpsamplingFactor;
+ int64_t mAnchorTimeUs;
+ int64_t mNumSamplesOutput;
+
+ bool mSignalledError;
+
+ enum {
+ NONE,
+ AWAITING_DISABLED,
+ AWAITING_ENABLED
+ } mOutputPortSettingsChange;
+
+ void initPorts();
+ status_t initDecoder();
+ bool isConfigured() const;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftAAC);
+};
+
+} // namespace android
+
+#endif // SOFT_AAC_H_
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index a545762..296cae4 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -52,3 +52,33 @@ LOCAL_CFLAGS := \
LOCAL_MODULE := libstagefright_amrnbdec
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftAMR.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../common/include \
+ $(LOCAL_PATH)/../common \
+ frameworks/base/media/libstagefright/codecs/amrwb/src \
+
+LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrnbdec libstagefright_amrwbdec
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_omx libstagefright_foundation libutils \
+ libstagefright_amrnb_common
+
+LOCAL_MODULE := libstagefright_soft_amrdec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
new file mode 100644
index 0000000..c0a588f
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftAMR"
+#include <utils/Log.h>
+
+#include "SoftAMR.h"
+
+#include "gsmamr_dec.h"
+#include "pvamrwbdecoder.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+template<class T>
+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;
+}
+
+SoftAMR::SoftAMR(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mMode(MODE_NARROW),
+ mState(NULL),
+ mDecoderBuf(NULL),
+ mDecoderCookie(NULL),
+ mInputBufferCount(0),
+ mAnchorTimeUs(0),
+ mNumSamplesOutput(0),
+ mSignalledError(false),
+ mOutputPortSettingsChange(NONE) {
+ if (!strcmp(name, "OMX.google.amrwb.decoder")) {
+ mMode = MODE_WIDE;
+ } else {
+ CHECK(!strcmp(name, "OMX.google.amrnb.decoder"));
+ }
+
+ initPorts();
+ CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftAMR::~SoftAMR() {
+ if (mMode == MODE_NARROW) {
+ GSMDecodeFrameExit(&mState);
+ mState = NULL;
+ } else {
+ free(mDecoderBuf);
+ mDecoderBuf = NULL;
+
+ mState = NULL;
+ mDecoderCookie = NULL;
+ }
+}
+
+void SoftAMR::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.audio.cMIMEType =
+ mMode == MODE_NARROW
+ ? const_cast<char *>("audio/amr")
+ : const_cast<char *>("audio/amrwb");
+
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+
+ def.nBufferSize =
+ (mMode == MODE_NARROW ? kNumSamplesPerFrameNB : kNumSamplesPerFrameWB)
+ * sizeof(int16_t);
+
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+ addPort(def);
+}
+
+status_t SoftAMR::initDecoder() {
+ if (mMode == MODE_NARROW) {
+ Word16 err = GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder");
+
+ if (err != 0) {
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ int32_t memReq = pvDecoder_AmrWbMemRequirements();
+ mDecoderBuf = malloc(memReq);
+
+ pvDecoder_AmrWb_Init(&mState, mDecoderBuf, &mDecoderCookie);
+ }
+
+ return OK;
+}
+
+OMX_ERRORTYPE SoftAMR::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioAmr:
+ {
+ OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+ (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+ if (amrParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ amrParams->nChannels = 1;
+ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatConformance;
+
+ if (!isConfigured()) {
+ amrParams->nBitRate = 0;
+ amrParams->eAMRBandMode = OMX_AUDIO_AMRBandModeUnused;
+ } else {
+ amrParams->nBitRate = 0;
+ amrParams->eAMRBandMode =
+ mMode == MODE_NARROW
+ ? OMX_AUDIO_AMRBandModeNB0 : OMX_AUDIO_AMRBandModeWB0;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ pcmParams->nChannels = 1;
+ pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eEndian = OMX_EndianBig;
+ pcmParams->bInterleaved = OMX_TRUE;
+ pcmParams->nBitPerSample = 16;
+
+ pcmParams->nSamplingRate =
+ (mMode == MODE_NARROW) ? kSampleRateNB : kSampleRateWB;
+
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftAMR::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (mMode == MODE_NARROW) {
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.amrnb",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+ } else {
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.amrwb",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAmr:
+ {
+ const OMX_AUDIO_PARAM_AMRTYPE *aacParams =
+ (const OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+ if (aacParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+bool SoftAMR::isConfigured() const {
+ return mInputBufferCount > 0;
+}
+
+static size_t getFrameSize(unsigned FT) {
+ static const size_t kFrameSizeWB[9] = {
+ 132, 177, 253, 285, 317, 365, 397, 461, 477
+ };
+
+ size_t frameSize = kFrameSizeWB[FT];
+
+ // Round up bits to bytes and add 1 for the header byte.
+ frameSize = (frameSize + 7) / 8 + 1;
+
+ return frameSize;
+}
+
+void SoftAMR::onQueueFilled(OMX_U32 portIndex) {
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
+ }
+
+ if (inHeader->nOffset == 0) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumSamplesOutput = 0;
+ }
+
+ const uint8_t *inputPtr = inHeader->pBuffer + inHeader->nOffset;
+ int32_t numBytesRead;
+
+ if (mMode == MODE_NARROW) {
+ numBytesRead =
+ AMRDecode(mState,
+ (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f),
+ (UWord8 *)&inputPtr[1],
+ reinterpret_cast<int16_t *>(outHeader->pBuffer),
+ MIME_IETF);
+
+ if (numBytesRead == -1) {
+ LOGE("PV AMR decoder AMRDecode() call failed");
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+
+ return;
+ }
+
+ ++numBytesRead; // Include the frame type header byte.
+
+ if (static_cast<size_t>(numBytesRead) > inHeader->nFilledLen) {
+ // This is bad, should never have happened, but did. Abort now.
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+
+ return;
+ }
+ } else {
+ int16 mode = ((inputPtr[0] >> 3) & 0x0f);
+ size_t frameSize = getFrameSize(mode);
+ CHECK_GE(inHeader->nFilledLen, frameSize);
+
+ int16 frameType;
+ RX_State_wb rx_state;
+ mime_unsorting(
+ const_cast<uint8_t *>(&inputPtr[1]),
+ mInputSampleBuffer,
+ &frameType, &mode, 1, &rx_state);
+
+ int16_t *outPtr = (int16_t *)outHeader->pBuffer;
+
+ int16_t numSamplesOutput;
+ pvDecoder_AmrWb(
+ mode, mInputSampleBuffer,
+ outPtr,
+ &numSamplesOutput,
+ mDecoderBuf, frameType, mDecoderCookie);
+
+ CHECK_EQ((int)numSamplesOutput, (int)kNumSamplesPerFrameWB);
+
+ for (int i = 0; i < kNumSamplesPerFrameWB; ++i) {
+ /* Delete the 2 LSBs (14-bit output) */
+ outPtr[i] &= 0xfffC;
+ }
+
+ numBytesRead = frameSize;
+ }
+
+ inHeader->nOffset += numBytesRead;
+ inHeader->nFilledLen -= numBytesRead;
+
+ outHeader->nFlags = 0;
+ outHeader->nOffset = 0;
+
+ if (mMode == MODE_NARROW) {
+ outHeader->nFilledLen = kNumSamplesPerFrameNB * sizeof(int16_t);
+
+ outHeader->nTimeStamp =
+ mAnchorTimeUs
+ + (mNumSamplesOutput * 1000000ll) / kSampleRateNB;
+
+ mNumSamplesOutput += kNumSamplesPerFrameNB;
+ } else {
+ outHeader->nFilledLen = kNumSamplesPerFrameWB * sizeof(int16_t);
+
+ outHeader->nTimeStamp =
+ mAnchorTimeUs
+ + (mNumSamplesOutput * 1000000ll) / kSampleRateWB;
+
+ mNumSamplesOutput += kNumSamplesPerFrameWB;
+ }
+
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
+
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+
+ ++mInputBufferCount;
+ }
+}
+
+void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) {
+}
+
+void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+ if (portIndex != 1) {
+ return;
+ }
+
+ switch (mOutputPortSettingsChange) {
+ case NONE:
+ break;
+
+ case AWAITING_DISABLED:
+ {
+ CHECK(!enabled);
+ mOutputPortSettingsChange = AWAITING_ENABLED;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+ CHECK(enabled);
+ mOutputPortSettingsChange = NONE;
+ break;
+ }
+ }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftAMR(name, callbacks, appData, component);
+}
+
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.h b/media/libstagefright/codecs/amrnb/dec/SoftAMR.h
new file mode 100644
index 0000000..9a596e5
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_AMR_H_
+
+#define SOFT_AMR_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+namespace android {
+
+struct SoftAMR : public SimpleSoftOMXComponent {
+ SoftAMR(const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftAMR();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+private:
+ enum {
+ kNumBuffers = 4,
+ kSampleRateNB = 8000,
+ kSampleRateWB = 16000,
+ kNumSamplesPerFrameNB = 160,
+ kNumSamplesPerFrameWB = 320,
+ };
+
+ enum {
+ MODE_NARROW,
+ MODE_WIDE
+
+ } mMode;
+
+ void *mState;
+ void *mDecoderBuf;
+ int16_t *mDecoderCookie;
+
+ size_t mInputBufferCount;
+ int64_t mAnchorTimeUs;
+ int64_t mNumSamplesOutput;
+
+ bool mSignalledError;
+
+ enum {
+ NONE,
+ AWAITING_DISABLED,
+ AWAITING_ENABLED
+ } mOutputPortSettingsChange;
+
+ int16_t mInputSampleBuffer[477];
+
+ void initPorts();
+ status_t initDecoder();
+ bool isConfigured() const;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftAMR);
+};
+
+} // namespace android
+
+#endif // SOFT_AMR_H_
+
diff --git a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
index 2a21472..5b111ef 100644
--- a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
+++ b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
@@ -177,7 +177,7 @@ status_t AMRWBDecoder::read(
CHECK(mInputBuffer->range_length() >= frameSize);
int16 frameType;
- RX_State rx_state;
+ RX_State_wb rx_state;
mime_unsorting(
const_cast<uint8_t *>(&inputPtr[1]),
mInputSampleBuffer,
diff --git a/media/libstagefright/codecs/amrwb/src/mime_io.cpp b/media/libstagefright/codecs/amrwb/src/mime_io.cpp
index 9ff8816..e1966c6 100644
--- a/media/libstagefright/codecs/amrwb/src/mime_io.cpp
+++ b/media/libstagefright/codecs/amrwb/src/mime_io.cpp
@@ -531,7 +531,7 @@ void mime_unsorting(uint8 unsorted_bits[],
int16 * frame_type,
int16 * mode,
uint8 quality,
- RX_State *st)
+ RX_State_wb *st)
{
int16 i;
diff --git a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.h b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.h
index 433fc92..c40bc10 100644
--- a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.h
+++ b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.h
@@ -101,7 +101,7 @@ typedef struct
{
int16 prev_ft;
int16 prev_mode;
-} RX_State;
+} RX_State_wb;
/*----------------------------------------------------------------------------
; ENUMERATED TYPEDEF'S
@@ -141,7 +141,7 @@ typedef struct
int16 *frame_type,
int16 *mode,
uint8 q,
- RX_State *st);
+ RX_State_wb *st);
/*----------------------------------------------------------------------------
diff --git a/media/libstagefright/codecs/avc/dec/Android.mk b/media/libstagefright/codecs/avc/dec/Android.mk
index 1b00347..afecdc4 100644
--- a/media/libstagefright/codecs/avc/dec/Android.mk
+++ b/media/libstagefright/codecs/avc/dec/Android.mk
@@ -3,25 +3,54 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
AVCDecoder.cpp \
- src/avcdec_api.cpp \
- src/avc_bitstream.cpp \
- src/header.cpp \
- src/itrans.cpp \
- src/pred_inter.cpp \
- src/pred_intra.cpp \
- src/residual.cpp \
- src/slice.cpp \
- src/vlc.cpp
+ src/avcdec_api.cpp \
+ src/avc_bitstream.cpp \
+ src/header.cpp \
+ src/itrans.cpp \
+ src/pred_inter.cpp \
+ src/pred_intra.cpp \
+ src/residual.cpp \
+ src/slice.cpp \
+ src/vlc.cpp
LOCAL_MODULE := libstagefright_avcdec
LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/src \
- $(LOCAL_PATH)/include \
- $(LOCAL_PATH)/../common/include \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../common/include \
$(TOP)/frameworks/base/media/libstagefright/include \
- $(TOP)/frameworks/base/include/media/stagefright/openmax
+ frameworks/base/include/media/stagefright/openmax \
LOCAL_CFLAGS := -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftAVC.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../common/include \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+
+LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_avcdec
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_avc_common \
+ libstagefright libstagefright_omx libstagefright_foundation libutils
+
+LOCAL_MODULE := libstagefright_soft_avcdec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/media/libstagefright/codecs/avc/dec/SoftAVC.cpp b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
new file mode 100644
index 0000000..9f141ac
--- /dev/null
+++ b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftAVC"
+#include <utils/Log.h>
+
+#include "SoftAVC.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include "avcdec_api.h"
+#include "avcdec_int.h"
+
+namespace android {
+
+static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
+
+template<class T>
+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;
+}
+
+static int32_t Malloc(void *userData, int32_t size, int32_t attrs) {
+ return reinterpret_cast<int32_t>(malloc(size));
+}
+
+static void Free(void *userData, int32_t ptr) {
+ free(reinterpret_cast<void *>(ptr));
+}
+
+SoftAVC::SoftAVC(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mHandle(new tagAVCHandle),
+ mInputBufferCount(0),
+ mWidth(160),
+ mHeight(120),
+ mCropLeft(0),
+ mCropTop(0),
+ mCropRight(mWidth - 1),
+ mCropBottom(mHeight - 1),
+ mSPSSeen(false),
+ mPPSSeen(false),
+ mCurrentTimeUs(-1),
+ mEOSStatus(INPUT_DATA_AVAILABLE),
+ mOutputPortSettingsChange(NONE) {
+ initPorts();
+ CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftAVC::~SoftAVC() {
+ PVAVCCleanUpDecoder(mHandle);
+
+ delete mHandle;
+ mHandle = NULL;
+}
+
+void SoftAVC::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumInputBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainVideo;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
+ def.format.video.pNativeRender = NULL;
+ def.format.video.nFrameWidth = mWidth;
+ def.format.video.nFrameHeight = mHeight;
+ def.format.video.nStride = def.format.video.nFrameWidth;
+ def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+ def.format.video.nBitrate = 0;
+ def.format.video.xFramerate = 0;
+ def.format.video.bFlagErrorConcealment = OMX_FALSE;
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
+ def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
+ def.format.video.pNativeWindow = NULL;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumOutputBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainVideo;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
+ def.format.video.pNativeRender = NULL;
+ def.format.video.nFrameWidth = mWidth;
+ def.format.video.nFrameHeight = mHeight;
+ def.format.video.nStride = def.format.video.nFrameWidth;
+ def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+ def.format.video.nBitrate = 0;
+ def.format.video.xFramerate = 0;
+ def.format.video.bFlagErrorConcealment = OMX_FALSE;
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
+ def.format.video.pNativeWindow = NULL;
+
+ def.nBufferSize =
+ (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
+
+ addPort(def);
+}
+
+status_t SoftAVC::initDecoder() {
+ memset(mHandle, 0, sizeof(tagAVCHandle));
+ mHandle->AVCObject = NULL;
+ mHandle->userData = this;
+ mHandle->CBAVC_DPBAlloc = ActivateSPSWrapper;
+ mHandle->CBAVC_FrameBind = BindFrameWrapper;
+ mHandle->CBAVC_FrameUnbind = UnbindFrame;
+ mHandle->CBAVC_Malloc = Malloc;
+ mHandle->CBAVC_Free = Free;
+
+ return OK;
+}
+
+OMX_ERRORTYPE SoftAVC::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamVideoPortFormat:
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex != 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ if (formatParams->nPortIndex == 0) {
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
+ formatParams->eColorFormat = OMX_COLOR_FormatUnused;
+ formatParams->xFramerate = 0;
+ } else {
+ CHECK_EQ(formatParams->nPortIndex, 1u);
+
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
+ formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
+ formatParams->xFramerate = 0;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftAVC::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.avc",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamVideoPortFormat:
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex != 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftAVC::getConfig(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexConfigCommonOutputCrop:
+ {
+ OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
+
+ if (rectParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ rectParams->nLeft = mCropLeft;
+ rectParams->nTop = mCropTop;
+ rectParams->nWidth = mCropRight - mCropLeft + 1;
+ rectParams->nHeight = mCropBottom - mCropTop + 1;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return OMX_ErrorUnsupportedIndex;
+ }
+}
+
+static void findNALFragment(
+ const OMX_BUFFERHEADERTYPE *inHeader,
+ const uint8_t **fragPtr, size_t *fragSize) {
+ const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
+
+ size_t size = inHeader->nFilledLen;
+
+ CHECK(size >= 4);
+ CHECK(!memcmp(kStartCode, data, 4));
+
+ size_t offset = 4;
+ while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) {
+ ++offset;
+ }
+
+ *fragPtr = &data[4];
+ if (offset + 3 >= size) {
+ *fragSize = size - 4;
+ } else {
+ *fragSize = offset - 4;
+ }
+}
+
+void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
+ if (mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
+ return;
+ }
+
+ while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty())
+ && outQueue.size() == kNumOutputBuffers) {
+ if (mEOSStatus == INPUT_EOS_SEEN) {
+ OMX_BUFFERHEADERTYPE *outHeader;
+ if (drainOutputBuffer(&outHeader)) {
+ List<BufferInfo *>::iterator it = outQueue.begin();
+ while ((*it)->mHeader != outHeader) {
+ ++it;
+ }
+
+ BufferInfo *outInfo = *it;
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(it);
+ outInfo = NULL;
+
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ return;
+ }
+
+ BufferInfo *outInfo = *outQueue.begin();
+ outHeader = outInfo->mHeader;
+
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ outHeader->nTimeStamp = 0;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ mEOSStatus = OUTPUT_FRAMES_FLUSHED;
+ return;
+ }
+
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ mEOSStatus = INPUT_EOS_SEEN;
+ continue;
+ }
+
+ mCurrentTimeUs = inHeader->nTimeStamp;
+
+ const uint8_t *fragPtr;
+ size_t fragSize;
+ findNALFragment(inHeader, &fragPtr, &fragSize);
+
+ bool releaseFragment;
+ OMX_BUFFERHEADERTYPE *outHeader;
+ status_t err = decodeFragment(
+ fragPtr, fragSize,
+ &releaseFragment, &outHeader);
+
+ if (releaseFragment) {
+ CHECK_GE(inHeader->nFilledLen, fragSize + 4);
+
+ inHeader->nOffset += fragSize + 4;
+ inHeader->nFilledLen -= fragSize + 4;
+
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
+ }
+
+ if (outHeader != NULL) {
+ List<BufferInfo *>::iterator it = outQueue.begin();
+ while ((*it)->mHeader != outHeader) {
+ ++it;
+ }
+
+ BufferInfo *outInfo = *it;
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(it);
+ outInfo = NULL;
+
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ return;
+ }
+
+ if (err == INFO_FORMAT_CHANGED) {
+ return;
+ }
+
+ if (err != OK) {
+ notify(OMX_EventError, OMX_ErrorUndefined, err, NULL);
+ return;
+ }
+ }
+}
+
+status_t SoftAVC::decodeFragment(
+ const uint8_t *fragPtr, size_t fragSize,
+ bool *releaseFragment,
+ OMX_BUFFERHEADERTYPE **outHeader) {
+ *releaseFragment = true;
+ *outHeader = NULL;
+
+ int nalType;
+ int nalRefIdc;
+ AVCDec_Status res =
+ PVAVCDecGetNALType(
+ const_cast<uint8_t *>(fragPtr), fragSize,
+ &nalType, &nalRefIdc);
+
+ if (res != AVCDEC_SUCCESS) {
+ LOGV("cannot determine nal type");
+ return ERROR_MALFORMED;
+ }
+
+ if (nalType != AVC_NALTYPE_SPS && nalType != AVC_NALTYPE_PPS
+ && (!mSPSSeen || !mPPSSeen)) {
+ // We haven't seen SPS or PPS yet.
+ return OK;
+ }
+
+ switch (nalType) {
+ case AVC_NALTYPE_SPS:
+ {
+ mSPSSeen = true;
+
+ res = PVAVCDecSeqParamSet(
+ mHandle, const_cast<uint8_t *>(fragPtr),
+ fragSize);
+
+ if (res != AVCDEC_SUCCESS) {
+ return ERROR_MALFORMED;
+ }
+
+ AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject;
+
+ int32_t width =
+ (pDecVid->seqParams[0]->pic_width_in_mbs_minus1 + 1) * 16;
+
+ int32_t height =
+ (pDecVid->seqParams[0]->pic_height_in_map_units_minus1 + 1) * 16;
+
+ int32_t crop_left, crop_right, crop_top, crop_bottom;
+ if (pDecVid->seqParams[0]->frame_cropping_flag)
+ {
+ crop_left = 2 * pDecVid->seqParams[0]->frame_crop_left_offset;
+ crop_right =
+ width - (2 * pDecVid->seqParams[0]->frame_crop_right_offset + 1);
+
+ if (pDecVid->seqParams[0]->frame_mbs_only_flag)
+ {
+ crop_top = 2 * pDecVid->seqParams[0]->frame_crop_top_offset;
+ crop_bottom =
+ height -
+ (2 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
+ }
+ else
+ {
+ crop_top = 4 * pDecVid->seqParams[0]->frame_crop_top_offset;
+ crop_bottom =
+ height -
+ (4 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
+ }
+ } else {
+ crop_bottom = height - 1;
+ crop_right = width - 1;
+ crop_top = crop_left = 0;
+ }
+
+ status_t err = OK;
+
+ if (mWidth != width || mHeight != height) {
+ mWidth = width;
+ mHeight = height;
+
+ updatePortDefinitions();
+
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+
+ err = INFO_FORMAT_CHANGED;
+ }
+
+ if (mCropLeft != crop_left
+ || mCropTop != crop_top
+ || mCropRight != crop_right
+ || mCropBottom != crop_bottom) {
+ mCropLeft = crop_left;
+ mCropTop = crop_top;
+ mCropRight = crop_right;
+ mCropBottom = crop_bottom;
+
+ notify(OMX_EventPortSettingsChanged,
+ 1,
+ OMX_IndexConfigCommonOutputCrop,
+ NULL);
+ }
+
+ return err;
+ }
+
+ case AVC_NALTYPE_PPS:
+ {
+ mPPSSeen = true;
+
+ res = PVAVCDecPicParamSet(
+ mHandle, const_cast<uint8_t *>(fragPtr),
+ fragSize);
+
+ if (res != AVCDEC_SUCCESS) {
+ LOGV("PVAVCDecPicParamSet returned error %d", res);
+ return ERROR_MALFORMED;
+ }
+
+ return OK;
+ }
+
+ case AVC_NALTYPE_SLICE:
+ case AVC_NALTYPE_IDR:
+ {
+ res = PVAVCDecodeSlice(
+ mHandle, const_cast<uint8_t *>(fragPtr),
+ fragSize);
+
+ if (res == AVCDEC_PICTURE_OUTPUT_READY) {
+ *releaseFragment = false;
+
+ if (!drainOutputBuffer(outHeader)) {
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+ }
+
+ if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) {
+ return OK;
+ } else {
+ LOGV("PVAVCDecodeSlice returned error %d", res);
+ return ERROR_MALFORMED;
+ }
+ }
+
+ case AVC_NALTYPE_SEI:
+ {
+ res = PVAVCDecSEI(
+ mHandle, const_cast<uint8_t *>(fragPtr),
+ fragSize);
+
+ if (res != AVCDEC_SUCCESS) {
+ return ERROR_MALFORMED;
+ }
+
+ return OK;
+ }
+
+ case AVC_NALTYPE_AUD:
+ case AVC_NALTYPE_FILL:
+ case AVC_NALTYPE_EOSEQ:
+ {
+ return OK;
+ }
+
+ default:
+ {
+ LOGE("Should not be here, unknown nalType %d", nalType);
+
+ return ERROR_MALFORMED;
+ }
+ }
+
+ return OK;
+}
+
+bool SoftAVC::drainOutputBuffer(OMX_BUFFERHEADERTYPE **outHeader) {
+ int32_t index;
+ int32_t Release;
+ AVCFrameIO Output;
+ Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL;
+ AVCDec_Status status =
+ PVAVCDecGetOutput(mHandle, &index, &Release, &Output);
+
+ if (status != AVCDEC_SUCCESS) {
+ return false;
+ }
+
+ PortInfo *port = editPortInfo(1);
+ CHECK_GE(index, 0);
+ CHECK_LT((size_t)index, port->mBuffers.size());
+ CHECK(port->mBuffers.editItemAt(index).mOwnedByUs);
+
+ *outHeader = port->mBuffers.editItemAt(index).mHeader;
+ (*outHeader)->nOffset = 0;
+ (*outHeader)->nFilledLen = port->mDef.nBufferSize;
+ (*outHeader)->nFlags = 0;
+
+ return true;
+}
+
+void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
+ if (portIndex == 0) {
+ PVAVCDecReset(mHandle);
+
+ mEOSStatus = INPUT_DATA_AVAILABLE;
+ }
+}
+
+void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+ if (portIndex != 1) {
+ return;
+ }
+
+ switch (mOutputPortSettingsChange) {
+ case NONE:
+ break;
+
+ case AWAITING_DISABLED:
+ {
+ CHECK(!enabled);
+ mOutputPortSettingsChange = AWAITING_ENABLED;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+ CHECK(enabled);
+ mOutputPortSettingsChange = NONE;
+ break;
+ }
+ }
+}
+
+void SoftAVC::updatePortDefinitions() {
+ OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
+ def->format.video.nFrameWidth = mWidth;
+ def->format.video.nFrameHeight = mHeight;
+ def->format.video.nStride = def->format.video.nFrameWidth;
+ def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+
+ def = &editPortInfo(1)->mDef;
+ def->format.video.nFrameWidth = mWidth;
+ def->format.video.nFrameHeight = mHeight;
+ def->format.video.nStride = def->format.video.nFrameWidth;
+ def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+
+ def->nBufferSize =
+ (def->format.video.nFrameWidth
+ * def->format.video.nFrameHeight * 3) / 2;
+}
+
+// static
+int32_t SoftAVC::ActivateSPSWrapper(
+ void *userData, unsigned int sizeInMbs, unsigned int numBuffers) {
+ return static_cast<SoftAVC *>(userData)->activateSPS(sizeInMbs, numBuffers);
+}
+
+// static
+int32_t SoftAVC::BindFrameWrapper(
+ void *userData, int32_t index, uint8_t **yuv) {
+ return static_cast<SoftAVC *>(userData)->bindFrame(index, yuv);
+}
+
+// static
+void SoftAVC::UnbindFrame(void *userData, int32_t index) {
+}
+
+int32_t SoftAVC::activateSPS(
+ unsigned int sizeInMbs, unsigned int numBuffers) {
+ PortInfo *port = editPortInfo(1);
+ CHECK_GE(port->mBuffers.size(), numBuffers);
+ CHECK_GE(port->mDef.nBufferSize, (sizeInMbs << 7) * 3);
+
+ return 1;
+}
+
+int32_t SoftAVC::bindFrame(int32_t index, uint8_t **yuv) {
+ PortInfo *port = editPortInfo(1);
+
+ CHECK_GE(index, 0);
+ CHECK_LT((size_t)index, port->mBuffers.size());
+
+ BufferInfo *outBuffer =
+ &port->mBuffers.editItemAt(index);
+
+ CHECK(outBuffer->mOwnedByUs);
+
+ outBuffer->mHeader->nTimeStamp = mCurrentTimeUs;
+ *yuv = outBuffer->mHeader->pBuffer;
+
+ return 1;
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftAVC(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/avc/dec/SoftAVC.h b/media/libstagefright/codecs/avc/dec/SoftAVC.h
new file mode 100644
index 0000000..1594b4d
--- /dev/null
+++ b/media/libstagefright/codecs/avc/dec/SoftAVC.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_AVC_H_
+
+#define SOFT_AVC_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct tagAVCHandle;
+
+namespace android {
+
+struct SoftAVC : public SimpleSoftOMXComponent {
+ SoftAVC(const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftAVC();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual OMX_ERRORTYPE getConfig(OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+private:
+ enum {
+ kNumInputBuffers = 4,
+ kNumOutputBuffers = 18,
+ };
+
+ enum EOSStatus {
+ INPUT_DATA_AVAILABLE,
+ INPUT_EOS_SEEN,
+ OUTPUT_FRAMES_FLUSHED,
+ };
+
+ tagAVCHandle *mHandle;
+
+ size_t mInputBufferCount;
+
+ int32_t mWidth, mHeight;
+ int32_t mCropLeft, mCropTop, mCropRight, mCropBottom;
+
+ bool mSPSSeen, mPPSSeen;
+
+ int64_t mCurrentTimeUs;
+
+ EOSStatus mEOSStatus;
+
+ enum {
+ NONE,
+ AWAITING_DISABLED,
+ AWAITING_ENABLED
+ } mOutputPortSettingsChange;
+
+ void initPorts();
+ status_t initDecoder();
+
+ status_t decodeFragment(
+ const uint8_t *fragPtr, size_t fragSize,
+ bool *releaseFrames,
+ OMX_BUFFERHEADERTYPE **outHeader);
+
+ void updatePortDefinitions();
+ bool drainOutputBuffer(OMX_BUFFERHEADERTYPE **outHeader);
+
+ static int32_t ActivateSPSWrapper(
+ void *userData, unsigned int sizeInMbs, unsigned int numBuffers);
+
+ static int32_t BindFrameWrapper(
+ void *userData, int32_t index, uint8_t **yuv);
+
+ static void UnbindFrame(void *userData, int32_t index);
+
+ int32_t activateSPS(
+ unsigned int sizeInMbs, unsigned int numBuffers);
+
+ int32_t bindFrame(int32_t index, uint8_t **yuv);
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftAVC);
+};
+
+} // namespace android
+
+#endif // SOFT_AVC_H_
+
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
index cfb9fe4..b6953bc 100644
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -10,3 +10,22 @@ LOCAL_C_INCLUDES := \
LOCAL_MODULE := libstagefright_g711dec
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftG711.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libstagefright_omx libstagefright_foundation libutils
+
+LOCAL_MODULE := libstagefright_soft_g711dec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
new file mode 100644
index 0000000..15e2c26
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftG711"
+#include <utils/Log.h>
+
+#include "SoftG711.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+
+namespace android {
+
+template<class T>
+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;
+}
+
+SoftG711::SoftG711(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mIsMLaw(true),
+ mNumChannels(1),
+ mSignalledError(false) {
+ if (!strcmp(name, "OMX.google.g711.alaw.decoder")) {
+ mIsMLaw = false;
+ } else {
+ CHECK(!strcmp(name, "OMX.google.g711.mlaw.decoder"));
+ }
+
+ initPorts();
+}
+
+SoftG711::~SoftG711() {
+}
+
+void SoftG711::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.audio.cMIMEType =
+ const_cast<char *>(
+ mIsMLaw
+ ? MEDIA_MIMETYPE_AUDIO_G711_MLAW
+ : MEDIA_MIMETYPE_AUDIO_G711_ALAW);
+
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingG711;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t);
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+ addPort(def);
+}
+
+OMX_ERRORTYPE SoftG711::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eEndian = OMX_EndianBig;
+ pcmParams->bInterleaved = OMX_TRUE;
+ pcmParams->nBitPerSample = 16;
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+ pcmParams->nChannels = mNumChannels;
+ pcmParams->nSamplingRate = 8000;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftG711::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) {
+ return OMX_ErrorUndefined;
+ }
+
+ mNumChannels = pcmParams->nChannels;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (mIsMLaw) {
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.g711mlaw",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+ } else {
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.g711alaw",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+void SoftG711::onQueueFilled(OMX_U32 portIndex) {
+ if (mSignalledError) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
+ }
+
+ if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) {
+ LOGE("input buffer too large (%ld).", inHeader->nFilledLen);
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ }
+
+ const uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset;
+
+ if (mIsMLaw) {
+ DecodeMLaw(
+ reinterpret_cast<int16_t *>(outHeader->pBuffer),
+ inputptr, inHeader->nFilledLen);
+ } else {
+ DecodeALaw(
+ reinterpret_cast<int16_t *>(outHeader->pBuffer),
+ inputptr, inHeader->nFilledLen);
+ }
+
+ outHeader->nTimeStamp = inHeader->nTimeStamp;
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = inHeader->nFilledLen * sizeof(int16_t);
+ outHeader->nFlags = 0;
+
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ }
+}
+
+// static
+void SoftG711::DecodeALaw(
+ int16_t *out, const uint8_t *in, size_t inSize) {
+ while (inSize-- > 0) {
+ int32_t x = *in++;
+
+ int32_t ix = x ^ 0x55;
+ ix &= 0x7f;
+
+ int32_t iexp = ix >> 4;
+ int32_t mant = ix & 0x0f;
+
+ if (iexp > 0) {
+ mant += 16;
+ }
+
+ mant = (mant << 4) + 8;
+
+ if (iexp > 1) {
+ mant = mant << (iexp - 1);
+ }
+
+ *out++ = (x > 127) ? mant : -mant;
+ }
+}
+
+// static
+void SoftG711::DecodeMLaw(
+ int16_t *out, const uint8_t *in, size_t inSize) {
+ while (inSize-- > 0) {
+ int32_t x = *in++;
+
+ int32_t mantissa = ~x;
+ int32_t exponent = (mantissa >> 4) & 7;
+ int32_t segment = exponent + 1;
+ mantissa &= 0x0f;
+
+ int32_t step = 4 << segment;
+
+ int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
+
+ *out++ = (x < 0x80) ? -abs : abs;
+ }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftG711(name, callbacks, appData, component);
+}
+
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.h b/media/libstagefright/codecs/g711/dec/SoftG711.h
new file mode 100644
index 0000000..bff0c68
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_G711_H_
+
+#define SOFT_G711_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+namespace android {
+
+struct SoftG711 : public SimpleSoftOMXComponent {
+ SoftG711(const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftG711();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+ enum {
+ kNumBuffers = 4,
+ kMaxNumSamplesPerFrame = 16384,
+ };
+
+ bool mIsMLaw;
+ OMX_U32 mNumChannels;
+ bool mSignalledError;
+
+ void initPorts();
+
+ static void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize);
+ static void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize);
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftG711);
+};
+
+} // namespace android
+
+#endif // SOFT_G711_H_
+
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index 2d9bcc6..65b642c 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -48,3 +48,29 @@ LOCAL_C_INCLUDES := \
LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftMPEG4.cpp
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+
+LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_m4vh263dec
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libstagefright_omx libstagefright_foundation libutils
+
+LOCAL_MODULE := libstagefright_soft_mpeg4dec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
new file mode 100644
index 0000000..13e1662
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftMPEG4"
+#include <utils/Log.h>
+
+#include "SoftMPEG4.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include "mp4dec_api.h"
+
+namespace android {
+
+template<class T>
+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;
+}
+
+SoftMPEG4::SoftMPEG4(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mMode(MODE_MPEG4),
+ mHandle(new tagvideoDecControls),
+ mInputBufferCount(0),
+ mWidth(352),
+ mHeight(288),
+ mCropLeft(0),
+ mCropTop(0),
+ mCropRight(mWidth - 1),
+ mCropBottom(mHeight - 1),
+ mSignalledError(false),
+ mInitialized(false),
+ mFramesConfigured(false),
+ mNumSamplesOutput(0),
+ mOutputPortSettingsChange(NONE) {
+ if (!strcmp(name, "OMX.google.h263.decoder")) {
+ mMode = MODE_H263;
+ } else {
+ CHECK(!strcmp(name, "OMX.google.mpeg4.decoder"));
+ }
+
+ initPorts();
+ CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftMPEG4::~SoftMPEG4() {
+ if (mInitialized) {
+ PVCleanUpVideoDecoder(mHandle);
+ }
+
+ delete mHandle;
+ mHandle = NULL;
+}
+
+void SoftMPEG4::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumInputBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainVideo;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.video.cMIMEType =
+ (mMode == MODE_MPEG4)
+ ? const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4)
+ : const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
+
+ def.format.video.pNativeRender = NULL;
+ def.format.video.nFrameWidth = mWidth;
+ def.format.video.nFrameHeight = mHeight;
+ def.format.video.nStride = def.format.video.nFrameWidth;
+ def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+ def.format.video.nBitrate = 0;
+ def.format.video.xFramerate = 0;
+ def.format.video.bFlagErrorConcealment = OMX_FALSE;
+
+ def.format.video.eCompressionFormat =
+ mMode == MODE_MPEG4 ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
+
+ def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
+ def.format.video.pNativeWindow = NULL;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumOutputBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainVideo;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
+ def.format.video.pNativeRender = NULL;
+ def.format.video.nFrameWidth = mWidth;
+ def.format.video.nFrameHeight = mHeight;
+ def.format.video.nStride = def.format.video.nFrameWidth;
+ def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+ def.format.video.nBitrate = 0;
+ def.format.video.xFramerate = 0;
+ def.format.video.bFlagErrorConcealment = OMX_FALSE;
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
+ def.format.video.pNativeWindow = NULL;
+
+ def.nBufferSize =
+ (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
+
+ addPort(def);
+}
+
+status_t SoftMPEG4::initDecoder() {
+ memset(mHandle, 0, sizeof(tagvideoDecControls));
+ return OK;
+}
+
+OMX_ERRORTYPE SoftMPEG4::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamVideoPortFormat:
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex != 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ if (formatParams->nPortIndex == 0) {
+ formatParams->eCompressionFormat =
+ (mMode == MODE_MPEG4)
+ ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
+
+ formatParams->eColorFormat = OMX_COLOR_FormatUnused;
+ formatParams->xFramerate = 0;
+ } else {
+ CHECK_EQ(formatParams->nPortIndex, 1u);
+
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
+ formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
+ formatParams->xFramerate = 0;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftMPEG4::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (mMode == MODE_MPEG4) {
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.mpeg4",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+ } else {
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.h263",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamVideoPortFormat:
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex != 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftMPEG4::getConfig(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexConfigCommonOutputCrop:
+ {
+ OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
+
+ if (rectParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ rectParams->nLeft = mCropLeft;
+ rectParams->nTop = mCropTop;
+ rectParams->nWidth = mCropRight - mCropLeft + 1;
+ rectParams->nHeight = mCropBottom - mCropTop + 1;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return OMX_ErrorUnsupportedIndex;
+ }
+}
+
+void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ PortInfo *port = editPortInfo(1);
+
+ OMX_BUFFERHEADERTYPE *outHeader =
+ port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ ++mInputBufferCount;
+
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ List<BufferInfo *>::iterator it = outQueue.begin();
+ while ((*it)->mHeader != outHeader) {
+ ++it;
+ }
+
+ BufferInfo *outInfo = *it;
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(it);
+ outInfo = NULL;
+
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ return;
+ }
+
+ uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
+
+ if (!mInitialized) {
+ uint8_t *vol_data[1];
+ int32_t vol_size = 0;
+
+ vol_data[0] = NULL;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+ vol_data[0] = bitstream;
+ vol_size = inHeader->nFilledLen;
+ }
+
+ MP4DecodingMode mode =
+ (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
+
+ Bool success = PVInitVideoDecoder(
+ mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode);
+
+ if (!success) {
+ LOGW("PVInitVideoDecoder failed. Unsupported content?");
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+
+ MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
+ if (mode != actualMode) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+
+ PVSetPostProcType((VideoDecControls *) mHandle, 0);
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
+
+ mInitialized = true;
+
+ if (mode == MPEG4_MODE && portSettingsChanged()) {
+ return;
+ }
+
+ continue;
+ }
+
+ if (!mFramesConfigured) {
+ PortInfo *port = editPortInfo(1);
+ OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
+
+ PVSetReferenceYUV(mHandle, outHeader->pBuffer);
+
+ mFramesConfigured = true;
+ }
+
+ uint32_t timestamp = 0xFFFFFFFF;
+ int32_t bufferSize = inHeader->nFilledLen;
+
+ uint32_t useExtTimestamp = 0;
+ if (PVDecodeVideoFrame(
+ mHandle, &bitstream, &timestamp, &bufferSize,
+ &useExtTimestamp,
+ outHeader->pBuffer) != PV_TRUE) {
+ LOGE("failed to decode video frame.");
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
+
+ if (portSettingsChanged()) {
+ return;
+ }
+
+ outHeader->nTimeStamp = inHeader->nTimeStamp;
+
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+
+ ++mInputBufferCount;
+
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
+ outHeader->nFlags = 0;
+
+ List<BufferInfo *>::iterator it = outQueue.begin();
+ while ((*it)->mHeader != outHeader) {
+ ++it;
+ }
+
+ BufferInfo *outInfo = *it;
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(it);
+ outInfo = NULL;
+
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+
+ ++mNumSamplesOutput;
+ }
+}
+
+bool SoftMPEG4::portSettingsChanged() {
+ int32_t disp_width, disp_height;
+ PVGetVideoDimensions(mHandle, &disp_width, &disp_height);
+
+ int32_t buf_width, buf_height;
+ PVGetBufferDimensions(mHandle, &buf_width, &buf_height);
+
+ CHECK_LE(disp_width, buf_width);
+ CHECK_LE(disp_height, buf_height);
+
+ LOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
+ disp_width, disp_height, buf_width, buf_height);
+
+ if (mCropRight != disp_width - 1
+ || mCropBottom != disp_height - 1) {
+ mCropLeft = 0;
+ mCropTop = 0;
+ mCropRight = disp_width - 1;
+ mCropBottom = disp_height - 1;
+
+ notify(OMX_EventPortSettingsChanged,
+ 1,
+ OMX_IndexConfigCommonOutputCrop,
+ NULL);
+ }
+
+ if (buf_width != mWidth || buf_height != mHeight) {
+ mWidth = buf_width;
+ mHeight = buf_height;
+
+ updatePortDefinitions();
+
+ if (mMode == MODE_H263) {
+ PVCleanUpVideoDecoder(mHandle);
+
+ uint8_t *vol_data[1];
+ int32_t vol_size = 0;
+
+ vol_data[0] = NULL;
+ if (!PVInitVideoDecoder(
+ mHandle, vol_data, &vol_size, 1, mWidth, mHeight,
+ H263_MODE)) {
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return true;
+ }
+ }
+
+ mFramesConfigured = false;
+
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ return true;
+ }
+
+ return false;
+}
+
+void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
+ if (portIndex == 0 && mInitialized) {
+ CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
+ }
+}
+
+void SoftMPEG4::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+ if (portIndex != 1) {
+ return;
+ }
+
+ switch (mOutputPortSettingsChange) {
+ case NONE:
+ break;
+
+ case AWAITING_DISABLED:
+ {
+ CHECK(!enabled);
+ mOutputPortSettingsChange = AWAITING_ENABLED;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+ CHECK(enabled);
+ mOutputPortSettingsChange = NONE;
+ break;
+ }
+ }
+}
+
+void SoftMPEG4::updatePortDefinitions() {
+ OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
+ def->format.video.nFrameWidth = mWidth;
+ def->format.video.nFrameHeight = mHeight;
+ def->format.video.nStride = def->format.video.nFrameWidth;
+ def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+
+ def = &editPortInfo(1)->mDef;
+ def->format.video.nFrameWidth = mWidth;
+ def->format.video.nFrameHeight = mHeight;
+ def->format.video.nStride = def->format.video.nFrameWidth;
+ def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+
+ def->nBufferSize =
+ (((def->format.video.nFrameWidth + 15) & -16)
+ * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftMPEG4(name, callbacks, appData, component);
+}
+
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
new file mode 100644
index 0000000..dff08a7
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_MPEG4_H_
+
+#define SOFT_MPEG4_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct tagvideoDecControls;
+
+namespace android {
+
+struct SoftMPEG4 : public SimpleSoftOMXComponent {
+ SoftMPEG4(const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftMPEG4();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual OMX_ERRORTYPE getConfig(OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+private:
+ enum {
+ kNumInputBuffers = 4,
+ kNumOutputBuffers = 2,
+ };
+
+ enum {
+ MODE_MPEG4,
+ MODE_H263,
+
+ } mMode;
+
+ tagvideoDecControls *mHandle;
+
+ size_t mInputBufferCount;
+
+ int32_t mWidth, mHeight;
+ int32_t mCropLeft, mCropTop, mCropRight, mCropBottom;
+
+ bool mSignalledError;
+ bool mInitialized;
+ bool mFramesConfigured;
+
+ int32_t mNumSamplesOutput;
+
+ enum {
+ NONE,
+ AWAITING_DISABLED,
+ AWAITING_ENABLED
+ } mOutputPortSettingsChange;
+
+ void initPorts();
+ status_t initDecoder();
+
+ void updatePortDefinitions();
+ bool portSettingsChanged();
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG4);
+};
+
+} // namespace android
+
+#endif // SOFT_MPEG4_H_
+
+
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 753500e..2d35183 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -57,3 +57,26 @@ LOCAL_ARM_MODE := arm
include $(BUILD_STATIC_LIBRARY)
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftMP3.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libstagefright_omx libstagefright_foundation libutils
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_mp3dec
+
+LOCAL_MODULE := libstagefright_soft_mp3dec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
new file mode 100644
index 0000000..f6770b0
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftMP3"
+#include <utils/Log.h>
+
+#include "SoftMP3.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+
+#include "include/pvmp3decoder_api.h"
+
+namespace android {
+
+template<class T>
+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;
+}
+
+SoftMP3::SoftMP3(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mConfig(new tPVMP3DecoderExternal),
+ mDecoderBuf(NULL),
+ mAnchorTimeUs(0),
+ mNumFramesOutput(0),
+ mNumChannels(2),
+ mSamplingRate(44100),
+ mSignalledError(false),
+ mOutputPortSettingsChange(NONE) {
+ initPorts();
+ initDecoder();
+}
+
+SoftMP3::~SoftMP3() {
+ if (mDecoderBuf != NULL) {
+ free(mDecoderBuf);
+ mDecoderBuf = NULL;
+ }
+
+ delete mConfig;
+ mConfig = NULL;
+}
+
+void SoftMP3::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.audio.cMIMEType =
+ const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG);
+
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = kOutputBufferSize;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+ addPort(def);
+}
+
+void SoftMP3::initDecoder() {
+ mConfig->equalizerType = flat;
+ mConfig->crcEnabled = false;
+
+ uint32_t memRequirements = pvmp3_decoderMemRequirements();
+ mDecoderBuf = malloc(memRequirements);
+
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
+}
+
+OMX_ERRORTYPE SoftMP3::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eEndian = OMX_EndianBig;
+ pcmParams->bInterleaved = OMX_TRUE;
+ pcmParams->nBitPerSample = 16;
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+ pcmParams->nChannels = mNumChannels;
+ pcmParams->nSamplingRate = mSamplingRate;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftMP3::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.mp3",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
+ }
+
+ if (inHeader->nOffset == 0) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumFramesOutput = 0;
+ }
+
+ mConfig->pInputBuffer =
+ inHeader->pBuffer + inHeader->nOffset;
+
+ mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+ mConfig->inputBufferMaxLength = 0;
+ mConfig->inputBufferUsedLength = 0;
+
+ mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
+
+ mConfig->pOutputBuffer =
+ reinterpret_cast<int16_t *>(outHeader->pBuffer);
+
+ ERROR_CODE decoderErr;
+ if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
+ != NO_DECODING_ERROR) {
+ LOGV("mp3 decoder returned error %d", decoderErr);
+
+ if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR ||
+ mConfig->outputFrameSize == 0) {
+
+ if (mConfig->outputFrameSize == 0) {
+ LOGE("Output frame size is 0");
+ }
+
+ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+ mSignalledError = true;
+ return;
+ }
+
+ // This is recoverable, just ignore the current frame and
+ // play silence instead.
+ memset(outHeader->pBuffer,
+ 0,
+ mConfig->outputFrameSize * sizeof(int16_t));
+
+ mConfig->inputBufferUsedLength = inHeader->nFilledLen;
+ } else if (mConfig->samplingRate != mSamplingRate
+ || mConfig->num_channels != mNumChannels) {
+ mSamplingRate = mConfig->samplingRate;
+ mNumChannels = mConfig->num_channels;
+
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ return;
+ }
+
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
+
+ outHeader->nTimeStamp =
+ mAnchorTimeUs
+ + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;
+
+ outHeader->nFlags = 0;
+
+ CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
+
+ inHeader->nOffset += mConfig->inputBufferUsedLength;
+ inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
+
+ mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
+
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
+
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ }
+}
+
+void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) {
+ if (portIndex == 0) {
+ // Make sure that the next buffer output does not still
+ // depend on fragments from the last one decoded.
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
+ }
+}
+
+void SoftMP3::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+ if (portIndex != 1) {
+ return;
+ }
+
+ switch (mOutputPortSettingsChange) {
+ case NONE:
+ break;
+
+ case AWAITING_DISABLED:
+ {
+ CHECK(!enabled);
+ mOutputPortSettingsChange = AWAITING_ENABLED;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+ CHECK(enabled);
+ mOutputPortSettingsChange = NONE;
+ break;
+ }
+ }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftMP3(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
new file mode 100644
index 0000000..70d0682
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_MP3_H_
+
+#define SOFT_MP3_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct tPVMP3DecoderExternal;
+
+namespace android {
+
+struct SoftMP3 : public SimpleSoftOMXComponent {
+ SoftMP3(const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftMP3();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+private:
+ enum {
+ kNumBuffers = 4,
+ kOutputBufferSize = 4608 * 2
+ };
+
+ tPVMP3DecoderExternal *mConfig;
+ void *mDecoderBuf;
+ int64_t mAnchorTimeUs;
+ int64_t mNumFramesOutput;
+
+ int32_t mNumChannels;
+ int32_t mSamplingRate;
+
+ bool mConfigured;
+
+ bool mSignalledError;
+
+ enum {
+ NONE,
+ AWAITING_DISABLED,
+ AWAITING_ENABLED
+ } mOutputPortSettingsChange;
+
+ void initPorts();
+ void initDecoder();
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftMP3);
+};
+
+} // namespace android
+
+#endif // SOFT_MP3_H_
+
+
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
index b769f0d..1b3088f 100644
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ b/media/libstagefright/codecs/on2/dec/Android.mk
@@ -2,15 +2,42 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- VPXDecoder.cpp
+ VPXDecoder.cpp \
LOCAL_MODULE := libstagefright_vpxdec
LOCAL_C_INCLUDES := \
$(TOP)/frameworks/base/media/libstagefright/include \
- $(TOP)/frameworks/base/include/media/stagefright/openmax \
+ frameworks/base/include/media/stagefright/openmax \
$(TOP)/external/libvpx \
$(TOP)/external/libvpx/vpx_codec \
$(TOP)/external/libvpx/vpx_ports
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftVPX.cpp
+
+LOCAL_C_INCLUDES := \
+ $(TOP)/external/libvpx \
+ $(TOP)/external/libvpx/vpx_codec \
+ $(TOP)/external/libvpx/vpx_ports \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_vpxdec \
+ libvpx
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright libstagefright_omx libstagefright_foundation libutils
+
+LOCAL_MODULE := libstagefright_soft_vpxdec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
new file mode 100644
index 0000000..e9ce719
--- /dev/null
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftVPX"
+#include <utils/Log.h>
+
+#include "SoftVPX.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+
+#include "vpx/vpx_decoder.h"
+#include "vpx/vpx_codec.h"
+#include "vpx/vp8dx.h"
+
+namespace android {
+
+template<class T>
+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;
+}
+
+SoftVPX::SoftVPX(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mCtx(NULL),
+ mWidth(320),
+ mHeight(240),
+ mOutputPortSettingsChange(NONE) {
+ initPorts();
+ CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftVPX::~SoftVPX() {
+ vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
+ delete (vpx_codec_ctx_t *)mCtx;
+ mCtx = NULL;
+}
+
+void SoftVPX::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainVideo;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VPX);
+ def.format.video.pNativeRender = NULL;
+ def.format.video.nFrameWidth = mWidth;
+ def.format.video.nFrameHeight = mHeight;
+ def.format.video.nStride = def.format.video.nFrameWidth;
+ def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+ def.format.video.nBitrate = 0;
+ def.format.video.xFramerate = 0;
+ def.format.video.bFlagErrorConcealment = OMX_FALSE;
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingVPX;
+ def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
+ def.format.video.pNativeWindow = NULL;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainVideo;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
+ def.format.video.pNativeRender = NULL;
+ def.format.video.nFrameWidth = mWidth;
+ def.format.video.nFrameHeight = mHeight;
+ def.format.video.nStride = def.format.video.nFrameWidth;
+ def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+ def.format.video.nBitrate = 0;
+ def.format.video.xFramerate = 0;
+ def.format.video.bFlagErrorConcealment = OMX_FALSE;
+ def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
+ def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
+ def.format.video.pNativeWindow = NULL;
+
+ def.nBufferSize =
+ (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
+
+ addPort(def);
+}
+
+status_t SoftVPX::initDecoder() {
+ mCtx = new vpx_codec_ctx_t;
+ vpx_codec_err_t vpx_err;
+ if ((vpx_err = vpx_codec_dec_init(
+ (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, NULL, 0))) {
+ LOGE("on2 decoder failed to initialize. (%d)", vpx_err);
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+OMX_ERRORTYPE SoftVPX::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamVideoPortFormat:
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex != 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ if (formatParams->nPortIndex == 0) {
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingVPX;
+ formatParams->eColorFormat = OMX_COLOR_FormatUnused;
+ formatParams->xFramerate = 0;
+ } else {
+ CHECK_EQ(formatParams->nPortIndex, 1u);
+
+ formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
+ formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
+ formatParams->xFramerate = 0;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftVPX::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (strncmp((const char *)roleParams->cRole,
+ "video_decoder.vpx",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamVideoPortFormat:
+ {
+ OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex != 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+void SoftVPX::onQueueFilled(OMX_U32 portIndex) {
+ if (mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
+ }
+
+ if (vpx_codec_decode(
+ (vpx_codec_ctx_t *)mCtx,
+ inHeader->pBuffer + inHeader->nOffset,
+ inHeader->nFilledLen,
+ NULL,
+ 0)) {
+ LOGE("on2 decoder failed to decode frame.");
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ return;
+ }
+
+ vpx_codec_iter_t iter = NULL;
+ vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
+
+ if (img != NULL) {
+ CHECK_EQ(img->fmt, IMG_FMT_I420);
+
+ int32_t width = img->d_w;
+ int32_t height = img->d_h;
+
+ if (width != mWidth || height != mHeight) {
+ mWidth = width;
+ mHeight = height;
+
+ updatePortDefinitions();
+
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ return;
+ }
+
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = (width * height * 3) / 2;
+ outHeader->nFlags = 0;
+ outHeader->nTimeStamp = inHeader->nTimeStamp;
+
+ const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y];
+ uint8_t *dst = outHeader->pBuffer;
+ for (size_t i = 0; i < img->d_h; ++i) {
+ memcpy(dst, srcLine, img->d_w);
+
+ srcLine += img->stride[PLANE_Y];
+ dst += img->d_w;
+ }
+
+ srcLine = (const uint8_t *)img->planes[PLANE_U];
+ for (size_t i = 0; i < img->d_h / 2; ++i) {
+ memcpy(dst, srcLine, img->d_w / 2);
+
+ srcLine += img->stride[PLANE_U];
+ dst += img->d_w / 2;
+ }
+
+ srcLine = (const uint8_t *)img->planes[PLANE_V];
+ for (size_t i = 0; i < img->d_h / 2; ++i) {
+ memcpy(dst, srcLine, img->d_w / 2);
+
+ srcLine += img->stride[PLANE_V];
+ dst += img->d_w / 2;
+ }
+
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+ }
+
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
+}
+
+void SoftVPX::onPortFlushCompleted(OMX_U32 portIndex) {
+}
+
+void SoftVPX::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+ if (portIndex != 1) {
+ return;
+ }
+
+ switch (mOutputPortSettingsChange) {
+ case NONE:
+ break;
+
+ case AWAITING_DISABLED:
+ {
+ CHECK(!enabled);
+ mOutputPortSettingsChange = AWAITING_ENABLED;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+ CHECK(enabled);
+ mOutputPortSettingsChange = NONE;
+ break;
+ }
+ }
+}
+
+void SoftVPX::updatePortDefinitions() {
+ OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
+ def->format.video.nFrameWidth = mWidth;
+ def->format.video.nFrameHeight = mHeight;
+ def->format.video.nStride = def->format.video.nFrameWidth;
+ def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+
+ def = &editPortInfo(1)->mDef;
+ def->format.video.nFrameWidth = mWidth;
+ def->format.video.nFrameHeight = mHeight;
+ def->format.video.nStride = def->format.video.nFrameWidth;
+ def->format.video.nSliceHeight = def->format.video.nFrameHeight;
+
+ def->nBufferSize =
+ (def->format.video.nFrameWidth
+ * def->format.video.nFrameHeight * 3) / 2;
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftVPX(name, callbacks, appData, component);
+}
+
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
new file mode 100644
index 0000000..3e814a2
--- /dev/null
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_VPX_H_
+
+#define SOFT_VPX_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+namespace android {
+
+struct SoftVPX : public SimpleSoftOMXComponent {
+ SoftVPX(const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftVPX();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+private:
+ enum {
+ kNumBuffers = 4
+ };
+
+ void *mCtx;
+
+ int32_t mWidth;
+ int32_t mHeight;
+
+ enum {
+ NONE,
+ AWAITING_DISABLED,
+ AWAITING_ENABLED
+ } mOutputPortSettingsChange;
+
+ void initPorts();
+ status_t initDecoder();
+
+ void updatePortDefinitions();
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftVPX);
+};
+
+} // namespace android
+
+#endif // SOFT_VPX_H_
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
index 5c768c8..06f0079 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -6,8 +6,33 @@ LOCAL_SRC_FILES := \
LOCAL_C_INCLUDES := \
frameworks/base/media/libstagefright/include \
- external/tremolo
+ external/tremolo \
LOCAL_MODULE := libstagefright_vorbisdec
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftVorbis.cpp
+
+LOCAL_C_INCLUDES := \
+ external/tremolo \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_vorbisdec
+
+LOCAL_SHARED_LIBRARIES := \
+ libvorbisidec libstagefright libstagefright_omx \
+ libstagefright_foundation libutils
+
+LOCAL_MODULE := libstagefright_soft_vorbisdec
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
new file mode 100644
index 0000000..4091111
--- /dev/null
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftVorbis"
+#include <utils/Log.h>
+
+#include "SoftVorbis.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+
+extern "C" {
+ #include <Tremolo/codec_internal.h>
+
+ int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
+ int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
+ int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
+}
+
+namespace android {
+
+template<class T>
+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;
+}
+
+SoftVorbis::SoftVorbis(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mInputBufferCount(0),
+ mState(NULL),
+ mVi(NULL),
+ mAnchorTimeUs(0),
+ mNumFramesOutput(0),
+ mNumFramesLeftOnPage(-1),
+ mOutputPortSettingsChange(NONE) {
+ initPorts();
+ CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftVorbis::~SoftVorbis() {
+ if (mState != NULL) {
+ vorbis_dsp_clear(mState);
+ delete mState;
+ mState = NULL;
+ }
+
+ if (mVi != NULL) {
+ vorbis_info_clear(mVi);
+ delete mVi;
+ mVi = NULL;
+ }
+}
+
+void SoftVorbis::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.audio.cMIMEType =
+ const_cast<char *>(MEDIA_MIMETYPE_AUDIO_VORBIS);
+
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+ addPort(def);
+}
+
+status_t SoftVorbis::initDecoder() {
+ return OK;
+}
+
+OMX_ERRORTYPE SoftVorbis::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioVorbis:
+ {
+ OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
+ (OMX_AUDIO_PARAM_VORBISTYPE *)params;
+
+ if (vorbisParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ vorbisParams->nBitRate = 0;
+ vorbisParams->nMinBitRate = 0;
+ vorbisParams->nMaxBitRate = 0;
+ vorbisParams->nAudioBandWidth = 0;
+ vorbisParams->nQuality = 3;
+ vorbisParams->bManaged = OMX_FALSE;
+ vorbisParams->bDownmix = OMX_FALSE;
+
+ if (!isConfigured()) {
+ vorbisParams->nChannels = 1;
+ vorbisParams->nSampleRate = 44100;
+ } else {
+ vorbisParams->nChannels = mVi->channels;
+ vorbisParams->nSampleRate = mVi->rate;
+ vorbisParams->nBitRate = mVi->bitrate_nominal;
+ vorbisParams->nMinBitRate = mVi->bitrate_lower;
+ vorbisParams->nMaxBitRate = mVi->bitrate_upper;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eEndian = OMX_EndianBig;
+ pcmParams->bInterleaved = OMX_TRUE;
+ pcmParams->nBitPerSample = 16;
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+ if (!isConfigured()) {
+ pcmParams->nChannels = 1;
+ pcmParams->nSamplingRate = 44100;
+ } else {
+ pcmParams->nChannels = mVi->channels;
+ pcmParams->nSamplingRate = mVi->rate;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftVorbis::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_decoder.vorbis",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioVorbis:
+ {
+ const OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
+ (const OMX_AUDIO_PARAM_VORBISTYPE *)params;
+
+ if (vorbisParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+bool SoftVorbis::isConfigured() const {
+ return mInputBufferCount >= 2;
+}
+
+static void makeBitReader(
+ const void *data, size_t size,
+ ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) {
+ buf->data = (uint8_t *)data;
+ buf->size = size;
+ buf->refcount = 1;
+ buf->ptr.owner = NULL;
+
+ ref->buffer = buf;
+ ref->begin = 0;
+ ref->length = size;
+ ref->next = NULL;
+
+ oggpack_readinit(bits, ref);
+}
+
+void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ if (mOutputPortSettingsChange != NONE) {
+ return;
+ }
+
+ if (portIndex == 0 && mInputBufferCount < 2) {
+ BufferInfo *info = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *header = info->mHeader;
+
+ const uint8_t *data = header->pBuffer + header->nOffset;
+ size_t size = header->nFilledLen;
+
+ ogg_buffer buf;
+ ogg_reference ref;
+ oggpack_buffer bits;
+
+ makeBitReader(
+ (const uint8_t *)data + 7, size - 7,
+ &buf, &ref, &bits);
+
+ if (mInputBufferCount == 0) {
+ CHECK(mVi == NULL);
+ mVi = new vorbis_info;
+ vorbis_info_init(mVi);
+
+ CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits));
+ } else {
+ CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits));
+
+ CHECK(mState == NULL);
+ mState = new vorbis_dsp_state;
+ CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
+
+ notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+ mOutputPortSettingsChange = AWAITING_DISABLED;
+ }
+
+ inQueue.erase(inQueue.begin());
+ info->mOwnedByUs = false;
+ notifyEmptyBufferDone(header);
+
+ ++mInputBufferCount;
+
+ return;
+ }
+
+ while (!inQueue.empty() && !outQueue.empty()) {
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ outHeader->nFilledLen = 0;
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+ return;
+ }
+
+ int32_t numPageSamples;
+ CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
+ memcpy(&numPageSamples,
+ inHeader->pBuffer
+ + inHeader->nOffset + inHeader->nFilledLen - 4,
+ sizeof(numPageSamples));
+
+ if (numPageSamples >= 0) {
+ mNumFramesLeftOnPage = numPageSamples;
+ }
+
+ if (inHeader->nOffset == 0) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumFramesOutput = 0;
+ }
+
+ inHeader->nFilledLen -= sizeof(numPageSamples);;
+
+ ogg_buffer buf;
+ buf.data = inHeader->pBuffer + inHeader->nOffset;
+ buf.size = inHeader->nFilledLen;
+ buf.refcount = 1;
+ buf.ptr.owner = NULL;
+
+ ogg_reference ref;
+ ref.buffer = &buf;
+ ref.begin = 0;
+ ref.length = buf.size;
+ ref.next = NULL;
+
+ ogg_packet pack;
+ pack.packet = &ref;
+ pack.bytes = ref.length;
+ pack.b_o_s = 0;
+ pack.e_o_s = 0;
+ pack.granulepos = 0;
+ pack.packetno = 0;
+
+ int numFrames = 0;
+
+ int err = vorbis_dsp_synthesis(mState, &pack, 1);
+ if (err != 0) {
+ LOGW("vorbis_dsp_synthesis returned %d", err);
+ } else {
+ numFrames = vorbis_dsp_pcmout(
+ mState, (int16_t *)outHeader->pBuffer,
+ kMaxNumSamplesPerBuffer);
+
+ if (numFrames < 0) {
+ LOGE("vorbis_dsp_pcmout returned %d", numFrames);
+ numFrames = 0;
+ }
+ }
+
+ if (mNumFramesLeftOnPage >= 0) {
+ if (numFrames > mNumFramesLeftOnPage) {
+ LOGV("discarding %d frames at end of page",
+ numFrames - mNumFramesLeftOnPage);
+ numFrames = mNumFramesLeftOnPage;
+ }
+ mNumFramesLeftOnPage -= numFrames;
+ }
+
+ outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels;
+ outHeader->nOffset = 0;
+ outHeader->nFlags = 0;
+
+ outHeader->nTimeStamp =
+ mAnchorTimeUs
+ + (mNumFramesOutput * 1000000ll) / mVi->rate;
+
+ mNumFramesOutput += numFrames;
+
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+
+ outInfo->mOwnedByUs = false;
+ outQueue.erase(outQueue.begin());
+ outInfo = NULL;
+ notifyFillBufferDone(outHeader);
+ outHeader = NULL;
+
+ ++mInputBufferCount;
+ }
+}
+
+void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) {
+ if (portIndex == 0 && mState != NULL) {
+ // Make sure that the next buffer output does not still
+ // depend on fragments from the last one decoded.
+
+ mNumFramesOutput = 0;
+ vorbis_dsp_restart(mState);
+ }
+}
+
+void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+ if (portIndex != 1) {
+ return;
+ }
+
+ switch (mOutputPortSettingsChange) {
+ case NONE:
+ break;
+
+ case AWAITING_DISABLED:
+ {
+ CHECK(!enabled);
+ mOutputPortSettingsChange = AWAITING_ENABLED;
+ break;
+ }
+
+ default:
+ {
+ CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+ CHECK(enabled);
+ mOutputPortSettingsChange = NONE;
+ break;
+ }
+ }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftVorbis(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
new file mode 100644
index 0000000..e252f55
--- /dev/null
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_VORBIS_H_
+
+#define SOFT_VORBIS_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct vorbis_dsp_state;
+struct vorbis_info;
+
+namespace android {
+
+struct SoftVorbis : public SimpleSoftOMXComponent {
+ SoftVorbis(const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftVorbis();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+private:
+ enum {
+ kNumBuffers = 4,
+ kMaxNumSamplesPerBuffer = 8192 * 2
+ };
+
+ size_t mInputBufferCount;
+
+ vorbis_dsp_state *mState;
+ vorbis_info *mVi;
+
+ int64_t mAnchorTimeUs;
+ int64_t mNumFramesOutput;
+ int32_t mNumFramesLeftOnPage;
+
+ enum {
+ NONE,
+ AWAITING_DISABLED,
+ AWAITING_ENABLED
+ } mOutputPortSettingsChange;
+
+ void initPorts();
+ status_t initDecoder();
+ bool isConfigured() const;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftVorbis);
+};
+
+} // namespace android
+
+#endif // SOFT_VORBIS_H_
+
diff --git a/media/libstagefright/include/SimpleSoftOMXComponent.h b/media/libstagefright/include/SimpleSoftOMXComponent.h
new file mode 100644
index 0000000..2a29a7d
--- /dev/null
+++ b/media/libstagefright/include/SimpleSoftOMXComponent.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SIMPLE_SOFT_OMX_COMPONENT_H_
+
+#define SIMPLE_SOFT_OMX_COMPONENT_H_
+
+#include "SoftOMXComponent.h"
+
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct ALooper;
+
+struct SimpleSoftOMXComponent : public SoftOMXComponent {
+ SimpleSoftOMXComponent(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+ virtual ~SimpleSoftOMXComponent();
+
+ void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+ struct BufferInfo {
+ OMX_BUFFERHEADERTYPE *mHeader;
+ bool mOwnedByUs;
+ };
+
+ struct PortInfo {
+ OMX_PARAM_PORTDEFINITIONTYPE mDef;
+ Vector<BufferInfo> mBuffers;
+ List<BufferInfo *> mQueue;
+
+ enum {
+ NONE,
+ DISABLING,
+ ENABLING,
+ } mTransition;
+ };
+
+ void addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def);
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+ List<BufferInfo *> &getPortQueue(OMX_U32 portIndex);
+
+ virtual void onPortFlushCompleted(OMX_U32 portIndex);
+ virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+
+ PortInfo *editPortInfo(OMX_U32 portIndex);
+
+private:
+ enum {
+ kWhatSendCommand,
+ kWhatEmptyThisBuffer,
+ kWhatFillThisBuffer,
+ };
+
+ Mutex mLock;
+
+ sp<ALooper> mLooper;
+ sp<AHandlerReflector<SimpleSoftOMXComponent> > mHandler;
+
+ OMX_STATETYPE mState;
+ OMX_STATETYPE mTargetState;
+
+ Vector<PortInfo> mPorts;
+
+ bool isSetParameterAllowed(
+ OMX_INDEXTYPE index, const OMX_PTR params) const;
+
+ virtual OMX_ERRORTYPE sendCommand(
+ OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data);
+
+ virtual OMX_ERRORTYPE getParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE setParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual OMX_ERRORTYPE useBuffer(
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size,
+ OMX_U8 *ptr);
+
+ virtual OMX_ERRORTYPE allocateBuffer(
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size);
+
+ virtual OMX_ERRORTYPE freeBuffer(
+ OMX_U32 portIndex,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ virtual OMX_ERRORTYPE emptyThisBuffer(
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ virtual OMX_ERRORTYPE fillThisBuffer(
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ virtual OMX_ERRORTYPE getState(OMX_STATETYPE *state);
+
+ void onSendCommand(OMX_COMMANDTYPE cmd, OMX_U32 param);
+ void onChangeState(OMX_STATETYPE state);
+ void onPortEnable(OMX_U32 portIndex, bool enable);
+ void onPortFlush(OMX_U32 portIndex, bool sendFlushComplete);
+
+ void checkTransitions();
+
+ DISALLOW_EVIL_CONSTRUCTORS(SimpleSoftOMXComponent);
+};
+
+} // namespace android
+
+#endif // SIMPLE_SOFT_OMX_COMPONENT_H_
diff --git a/media/libstagefright/include/SoftOMXComponent.h b/media/libstagefright/include/SoftOMXComponent.h
new file mode 100644
index 0000000..053bc22
--- /dev/null
+++ b/media/libstagefright/include/SoftOMXComponent.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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.
+ */
+
+#ifndef SOFT_OMX_COMPONENT_H_
+
+#define SOFT_OMX_COMPONENT_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AString.h>
+#include <utils/RefBase.h>
+
+#include <OMX_Component.h>
+
+namespace android {
+
+struct SoftOMXComponent : public RefBase {
+ SoftOMXComponent(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+ virtual OMX_ERRORTYPE initCheck() const;
+
+ void setLibHandle(void *libHandle);
+ void *libHandle() const;
+
+protected:
+ virtual ~SoftOMXComponent();
+
+ const char *name() const;
+
+ void notify(
+ OMX_EVENTTYPE event,
+ OMX_U32 data1, OMX_U32 data2, OMX_PTR data);
+
+ void notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header);
+ void notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header);
+
+ virtual OMX_ERRORTYPE sendCommand(
+ OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data);
+
+ virtual OMX_ERRORTYPE getParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE setParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual OMX_ERRORTYPE getConfig(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE setConfig(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual OMX_ERRORTYPE getExtensionIndex(
+ const char *name, OMX_INDEXTYPE *index);
+
+ virtual OMX_ERRORTYPE useBuffer(
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size,
+ OMX_U8 *ptr);
+
+ virtual OMX_ERRORTYPE allocateBuffer(
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size);
+
+ virtual OMX_ERRORTYPE freeBuffer(
+ OMX_U32 portIndex,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ virtual OMX_ERRORTYPE emptyThisBuffer(
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ virtual OMX_ERRORTYPE fillThisBuffer(
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ virtual OMX_ERRORTYPE getState(OMX_STATETYPE *state);
+
+private:
+ AString mName;
+ const OMX_CALLBACKTYPE *mCallbacks;
+ OMX_COMPONENTTYPE *mComponent;
+
+ void *mLibHandle;
+
+ static OMX_ERRORTYPE SendCommandWrapper(
+ OMX_HANDLETYPE component,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param,
+ OMX_PTR data);
+
+ static OMX_ERRORTYPE GetParameterWrapper(
+ OMX_HANDLETYPE component,
+ OMX_INDEXTYPE index,
+ OMX_PTR params);
+
+ static OMX_ERRORTYPE SetParameterWrapper(
+ OMX_HANDLETYPE component,
+ OMX_INDEXTYPE index,
+ OMX_PTR params);
+
+ static OMX_ERRORTYPE GetConfigWrapper(
+ OMX_HANDLETYPE component,
+ OMX_INDEXTYPE index,
+ OMX_PTR params);
+
+ static OMX_ERRORTYPE SetConfigWrapper(
+ OMX_HANDLETYPE component,
+ OMX_INDEXTYPE index,
+ OMX_PTR params);
+
+ static OMX_ERRORTYPE GetExtensionIndexWrapper(
+ OMX_HANDLETYPE component,
+ OMX_STRING name,
+ OMX_INDEXTYPE *index);
+
+ static OMX_ERRORTYPE UseBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size,
+ OMX_U8 *ptr);
+
+ static OMX_ERRORTYPE AllocateBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size);
+
+ static OMX_ERRORTYPE FreeBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_U32 portIndex,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ static OMX_ERRORTYPE EmptyThisBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ static OMX_ERRORTYPE FillThisBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE *buffer);
+
+ static OMX_ERRORTYPE GetStateWrapper(
+ OMX_HANDLETYPE component,
+ OMX_STATETYPE *state);
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftOMXComponent);
+};
+
+} // namespace android
+
+#endif // SOFT_OMX_COMPONENT_H_
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 6e069c8..08ad6f3 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -1,41 +1,28 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-ifneq ($(BUILD_WITHOUT_PV),true)
-# Set up the OpenCore variables.
-include external/opencore/Config.mk
-LOCAL_C_INCLUDES := $(PV_INCLUDES)
-LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
-endif
-
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_SRC_FILES:= \
- OMX.cpp \
+ OMX.cpp \
OMXComponentBase.cpp \
+ OMXMaster.cpp \
OMXNodeInstance.cpp \
- OMXMaster.cpp
-
-ifneq ($(BUILD_WITHOUT_PV),true)
-LOCAL_SRC_FILES += \
- OMXPVCodecsPlugin.cpp
-else
-LOCAL_CFLAGS += -DNO_OPENCORE
-endif
-
-LOCAL_C_INCLUDES += $(TOP)/frameworks/base/include/media/stagefright/openmax
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libmedia \
- libutils \
- libui \
- libcutils \
-
-ifneq ($(BUILD_WITHOUT_PV),true)
-LOCAL_SHARED_LIBRARIES += \
- libopencore_common
-endif
+ SimpleSoftOMXComponent.cpp \
+ SoftOMXComponent.cpp \
+ SoftOMXPlugin.cpp \
+
+LOCAL_C_INCLUDES += \
+ frameworks/base/media/libstagefright \
+ $(TOP)/frameworks/base/include/media/stagefright/openmax
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libmedia \
+ libutils \
+ libui \
+ libcutils \
+ libstagefright_foundation \
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
LOCAL_LDLIBS += -lpthread -ldl
@@ -49,5 +36,6 @@ LOCAL_MODULE:= libstagefright_omx
include $(BUILD_SHARED_LIBRARY)
-include $(call all-makefiles-under,$(LOCAL_PATH))
+################################################################################
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index 56b169a..545e6d4 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -20,23 +20,18 @@
#include "OMXMaster.h"
+#include "SoftOMXPlugin.h"
+
#include <dlfcn.h>
#include <media/stagefright/MediaDebug.h>
-#ifndef NO_OPENCORE
-#include "OMXPVCodecsPlugin.h"
-#endif
-
namespace android {
OMXMaster::OMXMaster()
: mVendorLibHandle(NULL) {
addVendorPlugin();
-
-#ifndef NO_OPENCORE
- addPlugin(new OMXPVCodecsPlugin);
-#endif
+ addPlugin(new SoftOMXPlugin);
}
OMXMaster::~OMXMaster() {
@@ -49,7 +44,11 @@ OMXMaster::~OMXMaster() {
}
void OMXMaster::addVendorPlugin() {
- mVendorLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
+ addPlugin("libstagefrighthw.so");
+}
+
+void OMXMaster::addPlugin(const char *libname) {
+ mVendorLibHandle = dlopen(libname, RTLD_NOW);
if (mVendorLibHandle == NULL) {
return;
diff --git a/media/libstagefright/omx/OMXMaster.h b/media/libstagefright/omx/OMXMaster.h
index 7ba8d18..feee1f9 100644
--- a/media/libstagefright/omx/OMXMaster.h
+++ b/media/libstagefright/omx/OMXMaster.h
@@ -58,6 +58,7 @@ private:
void *mVendorLibHandle;
void addVendorPlugin();
+ void addPlugin(const char *libname);
void addPlugin(OMXPluginBase *plugin);
void clearPlugins();
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index cdce772..8462988 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -234,6 +234,7 @@ status_t OMXNodeInstance::getParameter(
Mutex::Autolock autoLock(mLock);
OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
+
return StatusFromOMXError(err);
}
diff --git a/media/libstagefright/omx/OMXPVCodecsPlugin.cpp b/media/libstagefright/omx/OMXPVCodecsPlugin.cpp
deleted file mode 100644
index d1f5be3..0000000
--- a/media/libstagefright/omx/OMXPVCodecsPlugin.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source 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.
- */
-
-#include "OMXPVCodecsPlugin.h"
-
-#include "pv_omxcore.h"
-
-#include <media/stagefright/MediaDebug.h>
-
-namespace android {
-
-OMXPVCodecsPlugin::OMXPVCodecsPlugin() {
- OMX_MasterInit();
-}
-
-OMXPVCodecsPlugin::~OMXPVCodecsPlugin() {
- OMX_MasterDeinit();
-}
-
-OMX_ERRORTYPE OMXPVCodecsPlugin::makeComponentInstance(
- const char *name,
- const OMX_CALLBACKTYPE *callbacks,
- OMX_PTR appData,
- OMX_COMPONENTTYPE **component) {
- return OMX_MasterGetHandle(
- reinterpret_cast<OMX_HANDLETYPE *>(component),
- const_cast<char *>(name),
- appData,
- const_cast<OMX_CALLBACKTYPE *>(callbacks));
-}
-
-OMX_ERRORTYPE OMXPVCodecsPlugin::destroyComponentInstance(
- OMX_COMPONENTTYPE *component) {
- return OMX_MasterFreeHandle(component);
-}
-
-OMX_ERRORTYPE OMXPVCodecsPlugin::enumerateComponents(
- OMX_STRING name,
- size_t size,
- OMX_U32 index) {
- return OMX_MasterComponentNameEnum(name, size, index);
-}
-
-OMX_ERRORTYPE OMXPVCodecsPlugin::getRolesOfComponent(
- const char *name,
- Vector<String8> *roles) {
- roles->clear();
-
- OMX_U32 numRoles;
- OMX_ERRORTYPE err =
- OMX_MasterGetRolesOfComponent(
- const_cast<char *>(name),
- &numRoles,
- NULL);
-
- if (err != OMX_ErrorNone) {
- return err;
- }
-
- if (numRoles > 0) {
- OMX_U8 **array = new OMX_U8 *[numRoles];
- for (OMX_U32 i = 0; i < numRoles; ++i) {
- array[i] = new OMX_U8[OMX_MAX_STRINGNAME_SIZE];
- }
-
- OMX_U32 numRoles2;
- err = OMX_MasterGetRolesOfComponent(
- const_cast<char *>(name), &numRoles2, array);
-
- CHECK_EQ(err, OMX_ErrorNone);
- CHECK_EQ(numRoles, numRoles2);
-
- for (OMX_U32 i = 0; i < numRoles; ++i) {
- String8 s((const char *)array[i]);
- roles->push(s);
-
- delete[] array[i];
- array[i] = NULL;
- }
-
- delete[] array;
- array = NULL;
- }
-
- return OMX_ErrorNone;
-}
-
-} // namespace android
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
new file mode 100644
index 0000000..179b2a0
--- /dev/null
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SimpleSoftOMXComponent"
+#include <utils/Log.h>
+
+#include "include/SimpleSoftOMXComponent.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+SimpleSoftOMXComponent::SimpleSoftOMXComponent(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SoftOMXComponent(name, callbacks, appData, component),
+ mLooper(new ALooper),
+ mHandler(new AHandlerReflector<SimpleSoftOMXComponent>(this)),
+ mState(OMX_StateLoaded),
+ mTargetState(OMX_StateLoaded) {
+ mLooper->setName(name);
+ mLooper->registerHandler(mHandler);
+
+ mLooper->start(
+ false, // runOnCallingThread
+ false, // canCallJava
+ PRIORITY_AUDIO);
+}
+
+SimpleSoftOMXComponent::~SimpleSoftOMXComponent() {
+ mLooper->unregisterHandler(mHandler->id());
+ mLooper->stop();
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::sendCommand(
+ OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {
+ CHECK(data == NULL);
+
+ sp<AMessage> msg = new AMessage(kWhatSendCommand, mHandler->id());
+ msg->setInt32("cmd", cmd);
+ msg->setInt32("param", param);
+ msg->post();
+
+ return OMX_ErrorNone;
+}
+
+bool SimpleSoftOMXComponent::isSetParameterAllowed(
+ OMX_INDEXTYPE index, const OMX_PTR params) const {
+ if (mState == OMX_StateLoaded) {
+ return true;
+ }
+
+ OMX_U32 portIndex;
+
+ switch (index) {
+ case OMX_IndexParamPortDefinition:
+ {
+ portIndex = ((OMX_PARAM_PORTDEFINITIONTYPE *)params)->nPortIndex;
+ break;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ portIndex = ((OMX_AUDIO_PARAM_PCMMODETYPE *)params)->nPortIndex;
+ break;
+ }
+
+ case OMX_IndexParamAudioAac:
+ {
+ portIndex = ((OMX_AUDIO_PARAM_AACPROFILETYPE *)params)->nPortIndex;
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ CHECK(portIndex < mPorts.size());
+
+ return !mPorts.itemAt(portIndex).mDef.bEnabled;
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::getParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ Mutex::Autolock autoLock(mLock);
+ return internalGetParameter(index, params);
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::setParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ Mutex::Autolock autoLock(mLock);
+
+ CHECK(isSetParameterAllowed(index, params));
+
+ return internalSetParameter(index, params);
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *defParams =
+ (OMX_PARAM_PORTDEFINITIONTYPE *)params;
+
+ if (defParams->nPortIndex >= mPorts.size()
+ || defParams->nSize
+ != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
+ return OMX_ErrorUndefined;
+ }
+
+ const PortInfo *port =
+ &mPorts.itemAt(defParams->nPortIndex);
+
+ memcpy(defParams, &port->mDef, sizeof(port->mDef));
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return OMX_ErrorUnsupportedIndex;
+ }
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamPortDefinition:
+ {
+ OMX_PARAM_PORTDEFINITIONTYPE *defParams =
+ (OMX_PARAM_PORTDEFINITIONTYPE *)params;
+
+ if (defParams->nPortIndex >= mPorts.size()
+ || defParams->nSize
+ != sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
+ return OMX_ErrorUndefined;
+ }
+
+ PortInfo *port =
+ &mPorts.editItemAt(defParams->nPortIndex);
+
+ if (defParams->nBufferSize != port->mDef.nBufferSize) {
+ CHECK_GE(defParams->nBufferSize, port->mDef.nBufferSize);
+ port->mDef.nBufferSize = defParams->nBufferSize;
+ }
+
+ if (defParams->nBufferCountActual
+ != port->mDef.nBufferCountActual) {
+ CHECK_GE(defParams->nBufferCountActual,
+ port->mDef.nBufferCountMin);
+
+ port->mDef.nBufferCountActual = defParams->nBufferCountActual;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return OMX_ErrorUnsupportedIndex;
+ }
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::useBuffer(
+ OMX_BUFFERHEADERTYPE **header,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size,
+ OMX_U8 *ptr) {
+ Mutex::Autolock autoLock(mLock);
+ CHECK_LT(portIndex, mPorts.size());
+
+ *header = new OMX_BUFFERHEADERTYPE;
+ (*header)->nSize = sizeof(OMX_BUFFERHEADERTYPE);
+ (*header)->nVersion.s.nVersionMajor = 1;
+ (*header)->nVersion.s.nVersionMinor = 0;
+ (*header)->nVersion.s.nRevision = 0;
+ (*header)->nVersion.s.nStep = 0;
+ (*header)->pBuffer = ptr;
+ (*header)->nAllocLen = size;
+ (*header)->nFilledLen = 0;
+ (*header)->nOffset = 0;
+ (*header)->pAppPrivate = appPrivate;
+ (*header)->pPlatformPrivate = NULL;
+ (*header)->pInputPortPrivate = NULL;
+ (*header)->pOutputPortPrivate = NULL;
+ (*header)->hMarkTargetComponent = NULL;
+ (*header)->pMarkData = NULL;
+ (*header)->nTickCount = 0;
+ (*header)->nTimeStamp = 0;
+ (*header)->nFlags = 0;
+ (*header)->nOutputPortIndex = portIndex;
+ (*header)->nInputPortIndex = portIndex;
+
+ PortInfo *port = &mPorts.editItemAt(portIndex);
+
+ CHECK(mState == OMX_StateLoaded || port->mDef.bEnabled == OMX_FALSE);
+
+ CHECK_LT(port->mBuffers.size(), port->mDef.nBufferCountActual);
+
+ port->mBuffers.push();
+
+ BufferInfo *buffer =
+ &port->mBuffers.editItemAt(port->mBuffers.size() - 1);
+
+ buffer->mHeader = *header;
+ buffer->mOwnedByUs = false;
+
+ if (port->mBuffers.size() == port->mDef.nBufferCountActual) {
+ port->mDef.bPopulated = OMX_TRUE;
+ checkTransitions();
+ }
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::allocateBuffer(
+ OMX_BUFFERHEADERTYPE **header,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size) {
+ OMX_U8 *ptr = new OMX_U8[size];
+
+ OMX_ERRORTYPE err =
+ useBuffer(header, portIndex, appPrivate, size, ptr);
+
+ if (err != OMX_ErrorNone) {
+ delete[] ptr;
+ ptr = NULL;
+
+ return err;
+ }
+
+ CHECK((*header)->pPlatformPrivate == NULL);
+ (*header)->pPlatformPrivate = ptr;
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::freeBuffer(
+ OMX_U32 portIndex,
+ OMX_BUFFERHEADERTYPE *header) {
+ Mutex::Autolock autoLock(mLock);
+
+ CHECK_LT(portIndex, mPorts.size());
+
+ PortInfo *port = &mPorts.editItemAt(portIndex);
+
+#if 0 // XXX
+ CHECK((mState == OMX_StateIdle && mTargetState == OMX_StateLoaded)
+ || port->mDef.bEnabled == OMX_FALSE);
+#endif
+
+ bool found = false;
+ for (size_t i = 0; i < port->mBuffers.size(); ++i) {
+ BufferInfo *buffer = &port->mBuffers.editItemAt(i);
+
+ if (buffer->mHeader == header) {
+ CHECK(!buffer->mOwnedByUs);
+
+ if (header->pPlatformPrivate != NULL) {
+ // This buffer's data was allocated by us.
+ CHECK(header->pPlatformPrivate == header->pBuffer);
+
+ delete[] header->pBuffer;
+ header->pBuffer = NULL;
+ }
+
+ delete header;
+ header = NULL;
+
+ port->mBuffers.removeAt(i);
+ port->mDef.bPopulated = OMX_FALSE;
+
+ checkTransitions();
+
+ found = true;
+ break;
+ }
+ }
+
+ CHECK(found);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
+ OMX_BUFFERHEADERTYPE *buffer) {
+ sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler->id());
+ msg->setPointer("header", buffer);
+ msg->post();
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::fillThisBuffer(
+ OMX_BUFFERHEADERTYPE *buffer) {
+ sp<AMessage> msg = new AMessage(kWhatFillThisBuffer, mHandler->id());
+ msg->setPointer("header", buffer);
+ msg->post();
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SimpleSoftOMXComponent::getState(OMX_STATETYPE *state) {
+ Mutex::Autolock autoLock(mLock);
+
+ *state = mState;
+
+ return OMX_ErrorNone;
+}
+
+void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
+ Mutex::Autolock autoLock(mLock);
+
+ switch (msg->what()) {
+ case kWhatSendCommand:
+ {
+ int32_t cmd, param;
+ CHECK(msg->findInt32("cmd", &cmd));
+ CHECK(msg->findInt32("param", &param));
+
+ onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param);
+ break;
+ }
+
+ case kWhatEmptyThisBuffer:
+ case kWhatFillThisBuffer:
+ {
+ OMX_BUFFERHEADERTYPE *header;
+ CHECK(msg->findPointer("header", (void **)&header));
+
+ CHECK(mState == OMX_StateExecuting && mTargetState == mState);
+
+ bool found = false;
+ for (size_t i = 0; i < mPorts.size(); ++i) {
+ PortInfo *port = &mPorts.editItemAt(i);
+
+ for (size_t j = 0; j < port->mBuffers.size(); ++j) {
+ BufferInfo *buffer = &port->mBuffers.editItemAt(j);
+
+ if (buffer->mHeader == header) {
+ CHECK(!buffer->mOwnedByUs);
+
+ buffer->mOwnedByUs = true;
+
+ CHECK((msg->what() == kWhatEmptyThisBuffer
+ && port->mDef.eDir == OMX_DirInput)
+ || (port->mDef.eDir == OMX_DirOutput));
+
+ port->mQueue.push_back(buffer);
+ onQueueFilled(i);
+
+ found = true;
+ break;
+ }
+ }
+ }
+
+ CHECK(found);
+ break;
+ }
+
+ default:
+ TRESPASS();
+ break;
+ }
+}
+
+void SimpleSoftOMXComponent::onSendCommand(
+ OMX_COMMANDTYPE cmd, OMX_U32 param) {
+ switch (cmd) {
+ case OMX_CommandStateSet:
+ {
+ onChangeState((OMX_STATETYPE)param);
+ break;
+ }
+
+ case OMX_CommandPortEnable:
+ case OMX_CommandPortDisable:
+ {
+ onPortEnable(param, cmd == OMX_CommandPortEnable);
+ break;
+ }
+
+ case OMX_CommandFlush:
+ {
+ onPortFlush(param, true /* sendFlushComplete */);
+ break;
+ }
+
+ default:
+ TRESPASS();
+ break;
+ }
+}
+
+void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) {
+ // We shouldn't be in a state transition already.
+ CHECK_EQ((int)mState, (int)mTargetState);
+
+ switch (mState) {
+ case OMX_StateLoaded:
+ CHECK_EQ((int)state, (int)OMX_StateIdle);
+ break;
+ case OMX_StateIdle:
+ CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting);
+ break;
+ case OMX_StateExecuting:
+ {
+ CHECK_EQ((int)state, (int)OMX_StateIdle);
+
+ for (size_t i = 0; i < mPorts.size(); ++i) {
+ onPortFlush(i, false /* sendFlushComplete */);
+ }
+
+ mState = OMX_StateIdle;
+ notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL);
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+
+ mTargetState = state;
+
+ checkTransitions();
+}
+
+void SimpleSoftOMXComponent::onPortEnable(OMX_U32 portIndex, bool enable) {
+ CHECK_LT(portIndex, mPorts.size());
+
+ PortInfo *port = &mPorts.editItemAt(portIndex);
+ CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
+ CHECK(port->mDef.bEnabled == !enable);
+
+ if (!enable) {
+ port->mDef.bEnabled = OMX_FALSE;
+ port->mTransition = PortInfo::DISABLING;
+
+ for (size_t i = 0; i < port->mBuffers.size(); ++i) {
+ BufferInfo *buffer = &port->mBuffers.editItemAt(i);
+
+ if (buffer->mOwnedByUs) {
+ buffer->mOwnedByUs = false;
+
+ if (port->mDef.eDir == OMX_DirInput) {
+ notifyEmptyBufferDone(buffer->mHeader);
+ } else {
+ CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
+ notifyFillBufferDone(buffer->mHeader);
+ }
+ }
+ }
+
+ port->mQueue.clear();
+ } else {
+ port->mTransition = PortInfo::ENABLING;
+ }
+
+ checkTransitions();
+}
+
+void SimpleSoftOMXComponent::onPortFlush(
+ OMX_U32 portIndex, bool sendFlushComplete) {
+ if (portIndex == OMX_ALL) {
+ for (size_t i = 0; i < mPorts.size(); ++i) {
+ onPortFlush(i, sendFlushComplete);
+ }
+
+ if (sendFlushComplete) {
+ notify(OMX_EventCmdComplete, OMX_CommandFlush, OMX_ALL, NULL);
+ }
+
+ return;
+ }
+
+ CHECK_LT(portIndex, mPorts.size());
+
+ PortInfo *port = &mPorts.editItemAt(portIndex);
+ CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
+
+ for (size_t i = 0; i < port->mBuffers.size(); ++i) {
+ BufferInfo *buffer = &port->mBuffers.editItemAt(i);
+
+ if (!buffer->mOwnedByUs) {
+ continue;
+ }
+
+ buffer->mHeader->nFilledLen = 0;
+ buffer->mHeader->nOffset = 0;
+ buffer->mHeader->nFlags = 0;
+
+ buffer->mOwnedByUs = false;
+
+ if (port->mDef.eDir == OMX_DirInput) {
+ notifyEmptyBufferDone(buffer->mHeader);
+ } else {
+ CHECK_EQ(port->mDef.eDir, OMX_DirOutput);
+
+ notifyFillBufferDone(buffer->mHeader);
+ }
+ }
+
+ port->mQueue.clear();
+
+ if (sendFlushComplete) {
+ notify(OMX_EventCmdComplete, OMX_CommandFlush, portIndex, NULL);
+
+ onPortFlushCompleted(portIndex);
+ }
+}
+
+void SimpleSoftOMXComponent::checkTransitions() {
+ if (mState != mTargetState) {
+ bool transitionComplete = true;
+
+ if (mState == OMX_StateLoaded) {
+ CHECK_EQ((int)mTargetState, (int)OMX_StateIdle);
+
+ for (size_t i = 0; i < mPorts.size(); ++i) {
+ const PortInfo &port = mPorts.itemAt(i);
+ if (port.mDef.bEnabled == OMX_FALSE) {
+ continue;
+ }
+
+ if (port.mDef.bPopulated == OMX_FALSE) {
+ transitionComplete = false;
+ break;
+ }
+ }
+ } else if (mTargetState == OMX_StateLoaded) {
+ CHECK_EQ((int)mState, (int)OMX_StateIdle);
+
+ for (size_t i = 0; i < mPorts.size(); ++i) {
+ const PortInfo &port = mPorts.itemAt(i);
+ if (port.mDef.bEnabled == OMX_FALSE) {
+ continue;
+ }
+
+ size_t n = port.mBuffers.size();
+
+ if (n > 0) {
+ CHECK_LE(n, port.mDef.nBufferCountActual);
+
+ if (n == port.mDef.nBufferCountActual) {
+ CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_TRUE);
+ } else {
+ CHECK_EQ((int)port.mDef.bPopulated, (int)OMX_FALSE);
+ }
+
+ transitionComplete = false;
+ break;
+ }
+ }
+ }
+
+ if (transitionComplete) {
+ mState = mTargetState;
+
+ notify(OMX_EventCmdComplete, OMX_CommandStateSet, mState, NULL);
+ }
+ }
+
+ for (size_t i = 0; i < mPorts.size(); ++i) {
+ PortInfo *port = &mPorts.editItemAt(i);
+
+ if (port->mTransition == PortInfo::DISABLING) {
+ if (port->mBuffers.empty()) {
+ LOGV("Port %d now disabled.", i);
+
+ port->mTransition = PortInfo::NONE;
+ notify(OMX_EventCmdComplete, OMX_CommandPortDisable, i, NULL);
+
+ onPortEnableCompleted(i, false /* enabled */);
+ }
+ } else if (port->mTransition == PortInfo::ENABLING) {
+ if (port->mDef.bPopulated == OMX_TRUE) {
+ LOGV("Port %d now enabled.", i);
+
+ port->mTransition = PortInfo::NONE;
+ port->mDef.bEnabled = OMX_TRUE;
+ notify(OMX_EventCmdComplete, OMX_CommandPortEnable, i, NULL);
+
+ onPortEnableCompleted(i, true /* enabled */);
+ }
+ }
+ }
+}
+
+void SimpleSoftOMXComponent::addPort(const OMX_PARAM_PORTDEFINITIONTYPE &def) {
+ CHECK_EQ(def.nPortIndex, mPorts.size());
+
+ mPorts.push();
+ PortInfo *info = &mPorts.editItemAt(mPorts.size() - 1);
+ info->mDef = def;
+ info->mTransition = PortInfo::NONE;
+}
+
+void SimpleSoftOMXComponent::onQueueFilled(OMX_U32 portIndex) {
+}
+
+void SimpleSoftOMXComponent::onPortFlushCompleted(OMX_U32 portIndex) {
+}
+
+void SimpleSoftOMXComponent::onPortEnableCompleted(
+ OMX_U32 portIndex, bool enabled) {
+}
+
+List<SimpleSoftOMXComponent::BufferInfo *> &
+SimpleSoftOMXComponent::getPortQueue(OMX_U32 portIndex) {
+ CHECK_LT(portIndex, mPorts.size());
+ return mPorts.editItemAt(portIndex).mQueue;
+}
+
+SimpleSoftOMXComponent::PortInfo *SimpleSoftOMXComponent::editPortInfo(
+ OMX_U32 portIndex) {
+ CHECK_LT(portIndex, mPorts.size());
+ return &mPorts.editItemAt(portIndex);
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/SoftOMXComponent.cpp b/media/libstagefright/omx/SoftOMXComponent.cpp
new file mode 100644
index 0000000..b1c34dc
--- /dev/null
+++ b/media/libstagefright/omx/SoftOMXComponent.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftOMXComponent"
+#include <utils/Log.h>
+
+#include "include/SoftOMXComponent.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+SoftOMXComponent::SoftOMXComponent(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : mName(name),
+ mCallbacks(callbacks),
+ mComponent(new OMX_COMPONENTTYPE),
+ mLibHandle(NULL) {
+ mComponent->nSize = sizeof(*mComponent);
+ mComponent->nVersion.s.nVersionMajor = 1;
+ mComponent->nVersion.s.nVersionMinor = 0;
+ mComponent->nVersion.s.nRevision = 0;
+ mComponent->nVersion.s.nStep = 0;
+ mComponent->pComponentPrivate = this;
+ mComponent->pApplicationPrivate = appData;
+
+ mComponent->GetComponentVersion = NULL;
+ mComponent->SendCommand = SendCommandWrapper;
+ mComponent->GetParameter = GetParameterWrapper;
+ mComponent->SetParameter = SetParameterWrapper;
+ mComponent->GetConfig = GetConfigWrapper;
+ mComponent->SetConfig = SetConfigWrapper;
+ mComponent->GetExtensionIndex = GetExtensionIndexWrapper;
+ mComponent->GetState = GetStateWrapper;
+ mComponent->ComponentTunnelRequest = NULL;
+ mComponent->UseBuffer = UseBufferWrapper;
+ mComponent->AllocateBuffer = AllocateBufferWrapper;
+ mComponent->FreeBuffer = FreeBufferWrapper;
+ mComponent->EmptyThisBuffer = EmptyThisBufferWrapper;
+ mComponent->FillThisBuffer = FillThisBufferWrapper;
+ mComponent->SetCallbacks = NULL;
+ mComponent->ComponentDeInit = NULL;
+ mComponent->UseEGLImage = NULL;
+ mComponent->ComponentRoleEnum = NULL;
+
+ *component = mComponent;
+}
+
+SoftOMXComponent::~SoftOMXComponent() {
+ delete mComponent;
+ mComponent = NULL;
+}
+
+void SoftOMXComponent::setLibHandle(void *libHandle) {
+ CHECK(libHandle != NULL);
+ mLibHandle = libHandle;
+}
+
+void *SoftOMXComponent::libHandle() const {
+ return mLibHandle;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::initCheck() const {
+ return OMX_ErrorNone;
+}
+
+const char *SoftOMXComponent::name() const {
+ return mName.c_str();
+}
+
+void SoftOMXComponent::notify(
+ OMX_EVENTTYPE event,
+ OMX_U32 data1, OMX_U32 data2, OMX_PTR data) {
+ (*mCallbacks->EventHandler)(
+ mComponent,
+ mComponent->pApplicationPrivate,
+ event,
+ data1,
+ data2,
+ data);
+}
+
+void SoftOMXComponent::notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header) {
+ (*mCallbacks->EmptyBufferDone)(
+ mComponent, mComponent->pApplicationPrivate, header);
+}
+
+void SoftOMXComponent::notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header) {
+ (*mCallbacks->FillBufferDone)(
+ mComponent, mComponent->pApplicationPrivate, header);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::SendCommandWrapper(
+ OMX_HANDLETYPE component,
+ OMX_COMMANDTYPE cmd,
+ OMX_U32 param,
+ OMX_PTR data) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->sendCommand(cmd, param, data);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::GetParameterWrapper(
+ OMX_HANDLETYPE component,
+ OMX_INDEXTYPE index,
+ OMX_PTR params) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->getParameter(index, params);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::SetParameterWrapper(
+ OMX_HANDLETYPE component,
+ OMX_INDEXTYPE index,
+ OMX_PTR params) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->setParameter(index, params);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::GetConfigWrapper(
+ OMX_HANDLETYPE component,
+ OMX_INDEXTYPE index,
+ OMX_PTR params) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->getConfig(index, params);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::SetConfigWrapper(
+ OMX_HANDLETYPE component,
+ OMX_INDEXTYPE index,
+ OMX_PTR params) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->setConfig(index, params);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::GetExtensionIndexWrapper(
+ OMX_HANDLETYPE component,
+ OMX_STRING name,
+ OMX_INDEXTYPE *index) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->getExtensionIndex(name, index);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::UseBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size,
+ OMX_U8 *ptr) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->useBuffer(buffer, portIndex, appPrivate, size, ptr);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::AllocateBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->allocateBuffer(buffer, portIndex, appPrivate, size);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::FreeBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_U32 portIndex,
+ OMX_BUFFERHEADERTYPE *buffer) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->freeBuffer(portIndex, buffer);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::EmptyThisBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE *buffer) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->emptyThisBuffer(buffer);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::FillThisBufferWrapper(
+ OMX_HANDLETYPE component,
+ OMX_BUFFERHEADERTYPE *buffer) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->fillThisBuffer(buffer);
+}
+
+// static
+OMX_ERRORTYPE SoftOMXComponent::GetStateWrapper(
+ OMX_HANDLETYPE component,
+ OMX_STATETYPE *state) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ return me->getState(state);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+OMX_ERRORTYPE SoftOMXComponent::sendCommand(
+ OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::getParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::setParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::getConfig(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::setConfig(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::getExtensionIndex(
+ const char *name, OMX_INDEXTYPE *index) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::useBuffer(
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size,
+ OMX_U8 *ptr) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::allocateBuffer(
+ OMX_BUFFERHEADERTYPE **buffer,
+ OMX_U32 portIndex,
+ OMX_PTR appPrivate,
+ OMX_U32 size) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::freeBuffer(
+ OMX_U32 portIndex,
+ OMX_BUFFERHEADERTYPE *buffer) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::emptyThisBuffer(
+ OMX_BUFFERHEADERTYPE *buffer) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::fillThisBuffer(
+ OMX_BUFFERHEADERTYPE *buffer) {
+ return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE SoftOMXComponent::getState(OMX_STATETYPE *state) {
+ return OMX_ErrorUndefined;
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
new file mode 100644
index 0000000..6bd6624
--- /dev/null
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 "SoftOMXPlugin"
+#include <utils/Log.h>
+
+#include "SoftOMXPlugin.h"
+#include "include/SoftOMXComponent.h"
+
+#include <media/stagefright/foundation/AString.h>
+
+#include <dlfcn.h>
+
+namespace android {
+
+static const struct {
+ const char *mName;
+ const char *mLibNameSuffix;
+ const char *mRole;
+
+} kComponents[] = {
+ { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
+ { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },
+ { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },
+ { "OMX.google.avc.decoder", "avcdec", "video_decoder.avc" },
+ { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },
+ { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },
+ { "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" },
+ { "OMX.google.mpeg4.decoder", "mpeg4dec", "video_decoder.mpeg4" },
+ { "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" },
+ { "OMX.google.vorbis.decoder", "vorbisdec", "audio_decoder.vorbis" },
+ { "OMX.google.vpx.decoder", "vpxdec", "video_decoder.vpx" },
+};
+
+static const size_t kNumComponents =
+ sizeof(kComponents) / sizeof(kComponents[0]);
+
+SoftOMXPlugin::SoftOMXPlugin() {
+}
+
+OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component) {
+ LOGV("makeComponentInstance '%s'", name);
+
+ for (size_t i = 0; i < kNumComponents; ++i) {
+ if (strcmp(name, kComponents[i].mName)) {
+ continue;
+ }
+
+ AString libName = "libstagefright_soft_";
+ libName.append(kComponents[i].mLibNameSuffix);
+ libName.append(".so");
+
+ void *libHandle = dlopen(libName.c_str(), RTLD_NOW);
+
+ if (libHandle == NULL) {
+ LOGE("unable to dlopen %s", libName.c_str());
+
+ return OMX_ErrorComponentNotFound;
+ }
+
+ typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)(
+ const char *, const OMX_CALLBACKTYPE *,
+ OMX_PTR, OMX_COMPONENTTYPE **);
+
+ CreateSoftOMXComponentFunc createSoftOMXComponent =
+ (CreateSoftOMXComponentFunc)dlsym(
+ libHandle,
+ "_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"
+ "PvPP17OMX_COMPONENTTYPE");
+
+ if (createSoftOMXComponent == NULL) {
+ dlclose(libHandle);
+ libHandle = NULL;
+
+ return OMX_ErrorComponentNotFound;
+ }
+
+ sp<SoftOMXComponent> codec =
+ (*createSoftOMXComponent)(name, callbacks, appData, component);
+
+ if (codec == NULL) {
+ dlclose(libHandle);
+ libHandle = NULL;
+
+ return OMX_ErrorInsufficientResources;
+ }
+
+ OMX_ERRORTYPE err = codec->initCheck();
+ if (err != OMX_ErrorNone) {
+ dlclose(libHandle);
+ libHandle = NULL;
+
+ return err;
+ }
+
+ codec->incStrong(this);
+ codec->setLibHandle(libHandle);
+
+ return OMX_ErrorNone;
+ }
+
+ return OMX_ErrorInvalidComponentName;
+}
+
+OMX_ERRORTYPE SoftOMXPlugin::destroyComponentInstance(
+ OMX_COMPONENTTYPE *component) {
+ SoftOMXComponent *me =
+ (SoftOMXComponent *)
+ ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+
+ void *libHandle = me->libHandle();
+
+ me->decStrong(this);
+ me = NULL;
+
+ dlclose(libHandle);
+ libHandle = NULL;
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftOMXPlugin::enumerateComponents(
+ OMX_STRING name,
+ size_t size,
+ OMX_U32 index) {
+ if (index >= kNumComponents) {
+ return OMX_ErrorNoMore;
+ }
+
+ strcpy(name, kComponents[index].mName);
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE SoftOMXPlugin::getRolesOfComponent(
+ const char *name,
+ Vector<String8> *roles) {
+ for (size_t i = 0; i < kNumComponents; ++i) {
+ if (strcmp(name, kComponents[i].mName)) {
+ continue;
+ }
+
+ roles->clear();
+ roles->push(String8(kComponents[i].mRole));
+
+ return OMX_ErrorNone;
+ }
+
+ return OMX_ErrorInvalidComponentName;
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/OMXPVCodecsPlugin.h b/media/libstagefright/omx/SoftOMXPlugin.h
index c133232..f93c323 100644
--- a/media/libstagefright/omx/OMXPVCodecsPlugin.h
+++ b/media/libstagefright/omx/SoftOMXPlugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-#ifndef OMX_PV_CODECS_PLUGIN_H_
+#ifndef SOFT_OMX_PLUGIN_H_
-#define OMX_PV_CODECS_PLUGIN_H_
+#define SOFT_OMX_PLUGIN_H_
+#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/OMXPluginBase.h>
namespace android {
-struct OMXPVCodecsPlugin : public OMXPluginBase {
- OMXPVCodecsPlugin();
- virtual ~OMXPVCodecsPlugin();
+struct SoftOMXPlugin : public OMXPluginBase {
+ SoftOMXPlugin();
virtual OMX_ERRORTYPE makeComponentInstance(
const char *name,
@@ -45,10 +45,9 @@ struct OMXPVCodecsPlugin : public OMXPluginBase {
Vector<String8> *roles);
private:
- OMXPVCodecsPlugin(const OMXPVCodecsPlugin &);
- OMXPVCodecsPlugin &operator=(const OMXPVCodecsPlugin &);
+ DISALLOW_EVIL_CONSTRUCTORS(SoftOMXPlugin);
};
} // namespace android
-#endif // OMX_PV_CODECS_PLUGIN_H_
+#endif // SOFT_OMX_PLUGIN_H_
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 54c0d77..a404f1f 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -29,6 +29,7 @@
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
@@ -454,6 +455,7 @@ static const char *GetMimeFromComponentRole(const char *componentRole) {
{ "video_decoder.avc", "video/avc" },
{ "video_decoder.mpeg4", "video/mp4v-es" },
{ "video_decoder.h263", "video/3gpp" },
+ { "video_decoder.vpx", "video/x-vnd.on2.vp8" },
// we appear to use this as a synonym to amrnb.
{ "audio_decoder.amr", "audio/3gpp" },
@@ -461,7 +463,10 @@ static const char *GetMimeFromComponentRole(const char *componentRole) {
{ "audio_decoder.amrnb", "audio/3gpp" },
{ "audio_decoder.amrwb", "audio/amr-wb" },
{ "audio_decoder.aac", "audio/mp4a-latm" },
- { "audio_decoder.mp3", "audio/mpeg" }
+ { "audio_decoder.mp3", "audio/mpeg" },
+ { "audio_decoder.vorbis", "audio/vorbis" },
+ { "audio_decoder.g711alaw", MEDIA_MIMETYPE_AUDIO_G711_ALAW },
+ { "audio_decoder.g711mlaw", MEDIA_MIMETYPE_AUDIO_G711_MLAW },
};
for (size_t i = 0; i < sizeof(kRoleToMime) / sizeof(kRoleToMime[0]); ++i) {
@@ -492,7 +497,15 @@ static const char *GetURLForMime(const char *mime) {
{ "audio/mp4a-latm",
"file:///sdcard/media_api/video/H264_AAC.3gp" },
{ "audio/mpeg",
- "file:///sdcard/media_api/music/MP3CBR.mp3" }
+ "file:///sdcard/media_api/music/MP3CBR.mp3" },
+ { "audio/vorbis",
+ "file:///sdcard/media_api/metaDataTestMedias/OGG/"
+ "When You Say Nothing At All.ogg" },
+ { "video/x-vnd.on2.vp8",
+ "file:///sdcard/media_api/webm/big-buck-bunny_trailer.webm" },
+ { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "file:///sdcard/M1F1-Alaw-AFsp.wav" },
+ { MEDIA_MIMETYPE_AUDIO_G711_MLAW,
+ "file:///sdcard/M1F1-mulaw-AFsp.wav" },
};
for (size_t i = 0; i < sizeof(kMimeToURL) / sizeof(kMimeToURL[0]); ++i) {
@@ -746,6 +759,10 @@ status_t Harness::testAll() {
const IOMX::ComponentInfo &info = *it;
const char *componentName = info.mName.string();
+ if (strncmp(componentName, "OMX.google.", 11)) {
+ continue;
+ }
+
for (List<String8>::const_iterator role_it = info.mRoles.begin();
role_it != info.mRoles.end(); ++role_it) {
const char *componentRole = (*role_it).string();