Android多媒体开发需要添加FFmpeg支持,其实其步骤在前面Android Media Framework学习的一系列文章中就有讲述,《支持格式扩展》这篇文章已经讲完了Android多媒体需要扩展支持其他格式的步骤,这篇文章具体讲述Android怎么支持FFmpeg。

参考文章有两篇,分别是:文章一,文章二

1.Sniffer
音视频的解码播放是从探测文件格式开始的,即在DataSource.cpp中通过Sniff探测文件格式,扩展FFmpeg也是一样的,先要在DataSource中加入相应的Sniff。

DataSource通过RegisterDefaultSniffers给每一种格式添加相应的sniffer。

// staticvoid DataSource::RegisterDefaultSniffers() {    Mutex::Autolock autoLock(gSnifferMutex);    if (gSniffersRegistered) {        return;    }    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);    RegisterSniffer_l(SniffWVM);    RegisterSnifferPlugin();    char value[PROPERTY_VALUE_MAX];    if (property_get("drm.service.enabled", value, NULL)            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {        RegisterSniffer_l(SniffDRM);    }    //RegisterSniffer_l(SniffASF);    //RegisterSniffer_l(SniffNVAVI);    gSniffersRegistered = true;}

这里,我们需要关注的是RegisterSnifferPlugin()。

// staticvoid DataSource::RegisterSnifferPlugin() {    static void (*getExtractorPlugin)(MediaExtractor::Plugin *) =            (void (*)(MediaExtractor::Plugin *))loadExtractorPlugin();    MediaExtractor::Plugin *plugin = MediaExtractor::getPlugin();    if (!plugin->sniff && getExtractorPlugin) {        getExtractorPlugin(plugin);    }    if (plugin->sniff) {        RegisterSniffer_l(plugin->sniff);    }}

我们看到,RegisterSnifferPlugin()中有个loadExtractorPlugin()方法,具体看它的实现。

static void *loadExtractorPlugin() {    void *ret = NULL;    char lib[PROPERTY_VALUE_MAX];    if (property_get("media.stagefright.extractor-plugin", lib, "libFFmpegExtractor.so")) {        if (void *extractorLib = ::dlopen(lib, RTLD_LAZY)) {            ret = ::dlsym(extractorLib, "getExtractorPlugin");            ALOGW_IF(!ret, "Failed to find symbol, dlerror: %s", ::dlerror());        } else {            ALOGV("Failed to load %s, dlerror: %s", lib, ::dlerror());        }    }    return ret;}

可以看到,也就是在loadExtractorPlugin()方法加载了libFFmpegExtractor.so库。

2.Extractor
扩展了FFmpeg的sniffer,接下来就是创建FFmpegExtractor实例,如果不明白可以回头看看Android Media Framework的相关文章。
MediaExtractor管理着各种具体的Extractor,FFmpegExtractor也不例外。在上面的loadExtractorPlugin()方法中调用的是FFmpegExtractor的getExtractorPlugin()方法,看看具体实现:

extern "C" void getExtractorPlugin(android::MediaExtractor::Plugin *plugin){    plugin->sniff = android::SniffFFMPEG;    plugin->create = android::CreateFFmpegExtractor;}

很好理解,就是指明SniffFFMPEG并调用CreateFFmpegExtractor。其中SniffFFMPEG()方法就是通过设置confidence值来指定格式,我自己项目中的比较复杂,这里贴下文章二中的代码:

bool SniffFFMPEG(  const sp &source, String8 *mimeType,         float *confidence, sp *) {        LOGD("SniffFFMPEG: confidence force to be 1.0");        // QGC: ffmpeg force to be high confidence      *mimeType = MEDIA_MIMETYPE_CONTAINER_FFMPEG;      *confidence = 1.0f;      return true;    }

相当暴力,直接指定*confidence = 1.0f。

CreateFFmpegExtractor顾名思义就是创建FFmpegExtractor的实例。

MediaExtractor *CreateFFmpegExtractor(const sp &source, const char *mime, const sp &meta) {    MediaExtractor *ret = NULL;    AString notuse;    if (meta.get() && meta->findString("extended-extractor", ¬use) && (            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)          ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)           ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)        ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)          ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)           ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_APE)           ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_DTS)           ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II) ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RA)            ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_WMA)           ||            !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FFMPEG)        ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)     ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MOV)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)  ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_TS)        ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)   ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AVI)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_ASF)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WEBM)      ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WMV)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPG)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_FLV)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_DIVX)      ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_RM)        ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_FLAC)      ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_APE)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_DTS)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MP2)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_RA)        ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_VC1)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_HEVC)      ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WMA)       ||            !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_FFMPEG))) {        ALOGV("media format %s", mime);        bool audio_only = false;        if (!strncmp(mime, "audio/", 6)) {            ALOGV("set audio only mode");            audio_only = true;        }        ret = new FFmpegExtractor(source, meta, audio_only);    }    ALOGD("%ssupported mime: %s", (ret ? "" : "un"), mime);    return ret;}

这个方法用到的 meta->findString("extended-extractor", ¬use)其实就在SniffFFMPEG中指定(当然上边的SniffFFMPEG没有),这里给出:

(*meta)->setString("extended-extractor", "extended-extractor");(*meta)->setString("extended-extractor-subtype", "ffmpegextractor");(*meta)->setString("extended-extractor-mime", container);

3.kComponents
kComponents数组指定的是系统支持的编解码器,当然要加上FFmpeg的相关东西。

static const struct {    const char *mName;    const char *mLibNameSuffix;    const char *mRole;} kComponents[] = {    { "OMX.ffmpeg.mpeg2v.decoder", "ffmpegvdec", "video_decoder.mpeg2v" },    { "OMX.ffmpeg.h263.decoder", "ffmpegvdec", "video_decoder.h263" },    { "OMX.ffmpeg.mpeg4.decoder", "ffmpegvdec", "video_decoder.mpeg4" },    { "OMX.ffmpeg.wmv.decoder", "ffmpegvdec", "video_decoder.wmv" },    { "OMX.ffmpeg.rv.decoder", "ffmpegvdec", "video_decoder.rv" },    { "OMX.ffmpeg.h264.decoder", "ffmpegvdec", "video_decoder.avc" },    { "OMX.ffmpeg.vp8.decoder", "ffmpegvdec", "video_decoder.vp8" },    { "OMX.ffmpeg.vc1.decoder", "ffmpegvdec", "video_decoder.vc1" },    { "OMX.ffmpeg.flv1.decoder", "ffmpegvdec", "video_decoder.flv1" },    { "OMX.ffmpeg.divx.decoder", "ffmpegvdec", "video_decoder.divx" },    { "OMX.ffmpeg.hevc.decoder", "ffmpegvdec", "video_decoder.hevc" },    { "OMX.ffmpeg.vtrial.decoder", "ffmpegvdec", "video_decoder.trial" },    { "OMX.ffmpeg.aac.decoder", "ffmpegadec", "audio_decoder.aac" },    { "OMX.ffmpeg.mp3.decoder", "ffmpegadec", "audio_decoder.mp3" },    { "OMX.ffmpeg.vorbis.decoder", "ffmpegadec", "audio_decoder.vorbis" },    { "OMX.ffmpeg.wma.decoder", "ffmpegadec", "audio_decoder.wma" },    { "OMX.ffmpeg.ra.decoder", "ffmpegadec", "audio_decoder.ra" },    { "OMX.ffmpeg.flac.decoder", "ffmpegadec", "audio_decoder.flac" },    { "OMX.ffmpeg.mp2.decoder", "ffmpegadec", "audio_decoder.mp2" },    { "OMX.ffmpeg.ac3.decoder", "ffmpegadec", "audio_decoder.ac3" },    { "OMX.ffmpeg.ape.decoder", "ffmpegadec", "audio_decoder.ape" },    { "OMX.ffmpeg.dts.decoder", "ffmpegadec", "audio_decoder.dts" },    { "OMX.ffmpeg.atrial.decoder", "ffmpegadec", "audio_decoder.trial" },    { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },    { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" },    { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },    { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },    { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },    { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },    { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },    { "OMX.google.h264.encoder", "h264enc", "video_encoder.avc" },    { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },    { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },    { "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" },    { "OMX.google.h263.encoder", "mpeg4enc", "video_encoder.h263" },    { "OMX.google.mpeg4.decoder", "mpeg4dec", "video_decoder.mpeg4" },    { "OMX.google.mpeg4.encoder", "mpeg4enc", "video_encoder.mpeg4" },    { "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" },    { "OMX.google.vorbis.decoder", "vorbisdec", "audio_decoder.vorbis" },    { "OMX.google.vp8.decoder", "vpxdec", "video_decoder.vp8" },    { "OMX.google.vp9.decoder", "vpxdec", "video_decoder.vp9" },    { "OMX.google.vp8.encoder", "vpxenc", "video_encoder.vp8" },    { "OMX.google.raw.decoder", "rawdec", "audio_decoder.raw" },    { "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" },    { "OMX.google.gsm.decoder", "gsmdec", "audio_decoder.gsm" },};

"OMX.google."开头的是Android本身支持的,"OMX.ffmpeg."开头的是FFmpeg的。

4.media_codecs.xml
最后,在/etc/media_codecs.xml中配置自己需要的编解码器。

当然,要想完整的添加FFmpeg,还有很多头文件需要加,有的文件代码也需要稍许修改,但整个脉络是这样的。

更多相关文章

  1. Android(安卓)NDK开发:JNI基础篇
  2. MediaStore与Media.EXTERNAL_CONTENT_URI
  3. Android(安卓)app——常见控件的使用方法
  4. Android之如何打开USB调试模式
  5. android使用ExpandableListView控件实现小说目录效果的例子
  6. Android(安卓): GestureDetector手势检测
  7. 关于android socket编程时,“Error:ShouldNotReachHere()”错误的
  8. [置顶] android 自定义Toast,可设定显示时间
  9. Android(安卓)SDK Command line tools运行sdkmanager报告Warning

随机推荐

  1. Python分析5000+抖音大V,发现大家都喜欢这
  2. 原来炫酷的可视化地图,用Python就能搞定!
  3. 太骚了!Python模型完美切换SAS,还能这么玩
  4. pandas100个骚操作:变量类型自动转换
  5. Android(安卓)View中的onMeasure()方法详
  6. 原创丨带你体验一下云上编码的感觉
  7. Cetos 7 配置LAMP的解决办法
  8. 超赞,20个炫酷的数据可视化大屏(含源码)
  9. 安利 5 个拍案叫绝的 Matplotlib 骚操作!
  10. C语言学习心得(七)