分析下系統Camera和MediaRecorder(libstagefright中MPEG4Writer以及CameraSource的關係)。java
首先,經過圖示、看看Android系統Camera錄像時的調用時序:android
1.錄像命令時序cookie
2.錄像數據回調時序架構
1、應用部分app
1.主Activity啓動框架
packages/apps/Camera/src/com/android/camera/CameraActivity.javaide
[java] view plain copy函數
- public void onCreate(Bundle state)
- {
- mCurrentModule.init(this, mFrame, true);
- }
2.錄像Activity初始化ui
packages/apps/Camera/src/com/android/camera/VideoModule.javathis
[java] view plain copy
- public void init(CameraActivity activity, View root, boolean reuseScreenNail) {
- {
- CameraOpenThread cameraOpenThread = new CameraOpenThread();
- /*
- protected class CameraOpenThread extends Thread {
- @Override
- public void run() {
- openCamera();
- }
- }
- */
- }
3.開始錄製和中止錄製
[java] view plain copy
- //當用戶點擊錄像後調用
- public void onShutterButtonClick()
- {
- startVideoRecording();
- }
- private void startVideoRecording()
- {
- initializeRecorder();
- /*
- private void initializeRecorder()
- {
- mMediaRecorder = new MediaRecorder();
- //調用至frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
- /*
- status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera,
- const sp<ICameraRecordingProxy> &proxy) {
- mCamera = camera;
- }
- */
- mMediaRecorder.setCamera(mActivity.mCameraDevice.getCamera());
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
- mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
- mMediaRecorder.setProfile(mProfile);
- mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
- mMediaRecorder.setOutputFile(mVideoFilename);
- }
- */
- mMediaRecorder.start();
- }
- //當用戶點擊中止錄製後調用
- public void onShutterButtonClick() {
- public void onShutterButtonClick() {
- }
- private void onStopVideoRecording() {
- stopVideoRecording();
- }
- private boolean stopVideoRecording() {
- mMediaRecorder.setOnErrorListener(null);
- mMediaRecorder.setOnInfoListener(null);
- mMediaRecorder.stop();
- closeCamera(closeEffects);
- }
2、框架部分
1.MediaRecorder的API部分
frameworks/base/media/java/android/media/MediaRecorder.java
[java] view plain copy
- public native void start() throws IllegalStateException;
- public native void stop() throws IllegalStateException;
2.Native部分
frameworks/base/media/jni/android_media_MediaRecorder.cpp
[cpp] view plain copy
- static JNINativeMethod gMethods[] = {
- {"start", "()V", (void *)android_media_MediaRecorder_start},
- {"stop", "()V", (void *)android_media_MediaRecorder_stop},
- }
- static void
- android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
- {
- ALOGV("start");
- sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
- process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");
- }
- static void
- android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)
- {
- ALOGV("stop");
- sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
- process_media_recorder_call(env, mr->stop(), "java/lang/RuntimeException", "stop failed.");
- }
3.C++部分
frameworks/av/media/libmedia/MediaRecorder.cpp
[cpp] view plain copy
- status_t MediaRecorder::start()
- {
- status_t ret = mMediaRecorder->start();
- /*
- MediaRecorder::MediaRecorder() : mSurfaceMediaSource(NULL)
- {
- const sp<IMediaPlayerService>& service(getMediaPlayerService());
- mMediaRecorder = service->createMediaRecorder(getpid());
- //frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
- //sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
- //{
- // sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid);
- // return recorder;
- //}
- }
- */
- }
4.服務端(Android的Binder)
frameworks/av/media/libmediaplayerservice/MediaRecorderClient.cpp
[cpp] view plain copy
- MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid)
- {
- ALOGV("Client constructor");
- mPid = pid;
- mRecorder = new StagefrightRecorder;
- mMediaPlayerService = service;
- }
- status_t MediaRecorderClient::start()
- {
- return mRecorder->start();
- }
Android4.2多媒體使用Stagefright架構
frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
[cpp] view plain copy
- status_t StagefrightRecorder::start() {
- switch (mOutputFormat) {
- case OUTPUT_FORMAT_MPEG_4:
- status = startMPEG4Recording();
- break;
- case OUTPUT_FORMAT_AMR_WB:
- status = startAMRRecording();
- break;
- case OUTPUT_FORMAT_AAC_ADTS:
- status = startAACRecording();
- break;
- case OUTPUT_FORMAT_RTP_AVP:
- status = startRTPRecording();
- break;
- case OUTPUT_FORMAT_MPEG2TS:
- status = startMPEG2TSRecording();
- break;
- }
- }
- status_t StagefrightRecorder::startMPEG4Recording() {
- status_t err = setupMPEG4Recording(
- mOutputFd, mVideoWidth, mVideoHeight,
- mVideoBitRate, &totalBitRate, &mWriter);
- /*
- status_t StagefrightRecorder::setupMPEG4Recording(
- int outputFd,
- int32_t videoWidth, int32_t videoHeight,
- int32_t videoBitRate,
- int32_t *totalBitRate,
- sp<MediaWriter> *mediaWriter) {
- sp<MediaWriter> writer = new MPEG4Writer(outputFd);
- if (mVideoSource < VIDEO_SOURCE_LIST_END) {
- sp<MediaSource> mediaSource;
- //建立CameraSource:
- //這步使用mCamera,mMediaRecorder.setCamera(mActivity.mCameraDevice.getCamera())應用設置過來的
- err = setupMediaSource(&mediaSource);
- sp<MediaSource> encoder;
- //重要!!!!!設置輸入類型,如:YUV420SP等
- err = setupVideoEncoder(mediaSource, videoBitRate, &encoder);
- //sp<MetaData> meta = cameraSource->getFormat();
- //CameraSource.cpp
- ////mColorFormat = getColorFormat(params.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT));
- //CameraHal.cpp:
- ////p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP);
- //setVideoInputFormat(mMIME, meta);
- //setVideoPortFormatType
- writer->addSource(encoder);
- }
- if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
- //建立AudioSource;這步使用new AudioRecord
- err = setupAudioEncoder(writer);
- if (err != OK) return err;
- *totalBitRate += mAudioBitRate;
- }
- }
- */
- err = mWriter->start(meta.get());
- }
MPEG4編碼器部分
frameworks/av/media/libstagefright/MPEG4Writer.cpp
[cpp] view plain copy
- status_t MPEG4Writer::Track::start(MetaData *params) {
- pthread_create(&mThread, &attr, ThreadWrapper, this);
- /*
- void *MPEG4Writer::Track::ThreadWrapper(void *me) {
- Track *track = static_cast<Track *>(me);
- status_t err = track->threadEntry();
- return (void *) err;
- }
- status_t MPEG4Writer::Track::threadEntry() {
- while (!mDone && (err = mSource->read(&buffer)) == OK) {
- //如上read便是frameworks/av/media/libstagefright/CameraSource.cpp的read
- }
- }
- */
- }
- status_t MPEG4Writer::Track::stop() {
- mDone = true;
- void *dummy;
- pthread_join(mThread, &dummy); //等待剛纔的主線程退出
- }
當有數據來時CameraSource的dataCallbackTimestamp函數會被調用,如此、完成視頻錄製。
3、分析問題
咱們的問題就出在直接拔掉Camera時;應用程序調用mMediaRecorder.stop()超時卡死;經分析是上述框架部分「Camera拔出時錄製的主線程不能退出、致使接口阻塞」。後調試發現:mDone變量並不能在兩個線程間傳參數;後打入以前一個patcher(see bug 4724339),修改了主線程中的mSource->read、並在相應的while循環中作判斷,問題解決。
frameworks/av/media/libstagefright/CameraSource.cpp
[cpp] view plain copy
- status_t CameraSource::read(
- MediaBuffer **buffer, const ReadOptions *options) {
- ALOGW("Timed out waiting for incoming camera video frames: %lld us",
- mLastFrameTimestampUs);
- //add by tankai
- // For funtion OMXCodec::read timeout return in writer, then Writer (e.g. VECaptureWriter) thread can exit when
- // media recorder stop
- // reason: when media recorder start with no frame send to OMXCodec(with camera source),
- // media recorder can not stop always (because writer can't exit)
- // this change impact cameras: vecapture fake camera and Webcam
- return ERROR_END_OF_STREAM;
- //end tankai
- }
4、補充,分析MPEG4中Audio流程;接分析二中的實現
1.Audio錄音
frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
[cpp] view plain copy
- status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {() {
- sp<MediaSource> audioEncoder = createAudioSource();
- writer->addSource(audioEncoder);
- }
- sp<MediaSource> StagefrightRecorder::createAudioSource() {
- sp<AudioSource> audioSource =
- new AudioSource(
- mAudioSource,
- mSampleRate,
- mAudioChannels);
- }
frameworks/av/media/libstagefright/AudioSource.cpp
[cpp] view plain copy
- AudioSource::AudioSource(
- audio_source_t inputSource, uint32_t sampleRate, uint32_t channelCount)
- : mRecord(NULL),
- mStarted(false),
- mSampleRate(sampleRate),
- mPrevSampleTimeUs(0),
- mNumFramesReceived(0),
- mNumClientOwnedBuffers(0) {
- mRecord = new AudioRecord(
- inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
- audio_channel_in_mask_from_count(channelCount),
- bufCount * frameCount,
- AudioRecordCallbackFunction,
- this,
- frameCount);
- }
至此,MediaRecorder與AudioFlinger創建聯繫。
2.Audio放音
MediaPlayer播放音頻服務端(後邊有時間在具體分析應用程序/客戶端流程):
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
[cpp] view plain copy
- status_t MediaPlayerService::AudioOutput::open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags)
- {
- AudioTrack *t;
- //最終放聲音使用AudioTrack
- t = new AudioTrack(
- mStreamType,
- sampleRate,
- format,
- channelMask,
- frameCount,
- flags,
- CallbackWrapper,
- newcbd,
- 0, // notification frames
- mSessionId);
- }