ffmpeg中的位操作

news/2024/7/10 21:14:31 标签: ffmpeg

最近重构代码, 移植了ffmpeg源码, 有人问了两个问题:
1. MIN_CACHE_BITS的含义, 读取码值时为什么要判断该值
2. get_ue_golomb_long()的含义
这里简要分析下代码(原理性东西比如什么是哥伦布编码就不说了).

先来看下show_bits_long()(defined in libavcodec/get_bits.h), 为什么此处需要判断n的位数并走入两条分支?

 1 static inline unsigned int show_bits_long(GetBitContext *s, int n) 
 2 { 
 3     if (n <= MIN_CACHE_BITS) { 
 4         return show_bits(s, n); 
 5     } else { 
 6         GetBitContext gb = *s; 
 7         return get_bits_long(&gb, n); 
 8     } 
 9 } 
10 static inline unsigned int show_bits(GetBitContext *s, int n) 
11 { 
12     register int tmp; 
13     OPEN_READER_NOSIZE(re, s); 
14     av_assert2(n>0 && n<=25); 
15     UPDATE_CACHE(re, s); 
16     tmp = SHOW_UBITS(re, s, n); 
17     return tmp; 
18 } 
19 static inline unsigned int get_bits_long(GetBitContext *s, int n) 
20 { 
21     av_assert2(n>=0 && n<=32); 
22     if (!n) { 
23         return 0; 
24     } else if (n <= MIN_CACHE_BITS) { 
25         return get_bits(s, n); 
26     } else { 
27 #ifdef BITSTREAM_READER_LE 
28         unsigned ret = get_bits(s, 16); 
29         return ret | (get_bits(s, n - 16) << 16); 
30 #else 
31         unsigned ret = get_bits(s, 16) << (n - 16); 
32         return ret | get_bits(s, n - 16); 
33 #endif 
34    } 
35 } 

 

因为show_bits()一次读入int(4byte, 32bit)大小数据, 再根据当前读取bit数做移位操作(去除已读取的bit). 最坏的情况下需要左移7位(如果8位以上就是字节偏移了), 因此最少能保证读取25bit有效数据. 因此在已知读取位数少于25bit时走上面的fast path, 如果读取位数大于25bit呢? 那就走下面的slow path, 即先取地址两个字节, 再取高地址剩余的位. 那变长编码如何得知我要读取的位数呢? 再看下get_ue_golomb_long()(defined in libavcodec/golomb.h):

1 static inline unsigned get_ue_golomb_long(GetBitContext *gb) 
2 { 
3     unsigned buf, log; 
4     buf = show_bits_long(gb, 32); 
5     log = 31 - av_log2(buf); 
6     skip_bits_long(gb, log); 
7     return get_bits_long(gb, log + 1) - 1; 
8 } 

 

get_ue_golomb_long()先调用show_bits_long(), 传入的长度是32, 其逻辑是假定不存在32个连零的情况(否则实际值最小也是0xFFFFFFFF), 返回的值是当前读取位所在字节起始的连续四字节组成的unsigned int. av_log2()(defined in libavutil/intmath.h)是解析前导零个数的关键, 其思想分两步: 通过二分查找最高有效位所在的字节, 再通过查表得知最高有效位所在位的位数. 通过一个256字节的数组(ff_log2_tab[])节约了循环查找的时间开销. 最后用31减去最高位所在位数即得到前导零的个数.

 1 #define av_log2 ff_log2 
 2 #define ff_log2 ff_log2_c 
 3 static av_always_inline av_const int ff_log2_c(unsigned int v) 
 4 { 
 5     int n = 0; 
 6     if (v & 0xffff0000) { 
 7         v >>= 16; 
 8         n += 16; 
 9     } 
10     if (v & 0xff00) { 
11         v >>= 8; 
12         n += 8; 
13     } 
14     n += ff_log2_tab[v]; 
15     return n; 
16 } 

 

回到get_ue_golomb_long(), 得到前导零个数后将其跳过再读n+1位即得到码值, 减去1即实际哥伦布编码数据.

 

转载于:https://www.cnblogs.com/Five100Miles/p/8459178.html


http://www.niftyadmin.cn/n/976931.html

相关文章

bzoj3672 [Noi2014]购票

推一下式子发现就是普通的斜率优化&#xff0c;但是放到了树上&#xff0c;那么我们怎么做呢&#xff0c;树上有什么能保证复杂度的求路径的算法呢&#xff0c;点分治&#xff01; 但是这是有根树&#xff0c;我们对于首先处理点分治后的重心以及与根相连的那个块&#xff0c;之…

2018年第一天开工报名

2018-02-23今天是2018年初八&#xff0c;第一天开工&#xff0c;报名 Linux&#xff0c;开始学习Linux运维。转载于:https://blog.51cto.com/9298822/2072314

MacOS High Sierra 12 13系统转dmg格式

MacOS High Sierra 12.13 已经发布快一个月了&#xff0c;最近为了给公司的电脑装最新的系统&#xff0c;在网上找了资料如何将App Store下载的系统转成dmg格式的系统文件。 首先在App Store商店下载最新的MacOS High Sierra 12.13&#xff0c;下载时间比较久&#xff0c;请慢慢…

SFB 项目经验-27-SFB 2016(单独安装)-For-Windows 7-测试成功

项目问题&#xff1a;有一大客户&#xff0c;他们全是Windows 7上面安装Office 2010或者2013&#xff0c;但我们目前建议在做Skype for business Server 2015的项目的时候&#xff0c;建议客户端使用最新的Skype for business 2016&#xff0c;这是其中Office 2016中的单独组件…

robotframework环境搭建

0.如已安装RF环境&#xff0c;则在控制面板中卸载跟python相关的所有安装程序&#xff0c;将系统环境变量 D:\Python27;D:\Python27\Scripts删除掉&#xff08;盘符根据本机实际情况觉得&#xff09;&#xff0c;并重启电脑 1.安装python:python-2.7.12.amd64.msi&#xff08;安…

MySQL数据库操作类(PHP实现,支持连贯操作)

1 <?php2 /**3 * Author: suvan4 * CreateTime: 2018/2/275 * description: 数据库操作类(仅对接MySQL数据库,主要利用MySQLi函数)6 */7 class Database{8 9 //MySQL主机地址10 private $_host;11 //MySQL用户名12 private $_user;13 //MySQL用户密…

2017级面向对象程序设计寒假作业4

已学的内容总结 markdown入门用法github的基本命令尝试用面向对象写程序复习了链表c对于c的部分新特性写了复数类模版&#xff0c;以后可能可以用到在作业要求外&#xff0c;复习了以前学习的算法&#xff0c;重看以前自己写的算法模版复习线性代数...存在问题 目前struct和cla…

SAVE

SAVE 命令执行一个同步操作&#xff0c;以RDB文件的方式保存所有数据的快照 很少在生产环境直接使用SAVE 命令&#xff0c;因为它会阻塞所有的客户端的请求&#xff0c;可以使用BGSAVE 命令代替. 如果在BGSAVE命令的保存数据的子进程发生错误的时,用 SAVE命令保存最新的数据是最…