From 996dddff64f90d8469e24107c44bfd618cf0c2dd Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 25 Jan 2010 15:30:31 -0800 Subject: [PATCH] Support for audio recording into AMR NB/WB files as well as audio tracks in MPEG4 files. related-to-bug: 2295449 --- include/media/stagefright/AMRWriter.h | 13 ++- include/media/stagefright/MPEG4Writer.h | 12 +- include/media/stagefright/MediaWriter.h | 45 ++++++++ .../StagefrightRecorder.cpp | 104 +++++++++++++++++- .../StagefrightRecorder.h | 9 +- media/libstagefright/AMRWriter.cpp | 9 ++ media/libstagefright/MPEG4Writer.cpp | 4 +- 7 files changed, 177 insertions(+), 19 deletions(-) create mode 100644 include/media/stagefright/MediaWriter.h diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h index 6ee98698fe6c0..372909a0bfbbd 100644 --- a/include/media/stagefright/AMRWriter.h +++ b/include/media/stagefright/AMRWriter.h @@ -20,23 +20,23 @@ #include -#include +#include #include namespace android { struct MediaSource; -struct AMRWriter : public RefBase { +struct AMRWriter : public MediaWriter { AMRWriter(const char *filename); AMRWriter(int fd); status_t initCheck() const; - status_t addSource(const sp &source); - - status_t start(); - void stop(); + virtual status_t addSource(const sp &source); + virtual bool reachedEOS(); + virtual status_t start(); + virtual void stop(); protected: virtual ~AMRWriter(); @@ -49,6 +49,7 @@ private: sp mSource; bool mStarted; volatile bool mDone; + bool mReachedEOS; pthread_t mThread; static void *ThreadWrapper(void *); diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 2ca04fa593757..6b93f197c7684 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -20,8 +20,8 @@ #include +#include #include -#include #include namespace android { @@ -30,15 +30,15 @@ class MediaBuffer; class MediaSource; class MetaData; -class MPEG4Writer : public RefBase { +class MPEG4Writer : public MediaWriter { public: MPEG4Writer(const char *filename); MPEG4Writer(int fd); - void addSource(const sp &source); - status_t start(); - bool reachedEOS(); - void stop(); + virtual status_t addSource(const sp &source); + virtual status_t start(); + virtual bool reachedEOS(); + virtual void stop(); void beginBox(const char *fourcc); void writeInt8(int8_t x); diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h new file mode 100644 index 0000000000000..b8232c6698627 --- /dev/null +++ b/include/media/stagefright/MediaWriter.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 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 MEDIA_WRITER_H_ + +#define MEDIA_WRITER_H_ + +#include + +namespace android { + +struct MediaSource; + +struct MediaWriter : public RefBase { + MediaWriter() {} + + virtual status_t addSource(const sp &source) = 0; + virtual bool reachedEOS() = 0; + virtual status_t start() = 0; + virtual void stop() = 0; + +protected: + virtual ~MediaWriter() {} + +private: + MediaWriter(const MediaWriter &); + MediaWriter &operator=(const MediaWriter &); +}; + +} // namespace android + +#endif // MEDIA_WRITER_H_ diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index a55273d765f15..6383f0c0d242c 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -20,6 +20,8 @@ #include "StagefrightRecorder.h" +#include +#include #include #include #include @@ -146,7 +148,90 @@ status_t StagefrightRecorder::start() { return UNKNOWN_ERROR; } - if (mVideoSource == VIDEO_SOURCE_CAMERA) { + switch (mOutputFormat) { + case OUTPUT_FORMAT_DEFAULT: + case OUTPUT_FORMAT_THREE_GPP: + case OUTPUT_FORMAT_MPEG_4: + return startMPEG4Recording(); + + case OUTPUT_FORMAT_AMR_NB: + case OUTPUT_FORMAT_AMR_WB: + return startAMRRecording(); + + default: + return UNKNOWN_ERROR; + } +} + +sp StagefrightRecorder::createAMRAudioSource() { + uint32_t sampleRate = + mAudioEncoder == AUDIO_ENCODER_AMR_NB ? 8000 : 16000; + + sp audioSource = + new AudioSource( + mAudioSource, + sampleRate, + AudioSystem::CHANNEL_IN_MONO); + + status_t err = audioSource->initCheck(); + + if (err != OK) { + return NULL; + } + + sp encMeta = new MetaData; + encMeta->setCString( + kKeyMIMEType, + mAudioEncoder == AUDIO_ENCODER_AMR_NB + ? MEDIA_MIMETYPE_AUDIO_AMR_NB : MEDIA_MIMETYPE_AUDIO_AMR_WB); + + encMeta->setInt32(kKeyChannelCount, 1); + encMeta->setInt32(kKeySampleRate, sampleRate); + + OMXClient client; + CHECK_EQ(client.connect(), OK); + + sp audioEncoder = + OMXCodec::Create(client.interface(), encMeta, + true /* createEncoder */, audioSource); + + return audioEncoder; +} + +status_t StagefrightRecorder::startAMRRecording() { + if (mAudioSource == AUDIO_SOURCE_LIST_END + || mVideoSource != VIDEO_SOURCE_LIST_END) { + return UNKNOWN_ERROR; + } + + if (mOutputFormat == OUTPUT_FORMAT_AMR_NB + && mAudioEncoder != AUDIO_ENCODER_DEFAULT + && mAudioEncoder != AUDIO_ENCODER_AMR_NB) { + return UNKNOWN_ERROR; + } else if (mOutputFormat == OUTPUT_FORMAT_AMR_WB + && mAudioEncoder != AUDIO_ENCODER_AMR_WB) { + return UNKNOWN_ERROR; + } + + sp audioEncoder = createAMRAudioSource(); + + if (audioEncoder == NULL) { + return UNKNOWN_ERROR; + } + + CHECK(mOutputFd >= 0); + mWriter = new AMRWriter(dup(mOutputFd)); + mWriter->addSource(audioEncoder); + mWriter->start(); + + return OK; +} + +status_t StagefrightRecorder::startMPEG4Recording() { + mWriter = new MPEG4Writer(dup(mOutputFd)); + + if (mVideoSource == VIDEO_SOURCE_DEFAULT + || mVideoSource == VIDEO_SOURCE_CAMERA) { CHECK(mCamera != NULL); sp cameraSource = @@ -193,11 +278,20 @@ status_t StagefrightRecorder::start() { true /* createEncoder */, cameraSource); CHECK(mOutputFd >= 0); - mWriter = new MPEG4Writer(dup(mOutputFd)); mWriter->addSource(encoder); - mWriter->start(); } + if (mAudioSource != AUDIO_SOURCE_LIST_END) { + sp audioEncoder = createAMRAudioSource(); + + if (audioEncoder == NULL) { + return UNKNOWN_ERROR; + } + + mWriter->addSource(audioEncoder); + } + + mWriter->start(); return OK; } @@ -235,7 +329,9 @@ status_t StagefrightRecorder::reset() { } status_t StagefrightRecorder::getMaxAmplitude(int *max) { - return UNKNOWN_ERROR; + *max = 0; + + return OK; } } // namespace android diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 56c4e0e943724..7ec412dce3d4f 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -23,7 +23,8 @@ namespace android { -class MPEG4Writer; +struct MediaSource; +struct MediaWriter; struct StagefrightRecorder : public MediaRecorderBase { StagefrightRecorder(); @@ -54,7 +55,7 @@ private: sp mCamera; sp mPreviewSurface; sp mListener; - sp mWriter; + sp mWriter; audio_source mAudioSource; video_source mVideoSource; @@ -66,6 +67,10 @@ private: String8 mParams; int mOutputFd; + status_t startMPEG4Recording(); + status_t startAMRRecording(); + sp createAMRAudioSource(); + StagefrightRecorder(const StagefrightRecorder &); StagefrightRecorder &operator=(const StagefrightRecorder &); }; diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index 7b681f12c53b9..caff452cb33b1 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -115,6 +115,7 @@ status_t AMRWriter::start() { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + mReachedEOS = false; mDone = false; pthread_create(&mThread, &attr, ThreadWrapper, this); @@ -179,6 +180,14 @@ void AMRWriter::threadFunc() { break; } } + + Mutex::Autolock autoLock(mLock); + mReachedEOS = true; +} + +bool AMRWriter::reachedEOS() { + Mutex::Autolock autoLock(mLock); + return mReachedEOS; } } // namespace android diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 367459fa34a04..aee4d153999e5 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -92,9 +92,11 @@ MPEG4Writer::~MPEG4Writer() { mTracks.clear(); } -void MPEG4Writer::addSource(const sp &source) { +status_t MPEG4Writer::addSource(const sp &source) { Track *track = new Track(this, source); mTracks.push_back(track); + + return OK; } status_t MPEG4Writer::start() {