From a253734423f1c998349f90a106acc613365e1844 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Alamanda Date: Fri, 18 Feb 2011 16:25:40 +0530 Subject: 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 --- api/current.txt | 6 + include/media/MediaProfiles.h | 3 + include/media/mediarecorder.h | 9 + include/media/stagefright/ExtendedWriter.h | 126 +++++++ media/java/android/media/MediaRecorder.java | 13 +- media/libmedia/MediaProfiles.cpp | 12 + .../libmediaplayerservice/StagefrightRecorder.cpp | 99 ++++++ media/libmediaplayerservice/StagefrightRecorder.h | 5 + media/libstagefright/Android.mk | 4 +- media/libstagefright/ExtendedWriter.cpp | 386 +++++++++++++++++++++ media/libstagefright/OMXCodec.cpp | 11 +- 11 files changed, 667 insertions(+), 7 deletions(-) create mode 100644 include/media/stagefright/ExtendedWriter.h create mode 100644 media/libstagefright/ExtendedWriter.cpp 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 + +#include +#include + +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 &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 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 #include #include +#ifdef QCOM_HARDWARE +#include +#endif #include #include #include @@ -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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#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 &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 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(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, ×tampUs)); + 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 &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 //////////////////// -- cgit v1.1