1. 程式人生 > >Android系統Camera錄影過程分析

Android系統Camera錄影過程分析

  首先,通過圖示、看看Android系統Camera錄影時的呼叫時序:

1.錄影命令時序

2.錄影資料回撥時序

一、應用部分

1.主Activity啟動

packages/apps/Camera/src/com/android/camera/CameraActivity.java

[java] view plain copy

  1. public void onCreate(Bundle state)   
  2. {  
  3.   mCurrentModule.init(this, mFrame, true);  
  4. }  

2.錄影Activity初始化

packages/apps/Camera/src/com/android/camera/VideoModule.java

[java] view plain copy

  1. public void init(CameraActivity activity, View root, boolean reuseScreenNail) {  
  2. {  
  3.   CameraOpenThread cameraOpenThread = new CameraOpenThread();  
  4.   /* 
  5.   protected class CameraOpenThread extends Thread { 
  6.     @Override 
  7.     public void run() { 
  8.       openCamera(); 
  9.     } 
  10.   } 
  11.   */  
  12. }  

3.開始錄製和停止錄製

[java] view plain copy

  1. //當用戶點選錄影後呼叫  
  2. public void onShutterButtonClick()   
  3. {  
  4.   startVideoRecording();  
  5. }  
  6. private void startVideoRecording()   
  7. {  
  8.   initializeRecorder();  
  9.   /* 
  10.   private void initializeRecorder()    
  11.   { 
  12.     mMediaRecorder = new MediaRecorder(); 
  13.     //呼叫至frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp 
  14.     /* 
  15.     status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera, 
  16.                                         const sp<ICameraRecordingProxy> &proxy) { 
  17.       mCamera = camera; 
  18.     } 
  19.     */  
  20.     mMediaRecorder.setCamera(mActivity.mCameraDevice.getCamera());   
  21.     mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);  
  22.     mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);  
  23.     mMediaRecorder.setProfile(mProfile);  
  24.     mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);  
  25.     mMediaRecorder.setOutputFile(mVideoFilename);  
  26.   }  
  27.   */  
  28.   mMediaRecorder.start();  
  29. }  
  30. //當用戶點選停止錄製後呼叫  
  31. public void onShutterButtonClick() {  
  32.   public void onShutterButtonClick() {  
  33. }  
  34. private void onStopVideoRecording() {  
  35.   stopVideoRecording();  
  36. }  
  37. private boolean stopVideoRecording() {  
  38.   mMediaRecorder.setOnErrorListener(null);  
  39.   mMediaRecorder.setOnInfoListener(null);  
  40.   mMediaRecorder.stop();  
  41.   closeCamera(closeEffects);  
  42. }  

二、框架部分

1.MediaRecorder的API部分

frameworks/base/media/java/android/media/MediaRecorder.java

[java] view plain copy

  1. public native void start() throws IllegalStateException;  
  2. public native void stop() throws IllegalStateException;  

2.Native部分

frameworks/base/media/jni/android_media_MediaRecorder.cpp

[cpp] view plain copy

  1. static JNINativeMethod gMethods[] = {  
  2.   {"start",  "()V",   (void *)android_media_MediaRecorder_start},  
  3.   {"stop",  "()V",   (void *)android_media_MediaRecorder_stop},  
  4. }  
  5. static void  
  6. android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)  
  7. {  
  8.   ALOGV("start");  
  9.   sp<MediaRecorder> mr = getMediaRecorder(env, thiz);  
  10.   process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");  
  11. }  
  12. static void  
  13. android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)  
  14. {  
  15.   ALOGV("stop");  
  16.   sp<MediaRecorder> mr = getMediaRecorder(env, thiz);  
  17.   process_media_recorder_call(env, mr->stop(), "java/lang/RuntimeException", "stop failed.");  
  18. }  

3.C++部分

frameworks/av/media/libmedia/MediaRecorder.cpp

[cpp] view plain copy

  1. status_t MediaRecorder::start()  
  2. {  
  3.   status_t ret = mMediaRecorder->start();  
  4.   /* 
  5.   MediaRecorder::MediaRecorder() : mSurfaceMediaSource(NULL) 
  6.   { 
  7.     const sp<IMediaPlayerService>& service(getMediaPlayerService()); 
  8.     mMediaRecorder = service->createMediaRecorder(getpid()); 
  9.     //frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp 
  10.     //sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid) 
  11.     //{ 
  12.     //  sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid); 
  13.     //  return recorder; 
  14.     //} 
  15.   } 
  16.   */  
  17. }  

 

4.服務端(Android的Binder)

frameworks/av/media/libmediaplayerservice/MediaRecorderClient.cpp

[cpp] view plain copy

  1. MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid)  
  2. {  
  3.   ALOGV("Client constructor");  
  4.   mPid = pid;  
  5.   mRecorder = new StagefrightRecorder;  
  6.   mMediaPlayerService = service;  
  7. }  
  8. status_t MediaRecorderClient::start()  
  9. {  
  10.   return mRecorder->start();  
  11. }  

Android4.2多媒體使用Stagefright架構

frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp

[cpp] view plain copy

  1. status_t StagefrightRecorder::start() {  
  2.   switch (mOutputFormat) {  
  3.     case OUTPUT_FORMAT_MPEG_4:  
  4.       status = startMPEG4Recording();  
  5.       break;  
  6.     case OUTPUT_FORMAT_AMR_WB:  
  7.       status = startAMRRecording();  
  8.       break;  
  9.     case OUTPUT_FORMAT_AAC_ADTS:  
  10.       status = startAACRecording();      
  11.       break;  
  12.     case OUTPUT_FORMAT_RTP_AVP:    
  13.       status = startRTPRecording();  
  14.       break;  
  15.     case OUTPUT_FORMAT_MPEG2TS:  
  16.       status = startMPEG2TSRecording();  
  17.       break;  
  18.   }  
  19. }  
  20. status_t StagefrightRecorder::startMPEG4Recording() {  
  21.   status_t err = setupMPEG4Recording(  
  22.             mOutputFd, mVideoWidth, mVideoHeight,  
  23.             mVideoBitRate, &totalBitRate, &mWriter);  
  24.   /* 
  25.   status_t StagefrightRecorder::setupMPEG4Recording( 
  26.         int outputFd, 
  27.         int32_t videoWidth, int32_t videoHeight, 
  28.         int32_t videoBitRate, 
  29.         int32_t *totalBitRate, 
  30.         sp<MediaWriter> *mediaWriter) { 
  31.     sp<MediaWriter> writer = new MPEG4Writer(outputFd); 
  32.     if (mVideoSource < VIDEO_SOURCE_LIST_END) { 
  33.       sp<MediaSource> mediaSource; 
  34.       //建立CameraSource: 
  35.       //這步使用mCamera,mMediaRecorder.setCamera(mActivity.mCameraDevice.getCamera())應用設定過來的 
  36.       err = setupMediaSource(&mediaSource);  
  37.       sp<MediaSource> encoder; 
  38.       //重要!!!!!設定輸入型別,如:YUV420SP等 
  39.       err = setupVideoEncoder(mediaSource, videoBitRate, &encoder);  
  40.       //sp<MetaData> meta = cameraSource->getFormat(); 
  41.       //CameraSource.cpp 
  42.       ////mColorFormat = getColorFormat(params.get(CameraParameters::KEY_VIDEO_FRAME_FORMAT)); 
  43.       //CameraHal.cpp: 
  44.       ////p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, (const char *) CameraParameters::PIXEL_FORMAT_YUV420SP); 
  45.       //setVideoInputFormat(mMIME, meta); 
  46.       //setVideoPortFormatType 
  47.       writer->addSource(encoder); 
  48.     } 
  49.     if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) { 
  50.       //建立AudioSource;這步使用new AudioRecord 
  51.       err = setupAudioEncoder(writer);  
  52.       if (err != OK) return err; 
  53.       *totalBitRate += mAudioBitRate; 
  54.     } 
  55.   } 
  56.   */    
  57.   err = mWriter->start(meta.get());  
  58. }  

MPEG4編碼器部分

frameworks/av/media/libstagefright/MPEG4Writer.cpp

[cpp] view plain copy

  1. status_t MPEG4Writer::Track::start(MetaData *params) {  
  2.   pthread_create(&mThread, &attr, ThreadWrapper, this);  
  3.   /* 
  4.   void *MPEG4Writer::Track::ThreadWrapper(void *me) { 
  5.     Track *track = static_cast<Track *>(me); 
  6.     status_t err = track->threadEntry(); 
  7.     return (void *) err; 
  8.   } 
  9.   status_t MPEG4Writer::Track::threadEntry() { 
  10.     while (!mDone && (err = mSource->read(&buffer)) == OK) { 
  11.       //如上read即是frameworks/av/media/libstagefright/CameraSource.cpp的read 
  12.     } 
  13.   } 
  14.   */    
  15. }  
  16. status_t MPEG4Writer::Track::stop() {  
  17.   mDone = true;  
  18.   void *dummy;  
  19.   pthread_join(mThread, &dummy); //等待剛才的主執行緒退出  
  20. }  

當有資料來時CameraSource的dataCallbackTimestamp函式會被呼叫,如此、完成視訊錄製。

三、分析問題

  我們的問題就出在直接拔掉Camera時;應用程式呼叫mMediaRecorder.stop()超時卡死;經分析是上述框架部分“Camera拔出時錄製的主執行緒不能退出、導致介面阻塞”。後除錯發現:mDone變數並不能在兩個執行緒間傳引數;後打入之前一個patcher(see bug 4724339),修改了主執行緒中的mSource->read、並在相應的while迴圈中做判斷,問題解決。

frameworks/av/media/libstagefright/CameraSource.cpp

 

[cpp] view plain copy

  1. status_t CameraSource::read(  
  2.         MediaBuffer **buffer, const ReadOptions *options) {  
  3.   ALOGW("Timed out waiting for incoming camera video frames: %lld us",  
  4.                     mLastFrameTimestampUs);  
  5.   //add by tankai  
  6.   // For funtion OMXCodec::read timeout return in writer, then Writer (e.g. VECaptureWriter) thread can exit  when  
  7.   // media recorder stop  
  8.   // reason: when media recorder start with no frame send to OMXCodec(with camera source),  
  9.   // media recorder can not stop always (because writer can't exit)  
  10.   // this change impact cameras: vecapture fake camera and Webcam  
  11.   return ERROR_END_OF_STREAM;  
  12.   //end tankai  
  13. }  

 

四、補充,分析MPEG4中Audio流程;接分析二中的實現

1.Audio錄音

frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp

[cpp] view plain copy

  1. status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {() {  
  2.   sp<MediaSource> audioEncoder = createAudioSource();  
  3.   writer->addSource(audioEncoder);  
  4. }  
  5. sp<MediaSource> StagefrightRecorder::createAudioSource() {  
  6.   sp<AudioSource> audioSource =  
  7.         new AudioSource(  
  8.                 mAudioSource,  
  9.                 mSampleRate,  
  10.                 mAudioChannels);  
  11. }  

frameworks/av/media/libstagefright/AudioSource.cpp

[cpp] view plain copy

  1. AudioSource::AudioSource(  
  2.         audio_source_t inputSource, uint32_t sampleRate, uint32_t channelCount)  
  3.     : mRecord(NULL),  
  4.       mStarted(false),  
  5.       mSampleRate(sampleRate),  
  6.       mPrevSampleTimeUs(0),  
  7.       mNumFramesReceived(0),  
  8.       mNumClientOwnedBuffers(0) {  
  9.   mRecord = new AudioRecord(  
  10.                     inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,  
  11.                     audio_channel_in_mask_from_count(channelCount),  
  12.                     bufCount * frameCount,  
  13.                     AudioRecordCallbackFunction,  
  14.                     this,  
  15.                     frameCount);  
  16. }  

 

至此,MediaRecorder與AudioFlinger建立聯絡。

2.Audio放音

MediaPlayer播放音訊服務端(後邊有時間在具體分析應用程式/客戶端流程):

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

[cpp] view plain copy

  1. status_t MediaPlayerService::AudioOutput::open(  
  2.         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,  
  3.         audio_format_t format, int bufferCount,  
  4.         AudioCallback cb, void *cookie,  
  5.         audio_output_flags_t flags)  
  6. {  
  7.   AudioTrack *t;  
  8.   //最終放聲音使用AudioTrack  
  9.   t = new AudioTrack(  
  10.                 mStreamType,  
  11.                 sampleRate,  
  12.                 format,  
  13.                 channelMask,  
  14.                 frameCount,  
  15.                 flags,  
  16.                 CallbackWrapper,  
  17.                 newcbd,  
  18.                 0,  // notification frames  
  19.                 mSessionId);