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

Android系统Camera录像过程分析

2014-09-20 15:20 621 查看
最近调试系统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 plaincopy





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

2.录像Activity初始化

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

[java]
view plaincopy





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 plaincopy





//当用户点击录像后调用
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 plaincopy





public native void start() throws IllegalStateException;
public native void stop() throws IllegalStateException;

2.Native部分

frameworks/base/media/jni/android_media_MediaRecorder.cpp

[cpp]
view plaincopy





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 plaincopy





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 plaincopy





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 plaincopy





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_***P:
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 plaincopy





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 plaincopy





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 plaincopy





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 plaincopy





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 plaincopy





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