Android多媒体之录制 v&&Android系统Camera录像过程分析

  • Post author:
  • Post category:其他


http://blog.csdn.net/tankai19880619/article/details/9270837

一、运行相关

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

frameworks/base/media/jni/android_media_MediaRecorder.cpp

frameworks/av/media/libmedia/Mediarecoder.cpp

二、参数设置相关

frameworks/base/media/java/android/media/CamcorderProfile.java

frameworks/base/media/jni/android_media_MediaProfiles.cpp

frameworks/av/media/libmedia/MediaProfiles.cpp

/system/etc/media_profiles.xml

Android系统Camera录像过程分析

http://blog.csdn.net/tankai19880619/article/details/16848135

最近调试系统Camera,遇到如下问题:在录像过程中,拔掉Camera;会出现应用程序卡死现象。

先说说之前的设计架构:

当用户拔掉Camera时,会给应用程序发送广播;当应用程序收到广播后调用Activity类的finish方法(系统会自动调用onPause方法),而我们的onPause方法做了停止录制和关闭Camera的动作。

问题出在:

当调用系统MediaRecorder的stop方法停止录制时,应用程序因为阻塞而卡死。

下面就着重分析下系统Camera和MediaRecorder(libstagefright中MPEG4Writer以及CameraSource的关系)。

首先,通过图示、看看Android系统Camera录像时的调用时序:

1.录像命令时序


2.录像数据回调时序


一、应用部分

1.主Activity启动

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


  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


  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.开始录制和停止录制


  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


  1. public


    native


    void

    start()

    throws

    IllegalStateException;

  2. public


    native


    void

    stop()

    throws

    IllegalStateException;

2.Native部分

frameworks/base/media/jni/android_media_MediaRecorder.cpp


  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

  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

  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

  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

  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

  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

  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

  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

  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);
  20. }