http://blog.csdn.net/tankai19880619/article/details/16848135
分析下系統Camera和MediaRecorder(libstagefright中MPEG4Writer以及CameraSource的關係)。
首先,通過圖示、看看Android系統Camera錄像時的調用時序:
1.錄像命令時序
2.錄像數據回調時序
一、應用部分
1.主Activity啓動
packages/apps/Camera/src/com/android/camera/CameraActivity.java
-
public void onCreate(Bundle state)
-
{
-
mCurrentModule.init(this, mFrame, true);
-
}
2.錄像Activity初始化
packages/apps/Camera/src/com/android/camera/VideoModule.java
-
public void init(CameraActivity activity, View root, boolean reuseScreenNail) {
-
{
-
CameraOpenThread cameraOpenThread = new CameraOpenThread();
-
-
-
-
-
-
-
-
-
}
3.開始錄製和停止錄製
-
-
public void onShutterButtonClick()
-
{
-
startVideoRecording();
-
}
-
private void startVideoRecording()
-
{
-
initializeRecorder();
-
-
-
-
-
-
-
-
-
-
-
-
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
-
public native void start() throws IllegalStateException;
-
public native void stop() throws IllegalStateException;
2.Native部分
frameworks/base/media/jni/android_media_MediaRecorder.cpp
-
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
-
status_t MediaRecorder::start()
-
{
-
status_t ret = mMediaRecorder->start();
-
-
-
-
-
-
-
-
-
-
-
-
-
-
}
4.服務端(Android的Binder)
frameworks/av/media/libmediaplayerservice/MediaRecorderClient.cpp
-
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
-
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);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
err = mWriter->start(meta.get());
-
}
MPEG4編碼器部分
frameworks/av/media/libstagefright/MPEG4Writer.cpp
-
status_t MPEG4Writer::Track::start(MetaData *params) {
-
pthread_create(&mThread, &attr, ThreadWrapper, this);
-
-
-
-
-
-
-
-
-
-
-
-
-
}
-
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
-
status_t CameraSource::read(
-
MediaBuffer **buffer, const ReadOptions *options) {
-
ALOGW("Timed out waiting for incoming camera video frames: %lld us",
-
mLastFrameTimestampUs);
-
-
-
-
-
-
-
return ERROR_END_OF_STREAM;
-
-
}
四、補充,分析MPEG4中Audio流程;接分析二中的實現
1.Audio錄音
frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp
-
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
-
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
-
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;
-
-
t = new AudioTrack(
-
mStreamType,
-
sampleRate,
-
format,
-
channelMask,
-
frameCount,
-
flags,
-
CallbackWrapper,
-
newcbd,
-
0,
-
mSessionId);
-
}