summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRavi Kumar Alamanda <ralama@codeaurora.org>2011-02-18 16:25:40 +0530
committerRicardo Cerqueira <github@cerqueira.org>2012-03-27 17:00:50 +0100
commita253734423f1c998349f90a106acc613365e1844 (patch)
treef9367697eca149b7971dcdc09ae87a8f3cbbb5df
parent256fcc6a18ed092ab97b4b2f092c16daaa48f72c (diff)
downloadframeworks_base-a253734423f1c998349f90a106acc613365e1844.zip
frameworks_base-a253734423f1c998349f90a106acc613365e1844.tar.gz
frameworks_base-a253734423f1c998349f90a106acc613365e1844.tar.bz2
frameworks/base: Add support for QCELP/EVRC non-tunnel encoding in SF
Add support for QCELP and EVRC formats non-tunnel mode encoding in StageFright using hardware accelerated encoders. Patchset 1: Add QCOM_HARDWARE ifdefs. Patchset 2: Fix ifdef derp. Patchset 3: Fix endif derp, change omx-core include to vendor/qcom. Conflicts: media/libstagefright/Android.mk media/libstagefright/OMXCodec.cpp Change-Id: I179030d71a9598ddddcf754e963fbed1e1357024 Signed-off-by: Evan McClain <aeroevan@gmail.com>
-rw-r--r--api/current.txt6
-rw-r--r--include/media/MediaProfiles.h3
-rw-r--r--include/media/mediarecorder.h9
-rw-r--r--include/media/stagefright/ExtendedWriter.h126
-rw-r--r--media/java/android/media/MediaRecorder.java13
-rw-r--r--media/libmedia/MediaProfiles.cpp12
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp99
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h5
-rw-r--r--media/libstagefright/Android.mk4
-rw-r--r--media/libstagefright/ExtendedWriter.cpp386
-rw-r--r--media/libstagefright/OMXCodec.cpp11
11 files changed, 667 insertions, 7 deletions
diff --git a/api/current.txt b/api/current.txt
index b7ad1d6..7b79054 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10851,9 +10851,13 @@ package android.media {
public final class MediaRecorder.AudioEncoder {
field public static final int AAC = 3; // 0x3
+ field public static final int AAC_PLUS = 4; // 0x4
field public static final int AMR_NB = 1; // 0x1
field public static final int AMR_WB = 2; // 0x2
field public static final int DEFAULT = 0; // 0x0
+ field public static final int EAAC_PLUS = 5; // 0x5
+ field public static final int EVRC = 6; // 0x6
+ field public static final int QCELP = 7; // 0x7
}
public final class MediaRecorder.AudioSource {
@@ -10880,8 +10884,10 @@ package android.media {
field public static final int AMR_WB = 4; // 0x4
field public static final int DEFAULT = 0; // 0x0
field public static final int MPEG_4 = 2; // 0x2
+ field public static final int QCP = 9; // 0x9
field public static final int RAW_AMR = 3; // 0x3
field public static final int THREE_GPP = 1; // 0x1
+ field public static final int THREE_GPP2 = 10; // 0xa
}
public final class MediaRecorder.VideoEncoder {
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index 424b4e1..6eba32c 100644
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -459,6 +459,9 @@ private:
static VideoEncoderCap* createDefaultH264VideoEncoderCap();
#endif
static AudioEncoderCap* createDefaultAmrNBEncoderCap();
+#ifdef QCOM_HARDWARE
+ static AudioEncoderCap* createDefaultAacEncoderCap();
+#endif
static int findTagForName(const NameToTagMap *map, size_t nMappings, const char *name);
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 2d56728..794b928 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -67,6 +67,11 @@ enum output_format {
/* H.264/AAC data encapsulated in MPEG2/TS */
OUTPUT_FORMAT_MPEG2TS = 8,
+#ifdef QCOM_HARDWARE
+ OUTPUT_FORMAT_QCP = 9, // QCP file format
+ OUTPUT_FORMAT_THREE_GPP2 = 10, /*3GPP2*/
+#endif
+
OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
};
@@ -77,6 +82,10 @@ enum audio_encoder {
AUDIO_ENCODER_AAC = 3,
AUDIO_ENCODER_AAC_PLUS = 4,
AUDIO_ENCODER_EAAC_PLUS = 5,
+#ifdef QCOM_HARDWARE
+ AUDIO_ENCODER_EVRC = 6,
+ AUDIO_ENCODER_QCELP = 7,
+#endif
AUDIO_ENCODER_LIST_END // must be the last - used to validate the audio encoder type
};
diff --git a/include/media/stagefright/ExtendedWriter.h b/include/media/stagefright/ExtendedWriter.h
new file mode 100644
index 0000000..b5bda5c
--- /dev/null
+++ b/include/media/stagefright/ExtendedWriter.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011 Code Aurora Forum. All rights reserved
+ *
+ * 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 EXTENDED_WRITER_H_
+
+#define EXTENDED_WRITER_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/MediaWriter.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct MediaSource;
+struct MetaData;
+
+struct ExtendedWriter : public MediaWriter {
+ ExtendedWriter(const char *filename);
+ ExtendedWriter(int fd);
+
+ status_t initCheck() const;
+
+ virtual status_t addSource(const sp<MediaSource> &source);
+ virtual bool reachedEOS();
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual status_t pause();
+
+protected:
+ virtual ~ExtendedWriter();
+
+private:
+ FILE *mFile;
+ status_t mInitCheck;
+ sp<MediaSource> mSource;
+ bool mStarted;
+ volatile bool mPaused;
+ volatile bool mResumed;
+ volatile bool mDone;
+ volatile bool mReachedEOS;
+ pthread_t mThread;
+ int64_t mEstimatedSizeBytes;
+ int64_t mEstimatedDurationUs;
+
+ int32_t mFormat;
+
+ //QCP/EVRC header
+ struct QCPEVRCHeader
+ {
+ /* RIFF Section */
+ char riff[4];
+ unsigned int s_riff;
+ char qlcm[4];
+
+ /* Format chunk */
+ char fmt[4];
+ unsigned int s_fmt;
+ char mjr;
+ char mnr;
+ unsigned int data1;
+
+ /* UNIQUE ID of the codec */
+ unsigned short data2;
+ unsigned short data3;
+ char data4[8];
+ unsigned short ver;
+
+ /* Codec Info */
+ char name[80];
+ unsigned short abps;
+
+ /* average bits per sec of the codec */
+ unsigned short bytes_per_pkt;
+ unsigned short samp_per_block;
+ unsigned short samp_per_sec;
+ unsigned short bits_per_samp;
+ unsigned char vr_num_of_rates;
+
+ /* Rate Header fmt info */
+ unsigned char rvd1[3];
+ unsigned short vr_bytes_per_pkt[8];
+ unsigned int rvd2[5];
+
+ /* Vrat chunk */
+ unsigned char vrat[4];
+ unsigned int s_vrat;
+ unsigned int v_rate;
+ unsigned int size_in_pkts;
+
+ /* Data chunk */
+ unsigned char data[4];
+ unsigned int s_data;
+ } __attribute__ ((packed));
+
+ struct QCPEVRCHeader mHeader;
+ off_t mOffset; //note off_t
+
+ static void *ThreadWrapper(void *);
+ status_t threadFunc();
+ bool exceedsFileSizeLimit();
+ bool exceedsFileDurationLimit();
+
+ ExtendedWriter(const ExtendedWriter &);
+ ExtendedWriter &operator=(const ExtendedWriter &);
+
+ status_t writeQCPHeader( );
+ status_t writeEVRCHeader( );
+};
+
+} // namespace android
+
+#endif // AMR_WRITER_H_
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index aedc254..dd377be 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -227,6 +227,11 @@ public class MediaRecorder
/** @hide H.264/AAC data encapsulated in MPEG2/TS */
public static final int OUTPUT_FORMAT_MPEG2TS = 8;
+
+ /** QCP file format */
+ public static final int QCP = 9;
+ /** 3GPP2 media file format*/
+ public static final int THREE_GPP2 = 10;
};
/**
@@ -245,10 +250,14 @@ public class MediaRecorder
public static final int AMR_WB = 2;
/** AAC audio codec */
public static final int AAC = 3;
- /** @hide enhanced AAC audio codec */
+ /** enhanced AAC audio codec */
public static final int AAC_PLUS = 4;
- /** @hide enhanced AAC plus audio codec */
+ /** enhanced AAC plus audio codec */
public static final int EAAC_PLUS = 5;
+ /** EVRC audio codec */
+ public static final int EVRC = 6;
+ /** QCELP audio codec */
+ public static final int QCELP =7;
}
/**
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index f02cf67..084b4bc 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -817,6 +817,9 @@ MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
{
profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
+#ifdef QCOM_HARDWARE
+ profiles->mAudioEncoders.add(createDefaultAacEncoderCap());
+#endif
}
/*static*/ void
@@ -851,6 +854,15 @@ MediaProfiles::createDefaultAmrNBEncoderCap()
AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
}
+#ifdef QCOM_HARDWARE
+/*static*/ MediaProfiles::AudioEncoderCap*
+MediaProfiles::createDefaultAacEncoderCap()
+{
+ return new MediaProfiles::AudioEncoderCap(
+ AUDIO_ENCODER_AAC, 64000, 156000, 8000, 48000, 1, 2);
+}
+#endif
+
/*static*/ void
MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
{
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 6fb6a22..35f1c85 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -27,6 +27,9 @@
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AACWriter.h>
+#ifdef QCOM_HARDWARE
+#include <media/stagefright/ExtendedWriter.h>
+#endif
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
#include <media/stagefright/MPEG2TSWriter.h>
@@ -180,6 +183,19 @@ status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) {
mAudioEncoder = ae;
}
+#ifdef QCOM_HARDWARE
+ // Use default values if appropriate setparam's weren't called.
+ if(mAudioEncoder == AUDIO_ENCODER_AAC) {
+ mSampleRate = mSampleRate ? mSampleRate : 48000;
+ mAudioChannels = mAudioChannels ? mAudioChannels : 2;
+ mAudioBitRate = mAudioBitRate ? mAudioBitRate : 156000;
+ }
+ else{
+ mSampleRate = mSampleRate ? mSampleRate : 8000;
+ mAudioChannels = mAudioChannels ? mAudioChannels : 1;
+ mAudioBitRate = mAudioBitRate ? mAudioBitRate : 12200;
+ }
+#endif
return OK;
}
@@ -790,6 +806,11 @@ status_t StagefrightRecorder::start() {
status = startMPEG2TSRecording();
break;
+#ifdef QCOM_HARDWARE
+ case OUTPUT_FORMAT_QCP:
+ status = startExtendedRecording( );
+ break;
+#endif
default:
LOGE("Unsupported output file format: %d", mOutputFormat);
status = UNKNOWN_ERROR;
@@ -840,6 +861,14 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() {
case AUDIO_ENCODER_AAC:
mime = MEDIA_MIMETYPE_AUDIO_AAC;
break;
+#ifdef QCOM_HARDWARE
+ case AUDIO_ENCODER_EVRC:
+ mime = MEDIA_MIMETYPE_AUDIO_EVRC;
+ break;
+ case AUDIO_ENCODER_QCELP:
+ mime = MEDIA_MIMETYPE_AUDIO_QCELP;
+ break;
+#endif
default:
LOGE("Unknown audio encoder: %d", mAudioEncoder);
return NULL;
@@ -898,12 +927,32 @@ status_t StagefrightRecorder::startAMRRecording() {
mAudioEncoder);
return BAD_VALUE;
}
+#ifdef QCOM_HARDWARE
+ if (mSampleRate != 8000) {
+ LOGE("Invalid sampling rate %d used for AMRNB recording",
+ mSampleRate);
+ return BAD_VALUE;
+ }
+#endif
} else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
LOGE("Invlaid encoder %d used for AMRWB recording",
mAudioEncoder);
return BAD_VALUE;
}
+#ifdef QCOM_HARDWARE
+ if (mSampleRate != 16000) {
+ LOGE("Invalid sample rate %d used for AMRWB recording",
+ mSampleRate);
+ return BAD_VALUE;
+ }
+ }
+
+ if (mAudioChannels != 1) {
+ LOGE("Invalid number of audio channels %d used for amr recording",
+ mAudioChannels);
+ return BAD_VALUE;
+#endif
}
mWriter = new AMRWriter(mOutputFd);
@@ -1658,9 +1707,15 @@ status_t StagefrightRecorder::reset() {
mVideoHeight = 144;
mFrameRate = -1;
mVideoBitRate = 192000;
+#ifdef QCOM_HARDWARE
+ mSampleRate = 0;
+ mAudioChannels = 0;
+ mAudioBitRate = 0;
+#else
mSampleRate = 8000;
mAudioChannels = 1;
mAudioBitRate = 12200;
+#endif
mInterleaveDurationUs = 0;
mIFramesIntervalSec = 1;
mAudioSourceNode = 0;
@@ -1779,4 +1834,48 @@ status_t StagefrightRecorder::dump(
::write(fd, result.string(), result.size());
return OK;
}
+
+#ifdef QCOM_HARDWARE
+status_t StagefrightRecorder::startExtendedRecording() {
+ CHECK(mOutputFormat == OUTPUT_FORMAT_QCP);
+
+ if (mSampleRate != 8000) {
+ LOGE("Invalid sampling rate %d used for recording",
+ mSampleRate);
+ return BAD_VALUE;
+ }
+ if (mAudioChannels != 1) {
+ LOGE("Invalid number of audio channels %d used for recording",
+ mAudioChannels);
+ return BAD_VALUE;
+ }
+
+ if (mAudioSource >= AUDIO_SOURCE_CNT) {
+ LOGE("Invalid audio source: %d", mAudioSource);
+ return BAD_VALUE;
+ }
+
+ sp<MediaSource> audioEncoder = createAudioSource();
+
+ if (audioEncoder == NULL) {
+ LOGE("AudioEncoder NULL");
+ return UNKNOWN_ERROR;
+ }
+
+ mWriter = new ExtendedWriter(dup(mOutputFd));
+ mWriter->addSource(audioEncoder);
+
+ if (mMaxFileDurationUs != 0) {
+ mWriter->setMaxFileDuration(mMaxFileDurationUs);
+ }
+ if (mMaxFileSizeBytes != 0) {
+ mWriter->setMaxFileSize(mMaxFileSizeBytes);
+ }
+ mWriter->setListener(mListener);
+ mWriter->start();
+
+ return OK;
+}
+#endif
+
} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index d233f0e..ef33ede 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -190,6 +190,11 @@ private:
StagefrightRecorder(const StagefrightRecorder &);
StagefrightRecorder &operator=(const StagefrightRecorder &);
+
+#ifdef QCOM_HARDWARE
+ /* extension */
+ status_t startExtendedRecording();
+#endif
};
} // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2105c0b..d778086 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -75,6 +75,7 @@ LOCAL_SRC_FILES:= \
ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
LOCAL_SRC_FILES += ExtendedExtractor.cpp
+ LOCAL_SRC_FILES += ExtendedWriter.cpp
endif
LOCAL_C_INCLUDES:= \
@@ -183,7 +184,8 @@ LOCAL_CFLAGS += -Wno-multichar
ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
LOCAL_C_INCLUDES += $(TOP)/hardware/msm7k/libgralloc-qsd8k
- LOCAL_C_INCLUDES += $(TOP)/hardware/qcom/media/mm-core/omxcore/inc
+ LOCAL_C_INCLUDES += $(TOP)/vendor/qcom/opensource/omx/mm-core/omxcore/inc
+ LOCAL_C_INCLUDES += $(TOP)/system/core/include
LOCAL_CFLAGS += -DQCOM_HARDWARE
endif
diff --git a/media/libstagefright/ExtendedWriter.cpp b/media/libstagefright/ExtendedWriter.cpp
new file mode 100644
index 0000000..18e6e95
--- /dev/null
+++ b/media/libstagefright/ExtendedWriter.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2011 Code Aurora Forum. All rights reserved
+ *
+ * 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 <media/stagefright/ExtendedWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <system/audio.h>
+
+#include <sys/prctl.h>
+#include <sys/resource.h>
+
+#include <arpa/inet.h>
+
+#undef LOG_TAG
+#define LOG_TAG "ExtendedWriter"
+
+namespace android {
+
+ExtendedWriter::ExtendedWriter(const char *filename)
+ : mFile(fopen(filename, "wb")),
+ mInitCheck(mFile != NULL ? OK : NO_INIT),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false),
+ mOffset(0) {
+}
+
+ExtendedWriter::ExtendedWriter(int fd)
+ : mFile(fdopen(fd, "wb")),
+ mInitCheck(mFile != NULL ? OK : NO_INIT),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false),
+ mOffset(0) {
+}
+
+ExtendedWriter::~ExtendedWriter() {
+ if (mStarted) {
+ stop();
+ }
+
+ if (mFile != NULL) {
+ fclose(mFile);
+ mFile = NULL;
+ }
+}
+
+status_t ExtendedWriter::initCheck() const {
+ return mInitCheck;
+}
+
+status_t ExtendedWriter::addSource(const sp<MediaSource> &source) {
+ if (mInitCheck != OK) {
+ LOGE("Init Check not OK, return");
+ return mInitCheck;
+ }
+
+ if (mSource != NULL) {
+ LOGE("A source already exists, return");
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if ( !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
+ mFormat = AUDIO_FORMAT_QCELP;
+ } else if ( !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_EVRC)) {
+ mFormat = AUDIO_FORMAT_EVRC;
+ }
+ else {
+ return UNKNOWN_ERROR;
+ }
+
+ int32_t channelCount;
+ int32_t sampleRate;
+ CHECK(meta->findInt32(kKeyChannelCount, &channelCount));
+ CHECK_EQ(channelCount, 1);
+ CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+ CHECK_EQ(sampleRate, 8000);
+
+ mSource = source;
+
+ return OK;
+}
+
+status_t ExtendedWriter::start(MetaData *params) {
+ if (mInitCheck != OK) {
+ LOGE("Init Check not OK, return");
+ return mInitCheck;
+ }
+
+ if (mSource == NULL) {
+ LOGE("NULL Source");
+ return UNKNOWN_ERROR;
+ }
+
+ if (mStarted && mPaused) {
+ mPaused = false;
+ mResumed = true;
+ return OK;
+ } else if (mStarted) {
+ LOGE("Already startd, return");
+ return OK;
+ }
+
+ //space for header;
+ size_t headerSize = sizeof( struct QCPEVRCHeader );
+ uint8_t * header = (uint8_t *)malloc(headerSize);
+ memset( header, '?', headerSize);
+ fwrite( header, 1, headerSize, mFile );
+ mOffset += headerSize;
+ delete header;
+
+ status_t err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mReachedEOS = false;
+ mDone = false;
+
+ pthread_create(&mThread, &attr, ThreadWrapper, this);
+ pthread_attr_destroy(&attr);
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t ExtendedWriter::pause() {
+ if (!mStarted) {
+ return OK;
+ }
+ mPaused = true;
+ return OK;
+}
+
+status_t ExtendedWriter::stop() {
+ if (!mStarted) {
+ return OK;
+ }
+
+ mDone = true;
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ status_t err = (status_t) dummy;
+ {
+ status_t status = mSource->stop();
+ if (err == OK &&
+ (status != OK && status != ERROR_END_OF_STREAM)) {
+ err = status;
+ }
+ }
+
+ mStarted = false;
+ return err;
+}
+
+bool ExtendedWriter::exceedsFileSizeLimit() {
+ if (mMaxFileSizeLimitBytes == 0) {
+ return false;
+ }
+ return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
+}
+
+bool ExtendedWriter::exceedsFileDurationLimit() {
+ if (mMaxFileDurationLimitUs == 0) {
+ return false;
+ }
+ return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
+}
+
+// static
+void *ExtendedWriter::ThreadWrapper(void *me) {
+ return (void *) static_cast<ExtendedWriter *>(me)->threadFunc();
+}
+
+status_t ExtendedWriter::threadFunc() {
+ mEstimatedDurationUs = 0;
+ mEstimatedSizeBytes = 0;
+ bool stoppedPrematurely = true;
+ int64_t previousPausedDurationUs = 0;
+ int64_t maxTimestampUs = 0;
+ status_t err = OK;
+
+ prctl(PR_SET_NAME, (unsigned long)"ExtendedWriter", 0, 0, 0);
+ while (!mDone) {
+ MediaBuffer *buffer;
+ err = mSource->read(&buffer);
+
+ if (err != OK) {
+ break;
+ }
+
+ if (mPaused) {
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+
+ mEstimatedSizeBytes += buffer->range_length();
+ if (exceedsFileSizeLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+ break;
+ }
+
+ int64_t timestampUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
+ if (timestampUs > mEstimatedDurationUs) {
+ mEstimatedDurationUs = timestampUs;
+ }
+ if (mResumed) {
+ previousPausedDurationUs += (timestampUs - maxTimestampUs - 20000);
+ mResumed = false;
+ }
+ timestampUs -= previousPausedDurationUs;
+ LOGV("time stamp: %lld, previous paused duration: %lld",
+ timestampUs, previousPausedDurationUs);
+ if (timestampUs > maxTimestampUs) {
+ maxTimestampUs = timestampUs;
+ }
+
+ if (exceedsFileDurationLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+ break;
+ }
+ ssize_t n = fwrite(
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ 1,
+ buffer->range_length(),
+ mFile);
+ mOffset += n;
+
+ if (n < (ssize_t)buffer->range_length()) {
+ buffer->release();
+ buffer = NULL;
+
+ break;
+ }
+
+ // XXX: How to tell it is stopped prematurely?
+ if (stoppedPrematurely) {
+ stoppedPrematurely = false;
+ }
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ if (stoppedPrematurely) {
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, UNKNOWN_ERROR);
+ }
+
+ if ( mFormat == AUDIO_FORMAT_QCELP ) {
+ writeQCPHeader( );
+ }
+ else if ( mFormat == AUDIO_FORMAT_EVRC ) {
+ writeEVRCHeader( );
+ }
+
+ fflush(mFile);
+ fclose(mFile);
+ mFile = NULL;
+ mReachedEOS = true;
+ if (err == ERROR_END_OF_STREAM || (err == -ETIMEDOUT)) {
+ return OK;
+ }
+ return err;
+}
+
+bool ExtendedWriter::reachedEOS() {
+ return mReachedEOS;
+}
+
+status_t ExtendedWriter::writeQCPHeader() {
+ /* Common part */
+ struct QCPEVRCHeader header = {
+ {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'}, /* Riff */
+ {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0}, /* Fmt */
+ {'v','r','a','t'}, 0, 0, 0, /* Vrat */
+ {'d','a','t','a'},0 /* Data */
+ };
+
+ fseeko(mFile, 0, SEEK_SET);
+ header.s_riff = (mOffset - 8);
+ header.data1 = (0x5E7F6D41);
+ header.data2 = (0xB115);
+ header.data3 = (0x11D0);
+ header.data4[0] = 0xBA;
+ header.data4[1] = 0x91;
+ header.data4[2] = 0x00;
+ header.data4[3] = 0x80;
+ header.data4[4] = 0x5F;
+ header.data4[5] = 0xB4;
+ header.data4[6] = 0xB9;
+ header.data4[7] = 0x7E;
+ header.ver = (0x0002);
+ memcpy(header.name, "Qcelp 13K", 9);
+ header.abps = (13000);
+ header.bytes_per_pkt = (35);
+ header.vr_num_of_rates = 5;
+ header.vr_bytes_per_pkt[0] = (0x0422);
+ header.vr_bytes_per_pkt[1] = (0x0310);
+ header.vr_bytes_per_pkt[2] = (0x0207);
+ header.vr_bytes_per_pkt[3] = (0x0103);
+ header.s_vrat = (0x00000008);
+ header.v_rate = (0x00000001);
+ header.size_in_pkts = (mOffset - sizeof( struct QCPEVRCHeader ))/ header.bytes_per_pkt;
+ header.s_data = mOffset - sizeof( struct QCPEVRCHeader );
+ fwrite( &header, 1, sizeof( struct QCPEVRCHeader ), mFile );
+ return OK;
+}
+
+status_t ExtendedWriter::writeEVRCHeader() {
+ /* Common part */
+ struct QCPEVRCHeader header = {
+ {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'}, /* Riff */
+ {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0}, /* Fmt */
+ {'v','r','a','t'}, 0, 0, 0, /* Vrat */
+ {'d','a','t','a'},0 /* Data */
+ };
+
+ fseeko(mFile, 0, SEEK_SET);
+ header.s_riff = (mOffset - 8);
+ header.data1 = (0xe689d48d);
+ header.data2 = (0x9076);
+ header.data3 = (0x46b5);
+ header.data4[0] = 0x91;
+ header.data4[1] = 0xef;
+ header.data4[2] = 0x73;
+ header.data4[3] = 0x6a;
+ header.data4[4] = 0x51;
+ header.data4[5] = 0x00;
+ header.data4[6] = 0xce;
+ header.data4[7] = 0xb4;
+ header.ver = (0x0001);
+ memcpy(header.name, "TIA IS-127 Enhanced Variable Rate Codec, Speech Service Option 3", 64);
+ header.abps = (9600);
+ header.bytes_per_pkt = (23);
+ header.vr_num_of_rates = 4;
+ header.vr_bytes_per_pkt[0] = (0x0416);
+ header.vr_bytes_per_pkt[1] = (0x030a);
+ header.vr_bytes_per_pkt[2] = (0x0200);
+ header.vr_bytes_per_pkt[3] = (0x0102);
+ header.s_vrat = (0x00000008);
+ header.v_rate = (0x00000001);
+ header.size_in_pkts = (mOffset - sizeof( struct QCPEVRCHeader )) / header.bytes_per_pkt;
+ header.s_data = mOffset - sizeof( struct QCPEVRCHeader );
+ fwrite( &header, 1, sizeof( struct QCPEVRCHeader ), mFile );
+ return OK;
+}
+
+
+} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 3cb593b..b3a3554 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -988,11 +988,11 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
|| !strcmp(value, "msm7625_surf") || !strcmp(value, "msm7625_ffa"))
{
LOGE("OMX_QCOM_FramePacking_OnlyOneCompleteFrame not supported by component err: %d", err);
- }
- else
+ } else {
if(err!=OK){
return err;
}
+ }
#endif
} else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME)
|| !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) {
@@ -2684,7 +2684,9 @@ int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
CHECK(mIsEncoder);
if (mDecodingTimeList.empty()) {
+#ifndef QCOM_HARDWARE
CHECK(mSignalledEOS || mNoMoreOutputData);
+#endif
// No corresponding input frame available.
// This could happen when EOS is reached.
return 0;
@@ -4019,6 +4021,9 @@ void OMXCodec::setRawAudioFormat(
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = portIndex;
+#ifdef QCOM_HARDWARE
+ def.format.audio.cMIMEType = NULL;
+#endif
status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, (status_t)OK);
@@ -5632,8 +5637,6 @@ void OMXCodec::setEVRCFormat(int32_t numChannels, int32_t sampleRate, int32_t bi
}
void OMXCodec::setQCELPFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
-
-
if (mIsEncoder) {
CHECK(numChannels == 1);
//////////////// input port ////////////////////