您的位置:首页 > 移动开发 > Android开发

Android系统Camera录像过程分析

2016-04-14 10:27 435 查看
原文: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

[java] view
plain copy







public void onCreate(Bundle state)

{

mCurrentModule.init(this, mFrame, true);

}

2.录像Activity初始化

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

[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);

}

二、框架部分

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函数会被调用,如此、完成视频录制。

三、分析问题

我们的问题就出在直接拔掉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

}

四、补充,分析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);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: