stagefright dota是什么意思思

Android多媒体化编程培训-火龙果软件
追随技术信仰
随时听讲座
每天看新闻
相关课程 &
Android多媒体化编程
主讲嘉宾:
时间地点:北京
上海 深圳 根据报名开班
课程费用:5000元/人 详见
企业内训:可以根据企业需求,定制内训,详见
本课程针对Android多媒体框架,带领学员实践如何进行多媒体编程:了解多媒体编程原理、掌握硬件加速技术、实现输入输出、媒体播放应用软件开发、实现交互特性。
培训目标:
多媒体编程原理
多媒体处理基础知识
Android多媒体框架
Android多媒体编程
不同厂商的多媒体加速硬件特点
StageFright
多媒体应用极限编程
万能播放器之ffmpeg
万能播放器之VLC
文字语音互换
授课方式: 定制课程 + 案例讲解
+ 小组讨论,60%案例讲解,40%实践演练
培训内容:
多媒体编程原理
多媒体处理基础知识
多媒体技术
音视频编解码原理
已有的多媒体框架
开源多媒体框架的结构分析
音频输出处理
视频输出处理
图形加速,OpenGL框架
Android多媒体框架
Android处理多媒体的不同子框架
Media层次简要介绍
AudioFlinger
SurfaceFlinger
Media的后处理
Android多媒体编程
MediaPlayer
AudioTrack
Camera调用的不同方法
基于Service的音频播放器
P2P多媒体编程
线程化视频播放器
Framework里的Media框架层构造
OpenMAX框架
Media子框架的设计与实现
Media子框架内交互
Media框架的拓展
Media开发过程里的测试
多媒体编程硬件加速
不同厂商的多媒体加速硬件特点
多媒体加速的基本原理
Neon指令级加速
OpenCore的结构性特点
OpenCore软件框架
OpenCore实现分析
拓展OpenCore的多媒体格式处理能力
OpenCore的硬件解码加速
OpenCore的硬件编码加速
OpenCore的优缺点
StageFright
StageFright与OpenCore的异同
StageFright的结构
拓展StageFright的媒体处理能力
在StageFright里加入新的Codec
实现StageFright的硬件加速
OpenMAX IL
Gstreamer简介
Gstreamer框架结构
在Android里使用Gstreamer的缺点
在Android使用Gstreamer
Gstreamer的硬件加速
实践:(选一)
拓展OpenCore的格式支持,实现OpenCore的一种硬件加速插件
拓展OpenCore的格式支持,实现StageFright的一种硬件加速插件
多媒体的输入输出
Camera的基本原理
V4L2驱动框架
Android里的Camera框架
Camera HAL的结构
Overlay HAL
Camera HAL的实现
3D Camera支持
4.0里加入的Camera拓展
HDMI的V4L2支持
Android的HDMI支持框架
Android 2.3里的HDMI支持实例
Mirror与Video plane
HDMI的检测与自适应
Android 4.0的HDMI支持
Android显示处理的基本框架
显示处理层次
Linux内核的Framebuffer驱动框架
SurfaceFlinger
Gralloc HAL
Hardware Composer HAL
OpenGL ES与EGL
GPU驱动的Hack
linux里的音频处理概况
Android的音频处理框架
AudioFlinger
AudioManager
不同的Audio HAL实现
多媒体应用之极限编程
万能播放器之ffmpeg
Android多媒体处理的缺陷
Ffmpeg简介
在Android里编译FFmpeg
实现FFmpeg的JNI
FFMPEG的图像处理加速
FFMPEG的硬件加速
万能播放器之VLC
Libvlc编程
VLC的JNI实现
实现VLC播放器
Android里的音频处理缺陷
HIFI数字化
音频后处理原理
Android里的音频的EQ支持
Android里的多声道支持
Audio的多声道Mixing
使用PulseAudio
实践: (选一)
实现FFMPEG的Android多版本支持播放器
实现VLC的多版本支持播放器
移植Android里的PulseAudio
实现交互特性
基于JSON的WebService API
SmarterAdapter
支持不同视频网站的在线播放
DLNA网络协议
Android的DLNA支持
基于Android的Remote Control
文字语音互换
TTS与Speech Recognizer原理
构建基本的TTS引擎
Nuance语音引擎基本构架
基于Nuance语音引擎开发语音命令控制
山寨化Siri
图像处理基本原理与相关技术
图像的基本处理,放大缩小、旋转、变形
图像的高级处理,图像识别、滤镜
OpenCV简介
基于OpenCV的特殊应用
Face Detection
Vide Editor
Argmented Reality简介
AR的系统构成
基于AR的虚拟双向交互
Vuforia编程
使用ARToolKit
实践:实现简易Android下的DLNA客户端
如果课程内容不符合您的期望,
课程特点:1、理论与实践相结合,解决你的实际问题。2、真实案例的剖析,深入浅出的讲解,使你能学以致用。
&培训对象:Android应用开发工程师
&学员基础:具有一定开发经验。
最新活动计划
希望我们的资料可以帮助你学习,也欢迎投稿&提建议给我频道编辑: jely
&&&& 件:jely@
&&京ICP备号&&京公海网安备号温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
做我自己,让别人说去吧!
LOFTER精选
阅读(427)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'stagefright增加avi解码器',
blogAbstract:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
stagefright框架(一)Video Playback的流程
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口android&&stagefright框架
stagefright框架(一)Video
Playback的流程
在Android上,預設的多媒體框架(multimedia
framework)是OpenCORE。OpenCORE的優點是兼顧了跨平台的移植性,而且已經過多方驗證,所以相對來說較為穩定;但是其缺點是過於龐大複雜,需要耗費相當多的時間去維護。從Android
2.0開始,Google引進了架構稍為簡潔的Stagefright,並且有逐漸取代OpenCORE的趨勢&(註1)。
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
Stagefright在Android多媒體架構中的位置。
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
Stagefright所涵蓋的模組&(註2)。
以下我們就先來看看Stagefright是如何播放一個影片檔。
Stagefright在Android中是以shared
library的形式存在(libstagefright.so),其中的module --
AwesomePlayer可用來播放video/audio(註3)。AwesomePlayer提供許多API,可以讓上層的應用程式(Java/JNI)來呼叫,我們以一個簡單的程式來說明video
playback的流程。
在Java中,若要播放一個影片檔,我們會這樣寫:
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
......&(1)
mp.prepare();
........................&(2)、(3)
mp.start();
..........................&(4)
在Stagefright中,則會看到相對應的處理;
(1)將檔案的絕對路徑指定給mUri
status_t AwesomePlayer::setDataSource(constchar*&uri,...)
&&return&setDataSource_l(uri,...);
status_t AwesomePlayer::setDataSource_l(constchar*&uri,...)
&&mUri&=&uri;
(2)啟動mQueue,作為event handler
status_t AwesomePlayer::prepare()
&&return&prepare_l();
status_t AwesomePlayer::prepare_l()
&&prepareAsync_l();
&&while&(mFlags&&PREPARING)
&&&&mPreparedCondition.wait(mLock);
status_t AwesomePlayer::prepareAsync_l()
&&mQueue.start();
&&mFlags&|=&PREPARING;
&&mAsyncPrepareEvent&=&new&AwesomeEvent(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&this
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&AwesomePlayer::onPrepareAsyncEvent);
&&mQueue.postEvent(mAsyncPrepareEvent);
onPrepareAsyncEvent被觸發
void&AwesomePlayer::onPrepareAsyncEvent()
&&finishSetDataSource_l();
&&initVideoDecoder();......(3.3)
&&initAudioDecoder();
status_t AwesomePlayer::finishSetDataSource_l()
&&dataSource&=&DataSource::CreateFromURI(mUri.string(),...);
&&sp&&/span&MediaExtractor&&extractor=
&&&&&&&&&&&&&&&&&&&&&MediaExtractor::Create(dataSource);.....(3.1)
&&return&setDataSource_l(extractor);.........................(3.2)
(3.1)解析mUri所指定的檔案,並且根據其header來選擇對應的extractor
sp&&/span&MediaExtractor&&MediaExtractor::Create(const&sp&&/span&DataSource&&source,...)
&&source-&sniff(&tmp,...);
&&mime&=&tmp.string();
&&if&(!strcasecmp(mime,&MEDIA_MIMETYPE_CONTAINER_MPEG4)
&&&&return&new&MPEG4Extractor(source);
&&else&if&(!strcasecmp(mime,&MEDIA_MIMETYPE_AUDIO_MPEG))
&&&&return&new&MP3Extractor(source);
&&else&if&(!strcasecmp(mime,&MEDIA_MIMETYPE_AUDIO_AMR_NB)
&&&&return&new&AMRExtractor(source);
(3.2)使用extractor對檔案做A/V的分離
(mVideoTrack/mAudioTrack)
status_t AwesomePlayer::setDataSource_l(const&sp&&/span&MediaExtractor&&extractor)
&&for&(size_t&i=&0;&i&&/span&&extractor-&countTracks();++i)
&&&&sp&&/span&MetaData&&meta=&extractor-&getTrackMetaData(i);
&&&&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;
void&AwesomePlayer::setVideoSource(sp&&/span&MediaSource&&source)
&&mVideoTrack&=&source;
(3.3)根據mVideoTrack中的編碼類型來選擇video
(mVideoSource)
status_t AwesomePlayer::initVideoDecoder()
&&mVideoSource&=&OMXCodec::Create(mClient.interface(),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&mVideoTrack-&getFormat(),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&false,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&mVideoTrack);
(4)&將mVideoEvent放入mQueue中,開始解碼播放,並交由mVideoRenderer來畫出
status_t AwesomePlayer::play()
&&return&play_l();
status_t AwesomePlayer::play_l()
&&postVideoEvent_l();
void&AwesomePlayer::postVideoEvent_l(int64_t&delayUs)
&&mQueue.postEventWithDelay(mVideoEvent,&delayUs);
void&AwesomePlayer::onVideoEvent()
&&mVideoSource-&read(&mVideoBuffer,&options);
&&[Check Timestamp]
&&mVideoRenderer-&render(mVideoBuffer);
&&postVideoEvent_l();
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" STYLE="border-style:"
TITLE="android&&stagefright框架" />
(註1) 從Android2.3 (Gingerbread)
開始,預設的多媒體框架為 Stagefright。
(註2) Stagefright的架構尚不斷在演進中,本系列文章並未含括所有的模組。
(註3) Audio的播放是交由 AudioPlayer 來處理,請參考《》。
stagefright框架(二)-
和OpenMAX的運作
Stagefright的編解碼功能是利用OpenMAX框架,而且用的還是OpenCORE之OMX的實作,我們來看一下Stagefright和OMX是如何運作的。
(1) OMX_Init
OMXClient mC
AwesomePlayer::AwesomePlayer()
&&mClient.connect();
status_t OMXClient::connect()
service-&getOMX();
sp MediaPlayerService::getOMX()
&&mOMX = new OMX;
OMX::OMX() : mMaster(new OMXMaster)
OMXMaster::OMXMaster()
&&addPlugin(new
OMXPVCodecsPlugin);
OMXPVCodecsPlugin::OMXPVCodecsPlugin()
&&OMX_MasterInit();
OMX_ERRORTYPE OMX_MasterInit() &-- under OpenCORE
&&return OMX_Init();
(2) OMX_SendCommand
OMXCodec::function_name()
&&mOMX-&sendCommand(mNode,
OMX_CommandStateSet, OMX_StateIdle);
status_t OMX::sendCommand(node, cmd, param)
findInstance(node)-&sendCommand(cmd, param);
status_t OMXNodeInstance::sendCommand(cmd, param)
&&OMX_SendCommand(mHandle, cmd,
param, NULL);
(3)&其他作用在 OMX
元件的指令
其他作用在OMX元件的指令也和OMX_SendCommand的callpath一樣,請見下表:
OMXNodeInstance
(OMX_UseBuffer)
getParameter
getParameter
(OMX_GetParameter)
fillBuffer
fillBuffer
(OMX_FillThisBuffer)
emptyBuffer
emptyBuffer
(OMX_EmptyThisBuffer)
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
&(4) Callback Functions
OMX_CALLBACKTYPE
OMXNodeInstance::kCallbacks =
&&&OnEvent,
&--------------- omx_message::EVENT
&&&OnEmptyBufferDone,
&----- omx_message::EMPTY_BUFFER_DONE
&&&OnFillBufferDone
&------- omx_message::FILL_BUFFER_DONE
stagefright框架(三)-選擇Video
在《》中,我們並沒有詳述Stagefright是如何根據影片檔的類型來選擇適合的video
decoder,現在,就讓我們來看一看。
Video decoder是在onPrepareAsyncEvent中的initVideoDecoder被決定的
OMXCodec::Create()會回傳video decoder給mVideoSource。
AwesomePlayer::initVideoDecoder()
&&mVideoSource =
OMXCodec::Create(mClient.interface(),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&mVideoTrack-&getFormat(),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&false,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&mVideoTrack);
sp OMXCodec::Create(&omx, &meta, createEncoder,
&source, matchComponentName)
&&meta-&findCString(kKeyMIMEType,
&&findMatchingCodecs(mime, ...,
&matchingCodecs); ........ (2)
&&for (size_t i = 0; i &
matchingCodecs.size(); ++i)
&&&&componentName
= matchingCodecs[i].string();
&&&&softwareCodec
&&&&&&&&InstantiateSoftwareCodec(componentName,
...); ..... (3)
(softwareCodec != NULL) return softwareC
= omx-&allocateNode(componentName, ..., &node); ...
(err == OK)
&&&&&&codec
= new OMXCodec(..., componentName, ...); ...... (5)
&&&&&&return
(2) 根據mVideoTrack的MIME從kDecoderInfo挑出合適的components
OMXCodec::findMatchingCodecs(mime, ..., matchingCodecs)
&&for (int index = 0;;
&&&&componentName
= GetCodec(
&&&&&&&&&&&&&&&&&&&&&&&kDecoderInfo,
&&&&&&&&&&&&&&&&&&&&&&&sizeof(kDecoderInfo)/sizeof(kDecoderInfo[0]),
&&&&&&&&&&&&&&&&&&&&&&&mime,
&&&&&&&&&&&&&&&&&&&&&&&index);
&&&&matchingCodecs-&push(String8(componentName));
static const CodecInfo kDecoderInfo[] =
&&{ MEDIA_MIMETYPE_VIDEO_MPEG4,
"OMX.qcom.video.decoder.mpeg4" },
&&{ MEDIA_MIMETYPE_VIDEO_MPEG4,
"OMX.TI.Video.Decoder" },
&&{ MEDIA_MIMETYPE_VIDEO_MPEG4,
"M4vH263Decoder" },
GetCodec會依據mime從kDecoderInfo挑出所有的component
name,然後存到matchingCodecs中。
(3) 根據matchingCodecs中component的順序,我們會先去檢查其是否為software
InstantiateSoftwareCodec(name, ...)
&&FactoryInfo kFactoryInfo[]
&&&&FACTORY_REF(M4vH263Decoder)
&&for (i = 0; i &
sizeof(kFactoryInfo)/sizeof(kFactoryInfo[0]); ++i)
(!strcmp(name, kFactoryInfo[i].name))
&&&&&&return
(*kFactoryInfo[i].CreateFunc)(source);
所有的software
decoder都會被列在kFactoryInfo中,我們藉由傳進來的name來對應到適合的decoder。
(4) 如果該component不是software decoder,則試著去配置對應的OMX component
OMX::allocateNode(name, ..., node)
&&mMaster-&makeComponentInstance(
&&&&&&&&&&&&&&&&&&&&&&&&&&&name,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&OMXNodeInstance::kCallbacks,
&&&&&&&&&&&&&&&&&&&&&&&&&&&instance,
&&&&&&&&&&&&&&&&&&&&&&&&&&&handle);
OMX_ERRORTYPE OMXMaster::makeComponentInstance(name, ...)
&&plugin-&makeComponentInstance(name,
OMX_ERRORTYPE OMXPVCodecsPlugin::makeComponentInstance(name,
&&return OMX_MasterGetHandle(...,
name, ...);
OMX_ERRORTYPE OMX_MasterGetHandle(...)
OMX_GetHandle(...);
(5) 若該component為OMX deocder,則回傳;否則繼續檢查下一個component
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
stagefright框架(四)-Video
Buffer傳輸流程
這篇文章將介紹Stagefright中是如何和OMX
video decoder傳遞buffer。
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
OMXCodec會在一開始的時候透過read函式來傳送未解碼的data給decoder,並且要求decoder將解碼後的data傳回來
status_t OMXCodec::read(...)
&&if&(mInitialBufferSubmit)
&&&&mInitialBufferSubmit&=&false;
&&&&drainInputBuffers();&-----
OMX_EmptyThisBuffer
&&&&fillOutputBuffers();&-----
OMX_FillThisBuffer
void&OMXCodec::drainInputBuffers()
&&Vector&&/span&BufferInfo&*buffers=&&mPortBuffers[kPortIndexInput];
&&for&(i&=&0;&i&&&/span&&buffers-&size();++i)
&&&&drainInputBuffer(&buffers-&editItemAt(i));
void&OMXCodec::drainInputBuffer(BufferInfo*info)
&&mOMX-&emptyBuffer(...);
void&OMXCodec::fillOutputBuffers()
&&Vector&&/span&BufferInfo&*buffers=&&mPortBuffers[kPortIndexOutput];
&&for&(i&=&0;&i&&&/span&&buffers-&size();++i)
&&&&fillOutputBuffer(&buffers-&editItemAt(i));
void&OMXCodec::fillOutputBuffer(BufferInfo*info)
&&mOMX-&fillBuffer(...);
Decoder從input
port讀取資料後,開始進行解碼,並且回傳EmptyBufferDone通知OMXCodec
void&OMXCodec::on_message(const&omx_message&&msg)
&&switch&(msg.type)
&&&&case&omx_message::EMPTY_BUFFER_DONE:
&&&&&&IOMX::buffer_id
buffer=&msg.u.extended_buffer_data.buffer;
&&&&&&drainInputBuffer(&buffers-&editItemAt(i));
OMXCodec收到EMPTY_BUFFER_DONE之後,繼續傳送下一個未解碼的資料給decoder。
Decoder將解碼完的資料送到output
port,並回傳FillBufferDone通知OMXCodec
void&OMXCodec::on_message(const&omx_message&&msg)
&&switch&(msg.type)
&&&&case&omx_message::FILL_BUFFER_DONE:
&&&&&&IOMX::buffer_id
buffer=&msg.u.extended_buffer_data.buffer;
&&&&&&fillOutputBuffer(info);
&&&&&&mFilledBuffers.push_back(i);
&&&&&&mBufferFilled.signal();
OMXCodec收到FILL_BUFFER_DONE之後,將解碼後的資料放入mFilledBuffers,發出mBufferFilled信號,並且要求decoder繼續送出資料。
read函式在後段等待mBufferFilled信號。當mFilledBuffers被填入資料後,read函式將其指定給buffer指標,並回傳給AwesomePlayer
status_t OMXCodec::read(MediaBuffer**buffer,...)
&&while&(mFilledBuffers.empty())
&&&&mBufferFilled.wait(mLock);
&&BufferInfo&*info&=&&mPortBuffers[kPortIndexOutput].editItemAt(index);
&&info-&mMediaBuffer-&add_ref();
&&*buffer&=&info-&mMediaBuffer;
stagefright框架(五)-Video
Rendering&
AwesomePlayer::onVideoEvent除了透過OMXCodec::read取得解碼後的資料外,還必須將這些資料(mVideoBuffer)傳給video
renderer,以便畫到螢幕上去。
(1)&要將mVideoBuffer中的資料畫出來之前,必須先建立mVideoRenderer
void&AwesomePlayer::onVideoEvent()
&&if&(mVideoRenderer==NULL)
&&&&initRenderer_l();
void&AwesomePlayer::initRenderer_l()
&&if&(!strncmp("OMX.",&component,&4))
&&&&mVideoRenderer&=&new&AwesomeRemoteRenderer(
&&&&&&&&&&&&&&&&&&&&&&&&&&&mClient.interface()-&createRenderer(
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&mISurface,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&component,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&...));..........(2)
&&&&mVideoRenderer&=&new&AwesomeLocalRenderer(
&&&&&&&&&&&&&&&&&&&&&&&&&&&...,
&&&&&&&&&&&&&&&&&&&&&&&&&&&component,
&&&&&&&&&&&&&&&&&&&&&&&&&&&mISurface);............................(3)
(2)&如果video
decoder是OMX
component,則建立一個AwesomeRemoteRenderer作為mVideoRenderer
從上段的程式碼(1)來看,AwesomeRemoteRenderer的本質是由OMX::createRenderer所創建的。createRenderer會先建立一個hardware
renderer --SharedVideoRenderer
(libstagefrighthw.so);若失敗,則建立software
renderer -- SoftwareRenderer (surface)。
sp&&/span&IOMXRenderer&&OMX::createRenderer(...)
&&VideoRenderer&*impl&=&NULL;
&&libHandle&=&dlopen("libstagefrighthw.so",&RTLD_NOW);
&&if&(libHandle)
&&&&CreateRendererFunc
func&=&dlsym(libHandle,...);
&&&&impl&=&(*func)(...);&-----------------
Hardware Renderer
&&if&(!impl)
&&&&impl&=&new&SoftwareRenderer(...);&----
Software Renderer
(3)&如果video
decoder是software
component,則建立一個AwesomeLocalRenderer作為mVideoRenderer
AwesomeLocalRenderer的constructor會呼叫本身的init函式,其所做的事和OMX::createRenderer一模一樣。
void&AwesomeLocalRenderer::init(...)
&&mLibHandle&=&dlopen("libstagefrighthw.so",&RTLD_NOW);
&&if&(mLibHandle)
&&&&CreateRendererFunc
func&=&dlsym(...);
&&&&mTarget&=&(*func)(...);&----------------
Hardware Renderer
&&if&(mTarget==NULL)
&&&&mTarget&=&new&SoftwareRenderer(...);&---
Software Renderer
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
mVideoRenderer一經建立就可以開始將解碼後的資料傳給它
void&AwesomePlayer::onVideoEvent()
&&if&(!mVideoBuffer)
&&&&mVideoSource-&read(&mVideoBuffer,...);
&&[Check Timestamp]
&&if&(mVideoRenderer==NULL)
&&&&initRenderer_l();
&&mVideoRenderer-&render(mVideoBuffer);&&/span&-----&Render
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
stagefright框架(六)-Audio
Playback的流程
到目前為止,我們都只著重在video處理的部分,對於audio卻隻字未提。這篇文章將會開始audio處理的流程。
Stagefright中關於audio的部分是交由AudioPlayer來處理,它是在AwesomePlayer::play_l中被建立的。
(1)&當上層應用程式要求播放影音時,AudioPlayer同時被建立出來,並且被啟動
status_t AwesomePlayer::play_l()
&&mAudioPlayer&=&new&AudioPlayer(mAudioSink,...);
&&mAudioPlayer-&start(...);
AudioPlayer在啟動的過程中會先去讀取第一筆解碼後的資料,並且開啟audio
status_t AudioPlayer::start(...)
&&mSource-&read(&mFirstBuffer);
&&if&(mAudioSink.get()!=NULL)
&&&&mAudioSink-&open(...,&AudioPlayer::AudioSinkCallback,...);
&&&&mAudioSink-&start();
&&&&mAudioTrack&=&new&AudioTrack(...,&AudioPlayer::AudioCallback,...);
&&&&mAudioTrack-&start();
從AudioPlayer::start的程式碼來看,AudioPlayer似乎並沒有將mFirstBuffer傳給audio
(3)&開啟audio
output的同時,AudioPlayer會將callback函式設給它,之後每當callback函式被呼叫,AudioPlayer便去audio
decoder讀取解碼後的資料
size_t&AudioPlayer::AudioSinkCallback(audioSink,&buffer,&size,...)
&&return&fillBuffer(buffer,&size);
void&AudioPlayer::AudioCallback(...,&info)
&&buffer&=&info;
&&fillBuffer(buffer-&raw,&buffer-&size);
size_t&AudioPlayer::fillBuffer(data,&size)
&&mSource-&read(&mInputBuffer,...);
&&memcpy(data,&mInputBuffer-&data(),...);
解碼後audio資料的讀取就是由callback函式所驅動,但是callback函式又是怎麼由audio
output去驅動的,目前從程式碼上還看不出來。另外一方面,從上面的程式片段可以看出,fillBuffer將資料(mInputBuffer)複製到data之後,audio
output應該會去取用data。
(5)&至於audio
decoder的工作流程則和video
decoder相同,可參閱《》
<img src="/blog7style/images/common/sg_trans.gif" real_src ="http://blogimg.chinaunix.net/blog/upfile2/.jpg" ALT="" BORDER="0" WIDTH="500" STYLE="border-style:"
TITLE="android&&stagefright框架" />
stagefright框架(七)-Audio和Video的同步
講完了audio和video的處理流程,接下來要看的是audio和video同步化(synchronization)的問題。OpenCORE的做法是設置一個主clock,而audio和video就分別以此作為輸出的依據。而在Stagefright中,audio的輸出是透過callback函式來驅動,video則根據audio的timestamp來做同步。以下是詳細的說明:
(1)&當callback函式驅動AudioPlayer讀取解碼後的資料時,AudioPlayer會取得兩個時間戳&--
mPositionTimeMediaUs和mPositionTimeRealUs
size_t&AudioPlayer::fillBuffer(data,&size)
&&mSource-&read(&mInputBuffer,...);
&&mInputBuffer-&meta_data()-&findInt64(kKeyTime,&mPositionTimeMediaUs);
&&mPositionTimeRealUs&=&((mNumFramesPlayed&+&size_done&/&mFrameSize)*&1000000)/mSampleRate;
mPositionTimeMediaUs是資料裡面所載明的時間戳(timestamp);mPositionTimeRealUs則是播放此資料的實際時間(依據framenumber及samplerate得出)。
(2) Stagefright中的video便依據從AudioPlayer得出來之兩個時間戳的差值,作為播放的依據
void&AwesomePlayer::onVideoEvent()
&&mVideoSource-&read(&mVideoBuffer,...);
&&mVideoBuffer-&meta_data()-&findInt64(kKeyTime,&timeUs);
&&mAudioPlayer-&getMediaTimeMapping(&realTimeUs,&mediaTimeUs);
&&mTimeSourceDeltaUs&=&realTimeUs&-&mediaTimeUs;
&&nowUs&=&ts-&getRealTimeUs()-&mTimeSourceDeltaUs;
&&latenessUs&=&nowUs&-&timeUs;
AwesomePlayer從AudioPlayer取得realTimeUs(即mPositionTimeRealUs)和mediaTimeUs(即mPositionTimeMediaUs),並算出其差值mTimeSourceDeltaUs。
(3)&最後我們將該video資料做排程
void&AwesomePlayer::onVideoEvent()
&&if&(latenessUs&&40000)
&&&&mVideoBuffer-&release();
&&&&mVideoBuffer&=&NULL;
&&&&postVideoEvent_l();
&&&&return;
&&if&(latenessUs&&/span&-10000)
&&&&postVideoEvent_l(10000);
&&&&return;
&&mVideoRenderer-&render(mVideoBuffer);
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。}

我要回帖

更多关于 dota是什么意思 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信