资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

h264android的简单介绍

Android如何实现h264硬编码

使用Android中的StageFright框架调用OpenMAX进行硬件编码,OMX部分由硬件厂商实现,无需关注,看好StageFright的调用方法即可

成都创新互联是一家网站设计公司,集创意、互联网应用、软件技术为一体的创意网站建设服务商,主营产品:响应式网站开发成都品牌网站建设成都营销网站建设。我们专注企业品牌在网站中的整体树立,网络互动的体验,以及在手机等移动端的优质呈现。成都网站设计、网站制作、外贸营销网站建设、移动互联产品、网络运营、VI设计、云产品.运维为核心业务。为用户提供一站式解决方案,我们深知市场的竞争激烈,认真对待每位客户,为客户提供赏析悦目的作品,网站的价值服务。

Android 音视频01 --- H264的基本原理01

H264压缩技术主要采用了以下几种方法对视频数据进行压缩。包括:

解决的是空域数据冗余问题。

解决的是时域数据冗徐问题

将空间上的相关性变为频域上无关的数据然后进行量化。

经过压缩后的帧分为:I帧,P帧和B帧:

关键帧,采用帧内压缩技术。

向前参考帧,在压缩时,只参考前面已经处理的帧。采用帧音压缩技术。

双向参考帧,在压缩时,它即参考前而的帧,又参考它后面的帧。采用帧间压缩技术。

除了I/P/B帧外,还有图像序列GOP。

H264的基本原理其实非常简单,下我们就简单的描述一下H264压缩数据的过程。通过摄像头采集到的视频帧(按每秒 30 帧算),被送到 H264 编码器的缓冲区中。编码器先要为每一幅图片划分宏块。

划分好宏块后,计算宏块的象素值。以此类推,计算一幅图像中每个宏块的像素值。

对于视频数据主要有两类数据冗余,一类是时间上的数据冗余,另一类是空间上的数据冗余。其中时间上的数据冗余是最大的。为什么说时间上的冗余是最大的呢?假设摄像头每秒抓取30帧,这30帧的数据大部分情况下都是相关联的。也有可能不止30帧的的数据,可能几十帧,上百帧的数据都是关联特别密切的。

H264编码器会按顺序,每次取出两幅相邻的帧进行宏块比较,计算两帧的相似度。如下图:

在H264编码器中将帧分组后,就要计算帧组内物体的运动矢量了。

H264编码器首先按顺序从缓冲区头部取出两帧视频数据,然后进行宏块扫描。当发现其中一幅图片中有物体时,就在另一幅图的邻近位置(搜索窗口中)进行搜索。如果此时在另一幅图中找到该物体,那么就可以计算出物体的运动矢量了。

运动矢量计算出来后,将相同部分(也就是绿色部分)减去,就得到了补偿数据。我们最终只需要将补偿数据进行压缩保存,以后在解码时就可以恢复原图了。压缩补偿后的数据只需要记录很少的一点数据。

我们把运动矢量与补偿称为 帧间压缩技术 ,它解决的是视频帧在时间上的数据冗余。除了帧间压缩,帧内也要进行数据压缩,帧内数据压缩解决的是空间上的数据冗余。

人眼对图象都有一个识别度,对低频的亮度很敏感,对高频的亮度不太敏感。所以基于一些研究,可以将一幅图像中人眼不敏感的数据去除掉。这样就提出了帧内预测技术。

一幅图像被划分好宏块后,对每个宏块可以进行 9 种模式的预测。找出与原图最接近的一种预测模式。然后,将原始图像与帧内预测后的图像相减得残差值。再将我们之前得到的预测模式信息一起保存起来,这样我们就可以在解码时恢复原图了,经过帧内与帧间的压缩后,虽然数据有大幅减少,但还有优化的空间。

可以将残差数据做整数离散余弦变换,去掉数据的相关性,进一步压缩数据。

上面的帧内压缩是属于有损压缩技术。也就是说图像被压缩后,无法完全复原。而CABAC属于无损压缩技术。

无损压缩技术大家最熟悉的可能就是哈夫曼编码了,给高频的词一个短码,给低频词一个长码从而达到数据压缩的目的。MPEG-2中使用的VLC就是这种算法,我们以 A-Z 作为例子,A属于高频数据,Z属于低频数据。看看它是如何做的。

CABAC也是给高频数据短码,给低频数据长码。同时还会根据上下文相关性进行压缩,这种方式又比VLC高效很多。

制定了相互传输的格式,将宏快 有组织,有结构,有顺序的形成一系列的码流。这种码流既可 通过 InputStream 网络流的数据进行传输,也可以封装成一个文件进行保存,主要作用是为了传输。

组成H264码流的结构中 包含以下几部分 ,从大到小排序依次是:

H264视频序列,图像,片组,片,NALU,宏块 ,像素。

NAL层:(Network Abstraction Layer,视频数据网络抽象层) : 它的作用是H264只要在网络上传输,在传输的过程每个包以太网是1500字节,而H264的帧往往会大于1500字节,所以要进行拆包,将一个帧拆成多个包进行传输,所有的拆包或者组包都是通过NAL层去处理的。

VCL层:(Video Coding Layer,视频数据编码层) : 对视频原始数据进行压缩

起始码0x 00 00 00 01 或者 0x 00 00 01 作为 分隔符 。

两个 0x 00 00 00 01之间的字节数据 是表示一个NAL Unit。

I 帧的特点:

1.分组:把几帧图像分为一组(GOP,也就是一个序列),为防止运动变化,帧数不宜取多。

2.定义帧:将每组内各帧图像定义为三种类型,即I帧、B帧和P帧;

3.预测帧:以I帧做为基础帧,以I帧预测P帧,再由I帧和P帧预测B帧;

4.数据传输:最后将I帧数据与预测的差值信息进行存储和传输。

1.更高的编码效率:同H.263等标准的特率效率相比,能够平均节省大于50%的码率。

2.高质量的视频画面:H.264能够在低码率情况下提供高质量的视频图像,在较低带宽上提供高质量的图像传输是H.264的应用亮点。

3.提高网络适应能力:H.264可以工作在实时通信应用(如视频会议)低延时模式下,也可以工作在没有延时的视频存储或视频流服务器中。

4.采用混合编码结构:同H.263相同,H.264也使用采用DCT变换编码加DPCM的差分编码的混合编码结构,还增加了如多模式运动估计、帧内预测、多帧预测、基于内容的变长编码、4x4二维整数变换等新的编码方式,提高了编码效率。

5.H.264的编码选项较少:在H.263中编码时往往需要设置相当多选项,增加了编码的难度,而H.264做到了力求简洁的“回归基本”,降低了编码时复杂度。

6.H.264可以应用在不同场合:H.264可以根据不同的环境使用不同的传输和播放速率,并且提供了丰富的错误处理工具,可以很好的控制或消除丢包和误码。

7.错误恢复功能:H.264提供了解决网络传输包丢失的问题的工具,适用于在高误码率传输的无线网络中传输视频数据。

8.较高的复杂度:264性能的改进是以增加复杂性为代价而获得的。据估计,H.264编码的计算复杂度大约相当于H.263的3倍,解码复杂度大约相当于H.263的2倍。

H.264的目标应用涵盖了目前大部分的视频服务,如有线电视远程监控、交互媒体、数字电视、视频会议、视频点播、流媒体服务等。H.264为解决不同应用中的网络传输的差异。定义了两层:视频编码层(VCL:Video Coding Layer)负责高效的视频内容表示,网络提取层(NAL:Network Abstraction Layer)负责以网络所要求的恰当的方式对数据进行打包和传送。

Android音视频开发——H264的基本概念

ffmpeg常用命令

封装格式 。

编码的本质就是压缩数据

音频编码的作用: 将音频采样数据( PCM 等)压缩成音频码流,从而降低音频的数据量。 常用的音频编码方式有以下几种:

H264压缩技术主要采用了以下几种方法对视频数据进行压缩。包括:

经过压缩后的帧分为:I帧,P帧和B帧:

除了I/P/B帧外,还有图像序列GOP。

组成码流的结构中,包含了以下几个部分,从大到小依次是:

H264视频序列,图像,片组,片,NALU,宏块,像素

H264功能分为两层:

1.H264视频序列包括一系列的NAL单元,每个NAL单元包含一个RBSP。

2.一个原始的H.264由 N个NALU单元组成

3.NALU单元由[StartCode][NALU Header][NALU Payload]三部分组成

5.NAL Header

由三部分组成forbidden_bit(1bit)(禁止位),nal_reference_bit(2bits)(优先级,,值越大,该NAL越重要),nal_unit_type(5bits)(类型)

nal_unit_type

6.NAL的解码单元的流程如下

Android音频开发(三)——音频编解码

上一节中我们讲了怎么采集音频并播放,由于AudioRecord采集的是PCM数据,没有经过处理,所有播放的时候会有杂音,啸叫等现象出现。因此处理掉这些不需要的数据就是本节的内容,编码与解码。

Android官方提供给我们的用于编解码的类是 MediaCodec ,它是android 4.1(API 16)才引入的,所以只能工作于andorid4.1以上的手机,如果想兼容4.1以下版本的手机,只能使用第三方库,如大名鼎鼎的 ffmpeg ,B站的 ijkplayer 等。

(1)提供了一套访问 Android 底层多媒体模块的接口,主要是音视频的编解码接口

(2)在Android上,预设的多媒体框架是基于第三方PacketVideo公司的OpenCORE来实现,OpenCORE的优点是兼顾了跨平台的移植性,而且已经过多方验证,所以相对来说较为稳定;缺点是国语庞大复杂,需要耗费相当多的时间去维护。因此从Android 2.0开始,Google引进了较为简洁的StageFright。Android 底层多媒体模块采用的是 StageFright 框架,它是基于OpenMax标准实现的,任何 Android 底层编解码模块的实现,都必须遵循 OpenMax 标准。值得一提的是,OpenMAX是Khronos制定的API,Khronos也是OpenGL的制定者。Google 官方默认提供了一系列的软件编解码器:包括:OMX.google.h264.encoder,OMX.google.h264.encoder, OMX.google.aac.encoder, OMX.google.aac.decoder 等等,而硬件编解码功能,则需要由芯片厂商依照 OpenMax 框架标准来完成,所以,一般采用不同芯片型号的手机,硬件编解码的实现和性能是不同的

(3)Android 应用层统一由 MediaCodec API 来提供各种音视频编解码功能,由参数配置来决定采用何种编解码算法、是否采用硬件编解码加速等等

根据android官方文档的描述,MediaCodec的核心就是使用缓冲区队列来操作数据,使用流程如下:

//name既是媒体文件的类型,如audio/3gpp,详情参考MediaFormat的MIMETYPE常量

MediaCodec codec = MediaCodec.createByCodecName(name);

codec.configure(format, …);

MediaFormat outputFormat = codec.getOutputFormat(); // option B

codec.start();

for (;;) {

////获取可用的inputBuffer -1代表一直等待,0表示不等待 建议-1,避免丢帧

int inputBufferId = codec.dequeueInputBuffer(-1);

if (inputBufferId = 0) {

ByteBuffer inputBuffer = codec.getInputBuffer(…);

// fill inputBuffer with valid data

codec.queueInputBuffer(inputBufferId, …);

}

//执行上面的操作后就把待编解码的数据存入了输入缓冲区,然后下一步就是操作然后把编解码的数据存入输出缓冲区

int outputBufferId = codec.dequeueOutputBuffer(…);

if (outputBufferId = 0) {

ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);

MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A

// bufferFormat is identical to outputFormat

// outputBuffer is ready to be processed or rendered.

codec.releaseOutputBuffer(outputBufferId, …);

} else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {

// Subsequent data will conform to new format.

// Can ignore if using getOutputFormat(outputBufferId)

outputFormat = codec.getOutputFormat(); // option B

}

}

codec.stop();

codec.release();

MediaCodec codec = MediaCodec.createByCodecName(name);

MediaFormat mOutputFormat; // member variable

codec.setCallback(new MediaCodec.Callback() {

@Override

void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {

ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);

// fill inputBuffer with valid data

codec.queueInputBuffer(inputBufferId, …);

}

@Override

void onOutputBufferAvailable(MediaCodec mc, int outputBufferId, …) {

ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);

MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A

// bufferFormat is equivalent to mOutputFormat

// outputBuffer is ready to be processed or rendered.

codec.releaseOutputBuffer(outputBufferId, …);

}

@Override

void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {

// Subsequent data will conform to new format.

// Can ignore if using getOutputFormat(outputBufferId)

mOutputFormat = format; // option B

}

@Override

void onError(…) {

}

});

codec.configure(format, …);

mOutputFormat = codec.getOutputFormat(); // option B

codec.start();

// wait for processing to complete

codec.stop();

codec.release();

MediaCodec codec = MediaCodec.createByCodecName(name);

codec.configure(format, …);

codec.start();

//API的区别在这里

ByteBuffer[] inputBuffers = codec.getInputBuffers();

ByteBuffer[] outputBuffers = codec.getOutputBuffers();

for (;;) {

int inputBufferId = codec.dequeueInputBuffer(…);

if (inputBufferId = 0) {

// fill inputBuffers[inputBufferId] with valid data

codec.queueInputBuffer(inputBufferId, …);

}

int outputBufferId = codec.dequeueOutputBuffer(…);

if (outputBufferId = 0) {

// outputBuffers[outputBufferId] is ready to be processed or rendered.

codec.releaseOutputBuffer(outputBufferId, …);

} else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {

outputBuffers = codec.getOutputBuffers();

} else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {

// Subsequent data will conform to new format.

MediaFormat format = codec.getOutputFormat();

}

}

codec.stop();

codec.release();


网页名称:h264android的简单介绍
地址分享:http://www.cdkjz.cn/article/hoosjc.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

大客户专线   成都:13518219792   座机:028-86922220