【多媒体编解码】Android 视频解析MediaExtractor

编程入门 行业动态 更新时间:2024-10-25 14:24:28

【<a href=https://www.elefans.com/category/jswz/34/1768490.html style=多媒体编解码】Android 视频解析MediaExtractor"/>

【多媒体编解码】Android 视频解析MediaExtractor

写在前面:

学习Android多媒体的步骤:
1,Audio PCM &video YUV各种数据的处理,格式的封装与装换原理
2,多媒体的播放框架,nuplayer ,stagefright
3,音视频分离 MediaExtractor
4,音频编解码(以AAC为例)
5,视频图像编解码(以H264为例)
6,音视频同步技术

这一部分的学习之前,需要了解:
1,音视频容器的概念,参考博文:

2,不同的视频封装格式标准(这里以MP4文件分析),参考博文:

3,openmax IL框架

4,查看视频文件工具:

ultraedit 一个文本编辑器
Elecard Video Format Analyzer视频格式分析器,可以看到视频每个box的各个元素的说明,偏移值,大小等信息。通过某些具体的box可以查询到视频的格式信息。

=============以下是正文部分====================

以播放本地视频文件为例,创建MediaExtractor的流程,序列图如下:


序列图说明(以下标号代表序列图中的交互序列编号):

交互1,nuplayer::setDataSourceAsync
从MediaPlayer setDataSource开始,实质是调用
setDataSourceAsync(int fd, int64_t offset, int64_t length),不同的播放方式,参数不一样。
主要工作是:

交互2~4 :创建一个GenericSource,同时将获取的参数通过GenericSource::setDataSource传递
交互5: 发送消息kWhatSetDataSource给 nuplayer(AHandler)处理事件。主要是
将获得的nuplayer::Source(GenericSource)赋值给snuplayer::mSource
发送消息给NuPlayerDriver,告诉上层setDataSource完成,提示上层可以开始下一步指令。见交互6:driver->notifySetDataSourceCompleted

交互8:Nuplayer::prepareAsync

上层得到设置谁完成的消息之后,调用这个函数开始下一步的指令,主要工作是:

  • 交互 9, :发送消息kWhatPrepare给Nuplayer(AHandler)

  • 交互10 :nuplayer收到消息后,操作mSource (也是一个AHandler),在这个离职中间,实质是调用NuPlayer::GenericSource::prepareAsync(),主要工作是:
    给Souece创建一个ALooper,用来循环接收处理AMessage
    发送消息kWhatPrepareAsync给Source(AHandler)开始异步准备

  • 交互12: 接受到消息后,调用GenericSource::onPrepareAsync(),主要的工作是:
    根据条件,实例化NuPlayer::GenericSource::mDataSource,一个具体的DataSource的派生类,本例是 FileSource。
    根据mDataSource,创建一个MediaExtractor,GenericSource::initFromDataSource;具体流程,就是交互13~20,这个流程比较繁琐,但是只需要关注17,18,20

交互13~17:这里才是重点

  • 交互13:GenericSource::initFromDataSource
    后面还将具体分析这个函数的其他重要工作
    1,根据sniff创建指定的mediaExtractor,创建同时读取数据,创建metaData,解析“track”并且分离
    2,根据track,初始化mVideoTrack和mAudioTrack,加入 mSources
    3,从metaData获取
    kKeyDuration
    kKeyBitRate

  • 交互16:sp MediaExtractor::CreateFromService

    主要工作是遍历所有注册的Extractor,分别去读取文件头,根据条件判断具体选用哪个Extractor,以及初始化minetype,具体看下面:

  • 交互17:DataSource::RegisterDefaultSniffers()

 // The sniffer can optionally fill in "meta" with an AMessage containing// a dictionary of values that helps the corresponding extractor initialize// its state without duplicating effort already exerted by the sniffer.typedef bool (*SnifferFunc)(const sp<DataSource> &source, String8 *mimeType,float *confidence, sp<AMessage> *meta);// static
void DataSource::RegisterSniffer_l(SnifferFunc func) {for (List<SnifferFunc>::iterator it = gSniffers.begin();it != gSniffers.end(); ++it) {if (*it == func) {return;}}gSniffers.push_back(func);
}
// static
void DataSource::RegisterDefaultSniffers() {Mutex::Autolock autoLock(gSnifferMutex);if (gSniffersRegistered) {return;}/*实质就是将左右的extractor注册并且保存在DataSource::gSniffers(Vector)中间可见,如果需要自定义一个IMediaExtrector的派生类,则必须实现这个方法,这个方法具体什么作用,看下面分析*/RegisterSniffer_l(SniffMPEG4);RegisterSniffer_l(SniffMatroska);RegisterSniffer_l(SniffOgg);RegisterSniffer_l(SniffWAV);RegisterSniffer_l(SniffFLAC);RegisterSniffer_l(SniffAMR);RegisterSniffer_l(SniffMPEG2TS);RegisterSniffer_l(SniffMP3);RegisterSniffer_l(SniffAAC);RegisterSniffer_l(SniffMPEG2PS);+if (getuid() == AID_MEDIA) {// WVM only in the media server processRegisterSniffer_l(SniffWVM);}RegisterSniffer_l(SniffMidi);//RegisterSniffer_l(AVUtils::get()->getExtendedSniffer());char value[PROPERTY_VALUE_MAX];if (property_get("drm.service.enabled", value, NULL)&& (!strcmp(value, "1") || !strcasecmp(value, "true"))) {RegisterSniffer_l(SniffDRM);}gSniffersRegistered = true;
}
  • 交互18:DataSource::sniff:
    主要作用是遍历DataSource::gSniffers,按序执行每个Extractor的SniffXXX函数,给mineType,confidence和meta赋值

bool DataSource::sniff(String8 *mimeType, float *confidence, sp<AMessage> *meta) {*mimeType = "";*confidence = 0.0f;meta->clear();int count =0;{Mutex::Autolock autoLock(gSnifferMutex);if (!gSniffersRegistered) {return false;}}for (List<SnifferFunc>::iterator it = gSniffers.begin();it != gSniffers.end(); ++it) {//遍历DataSource::gSniffersString8 newMimeType;float newConfidence;sp<AMessage> newMeta;if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {//执行每一个已注册的sniffXXX函数,比较所有返回true的sniffXXX函数中间,将confidence最大的那个的相关赋值,返回if (newConfidence > *confidence) {*mimeType

更多推荐

【多媒体编解码】Android 视频解析MediaExtractor

本文发布于:2024-03-08 17:36:23,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1721650.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:多媒体   编解码   视频   Android   MediaExtractor

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!