c 试水解码jpeg图片比特流(已成功解码)

1c07421828194f0abd0b837d28bd185c.jpeg找到一张采用霍夫曼通用DC,AC编码表的图片,提取出此图片的比特流准备对它解码,再反推怎样编码。

下图是此图片比特流前100个字节。解码是每次读一字节,对这8比特解码,如8比特不能解码,再读入一字节。因为霍夫曼表最多是16比特位编码,意思是说超过16位比特还没有被解码就是错误的。当然不一定都是8比特,有时候是2比特等,这就涉及到比特的移位等操作。但操作单位是1字节8比特。

75a09a2e3d96400a96bb9e896184c227.jpeg

图1

上传此图片文件

下面是霍夫曼4张通用表;

cd389c8f03844d67a41b950187f2301c.jpeg

此图片帧全局(0xffc0)

ff ,c0 ,0 ,11 ,8 ,1 ,67 ,1 ,da ,3 ,1 ,22 ,0 ,2 ,11 ,1 ,3 ,11 ,1 ,

对全局头分析:

总长0x11=17位,8 代表采样精度是8位,1,67  是图片行数=1×256+0 x67=359行,1,da 代表图片列数:1x256+0xda=474,    3 代表图片的分量数:亮度Y,色度U,V 三个。

后9字节分为3组,每组3字节,第一组id为1(Y),第二为2(U),第三3(V),id号为第一字节,第3字节为每个分量采样的量化表id,第二个字节高4位代表水平采样个数,低4位垂直采样个数。

1,22,0    表示Y  在MCU中水平垂直隔有2个

2, 11 ,1   U 各一次

3, 11,  1         V 各一次 

意思就是说:此图片采样的是YUV 422 格式,有2个Y,1个U,1个V。

------------------------------------------------

此图片扫描头 SOS (0xffda)

ff ,da ,0 ,c ,3 ,1 ,0 ,2 ,11 ,3 ,11 ,0 ,3f ,0 ,

0,c:   扫描头长度 0×256+0xc=12 字节

 3: 3分量 ,Y,U,V

1,0,2,11,3,11  分位三组,每组2字节,第一个是id号

第二字节高4位是DC 号,低4位为AC 号

0 :代表Z排序是从0开始编号

3f: 0x3f=63   表示Z排序是63结束,最后一字节默认是0

有这些信息就可以解码了。

因为采用的是yuv422格式,那比特流开始就是2个Y,.紧跟1个U  ,1个V,组成一个MCU。比特流以此MCU格式为单位循环直到结束。

首先是亮度DC解码,马上是亮度AC解码,再是第二个亮度DC解码,再是第二个亮度AC解码。

现在在验证转换的方法是否正确:对,正确!现在解码出亮度DC=94,马上就是对亮度AC解码。

其实最简单粗暴的方法是把每一个比特位用一个char数组元素存储,这样就可连续读取。

特别要注意存入char数组时,读入的比特位是存储在数组的最高位。换一句话说,比特流是反序排列的,比如编码后是2字节,是先写入高字节,再写入低字节。8位二进制数是先读入高位,最后读入低位。
  下一步把另外3张表加入,完整解码看还遇到什么问题

已加入Y_AC  表,遇到0xff 0  报错

太绕了,还有各种判断要加,如0xff 0.     0.0

虽然报错,也解出4对:

94,(9, 1),(0 ,-17),(0,3)

现在有点麻烦,不能验证这些数据是否正确。感觉不理想,咋DC过后是9个0。只有一个办法验证了,手算,把前几位data数据全部用二进制位表示后手算验证程序是否正确。如正确再往下进行。

b9029bc6d23948d0a408354a494b1f1e.jpeg                                                                                                                                                                                                                    

I上图是验证数据,程序正确解码。证明ALI,霍夫曼解码部分正确。

​
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>  
#include <string.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <math.h>int main(void) {
//	unsigned char dc0[28]={0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0xa,0xb};char y_dc(unsigned char len,int bit ){   //亮度DCif((len==2)&&(bit==0b00)){return 0;	}	if((len==3)&&(bit==0b010)){return 1;}if((len==3)&&(bit==0b011)){return 2;}if((len==3)&&(bit==0b100)){return 3;}if((len==3)&&(bit==0b101)){return 4;}if((len==3)&&(bit==0b110)){return 5;}if((len==4)&&(bit==0b1110)){return 6;}if((len==5)&&(bit==0b11110)){return 7;}if((len==6)&&(bit==0b111110)){return 8;}if((len==7)&&(bit==0b1111110)){return 9;}if((len==8)&&(bit==0b11111110)){return 10;}if((len==9)&&(bit==0b111111110)){return 11;}else return -1;}//----------------------------------char ali(char len,char i){            //ALI   char o;if (len == 0) {o = 0;}if ((len == 1) && (i == 0)) {o = -1;}if ((len == 1) && (i == 1)) {o = 1;}//--------------------------if ((i >= pow(2, len - 1)) && (i <= pow(2, len))) {o = i;}if ((i >= 0) && (i < pow(2, len - 1))) {o = i - pow(2, len) + 1;}return o;}	//-------Y——AC-----------------​int  y_ac(unsigned char cd,unsigned int i,unsigned char out[2]){int bb=1;unsigned int i_bit=i;unsigned char i_len=cd;unsigned char len;unsigned char o;unsigned char  ws[16]={0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};unsigned char zh[162]={0x1, 0x2, 0x3, 0x0, 0x4, 0x11, 0x5,0x12,0x21,0x31,0x41,0x6, 0x13,0x51,0x61,0x7,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf9,0xfa};unsigned char  cx_ws,cx_b;unsigned char hfm[17][0x7d]={};int t=0;for(int a=0;a<16;a++){             if(ws[a]==0){continue;}for(int b=0;b<ws[a];b++){hfm[a+1][b]=zh[t];t++;}}
//---------------------------------------cx_ws=i_len;int o_js=0;      if(cx_ws==2){o_js=0;cx_b=i_bit-o_js;}if(cx_ws==3){o_js=0b100;cx_b=i_bit-o_js;}if(cx_ws==4){o_js=0b1010;cx_b=i_bit-o_js;}if(cx_ws==5){o_js=0b11010;cx_b=i_bit-o_js;}if(cx_ws==6){o_js=0b111010;cx_b=i_bit-o_js;}if(cx_ws==7){o_js=0b1111000;cx_b=i_bit-o_js;}if(cx_ws==8){o_js=0b11111000;cx_b=i_bit-o_js;}if(cx_ws==9){o_js=0b111110110;cx_b=i_bit-o_js;}if(cx_ws==10){o_js=0b1111110110;cx_b=i_bit-o_js;}if(cx_ws==11){o_js=0b11111110110;cx_b=i_bit-o_js;}if(cx_ws==12){o_js=0b111111110100;cx_b=i_bit-o_js;}if(cx_ws==15){o_js=0b111111111000000;cx_b=i_bit-o_js;}if(cx_ws==16){o_js=0b1111111110000010;cx_b=i_bit-o_js;}//-----------------------------------------unsigned char o_zj=hfm[cx_ws][cx_b];if(o_zj==0)  bb=-1;len=o_zj/16;o=o_zj%16;out[0]=len;out[1]=o;if((cx_ws==4)&&((i_bit-0b1010)==0)){out[0]=0;out[1]=0;bb=0;}return bb;	}​//------------------------------------------------------------------unsigned char data[100]={0xf5,0xe6,0x24,0x4e,0xff,0x41,0xfd,0x68,0xde,0xde,0xb4,0xd6,0xff,0,0x8f,0x97,0xfa,0xf,0xeb};//    0xf5           ,  0xe6       ,    0x24//  1 1 1 1 0 1 0 1 ,1 1 1 0 0 1 1 0,0 0 1 0 0 1 0 0//11110   得到7,马上取7位 1011110=x   现在就可把7位加x,利用ALI 反退出真实的DC系数=94。    //思路:	
//--------一个字节的段位字------------------------------------typedef struct{unsigned char b1:1;unsigned char b2:1;unsigned char b3:1;unsigned char b4:1;unsigned char b5:1;unsigned char b6:1;unsigned char b7:1;unsigned char b8:1;}BIT;BIT bit;unsigned char z[10000]={};     //一个程序单位int t=0;for(int dn=0;dn<10000;dn=dn+8){memset(&bit,0,1);memcpy(&bit,&data[t],1);z[dn+0]=bit.b8;	      z[dn+1]=bit.b7;	z[dn+2]=bit.b6;		z[dn+3]=bit.b5;	z[dn+4]=bit.b4;	z[dn+5]=bit.b3;		z[dn+6]=bit.b2;z[dn+7]=bit.b1;		t++;if(t==16){break;}           //验证数据:-8,12,10,1,-7,(2,-4),EOF}//    1               1               1     1           1                         1
//	unsigned char z[1000]={1,0,1,0,1,1,1,1,0,1,1,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0};/*  for(int a=0;a<100;a++){printf("%d  ,",z[a]);}*/int o=0;                //输出位数int y=0;unsigned char yac_o[2]={0};unsigned char n0=0;int a=0;int jb=0;int n=0;while(1){	for( a=2;a<17;a++){          //霍夫曼转换都是从2位开始,最多16位int ls=0;int b=0;for(b=0;b<a;b++){       //位数读取char ls=ls+z[jb+b]*(pow(2,(a-b-1)));   //把n个char 转换为2进制的a位二进制整数		}if(y==0){           //处理 Y_DCo=y_dc(a,ls);	if(o>=0){         //得到位数len,此位数是马上要从data[]读取的二进制位,此o位二进制的值假如是c,不用解码jb=jb+a;      // ali 利用len 和 c  推算出DC值//	y=1;          break;}}else{             //处理 Y_ACo=y_ac(a,ls,yac_o);if(o>=0){         //得到位数len,此位数是马上要从data[]读取的二进制位,此o位二进制的值假如是c,不用解码jb=jb+a;      // ali 利用len 和 c  推算出DC值break;}}if(a==16){puts("hfm error");exit(-1);}}//--------------------
//	
//-----读len 二进制 c-------------if(y==1){n0=yac_o[0];o=yac_o[1];}int ls=0;for(int b=0;b<o;b++){ls=ls+z[jb+b]*(pow(2,(o-b-1)));		}printf("n0:%d  o:%d\n",n0,ali(o,ls)); jb=jb+o;y=1;n++;//	y_ac(10,0b1111111010,yac_o);//	printf("%d   %d,",yac_o[0],yac_o[1]);if(n==15){break;}if((n0==0)&&(o==0)){puts("one Y over");break;}};return 0;
}​

为了简单,读比特流采用char数组,一个比特存入一个char.连续读取。

终于解码出亮度DC,AC。下一条也是亮度数据,但它的DC头是与首DC(94)的差。后面紧跟的是U与V,这4条组成一个MCU,可以解码出一个16*8的yuv块。此解码数据和手算的相同,如遇到0xff,0,则舍弃0。意思就是跳过0读下一字节。

到目前为止,已攻克了jpeg编码,解码的所有环节,完整编解码就是把这些环节串联起来。

bef5af04690b4662900ca3893a31942c.jpeg

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

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

相关文章

Raft算法详解

Raft算法属于Multi-Paxos算法&#xff0c;它是在Multi-Paxos思想的基础上&#xff0c;做了一些简化和限制&#xff0c;比如增加了日志必须是连续的&#xff0c;只支持领导者、跟随者和候选人三种状态&#xff0c;在理解和算法实现上都相对容易许多 从本质上说&#xff0c;Raft算…

淘宝弹性布局方案lib-flexible研究

1. lib-flexible不能与响应式布局兼容 先说说响应式布局的一些基本认识&#xff1a; 响应式布局的表现是&#xff1a;网页通过css媒介查询判断可视区域的宽度&#xff0c;在不同的范围应用不同的样式&#xff0c;以便在不同尺寸的设备上呈现最佳的界面效果。典型的例子是&#…

WPF效果第一百九十四篇之伸缩面板

前面一篇玩耍了一下登录实现效果;今天在原来的基础上来玩耍一下伸缩面板的效果;闲话不多扯直接看效果:1、关于前台简单布局:2、左侧面板伸缩动画&#xff1a;<Storyboard x:Key"ShowConfigSb"><ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty…

【.NET 6】开发minimal api以及依赖注入的实现和代码演示

前言&#xff1a;.net 6 LTS版本发布已经有一段时间了。此处做一个关于使用.net 6 开发精简版webapi&#xff08;minimal api&#xff09;的入门教程演示。1、新建一个项目。此处就命名为 SomeExample:2、选择 .net6版本&#xff0c;并且此处先去掉HTTPS配置以及去掉使用控制器…

(转载)VS2010/MFC编程入门之四(MFC应用程序框架分析)

上一讲鸡啄米讲的是VS2010应用程序工程中文件的组成结构&#xff0c;可能大家对工程的运行原理还是很模糊&#xff0c;理不出头绪&#xff0c;毕竟跟C编程入门系列中的例程差别太大。这一节鸡啄米就为大家分析下MFC应用程序框架的运行流程。 一.SDK应用程序与MFC应用程序运行过…

2022年中国中小学教育信息化行业研究报告

教育信息化丨研究报告 核心摘要&#xff1a; 背景篇 目前&#xff0c;我国中小学教育主要呈现信息时代教育的特征&#xff0c;智能时代教育特征初露端倪&#xff1b;中小学教育信息化正从量变迈向质变&#xff0c;创新引领与生态变革成为行业纵深的主旋律&#xff1b; 2021年…

使用curl指令发起websocket请求

昨日的文章没指出websocket请求协商切换的精髓&#xff0c;删除重发。前文相关&#xff1a;• .NET WebSockets 核心原理初体验[1]• SignalR 从开发到生产部署避坑指南[2]tag&#xff1a;浏览器--->nginx--> server其中提到nginx默认不会为客户端转发Upgrade、Connectio…

Yii 2 的安装 之 踩坑历程

由于刚接触yii2 ,决定先装个试试&#xff1b;可是这一路安装差点整吐血&#xff0c;可能还是水平有限吧&#xff0c; 但还是想把这个过程分享出来&#xff0c;让遇到同样问题的同学有个小小的参考&#xff0c;好了言归正传&#xff01;&#xff01; <(~.~)> 下面是安装流…

设计模式之代理模式(上) 静态代理与JDK动态代理

2019独角兽企业重金招聘Python工程师标准>>> 代理模式 给某一个对象提供一个代理&#xff0c;并由代理对象控制对原对象的引用。静态代理 静态代理是由我们编写好的类&#xff0c;在程序运行之前就已经编译好的的类&#xff0c;此时就叫静态代理。 说理论还是比较懵…

WPF 实现更换主题色

WPF 实现更换主题色WPF 使用 WPFDevelopers.Minimal 如何更换主题色作者&#xff1a;WPFDevelopersOrg原文链接&#xff1a; https://github.com/WPFDevelopersOrg/WPFDevelopers.Minimal框架使用大于等于.NET40&#xff1b;Visual Studio 2022;项目使用 MIT 开源许可协议&a…

vue3与vue2的区别

先来说说当下市场开发使用的问题&#xff0c;目前2021年使用vue3开发的企业还是少&#xff0c;基本上都还是以vue2的形式进行开发&#xff0c;vue3的开发模式跟react很像&#xff0c;这时候有人就会想那我学vue3有用么&#xff0c;淦&#xff0c;他喵的&#xff0c;先别激动&am…

Spring Data REST API集成Springfox、Swagger

原文: Documenting a Spring Data REST API with Springfox and Swagger 使用Spring Date REST&#xff0c;你可以迅速为Spring Date repositories的创建REST API&#xff0c;并提供CRUD和更多功能。然而&#xff0c;在严谨的API开发过成功&#xff0c;您还希望拥有自动生成的最…

【系统设计】S3 对象存储

在本文中&#xff0c;我们设计了一个类似于 Amazon Simple Storage Service (S3) 的对象存储服务。S3 是 Amazon Web Services (AWS) 提供的一项服务&#xff0c; 它通过基于 RESTful API 的接口提供对象存储。根据亚马逊的报告&#xff0c;到 2021 年&#xff0c;有超过 100 万…

转: telnet命令学习

1.每天一个linux命令&#xff08;58&#xff09;&#xff1a;telnet命令 转自&#xff1a; http://www.cnblogs.com/peida/archive/2013/03/13/2956992.html telnet命令通常用来远程登录。telnet程序是基于TELNET协议的远程登录客户端程序。Telnet协议是TCP/IP协议族中的一员&a…

禅道、码云、coding、redmine、jira、teambition几大敏捷开发项目管理系统试用对比体验

作为一个软件公司的管理人员&#xff0c;在项目和人员多起来后&#xff0c;就需要通过系统来对项目和人员进行管理。 我们是典型的软件外包公司&#xff0c;专为客户定制软件&#xff0c;所以我们的业务都是项目型的。因此&#xff0c;在管理模式上&#xff0c;我们就要用所谓…

Dubbo中的SPI机制

Dubbo中的SPI机制 概述 Service Provider Interface 即 SPI&#xff0c;是JDK内置的一种服务提供发现机制&#xff0c;可以用来启用框架扩展和替换组件。可以让不同的厂商针对统一接口编写不同的实现 SPI实际上是“接口策略模式配置文件”实现的动态加载机制。在系统设计中&…

JWT:拥有我,即拥有权力

Hi&#xff0c;这里是桑小榆。上篇文章中&#xff0c;我们一起探讨了 OAuth 协议的原理以及授权认证流程&#xff0c;本次我们一起探讨 jwt 令牌作为授权协议的传输介质。OAuth协议规范了几个参与角色的授权标准&#xff0c;安全可控的授予第三方应用&#xff0c;第三方应用获取…

双十一到来之前,阿里AI设计师“鲁班”1天能做4000万张海报

相比较去年&#xff0c;“鲁班”的设计技艺有所提升。 人工智能很大程度上便利了我们的生活&#xff0c;现在他们甚至还能取代了一些设计师的工作&#xff0c;在双十一正式到来之前&#xff0c;淘宝的宣传已经铺天盖地&#xff0c;然而很多人都没想到&#xff0c;我们打开淘宝…

Appium移动自动化测试之获取appPackage和appActivity

方法一&#xff1a;直接打开Appium,点击左上角机器人图标 选择apk所在位置&#xff0c;如图所示&#xff0c;这里以ContactManager.apk为例 方法二&#xff1a;利用dex2jar和jd-gui这两个工具反编译apk文件 这里仍以ContactManager.apk为例 (1)重命名ContactManager.apk为Conta…

CAD转WPF: 关于CAD图纸文件转换为WPF矢量代码文件(xaml文件)的技巧

前言&#xff1a;下面的文章&#xff0c;我将会以几个很简单的步骤&#xff0c;来演示一下通过CAD图纸转换为XAML代码文件的方法&#xff0c;供大佬们参考。一、为了演示一个简单的操作&#xff0c;我此处先打开一个空白的CAD&#xff0c;等下用来进行绘制点内容使用。二、自定…