最近做了一个android项目用到编解码功能。大概需求是:通过摄像头拍摄一段视频,然后抽帧,生成一个短视频,以及倒序视频,刚开始直接用 H.264 编码格式,没有使用MP4容器封装。做了这些功能后,反而觉得使用MP4格式更加兼容各机型,减少BUG出现。举个明显例子:在Android硬编的时候,常常会用到 MediaCodec和MediaExtractor 相结合。但是,如果你用的 H.264 裸视频文件,MediaExtractor 的 setSource 函数会报异常,它在某些机型(如魅族Note2,系统是5.1)无法解析该视频文件。
      得到大概的需求后,最初我们使用FFmpeg来做视频编解码,所谓软件编解码。由于在处理的过程中速率太慢,且需要在解码后快速展示,所以该方案无法达到我们的预想效果(一个FFmpeg视频解码,并保存为jpeg例子:https://github.com/xiaoxiaoqingyi/ffmpeg-android-video-decoder)。但其也有一些优点,比如在兼容方面,颜色转换方面都做得很好,毕竟不是硬件编解码(国内这么多机型,你懂的),其次FFmpeg能输出指定帧,而Android硬解(MediaCodec)不能输出指定帧,需要输入好几帧到解码器,才能解码出一帧。目前我还是没有找到输入一帧解出一帧的方案,哪位大神知道的,可以指导指导。
       在软件编解码不太适合的情况下,就只能考虑用硬件编解码了(MediaCodec)。在前些日子,我参加了腾讯2017LIVE 直播开发者大会,了解到,现在的直播已经大部分使用硬件来编解码了。刚说了,有些机型不能使用MediaExtractor来解析 h.264文件,为了兼容大部分的机型,需要自己来解析,通过分析h.264文件的每一个字节区分每一帧位置且是什么类型帧。实现该需求,首先在从摄像头获取的数据,如果使用 Camera,一般设置为NV21格式, 但有些人使用Camera2,设置的格式是IMAGE。不管是哪种格式,最终都需要转换成yuv420sp或yuv420p(注意:在转码时候,最好使用jni,用C/C++来转格式,效率会高很多倍),才能供MediaCodec编码,然后保存h.264文件。在创建MediaCodec实例化的时候,除了设置必须参数外,也要注意一些地方,比如,选择哪种编码器,一般情况会选择如下:
 MediaCodec.createEncoderByType("video/avc");
这看上去其实没什么问题,大概原理就是获取最优的Encoder,获取Android系统中编码器注册表最前的一个,一般都是硬件解码(MediaCodec也能调用软件编解码)。这样创建编码器其实不太靠谱,虽然官网也是这么推荐,但是在国内众多的Android机型中,有些手机就会出问题,有的编码出现蓝屏,有些直接就闪退了。有个国外的例子,大概的意思就是先获取 "video/avc" 类型的编码器,然后通过 try catch 一个个试验,如果没问题,就选用这个编码器。源码:https://github.com/ldm520/android_mediacodec_rtsp_h264
还有一个问题就是在设置 I 帧间隔的时候,有些手机不起作用,如下设置:
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, interval);
 
针对这种情况,需要使用另外一种设置I帧的方式,强制设置:
 
Bundle params = new Bundle();
params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
mMediaCodec.setParameters(params);
 
在编解码时,当把所有的数据都输入编解码器的时候,要记得输入结束符,编解码器才会输出所有的帧。
 
    还有一个抽帧问题,如果使用MediaCodec来抽帧,生成一个新的视频。是否可以直接把H.264文件里的帧去掉就行了?这样不行的,通常会出现花屏。这需要重新把h.264文件输入到解码器,然后获取到自己想要的帧,再输入到一个新的编码器中,生成你想要的H.264文件。在这里还有一个格式问题,并不是从解码器解码出来的数据,就能直接使用编码器来编码,有部分手机可以,有些会出现蓝屏,甚至闪退的情况。这时候需要统一解码器处理的格式。如果你使用这种形式获取:
 
mMediaCodec.getOutputBuffer()
 
出来的格式各种各样,你很难去兼容。google已经推出了一种新的格式:
 
mMediaCodec.getOutputImage(outIndex)
 
得出的是一个Image 对象,该对象可以保存为 JPEG格式图片,也可以转换成NV21(参考:http://www.cnblogs.com/welhzh/p/6079631.html),像上面拍摄部分,转换成yuv422格式,再输入到编码器编码。这样不管什么机型都可以兼容了(我试用10多部不同厂商手机),虽然绕了很多弯路。
 
        在使用MediaCodec还是遇到比较多的问题,毕竟官网都说它是一个轻量的编解码器封装。该总结适合使用过MediaCodec或有一定的解码编码经验的童鞋们。如果你还没了解过 MediaCodec,可以参考官网:
 
     在使用MediaCodec的时候还遇到很多问题,这里没有一一列举出来, 欢迎有遇到同样问题或类似问题的童鞋留言讨论!

 
 

Android硬件编解码与软件编解码的更多相关文章

  1. 【GPU编解码】GPU硬解码---CUVID

    问题描述:项目中,需要对高清监控视频分析处理,经测试,其解码过程所占CPU资源较多,导致整个系统处理效率不高,解码成为系统的瓶颈. 解决思路: 利用GPU解码高清视频,降低解码所占用CPU资源,加速解 ...

  2. 使用多字节字符集的跨平台(PC、Android、IOS、WP)编码/解码方法

    随着移动端的发展,跨平台已成为通讯架构设计的重要考虑因素,PC.Android.IOS.WP等跨多平台间的数据通讯,必然要解决字符编码/解码的问题. 多字节字符集MBCS不是跨平台的首选字符集,面向跨 ...

  3. FFmpeg软件只是个解码编码软件,如果支持多种格式必须先安装好对应的库,下面就说下我装的库

    FFmpeg软件只是个解码编码软件,如果支持多种格式必须先安装好对应的库,下面就说下我装的库:1. 安装faad2 # wget http://downloads.sourceforge.net/fa ...

  4. EasyNVR智能云终端硬件与EasyNVR解决方案软件综合对比

    背景分析 互联网视频直播越来越成为当前视频直播的大势,对于传统的安防监控,一般都是局限于内网,无法成批量上云台.传统的海康和大华的平台虽然可以通过自身私有协议上云平台 集总管控,但是往往只是支持自身的 ...

  5. Android版Ftp服务端软件

    分享一款开发的Android版Ftp服务端软件,支持Android4.0及以上版本,可以实现局域网无线传输文件到手机,或者把手机上的多媒体文件分享到iPad等设备来扩展这些设备的存储空间,详情请见软件 ...

  6. Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

    Android服务器--使用TomCat实现软件的版本检测,升级,以及下载更新进度! 算下来,TomCat服务器已经写了很长一段时间了,一直说拿他来搞点事 情,也一直没做,今天刚好有空,交流群还有人请 ...

  7. C++的静态联编和动态联编

    联编的概念 联编是指一个计算机程序自身彼此关联的过程,在这个联编过程中,需要确定程序中的操作调用(函数调用)与执行该操作(函数)的代码段之间的映射关系. 意思就是这个函数的实现有多种,联编就是把调用和 ...

  8. C++_类继承3-动态联编和静态联编

    程序调用函数时,将使用哪个可执行代码块呢?编译器负责回答这个问题. 将源代码中的函数调用解释为特定的函数代码块被称为函数名联编(binding). 在C语言中,这非常简单,因为每个函数名对应一个不同的 ...

  9. C++的静态联编和动态联编详解

    一.概述: 通常来说联编就是将模块或者函数合并在一起生成可执行代码的处理过程,同时对每个模块或者函数调用分配内存地址,并且对外部访问也分配正确的内存地址,它是计算机程序彼此关联的过程.按照联编所进行的 ...

随机推荐

  1. web.xml 报错

    1.The markup in the document following the root element must be well-formed. 原因是配置时没有 放在根下 <web-a ...

  2. Lucene.net(4.8.0) 学习问题记录四: IndexWriter 索引的优化以及思考

    前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...

  3. linux libpcap的性能问题,请大家注意绕行。

    内核代码中,ip_rcv是ip层收包的主入口函数,该函数由软中断调用.存放数据包的sk_buff结构包含有目的地ip和端口信息,此时ip层进行检查,如果目的地ip不是本机,且没有开启转发的话,则将包丢 ...

  4. Python---多线程(threading)

    1. 概述 threading提供线程相关操作,python当前版本的多线程库没有实现优先级.线程组,线程也不能被停止.暂停.恢复和中断 threading提供的类: Thread,Lock,Rloc ...

  5. j2e中操作EXCEL

    在j2e中操作excel,无非2种情况,在这里我贴部分代码做个例子就OK,不管是导入和导出都是操作的都是流 1,导入,浏览器输入EXCEL到java后台解析 package action; impor ...

  6. web.xml 中<context-param>与<init-param>的区别与作用

    <context-param>的作用: web.xml的配置中<context-param>配置作用 1. 启动一个WEB项目的时候,容器(如:Tomcat)会去读它的配置文件 ...

  7. CentOS7下 Java、Tomcat、MySQL、Maven热部署

    本文介绍了CentOS7 64位下Java.Tomcat.MySQL.Maven热部署等服务器环境的搭建和调试过程. 学生服务器资源获取方法: 云+校园计划 - 腾讯云 阿里云云翼计划 github ...

  8. mysql SQL语法总结

    mysql主键操作 删除表主键: alter table student drop primary key; 增加表主键: alter table student add primary key(id ...

  9. 解决axios传递参数后台无法接收问题

    1.根据下面几个方法改变前台传递参数方式 这样后台就可以直接根据传递的参数获取数据,如下图用户登录时直接传递用户名和密码 2.不改变前台传递样式修改后台接收方式

  10. ABP官方文档翻译 6.6 Javascript API

    JavaScript API AJAX 通知 消息 UI Block和Busy 事件总线 日志 其他实用功能 ABP提供了一套对象和函数,用来简化.标准化javascript的开发. 这里是ABP提供 ...