转载请注明出处:http://blog.csdn.net/itachi85/article/details/7216639

从Android 2.0,Google引进了Stagefright,并在android2.3时用Stagefright在Android中是以shared library的形式存在(libstagefright.so),其中AwesomePlayer可用來播放video/audio。AwesomePlayer提供許多API,可以让上层的应用用程式(Java/JNI)來呼叫,我在这里简单说明一下video playback的流程(采用的是android2.2的源码)。

在Java中,若要播放一个影片,我們通常会这样写:

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)音视频处理流程 1. 概要 2. 音频处理流程 3. 视频处理流程 4. 直播客户端处理流程 5. 音频数据流转 音视频基础(1)音视频处理流程 理解音频处理流程对我们做音视 ...

  2. 音视频直播流程及常见视频流协议介绍

    音视频直播流程介绍 常见视频流协议介绍 HLS HLS是苹果公司实现的基于 HTTP 的流媒体传输协议,全称 HTTP Live Streaming,可支持流媒体的直播和点播,主要应用在 iOS 系统 ...

  3. 音视频的流程:录制、播放、编码解码、上传下载等

    仿网易云音乐 安卓版-- https://github.com/aa112901/remusic Android本地视频播放器开发- http://blog.csdn.NET/jwzhangjie/a ...

  4. 内联框架和音视频的播放

    内联框架的作用:用于向当前页面引入一个其他页面 <iframe src="指定引入网页的路径" frameborder="0"(指定内联框架的边框,0表示 ...

  5. 图片标签,内联框架,音视频

    图片标签 图片标签用于向当前页面中引入一个外部图片 使用img标签来引入外部图片,img标签是一个自结束标签 img这种元素属于替换元素(块和行内元素之间,具有两种元素的特点) 属性: src 属性指 ...

  6. HTML5之内联框架和音视频标签

    1.内联框架 使用iframe标签向当前页面中引入其他页面 属性: -src 指定要引入的网页的路径 -framborder 指定内联框架的边框(只有0和1,0表示没有边框,1表示有边框) 2.音频标 ...

  7. Android音视频开发(一)——音视频开发流程

    一.视频文件是什么? 视频文件就相当于是:音频码流和视频码流结合封装的一个容器.其中一个视频文件中可以放入多个音频码流和视频码流的文件. 并且从视频文件中导出来的视频压缩数据是不可以直接进行播放的(假 ...

  8. 音视频开发-ffmpeg介绍-系列一

    目录 一.简介 FFmpeg框架的基本组成包含: 二. FFmpeg框架梳理音视频的流程​编辑 基本概念: 三.ffmpeg.ffplay.ffprobe区别 4.1 ffmpeg是用于转码的应用程序 ...

  9. 音视频通讯QoS技术及其演进

    利用多种算法和策略进行网络传输控制,最大限度满足弱网场景下的音视频用户体验. 良逸|技术作者 01 什么是QoS?音视频通讯QoS是哪一类? QoS(Quality of Service)是服务质量的 ...

最新文章

  1. 力扣(LeetCode)刷题,简单题(第16期)
  2. css中background-image背景图片路径设置
  3. POJ-3621 Sightseeing Cows 最优比率环、01分数规划
  4. 【转载】MySQL Show命令总结
  5. java 同步锁_java线程中的同步锁和互斥锁有什么区别?
  6. centos 7.x 实现免密登录
  7. RocketMQ(十三)——实战-普通消息的发送与消费
  8. linux写文件操作同步,linux 可执行文件与写操作的同步问题(文件读写操作产生的锁机制)...
  9. 用汇编的眼光看C++(之算术符重载陷阱)
  10. ios -特殊符号大全分享给大家,直接复制粘贴就可以使用了!
  11. 安装双系统:Win7/Win10 + Ubuntu(亲测可用)
  12. android 电脑 共享文件夹,安卓手机如何访问电脑局域网共享的文件
  13. android短信uri,Android开发,URI 如:发短信,发彩信,调用通讯录等
  14. linux 冒号命令,Linux命令之:(冒号)
  15. Microsoft visual studio安装2013
  16. Docker生态不会重蹈Hadoop的覆辙
  17. 查看内存大小时解决的单位问题
  18. C语言中,的三种作用
  19. Windows安装Redis5.x
  20. fiddler改网页内容(附常用快捷键)

热门文章

  1. 浅析YUV422模式
  2. 把握好每一个属于自己的清晨
  3. 如何在不丢失游戏数据的情况下重置Nintendo Switch
  4. 经典算法——筛选法求素数(素数筛选)
  5. 自适应均衡matlab仿真,对比RLS,LMS以及NLMS的均衡前后星座图效果,调制采用4QAM,16QAM,64QAM
  6. JavaScript循环语句的性能问题
  7. STM32F205ZET引脚控制FM24CL16B问题记录
  8. Laplace变换笔记(2)
  9. 【转载】什么是计算机图形学?
  10. openharmony移植之编写电阻触摸屏驱动