视频解码优化

以下通过剖析一些经验来了解视频解码优化
1. 在嵌入式系统中实现MPEG4的视频解码
有两种方法可行
(1)采用ffmpeg(mplayer 的核心就是采用ffmpeg),然后对ffmpeg mp4解码优化

1).对IDCT汇编化,并优化VLD的实现   ->inline&汇编化
2).根据ARM9 cache&cache line的大小做MB的分组,使得每次可以同时处理多个MB
  即对多个MB在一个循环内做VLD--->IDCT-->MC--.......  ->耦合
3).优化关键代码段的内存访问(MC)    ->inline&汇编化
4).不要使用FFmpeg内置的img_convert()做yuv2rgb转换  ->inline&汇编化
5).对解码库做ARM指令集优化    ->体系结构优化
  configured ffmpeg with cpu = ARMV4L would give you a better performance
  If you have IPP,you can enable it, you can obtain huge enhancement
  IPP=Intel? Integrated Performance Primitives intel高性能构件库(only for xScale)
 
(2)用xvid来做,ffmpeg包含的解码库太多,如果你只做MPPEG4解码,何必用这么复杂的库.
btw,在嵌入式系统中最好用0.9.2版的xvid。因为1.1.0的版本包含了很多AS的特性,通常在
嵌入式系统中都不需要用,并且也不容易实现。要自己做编码算法的话,不能总想依赖别人
,最好还是需要自己花功夫去实现和优化。因此我觉得从实际出发的话,XVID0.9.2版的比
1.1.0的好。实际上,通常在主频400MHz的平台上,要优化XVID的算法达到CIF实时解码也还
是很容易的,最多就一个多月

2. 视频解码流程对解码带来的影响
视频解码优化一般代码量大,而且源代码往往是从其他地方获取得到的,所以阅读比较困难
,更别说优化了,最近在优化realVideo,有几点心得:
1).阅读代码前必须先熟悉流程,抓住关键的点,比如视频解码不外乎熵解码,反量化,反变
换,插值,重建,滤波,参考帧插入等。把握住这几个点,可以将代码很快分离出来。
2). 分析解码流程,了解解码需要的最小buffer是多大,各个buffer 的位宽多大。
3).根据已经知道的流程,跟踪代码buffer流向,是否存在多余的内存拷贝。想办法将buffer
减少,经验说明,减少buffer带来的速度上的提升远大于局部算法的优化。 ->耦合
4).观察程序结构顺序是否合理,不合理的程序结构会导致buffer增大。
这两天研究视频解码顺序,发现先插值后做反变换要比先做反变换再做插值效率要高许多,
原因是插值后的位宽是8bits,而往往反变换后是9bits,所以在重建之前要保存插值后的值
要比保存反变换后的值要省一半的空间,这样在重建时访问的内存就少很多了。据我了解,
大部分高效率的解码器都是先插值再反变换,而且变换后马上做重建,这样既减少内存使用
,也避免内存访问抖动太厉害,最终减少缓存不命中。 ->修改解码流程 耦合

3. cache机制对解码带来的影响
先看 http://www.hongen.com/pc/diy/know/mantan/cache0.htm
写透(直写式)和写回(回写式)有着截然不同的操作,在不同的场合,不同的内存块使用
不同的回写策略(如果你的系统可以实现的话)要比使用一种策略要高效得多。具体一点,
对于反复存取的内存块置成写回,而把一次写入而很长时间以后再使用的内存置为写透,可
以大大提高cache的效率。
第一点很容易理解,第二点就需要琢磨一下了,由于写透的操作是,当缓存有该地址的数据
时同时更新缓存和主存,当缓存没有该地址数据直接写主存,忽略缓存。当该地址的数据很
长时间后才被使用到,那么在使用的时候该数据肯定不在cache中(被替换了),所以不如直
接写入主存来得直接;
相反,如果使用写回操作,当 cache中有该地址数据,需要更新该数据,设置dirty位,很长
时间后再使用该数据或被替换的时候才将其刷进主存,这有占了茅坑不拉屎的嫌疑;而当
 cache没有该地址数据时,情况更糟糕,首先需要将相应的主存数据(一个cache line)导
 入cache,再更新数据,设置dirty位,再等待被刷回内存,这种情况不仅占用了cache的空
 间,还多一次从主存中导入数据的过程,同样占据总线,开销很大。至于为什么要先从主存
 中导入数据,是因为cache往主存回写数据时是按照一个cache line 单位来写的,但被更新
 的数据可能没有一个cache line这么多,所以为了保证数据一致性,必须先把数据导入
 cache,更新后再刷回来。
对于很多视频解码来说,帧写入过程是一个一次性的动作,只有在下一次作为参考帧时才会
被使用到,所以帧缓冲内存可以设置为写透操作,而下一次使用它的时候很可能是作为参考
帧来使用,而作为参考帧不需要反复的存取,只需一次读操作就可以了,所以效率并不会因
为不经过cache而降低。实验证明该方法可以使 mpeg4 sp解码提高20-30%的效率。
相似的内容cache操作的小技巧还有prefetch操作,prefetch操作是将主存的数据导入cache
而期间cpu不需要等待,继续下一条指令的执行,如果下一条指令也是总线的操作,那么就必
须等待prefetch完成以后再开始。所以,在使用该指令时,在prefetch指令后面插入尽可能
大于一次缓存不命中所需要的clock数对应的指令,那么prefetch与其后面的指令可以并行执
行,从而省去了等待的过程,相当于抵消缓存不命中的损失。当然,如果插入的指令太多而
cache太小,有可能prefetch的数据进入cache 后又被替换掉了,所以,这需要自己去评估。 
->cache优化

4. 总结
IDCT是视频解码中关键步骤中的第一步,目前一般采用快速算法来做,如chen-wang 算法,
c语言和汇编的效果差别还是比较大的。
对一个8x8的block做idct做变换,如   
    for (i = 0; i < 8; i++)
         idct_row (block + 8 * i);
    for (i = 0; i < 8; i++)
         idct_col (block + i);
把他汇编后,主要是可以减少存储器带宽,提高存储效率,避免无谓的内存读写。
mplayer 在此方面做了很多努力,针对armv4(s3c2440属于armv4l架构)的相关文件放在
dsputil_arm_s.S文件中。但遗憾的是,它里面有一条指令PLD,cache预取指令2440是不支持
的。PLD指令属于enhanced DSP指令,在armv4E(E 既代表enhanced DSP)才被支持,因此在我
们orchid上跑的代码必须注释掉这条指令,否则编译不过.再把话题转回来,在IDCT之前,视
频压缩流通过VLD(variable lenght decode)变长解码得到DCT数据。这部分工作一般是通过
查表来加速性能,所有的编码表会预先存起来。而取视频比特流的代码通常是宏,通过宏的
扩展来达到和汇编同样的效果。在IDCT后还有关键的运动补偿和色彩空间转换两个步骤。对
运动补偿的加速也是通过汇编化,其代码也同样放在dsputil_arm_s.S 有必要一提的是在这
部分,如果有SIMD指令将会极大的提高它的速度。
color space转换是解码输出后的最重要的一步。在嵌入式系统中,一般都是采用rgb565既
16bit来表示一个像素的色彩。
一个8x8的block,它的yuv(420格式)表示如下,
        YYYYYYYY
        YYYYYYYY
        YYYYYYYY
        YYYYYYYY
        UUUUUUUU
        VVVVVVVV
注意它的值是8bit的,通过装换方程计算,可以得到像素值。在实现中通常采用查表来加速
计算,对于每一个Y,U,V都有一个对应表。对于1个320x240的video,共76800像素。如果每
个像素在这个转换中节省10个cycle,那save下来的cpu还是相当可观的。
当色彩空间转换完后,就是通过把这个picture copy到framebuffer的内存里,这里存在一大
片的copy时间。有两方面可以注意,一是有人实现过把转换后的内存直接往framebuffer送,
减少最后所需的copy过程,这个idea确实不错,但是需要一些技巧去实现,二是copy这个过程
本省也是可以加速的,在armv5以上的体系结构里,cpu----cache---memory,其中cache和
memory的宽度是32位,但cpu和cache的bus width确是64位,用32位的成本实现了64位的存储
器。如果这个能被使用,那么理论上,copy速度可以加倍。在PC机上,一般我们的应用程序会有
fastmemorycopy这个函数,它们是用simd等特殊指令来实现,在armv5上则是通过它的总
线宽度来加速在s3c2440上不可用:( 它是v4架构。
总的来说:
(1).算法级的优化基本用无可用,ffmpeg/mplayer已经实现的相当不错,除非自己实现一个
新的decoder;
(2).在代码级,主要是通过关键代码的inline(宏,inline函数)和汇编来加速。这部分在
arm平台还是有一些潜力可挖
(3).硬件级,在这一层,cpu的体系结构决定指令集、cache的形式和大小等。如指令集是否
有enhanced DSP指令、SIMD指令,cache是否可配置、cache line大小,这些都会影响代码级
和算法级的优化
(4).系统层优化,之所以把它放在最后一层,是由于它建立在整个系统之上,只有对整个系
统包括硬件和软件有深刻的理解才能做到。
纵观优化,其实质是尽可能的去除冗余计算,最大化的利用系统硬件资源。
对于RISC架构的cpu来讲,先天不足的就是需要比较大的存储器带宽(因为RISC的指令都是基
于寄存器的,必须把操作数都load到内存才能计算),cpu资源被过多的使用在内存的read和
write。
以下面代码为例,它是解码输出后,把yuv空间装换成rgb空间的一个片断
000111c :       
    111c:       e92d4ff0        stmdb   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
    1120:       e1a0a000        mov     sl, r0
    1124:       e5900038        ldr     r0, [r0, #56]
    1128:       e1a0c001        mov     ip, r1
    112c:       e3500004        cmp     r0, #4  ; 0x4
    1130:       e24dd034        sub     sp, sp, #52     ; 0x34
    1134:       e1a00002        mov     r0, r2
    1138:       e1a01003        mov     r1, r3
    113c:       0a00055d        beq     157c
    1140:       e59d2058        ldr     r2, [sp, #88]
    1144:       e3520000        cmp     r2, #0  ; 0x0
    1148:       d1a00002        movle   r0, r2
    114c:       da00055b        ble     1574
    1150:       e59d3060        ldr     r3, [sp, #96]
    1154:       e58d1030        str     r1, [sp, #48]
    1158:       e5933000        ldr     r3, [r3]
    115c:       e59f2434        ldr     r2, [pc, #1076] ; 1598 <.text+0x1598>
    1160:       e0213193        mla     r1, r3, r1, r3
    1164:       e58d3018        str     r3, [sp, #24]
    1168:       e59d305c        ldr     r3, [sp, #92]
    116c:       e58d1000        str     r1, [sp]
    1170:       e5933000        ldr     r3, [r3]
    1174:       e79a1002        ldr     r1, [sl, r2]
    1178:       e58d301c        str     r3, [sp, #28]
    117c:       e5903008        ldr     r3, [r0, #8]
    1158:       e5933000        ldr     r3, [r3]
    115c:       e59f2434        ldr     r2, [pc, #1076] ; 1598 <.text+0x1598>
    1160:       e0213193        mla     r1, r3, r1, r3
    1164:       e58d3018        str     r3, [sp, #24]
    1168:       e59d305c        ldr     r3, [sp, #92]
    116c:       e58d1000        str     r1, [sp]
    1170:       e5933000        ldr     r3, [r3]
    1174:       e79a1002        ldr     r1, [sl, r2]
    1178:       e58d301c        str     r3, [sp, #28]
    117c:       e5903008        ldr     r3, [r0, #8]
    1180:       e59c4008        ldr     r4, [ip, #8]
    1184:       e590e000        ldr     lr, [r0]
    1188:       e59c2000        ldr     r2, [ip]
    118c:       e5900004        ldr     r0, [r0, #4]
    1190:       e59cc004        ldr     ip, [ip, #4]
    1194:       e58d3014        str     r3, [sp, #20]
    1198:       e1a011c1        mov     r1, r1, asr #3  ;h_size
    119c:       e3a03000        mov     r3, #0  ; 0x0
    11a0:       e58d4010        str     r4, [sp, #16]
    11a4:       e58d2004        str     r2, [sp, #4]
    11a8:       e58de020        str     lr, [sp, #32]
    11ac:       e58d000c        str     r0, [sp, #12]
    11b0:       e58dc008        str     ip, [sp, #8]
    11b4:       e58d1028        str     r1, [sp, #40]
    11b8:       e58d3024        str     r3, [sp, #36]
    11bc:       e1a08003        mov     r8, r3
    .................................................
    .................................................
我们可以发现在这个片断中有太多的ldr(load, read from memory)和
str(store, wirte to memory),而且过多的load和str还影响了cpu和memory之间的cache的效
率,形成cache抖动。当发生cache miss时,cahce控制器花了大力气把内容从memory搬到
cache,但是没怎么用这个entry马上又被替换掉。如果运气不好,cache就一直这样"抖动"。
在解码过程中,各个模块都各自为战,都各自去占比较大的memory带宽
如何减少这种无用的行为呢?必须让关键代码适应硬件体系结构,把数据流相关的代码耦合
在一起。很多代码通过模块化得到了优秀的可读性和可扩展性。鱼与熊掌不可兼得,耦合在
一起的代码会显得比较晦涩难懂。ffmpeg/mplayer在这方面作了一个比较好的trade-off。
1、2、3的知识摘自网上,要比较好的理解以上内容需要一些视频编、解码的知识。 

BTW:http://blog.csdn.net/weixianlin/archive/2008/05/01/2358035.aspx

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/455045.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Logstash入门简介

Logstash入门简介 介绍 Logstash是一个开源的服务器端数据处理管道&#xff0c;能够同时从多个来源采集数据&#xff0c;转换数据&#xff0c;然后将数据发送到最喜欢的存储库中&#xff08;我们的存储库当然是ElasticSearch&#xff09; 我们回到我们ElasticStack的架构图&a…

Django templates 和 urls 拆分

如果在Django项目 下面新建了blog和polls两个APP应用&#xff0c;在每个APP下面都各自新建自己的url和templates&#xff0c;那么我们需要如何进行项目配置呢&#xff1f; INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, dja…

springboot怎么杀进程_线上服务平均响应时间太长,怎么排查?

线上服务平均响应时间太长&#xff0c;怎么排查&#xff1f;https://xie.infoq.cn/article/914b5c56000a3880016abd8d6前言&#xff1a;最近线上环境某个接口服务响应时间偏长&#xff0c;导致用户体验超差&#xff0c;那平时该怎么快速的排查这类问题呢&#xff1f;①、为代码…

Redis学习第五课:Redis Set类型及操作

Set是集合&#xff0c;它是string类型的无序集合。set是通过hash table实现的&#xff0c;添加、删除和查找的复杂度都是O(1)。 对集合我们可以取并集、交集、差集。通过这些操作我们可以实现SNS中的好友推荐和blog的tag功能。 Set集合操作&#xff1a; sadd:向名称为Key的set中…

MPEG音视频编解码之MP3编解码概述

2 MP3编解码原理 2.1 MP3音频压缩标准概述 MP3全称是动态影像专家压缩标准音频层面3&#xff08;Moving Picture Experts Group Audio Layer III&#xff09;。是当今较流行的一种数字音频编码和有损压缩格式&#xff0c;它设计用来大幅度地降低音频数据量&#xff0c;而对于…

Python实现GitBook工具

写在前面 本工具是通过Python脚本实现 GitBook 自动 生成 执行 编译 发布的功能 你可以在这里下载exe 使用 1. exe下载,并移动位置 将exe文件放在你的gitbook文件夹中,或者放在空文件夹中 2. file.md 创建 名为file.md的文件,在你要写book的目录下 注意: 这里file.md文件名…

shell脚本中用到的条件和循环语句

本博文介绍一下shell脚本中常用的条件和循环语句&#xff1a;条件语句&#xff1a;循环语句&#xff1a;示例&#xff1a;if语句&#xff1a;eg1.eg2.2.case语句&#xff1a;简单的case语句&#xff1a;配合循环的case语句&#xff1a;3.for语句&#xff1a;简单的for语句&…

BZOJ 2243 染色(树链剖分好题)

2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 7971 Solved: 2990[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作&#xff0c;操作有2类&#xff1a; 1、将节点a到节点b路径上所有点都染成颜色c&#xff1b; 2、询问…

processing动态代码大全_做一张动态海报需要多少步?

人们习惯性地把程序员跟设计师分成两种不同性质的人&#xff0c;好像程序员就不会有美感&#xff0c;设计师逻辑思维就一定会很弱&#xff0c;但最近几年我们发现越来越多的程序员学设计&#xff0c;设计师学编程的跨界故事。新媒体艺术家&#xff0c;邱伟豪也是其中一员&#…

【ffmpeg for wince】音视频编解码多平台移植(for window/wince)

from: http://www.cnblogs.com/windwithlife/archive/2009/05/31/1492728.html 终于完成了了第二个Client side原型&#xff08;for Wince)&#xff0c;其中花掉我最多时间的就是ffmpeg的对WINCE的移植。其中有大半时间是由于网上的一些不完整及不正确信息所误导&#xff0c;…

python实现猴子爬山算法

猴子爬山一只顽猴在一座有N级台阶的小山上爬山跳跃。上山时需从山脚至山顶往上跳N级台阶&#xff0c;一步可跳1级&#xff0c;或跳3级&#xff0c;求上山有多少种不同的跳法&#xff1f; &#xff08;N<50&#xff09; 问题分析: 每一次都可以选择1,2,3有3种跳法 方法1 直…

指针版 单链表复习

#include <bits/stdc.h> #define P pair<int,int> using namespace std;typedef long long LL;typedef struct LNode{int data;struct LNode *nxt; }LNode,*LinkList;bool Linklist_init(LinkList &root){root new LNode; ///分配头结点&#xff0c;指针域为空…

手写springboot_Spring Boot 入门教程 | 图文讲解

目录一、Spring Boot 是什么二、为什么要使用 Spring Boot三、快速入门3.1 创建 Spring Boot 项目3.2 项目结构3.3 引入 Web 依赖3.4 编写第一个接口3.5 启动程序&#xff0c;验证效果四、总结五、GitHub 示例代码一、Spring Boot 是什么以下截图自 Spring Boot 官方文档&#…

lunix 安装python3

Linux下默认系统自带python2.6的版本&#xff0c;这个版本被系统很多程序所依赖&#xff0c;所以不建议删除&#xff0c;如果使用最新的Python3那么我们知道编译安装源码包和系统默认包之间是没有任何影响的&#xff0c;所以可以安装python3和python2共存 首先去python官网下载…

手机音视频应用开发(专注于Symbian、iPhone、Android等跨平台音视频应用开发方案)

一款好的手机应用&#xff0c; 能让用户在第一分钟就爱上他&#xff0c; 一款烂的手机应用&#xff0c; 能让用户在第一分钟就要卸载它。 好的应用必须的稳定、快速。市场日益激励&#xff0c;一个项目的周期是一个漫长的过程&#xff0c;投入的时间、精力、费用。一笔庞大的预…

Colemak布局的实现 Window+Linux+Android

Colemak布局的实现 WindowLinuxAndroid title: ‘Colemak布局的实现’ subtitle: ‘一个极客的键盘布局’ tags: entertainment solution 前言 大部分同学使用的键盘布局都是QWERTY布局 而科学研究表明,可能这个设计不是最高效率的布局,甚至的有意为了降低打字的效率而研究的…

机器学习之朴素贝叶斯法

转载请注明出处&#xff1a;http://www.cnblogs.com/Peyton-Li/ 朴素贝叶斯法是机器学习模型中一个比较简单的模型&#xff0c;实现简单&#xff0c;比较常用。 是定义在输入空间上的随机向量&#xff0c;是定义在输出空间上的随机变量。是和的联合概率分布。训练数据集由独立同…

如何让梯形变成平行四边形_开放的课堂 创新的天地——平行四边形的面积教学片段与反思...

一、 课题的确定学生在三年级学过长方形、正方形的面积计算&#xff0c;经历过从数方格的办法得出面积计算公式的过程。因此&#xff0c;学生对于面积计算公式的推导有一定的经验和知识基础。基于上述考虑&#xff0c;我想完全放手让学生去研究如何计算平行四边形的面积。这对学…

bzoj1670【Usaco2006 Oct】Building the Moat 护城河的挖掘

1670: [Usaco2006 Oct]Building the Moat护城河的挖掘 Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 387 Solved: 288[Submit][Status][Discuss]Description 为了防止口渴的食蚁兽进入他的农场&#xff0c;Farmer John决定在他的农场周围挖一条护城河。农场里一共同拥有N(8…

音视频编解码的一些源代码

音视频编解码的一些源代码 &#xff08;转&#xff09;资料名称&#xff1a;音视频编解码的一些源代码 资料成文时间&#xff1a;不详 语言&#xff1a;英文 页数&#xff1a;很多 何人所著&#xff08;来源&#xff09;&#xff1a; 文件格式&#xff1a;原代码 开发工具:vc 说…