Stagefright框架解读(—)音视频Playback流程
转载请注明出处:http://blog.csdn.net/itachi85/article/details/7216639
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
mp.prepare();
mp.start();
在Stagefright中,会看到如下的处理:
1.将影片文件的绝对路径指定给uri:
status_t AwesomePlayer::setDataSource(const char *uri, const KeyedVector<String8, String8> *headers) {Mutex::Autolock autoLock(mLock);return setDataSource_l(uri, headers);
}status_t AwesomePlayer::setDataSource_l(const char *uri, const KeyedVector<String8, String8> *headers) {reset_l();mUri = uri;if (headers) {mUriHeaders = *headers;}// The actual work will be done during preparation in the call to// ::finishSetDataSource_l to avoid blocking the calling thread in// setDataSource for any significant time.return OK;
}
2.启动mQueue:
status_t AwesomePlayer::prepare() {Mutex::Autolock autoLock(mLock);return prepare_l();
}status_t AwesomePlayer::prepare_l() {if (mFlags & PREPARED) {return OK;}if (mFlags & PREPARING) {return UNKNOWN_ERROR;}mIsAsyncPrepare = false;status_t err = prepareAsync_l();if (err != OK) {return err;}while (mFlags & PREPARING) {mPreparedCondition.wait(mLock);}return mPrepareResult;
}status_t AwesomePlayer::prepareAsync() {Mutex::Autolock autoLock(mLock);if (mFlags & PREPARING) {return UNKNOWN_ERROR; // async prepare already pending}mIsAsyncPrepare = true;return prepareAsync_l();
}status_t AwesomePlayer::prepareAsync_l() {if (mFlags & PREPARING) {return UNKNOWN_ERROR; // async prepare already pending}if (!mQueueStarted) {mQueue.start();mQueueStarted = true;}mFlags |= PREPARING;mAsyncPrepareEvent = new AwesomeEvent(this, &AwesomePlayer::onPrepareAsyncEvent);mQueue.postEvent(mAsyncPrepareEvent);return OK;
}
3.onprepareAsyncEvent被触发,根据传来文件的header来创建相应的解析器,并初始化音视频解码器:
void AwesomePlayer::onPrepareAsyncEvent() {sp<Prefetcher> prefetcher;{Mutex::Autolock autoLock(mLock);if (mFlags & PREPARE_CANCELLED) {LOGI("prepare was cancelled before doing anything");abortPrepare(UNKNOWN_ERROR);return;}if (mUri.size() > 0) {//在这个方法中创建解析器<strong>status_t err = finishSetDataSource_l();</strong>if (err != OK) {abortPrepare(err);return;}}if (mVideoTrack != NULL && mVideoSource == NULL) {//初始化视频解码器<strong>status_t err = initVideoDecoder();</strong>if (err != OK) {abortPrepare(err);return;}}if (mAudioTrack != NULL && mAudioSource == NULL) {//初始化音频解码器<strong>status_t err = initAudioDecoder();
</strong>if (err != OK) {abortPrepare(err);return;}}prefetcher = mPrefetcher;}if (prefetcher != NULL) {{Mutex::Autolock autoLock(mLock);if (mFlags & PREPARE_CANCELLED) {LOGI("prepare was cancelled before preparing the prefetcher");prefetcher.clear();abortPrepare(UNKNOWN_ERROR);return;}}LOGI("calling prefetcher->prepare()");status_t result =prefetcher->prepare(&AwesomePlayer::ContinuePreparation, this);prefetcher.clear();if (result == OK) {LOGI("prefetcher is done preparing");} else {Mutex::Autolock autoLock(mLock);CHECK_EQ(result, -EINTR);LOGI("prefetcher->prepare() was cancelled early.");abortPrepare(UNKNOWN_ERROR);return;}}Mutex::Autolock autoLock(mLock);if (mIsAsyncPrepare) {if (mVideoWidth < 0 || mVideoHeight < 0) {notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);} else {notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);}notifyListener_l(MEDIA_PREPARED);}mPrepareResult = OK;mFlags &= ~(PREPARING|PREPARE_CANCELLED);mFlags |= PREPARED;mAsyncPrepareEvent = NULL;mPreparedCondition.broadcast();postBufferingEvent_l();
}
status_t AwesomePlayer::finishSetDataSource_l() {sp<DataSource> dataSource;if (!strncasecmp("http://", mUri.string(), 7)) {mConnectingDataSource = new HTTPDataSource(mUri, &mUriHeaders);mLock.unlock();status_t err = mConnectingDataSource->connect();mLock.lock();if (err != OK) {mConnectingDataSource.clear();LOGI("mConnectingDataSource->connect() returned %d", err);return err;}dataSource = new CachingDataSource(mConnectingDataSource, 64 * 1024, 10);mConnectingDataSource.clear();} else {dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);}if (dataSource == NULL) {return UNKNOWN_ERROR;}<strong>sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
</strong>if (extractor == NULL) {return UNKNOWN_ERROR;}dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);if (mDecryptHandle != NULL&& RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);}if (dataSource->flags() & DataSource::kWantsPrefetching) {mPrefetcher = new Prefetcher;}<strong> return setDataSource_l(extractor)</strong>;
}
4.使用extractor对文件进行A/V分离:
status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {bool haveAudio = false;bool haveVideo = false;for (size_t i = 0; i < extractor->countTracks(); ++i) {sp<MetaData> meta = extractor->getTrackMetaData(i);const char *mime;CHECK(meta->findCString(kKeyMIMEType, &mime));if (!haveVideo && !strncasecmp(mime, "video/", 6)) {setVideoSource(extractor->getTrack(i));haveVideo = true;} else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {setAudioSource(extractor->getTrack(i));haveAudio = true;}if (haveAudio && haveVideo) {break;}}if (!haveAudio && !haveVideo) {return UNKNOWN_ERROR;}mExtractorFlags = extractor->flags();return OK;
}
5.将解析后的音视频数据分别交给VideoTrack和AudioTrack:
void AwesomePlayer::setVideoSource(sp<MediaSource> source) {CHECK(source != NULL);if (mPrefetcher != NULL) {source = mPrefetcher->addSource(source);}mVideoTrack = source;
}void AwesomePlayer::setAudioSource(sp<MediaSource> source) {CHECK(source != NULL);if (mPrefetcher != NULL) {source = mPrefetcher->addSource(source);}mAudioTrack = source;
}
6.根据mVideoTrck中的编码类型来选择 video decoder 同理根据mAudioTrack中的编码类型来选择 audio decoder:
status_t AwesomePlayer::initVideoDecoder() {mVideoSource = OMXCodec::Create(mClient.interface(), mVideoTrack->getFormat(),false, // createEncodermVideoTrack);if (mVideoSource != NULL) {int64_t durationUs;if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {Mutex::Autolock autoLock(mMiscStateLock);if (mDurationUs < 0 || durationUs > mDurationUs) {mDurationUs = durationUs;}}CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));status_t err = mVideoSource->start();if (err != OK) {mVideoSource.clear();return err;}}return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
}
7.将mVideoEvent放入mQueue中,开始解码播放,并交由mvideoRenderer来画出 audio的数据则交由audioplayer来管理,它最终将解码的数据交给audioTrack并由audioTrack和audioFlinger进行交互,最终将数据交给audio hal层,这个我们以后会做讲解:
status_t AwesomePlayer::play() {Mutex::Autolock autoLock(mLock);return play_l();
}
status_t AwesomePlayer::play_l() {if (mFlags & PLAYING) {return OK;}if (!(mFlags & PREPARED)) {status_t err = prepare_l();if (err != OK) {return err;}}mFlags |= PLAYING;mFlags |= FIRST_FRAME;bool deferredAudioSeek = false;if (mAudioSource != NULL) {if (mAudioPlayer == NULL) {if (mAudioSink != NULL) {//音频数据由audioplayer进行管理mAudioPlayer = new AudioPlayer(mAudioSink);mAudioPlayer->setSource(mAudioSource);// We've already started the MediaSource in order to enable// the prefetcher to read its data.//调用audioPlayer的start方法则是调用audioSource对数据进行解码//并将解码似得数据最终交给audioTrack,并调用audioTrack的start方法与audioFlinger进行交互status_t err = mAudioPlayer->start(true /* sourceAlreadyStarted */);if (err != OK) {delete mAudioPlayer;mAudioPlayer = NULL;mFlags &= ~(PLAYING | FIRST_FRAME);return err;}delete mTimeSource;mTimeSource = mAudioPlayer;deferredAudioSeek = true;mWatchForAudioSeekComplete = false;mWatchForAudioEOS = true;}} else {mAudioPlayer->resume();}postCheckAudioStatusEvent_l();}if (mTimeSource == NULL && mAudioPlayer == NULL) {mTimeSource = new SystemTimeSource;}if (mVideoSource != NULL) {// Kick off video playback//将mVideoEvent放入queue中postVideoEvent_l();}if (deferredAudioSeek) {// If there was a seek request while we were paused// and we're just starting up again, honor the request now.seekAudioIfNecessary_l();}if (mFlags & AT_EOS) {// Legacy behaviour, if a stream finishes playing and then// is started again, we play from the start...seekTo_l(0);}if (mDecryptHandle != NULL) {int64_t position;getPosition(&position);mDrmManagerClient->setPlaybackStatus(mDecryptHandle,Playback::START, position / 1000);}return OK;
}void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {if (mVideoEventPending) {return;}mVideoEventPending = true;mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
}
void AwesomePlayer::onVideoEvent()
{mVideoSource->read(&mVideoBuffer, &options);mVideoRenderer->render(mVideoBuffer);postVideoEvent_l();
}
Stagefright框架解读(—)音视频Playback流程相关推荐
- 音视频基础(1)音视频处理流程
文章目录 音视频基础(1)音视频处理流程 1. 概要 2. 音频处理流程 3. 视频处理流程 4. 直播客户端处理流程 5. 音频数据流转 音视频基础(1)音视频处理流程 理解音频处理流程对我们做音视 ...
- 音视频直播流程及常见视频流协议介绍
音视频直播流程介绍 常见视频流协议介绍 HLS HLS是苹果公司实现的基于 HTTP 的流媒体传输协议,全称 HTTP Live Streaming,可支持流媒体的直播和点播,主要应用在 iOS 系统 ...
- 音视频的流程:录制、播放、编码解码、上传下载等
仿网易云音乐 安卓版-- https://github.com/aa112901/remusic Android本地视频播放器开发- http://blog.csdn.NET/jwzhangjie/a ...
- 内联框架和音视频的播放
内联框架的作用:用于向当前页面引入一个其他页面 <iframe src="指定引入网页的路径" frameborder="0"(指定内联框架的边框,0表示 ...
- 图片标签,内联框架,音视频
图片标签 图片标签用于向当前页面中引入一个外部图片 使用img标签来引入外部图片,img标签是一个自结束标签 img这种元素属于替换元素(块和行内元素之间,具有两种元素的特点) 属性: src 属性指 ...
- HTML5之内联框架和音视频标签
1.内联框架 使用iframe标签向当前页面中引入其他页面 属性: -src 指定要引入的网页的路径 -framborder 指定内联框架的边框(只有0和1,0表示没有边框,1表示有边框) 2.音频标 ...
- Android音视频开发(一)——音视频开发流程
一.视频文件是什么? 视频文件就相当于是:音频码流和视频码流结合封装的一个容器.其中一个视频文件中可以放入多个音频码流和视频码流的文件. 并且从视频文件中导出来的视频压缩数据是不可以直接进行播放的(假 ...
- 音视频开发-ffmpeg介绍-系列一
目录 一.简介 FFmpeg框架的基本组成包含: 二. FFmpeg框架梳理音视频的流程编辑 基本概念: 三.ffmpeg.ffplay.ffprobe区别 4.1 ffmpeg是用于转码的应用程序 ...
- 音视频通讯QoS技术及其演进
利用多种算法和策略进行网络传输控制,最大限度满足弱网场景下的音视频用户体验. 良逸|技术作者 01 什么是QoS?音视频通讯QoS是哪一类? QoS(Quality of Service)是服务质量的 ...
最新文章
- 力扣(LeetCode)刷题,简单题(第16期)
- css中background-image背景图片路径设置
- POJ-3621 Sightseeing Cows 最优比率环、01分数规划
- 【转载】MySQL Show命令总结
- java 同步锁_java线程中的同步锁和互斥锁有什么区别?
- centos 7.x 实现免密登录
- RocketMQ(十三)——实战-普通消息的发送与消费
- linux写文件操作同步,linux 可执行文件与写操作的同步问题(文件读写操作产生的锁机制)...
- 用汇编的眼光看C++(之算术符重载陷阱)
- ios -特殊符号大全分享给大家,直接复制粘贴就可以使用了!
- 安装双系统:Win7/Win10 + Ubuntu(亲测可用)
- android 电脑 共享文件夹,安卓手机如何访问电脑局域网共享的文件
- android短信uri,Android开发,URI 如:发短信,发彩信,调用通讯录等
- linux 冒号命令,Linux命令之:(冒号)
- Microsoft visual studio安装2013
- Docker生态不会重蹈Hadoop的覆辙
- 查看内存大小时解决的单位问题
- C语言中,的三种作用
- Windows安装Redis5.x
- fiddler改网页内容(附常用快捷键)