NSBlacker

此人决不闷骚


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

h264硬解码

发表于 2017-05-25   |     |   阅读次数

了解h264的桢结构

起始标志:4个字节 0000 0001
起始标志之后的第一个字节的低5位表示nalu_type = buf[4]&0x1f
5为I桢、7为sps、8为pps、1为p桢
构成顺序为sps+pps+I+p+p+…+p

1
00000001674d001f95a814016e8400000fa00001d4c0100000000168ee3c800000000106e501a8800000000165b800000f9bf0bffeced6afe1b11a32d639e05db83b1341baefb9ded91702fbd91a7c6c4700bfbcf1ae33ebce56e84c01f0d6b06c77669fc13c4903f755227

框架

framework VideoToolbox.h

数据结构

  • CMSampleBuffer:存放编解码前后的视频图像的容器数据结构。
  • CMBlockBuffer:编码后,结果图像的数据结构。
  • CVPixelBuffer:编码前和解码后的图像数据结构。
  • VTDecompressionRef:session
  • CMVideoFormatDescriptionRef:视频信息描述
    关系如下图
    image

方法

解码前期需要以下三个函数

  • CMVideoFormatDescriptionCreateFromH264ParameterSets 设置描述信息
  • VTDecompressionSessionCreate 创建解码 session
  • CMBlockBufferCreateWithMemoryBlock (uint_8 *) -> CMBlockBuffer
  • CMSampleBufferCreateReady CMBlockBuffer -> CMSampleBuffer

  • VTDecompressionSessionDecodeFrame 解码 CMSampleBuffer -> CVPixelBuffer

  • VTDecompressionSessionInvalidate 销毁解码 session

解码流程

  1. 设置CMVideoFormatDescriptionRef _description视频信息描述信息:

通过CMVideoFormatDescriptionCreateFromH264ParameterSets方法,带入sps、pps、&_description,可以提取出sps、pps中携带的视频属性信息。

  1. 创建 decode session
    1
    2
    3
    4
    5
    OSStatus status = VTDecompressionSessionCreate(kCFAllocatorDefault,
    decoderFormatDescription,
    NULL, attrs,
    &callBackRecord,
    &deocderSession);

decoderFormatDescription即为description 1中已经设置OK,

这个Session的作用是把callBackRecord函数、description描述信息连接起来,callBackRecord 是用来指定回调函数的,解码器支持异步模式,解码后会调用这里的回调函数

  1. 创建CMSampleBuffer
  • 先用CMBlockBufferCreateWithMemoryBlock从H.264数据创建一个CMBlockBufferRef实例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    CMBlockBufferCreateWithMemoryBlock(NULL,
    (void *)frame,
    frameSize,
    kCFAllocatorNull,
    NULL,
    0,
    frameSize,
    FALSE,
    &blockBuffer);
  • 然后用 CMSampleBufferCreateReady创建CMSampleBufferRef实例。当然这个CMSampleBuffer按照最上面的关系,应该是进行了一次封装,将blockbuffer封装进samplebuffer。以备之后加码使用。

    1
    2
    3
    4
    5
    status = CMSampleBufferCreateReady(kCFAllocatorDefault,
    blockBuffer,
    _decoderFormatDescription ,
    1, 0, NULL, 1, sampleSizeArray,
    &sampleBuffer);

这样可以得到一个CMSampleBufferRef的实例。

  1. 解码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    VTDecodeFrameFlags flags = 0;
    //kVTDecodeFrame_EnableTemporalProcessing | kVTDecodeFrame_EnableAsynchronousDecompression;
    VTDecodeInfoFlags flagOut = 0;
    CVPixelBufferRef outputPixelBuffer = NULL;
    OSStatus decodeStatus = VTDecompressionSessionDecodeFrame(deocderSession,
    sampleBuffer,
    flags,
    &outputPixelBuffer,
    &flagOut);

解码成功之后,outputPixelBuffer里就是一帧 NV12格式的YUV图像了。

  1. 显示
    配合Apple提供的Layer类,”AAPLEAGLLayer.h”,在controller中声明一个该类的实例_glLayer,在解码的回调中将解码出的CVPixelBuffer赋值给 _glLayer.pixelBuffer属性即可显示出来。

口答流程:

  1. 主要用到了四个数据结构和六个方法,列在纸上,说到哪里指到哪里;四个数据结构都是干什么用的,以及它们之间的关系。
  2. 画一个整体的流程图
  3. image
  4. 对于拿到的NSData数据我们要如何处理,首先要知道h264的数据格式,sps、pps、i、p的排列以及作用
  5. sps,pps设置CMVideoFormatDescriptionRef 视频信息描述,通过一个H264ParameterSets函数
  6. 刚刚提到四个函数,用了一个,剩下的三个怎么用?首先我们要调用VTDecompressionSessionCreate创建session,这就用到了刚刚的description,同时这个过程也把解码后的callBack声明好了
  7. 接下来要用VTDecompressionSessionDecodeFrame进行解码了,但是传入的参数应该时CMSampleBuffer类型,所以在这之前我们需要把(uint8_t *)类型的参数进行转化。
  8. 这就要用到CMBlockBufferCreateWithMemoryBlock和CMSampleBufferCreateReady这个两个函数了,作用我的理解就是数据结构的转化uint_8* -> CMBlockBuffer 、CMBlockBuffer -> CMSampleBuffer
  9. 终于到了解码过程,从解码函数的参数我们可以看到,把CMSampleBuffer、CVPixelBuffer和session联系起来了,而session又与description、callBack关联,输出的CVPixelBuffer直接添加到callback中,进行显示就可以了。

计算机网络——概要

发表于 2017-05-04   |     |   阅读次数

当我们在谈论HTTP、TCP/IP、Socket时,我们在谈论什么?

网络协议层

网络七层协议

即,osi 7层模型,一般的教材都会给出,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
graph TD
A[应用层]-->B[表示层]
B-->C[会话层]
C-->D[传输层]
D-->E[网络层]
E-->F[数据链路层]
F-->G[物理层]
G-->F
F-->E
E-->D
D-->C
C-->B
B-->A

网络七层协议由下往上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。其中物理层、数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象;传输层、会话层、表示层和应用层则被称作主机层,是用户所面向和关心的内容。

++HTTP协议++对应于++应用层++,++TCP协议++对应于++传输层++,++IP协议++对应于++网络层++,HTTP协议是基于TCP连接的,三者本质上没有可比性。

TCP/IP是传输层协议,主要解决数据如何在网络中传输;而HTTP是应用层协议,主要解决如何包装数据。

Socket是应用层与TCP/IP协议族通信的++中间软件抽象层++,是它的一组接口。

1
2
3
graph TD
a[HTTP所在的应用层]-->|socket| b[TCP/IP所在的传输层]
b-->|socket| a

每个层级下有着多种协议支持,下面这个表是在网络上找到的,是一个早期的图,我觉得了解那么回事儿就可以了。

序号 层级 协议
7 应用层 例如HTTP、SMTP、SNMP、FTP、Telnet、SIP、SSH、NFS、RTSP、XMPP、Whois、ENRP
6 表示层 例如XDR、ASN.1、SMB、AFP、NCP
5 会话层 例如ASAP、TLS、SSH、ISO 8327 / CCITT X.225、RPC、NetBIOS、ASP、Winsock、BSD sockets
4 传输层 例如TCP、UDP、RTP、SCTP、SPX、ATP、IL
3 网络层 例如IP、ICMP、IGMP、IPX、BGP、OSPF、RIP、IGRP、EIGRP、ARP、RARP、 X.25
2 数据链路层 例如以太网、令牌环、HDLC、帧中继、ISDN、ATM、IEEE 802.11、FDDI、PPP
1 物理层 例如线路、无线电、光纤、信鸽

TCP/IP五层模型

TCP/IP五层模型的协议分为:应用层、传输层、网络层、数据链路层和物理层。中继器、集线器、还有我们通常说的双绞线也工作在物理层;网桥(现已很少使用)、以太网交换机(二层交换机)、网卡(其实网卡是一半工作在物理层、一半工作在数据链路层)在数据链路层;路由器、三层交换机在网络层;传输层主要是四层交换机、也有工作在四层的路由器。

image

TCP/IP协议中的应用层处理七层模型中的第五层、第六层和第七层的功能。TCP/IP协议中的传输层并不能总是保证在传输层可靠地传输数据包,而七层模型可以做到。TCP/IP协议还提供一项名为UDP(用户数据报协议)的选择。UDP不能保证可靠的数据包传输。

  • TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。
  • UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。

TCP是一种流模式的协议,UDP是一种数据报模式的协议。


当我们谈论HTTP、TCP/IP、Socket时,我们在谈论什么

上面简单提到了以HTTP为代表的应用层,以TCP为代表传输层,以及以IP为代表的网络层的分工,那么,如果以一个WEB应用为例,这三种协议所代表的层级之间是如何协作分工的呢?换句话说,我在我的手机微信发的消息,经过了怎样的封装,途中经历了怎样的传输,就送到了另一部手机上显示出来的呢?这中间,Socket又是一个怎样的角色?它仅仅是一个概念吗?既然TCP和IP本是属于不同层级的两种协议,为何总是表达成TCP/IP这种组合的形式?

区分概念

  • TCP/IP协议是传输层协议,主要解决数据如何在网络中传输;
  • 而HTTP是应用层协议,主要解决如何包装数据
  • Socket是API,主要实现了TCP协议,bind、listen、connect、accept、close都是这个API中提供的接口函数。

“协议”汉语上可以这样解释:

经过谈判、协商而制定的共同承认、共同遵守、经协商取得的一致意见

就比如,TCP协议就是一个规则,这个规则中,提出了三次握手(Client端提出连接请求的时候),四次握手(在有一方提出断开请求的时候)的等概念。通过这个规则,人们可以更准确更及时,尽可能“完美”地实现层到层的数据传输,完成传输层应该完成的任务。而经过多年的实践,这个规则人们用着挺舒服,也就有继续研究和使用的必要了,至于怎么去实现这些规则,类似Socket的种种API应运而生。
下面几个部分,我们先说TCP,再说Socket,最后说HTTP

TCP

要想明白Socket连接,先要明白TCP连接。手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。

TCP协议基于在客户端Client与服务端Server的信息交互,TCP最重要的特点是建立Client与Server的连接时需要三次握手,有关三次握手,我真是不想看,不想看又不会【sad】

  1. 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

  2. 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

  3. 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

三次握手(Three-way Handshake)即建立一个TCP连接时,需要客户端和服务器总共发送3个包。三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换TCP 窗口大小信息。在socket编程中,客户端执行connect()时,将触发三次握手。

image

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次握手”。

image

TCP连接的拆除需要发送四个包,因此称为四次握手(four-way handshake)。在socket编程中,任何一方执行close()操作即可产生握手(有地方称为“挥手”)操作。之所以有“三次握手”和“四次握手”的区别,是因为连接时当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

Socket

Http

综上,我们得出一下结论

  • HTTP、TCP/IP是协议,Socket是API
  • Socket不是协议,而是API,实现了TCP协议的API。
  • HTTP协议将封装内容,TCP/IP负责在网络中运输HTTP封装的内容

这回,如果有人问你:“什么是socket?”,请不要只是说:“套接字”,这会然你直接进行不下去,因为你对套接字听得多,但实际上没有什么研究。在遇到这个问题,可以直接从“网络编程7层模型的传输层”说起,

参考资料

简单理解Socket及TCP/IP、Http、Socket的区别

关于iOS socket都在这里了

TCP/IP、Http的区别

iOS开发代码片段整理.Part1

发表于 2016-11-14   |     |   阅读次数

1.将NavigationBar设置为透明

在viewWillAppear中

1
2
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0]] forBarMetrics:0];
[self.navigationController.navigationBar setShadowImage:[UIImage imageWithColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0]]];

记得在viewWillDisappear中设置回原来的颜色

1
2
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:BlackCustom] forBarMetrics:0];
[self.navigationController.navigationBar setShadowImage:[UIImage imageWithColor:BlackCustom]];

2.创建纯色图片

1
2
3
@interface UIImage (ImageExtend)
+ (UIImage *)imageWithColor:(UIColor *)color;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@implementation  UIImage (ImageExtend)

+ (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return image;
}

3.水印图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
加半透明水印
@param useImage 需要加水印的图片
@param addImage1 水印
@returns 加好水印的图片
*/
+ (UIImage *)addImage:(UIImage *)useImage addMaskImage:(UIImage *)maskImage
{
CGFloat w = useImage.size.width;
CGFloat h = useImage.size.height;

//TV提供的useImage的尺寸有所不同,用scale作统一化
CGFloat scale = w /1920.0;
//NSLog(@"scale:%f",scale);

//这个数值不是pt,且为px ; 应按照画布的坐标体系(左下角为原点)
CGFloat logoWidth = maskImage.size.width*scale;
CGFloat logoHeight = maskImage.size.height*scale;
//NSLog(@"useImageWidth:%f,useImageHeight:%f",w,h);
//NSLog(@"logoWidth:%f,logoHeight:%f",logoWidth,logoHeight);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//create a graphic context with CGBitmapContextCreate
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 44 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), useImage.CGImage);
CGContextDrawImage(context, CGRectMake(w-logoWidth, 0, logoWidth, logoHeight), [maskImage CGImage]);
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage:imageMasked];
}

注意:用image.size.width得到的尺寸,在数值上是原图useImage的尺寸,单位为px,所以原图的分辨率直接影响了最后水印的尺寸,所以要做了一下同一化。

4. RGBA与Hex Color

1
2
3
4
5
6
7
8
//#根据十六进制换算成颜色
#define UIColorBaseRGB(rgbValue) \
[UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
//#根据十进制换算成颜色并可以设置透明度
#define RGBACOLOR(r,g,b,a) [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f \
alpha:(a)]

5.设备信息

1
2
3
4
5
6
7
8
9
10
11
#define INTERFACE_IS_PAD     ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
#define INTERFACE_IS_PHONE ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
#define isPhone5 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 1136), [[UIScreen mainScreen] currentMode].size) : NO)
#define isPadMini ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(768, 1024), [[UIScreen mainScreen] currentMode].size) : NO)

#define ScreenHeight [[UIScreen mainScreen] bounds].size.height
#define ScreenWidth [[UIScreen mainScreen] bounds].size.width

#define DEV_UUID [[UIDevice currentDevice].identifierForVendor UUIDString]

#define BUNDLE_VERSION NSDictionary [[[NSBundle mainBundle] infoDictionary]objectForKey:@"CFBundleShortVersionString"]

NavigationBar

发表于 2016-06-28   |     |   阅读次数

前言


最近的做的这个TCast项目,其中我负责了大部分UI的问题,发现NavigationBar这一块大约64pt高度的控件,涉及到的知识还真不少,有些涉及到的类名字也差不多,每次用到哪里就查哪里的资料,回头看看,好像这里面涉及的概念也好,坑也好,不整理一下确实糊涂。

现在能记得的坑就有好几个:

  1. title的字体、颜色如何定制;
  2. 为什么会出现字符显示不全的情况?如小写“g”的下半部分;
  3. 设置NavigationBar的背景颜色setBackgroundColor为什么起作用;
  4. 全局设置NavigationBar的方法;

……

这些“犄角旮旯”的问题,当时遇到的时候,查到了解决方法。确实不幸,我把所有问题都遇上了!有必要投入时间把这一小块控件研究透彻。

阅读全文 »

iOS中可复用的代码片段整理

发表于 2016-06-27   |   分类于 iOS , 代码块   |     |   阅读次数

使用场景


在项目中遇到的一些问题,iOS SDK没有直接提供方法,所以需要自己动手写,需求本身以及使用的方法都不难,不过整理为类方法,之后放到项目中专门的工具类中,使用起来很方便的。

阅读全文 »

Ubuntu搭建J2EE环境 Part2

发表于 2016-06-25   |   分类于 Reference , 其他   |     |   阅读次数

设置tomcat和eclipse的连接


1 按照上面的方法安装完tomcat后(在/user/java/tomcat7.0.57)

2 打开eclipse,在Window->Preferences->Server->Runtime Environments 点ADD(或Search),选择tomcat的安装目录。

Note:eclipse在使用tomcat服务器来开发的时候,需要对tomcat安装目录的文件进行读写操作,所以应当赋予eclipse对tomcat目录的读写权限。

阅读全文 »

Ubuntu搭建J2EE环境 Part1

发表于 2016-06-25   |   分类于 Reference , 其他   |     |   阅读次数

前言


这篇详细记录了在Ubuntu中搭建J2EE环境的过程,包括

  • 配置基础Java环境
  • 安装tomcat
  • 与Eclipse的连接
  • 安装数据库

其中引用他人的方法均已给出链接。

阅读全文 »

微信公众号的一些概念

发表于 2016-06-25   |   分类于 Reference , web   |     |   阅读次数

申请及概念


首先注册微信公众号,公众号分好几种类型,服务号、订阅号等,申请很严格,条件很苛刻
公众号和自己的微信号没有关系,当然之后可以用自己的微信号和这个新申请的公众号进行绑定

阅读全文 »

Tesla K40c加速卡的安装已使用(2)软件篇

发表于 2016-06-25   |   分类于 Reference , 其他   |     |   阅读次数

前言


在硬件篇中已经安装了Tesla K40加速卡安装在机箱中,接下来详细记录一下软件环境的搭建,更深层地,试着研究如何将该卡应用在大型工程运算中,主要是Visual Studio和Matlab环境下的运算。

阅读全文 »

Tesla K40c加速卡的安装已使用(1)硬件篇

发表于 2016-06-25   |   分类于 Reference , 其他   |     |   阅读次数

在Tesla计算卡的安装过程中,我学会了攒电脑……

阅读全文 »
123
那强

那强

不问是非 只争高下

23 日志
11 分类
25 标签
GitHub Weibo
© 2015 - 2017 那强
由 Hexo 强力驱动
主题 - NexT.Mist