qianyi

Results 91 issues of qianyi

MP4的视频H264封装有2种格式:h264和avc1,对于这个细节,很容易被忽略(是的,我是新手,不知道MP4里面是AVC1,走了很多弯路)。其次,通过`ffprobe`也可以看到我测试的mp4文件里面H264是AVC1格式的。 ![image](https://user-images.githubusercontent.com/8001473/61624496-49db3a80-acab-11e9-9fe5-092ec982b9e2.png) ## AVCC与Annex-B H264码流分为AVCC与Annex-B两种组织格式。 - AVCC格式 也叫AVC1格式,MPEG-4格式,字节对齐,因此也叫Byte-Stream Format。用于mp4/flv/mkv等封装中。 - Annex-B格式 也叫MPEG-2 transport stream format格式(ts格式), ElementaryStream格式。用于TS流中(以及使用TS作为切片的hls格式中)。 这两种格式的区别有两点: 1. NALU的分割方式不同; 2. SPS/PPS的数据结构不同。 -  AVCC格式使用NALU长度(固定字节,字节数由extradata中的信息给定)进行分割,在封装文件或者直播流的头部包含extradata信息(非NALU),extradata中包含NALU长度的字节数以及SPS/PPS信息。 - Annex-B格式使用start code进行分割,start code为0x000001或0x00000001,SPS/PPS作为一般NALU单元以start code作为分隔符的方式放在文件或者直播流的头部。 我们知道H264是由多个NALU组成,每个NALU之间都使用start code(起始码)分隔。...

FFmpeg

## H264基本概念 - I帧 关键帧,采用帧内压缩技术 - P帧 向前参考帧,压缩时只参考前一帧,属于帧间压缩技术 - B帧 双向参考帧,压缩时既参考前一帧,也参考后一帧,属于帧间压缩技术 帧内预测压缩:解决的是空域数据冗余问题,比如删除一副图里人眼不是很敏感的颜色光亮等。 帧间预测压缩:解决的是时域数据冗余问题,随着时间轴的推移,删除重复的数据。 整数离散余弦变换(DCT):将空间上的相关性变为频域上无关的数据然后进行量化。 ### H264编码分层 - NAL层 Network Abstraction Layer,视频数据网络抽象层 网络数据包一般最大为1500个字节,H264数据帧一般大于这个数据,通过NAL拆包。 - VCL层 Video Coding Layer,视频数据编码层 ## 码流基本概念 -...

FFmpeg

## 制作开机logo图片 ``` sudo apt-get install netpbm pngtopnm mylogo.png > mylogo.pnm pnmquant 224 mylogo.pnm > mylogo224.pnm pnmtoplainpnm mylogo224.pnm > logo_linux_clut224.ppm ``` 将logo_linux_clut224.ppm拷贝值kernel主目录下的driver/video/logo/中,打开下面的宏,最后编译内核即可。 ``` CONFIG_LOGO=y CONFIG_LOGO_LINUX_CLUT224=y ``` ## 遇到的问题 **不能显示开机logo** 需要打开framebuffer...

Linux

Android系统开机优化设计到的地方比较多,从Frameworks,Kernel到Bootloader都需要改动。 后面慢慢总结更新 ## 软硬件平台 硬件平台:iMX6DL双核 软件平台:Android4.4 Kernel3.0 ## 调试工具 - logcat - bootchart - [grabserial](https://elinux.org/Grabserial) 可以方便抓取串口打印时机,对评估u-boot和内核启动时间很有作用。 ``` sudo grabserial -v -d "/dev/ttyUSB0" -b 115200 -w 8 -p N -s 1...

Android

## 音频量化过程 首先声音是模拟信号,而计算机只能识别0和1,所有需要对模拟信号进行量化,并编码。 ![image](https://user-images.githubusercontent.com/8001473/60864336-e2a69a80-a255-11e9-8ad8-ee0410c864e0.png) 可以看到需要先对模拟信号采样,接着是量化,然后再是编码 ### 量化基本概念 **采样大小** 一个采样用多少bit存放。常用的是16bit。 **采样率** 采样频率8k,16k,32k,44.1k,48k **声道数** 单声道,双声道,多声道 **码率计算** PCM音频流码率计算 采样率×采样大小×声道数 比如,采样率为44.1khz,采样大小为16bit,双声道的PCM编码wav文件, 它的码率是44.1k×16*2=1411.2kb/s。可以看到PCM的文件是很大的,所以一般需要压缩。 ## 音频冗余信息 压缩方法主要是去除采集到的音频冗余信息,所谓冗余信息包括人耳听觉范围外的音频信号,以及被遮蔽掉的音频信号。 ### 时域屏蔽效应 ![image](https://user-images.githubusercontent.com/8001473/60882754-1d6ef980-a27b-11e9-9dea-afde11aa0b83.png) 时域掩蔽发生在时间上相邻的声音之间。如噪音在欲听到的声音之前,称为超前掩蔽;噪音在该声音之后,称为滞后掩蔽。一般来说,超前掩蔽很短,只有5~20ms,而滞后掩蔽可以持续50~200ms。 ### 频域遮蔽

FFmpeg

这个问题很坑,走了不少弯路,在此记录一下。 背景: 在车机上先插入u盘(车机Host)播放音乐,再插入iPhone(车机OTG)然后U盘会掉。 ## 开始调试 跟踪内核打印发现每次掉的时候内核都有`"disconnect by usbfs`的打印,搜索内核源码,发现是通过ioctl主动调用的。 ```C /* disconnect kernel driver from interface */ case USBDEVFS_DISCONNECT: if (intf->dev.driver) { driver = to_usb_driver(intf->dev.driver); dev_dbg(&intf->dev, "disconnect by usbfs\n"); usb_driver_release_interface(driver, intf);...

Android

最近调试一个U盘的问题,一直以为是驱动的问题,也借此机会回顾了下Linux USB驱动的大体框架。 ## 驱动模型 其实Linux 下的驱动大部分都遵守总线(BUS),设备(Device),驱动(Driver)模型。这种模型简单说就是总线上有两个链表,一个是驱动链表,一个是设备链表,总线都有一个`match`函数,负责匹配设备和驱动,这个匹配过程一般是匹配名字,或者id;当匹配成功后,总线就会调用驱动的`probe`函数,至于probe函数做什么事情,那就是具体驱动做的事了。Linux下的i2c,spi,platform,包括USB都是属于这种模型。 ### 匹配过程 代码在driver/usb/core/driver.c中, ```C static int usb_device_match(struct device *dev, struct device_driver *drv) { //先是一些判断,暂时不关心 ... //匹配驱动里面的id_table id = usb_match_id(intf, usb_drv->id_table); ... if(id) return 1;...

Linux

## epoll技术简介 epoll是一种典型的I/O多路复用技术,epoll技术的最大特点是支持高并发。传统多路复用技术select,poll当并发量达到一两千的时候性能就会下降,而epoll能支持上万的并发连接,并且依然能快速稳定的响应。当然,并发连接每增加一个,必定要消耗一定的内存去保存这个连接相关的数据。 ## epoll_create()函数 ```C int epoll_create(int size) ``` 功能:创建一个epoll对象,返回该对象的描述符(文件描述符),这个描述符就代表这个epoll对象,后续会用到。从内核代码可以看出来,这个size貌似只需要大于0即可。 ```C SYSCALL_DEFINE1(epoll_create, int, size) { if (size file = file; return fd; } ``` 首先分配一个`eventpoll`结构并初始化,这个结构有两个非常重要的数据结构`struct list_head rdllist`和`struct rb_root rbr`。...

linux下的IO模型一直没有理解清楚过,直到最近的学习实战才有了较深入的理解。 5种IO模型分别是阻塞IO模型、非阻塞IO模型、IO复用模型、信号驱动的IO模型、异步IO模型;前4种可以称为同步IO操作,只有异步IO模型是异步IO操作。 ## 阻塞IO 先看一个图。 ![image](https://user-images.githubusercontent.com/8001473/57822836-e377fe80-77c7-11e9-83fd-fdf9f5111a12.png) 阻塞和非阻塞主要是指调用某个系统函数时,这个函数是否会导致我们的进程进入休眠状态而言的。调用一个函数,这个函数就卡在在这里,整个程序流程不往下走了,该函数卡在这里等待一个事情发生,只有这个事情发生了,这个函数才会往下走,这种函数,就认为是阻塞函数。比如前面说的accept()函数。 ## 非阻塞IO 不会阻塞当前进程,充分利用时间片,执行效率更高。看一下它的应用模型。 ![image](https://user-images.githubusercontent.com/8001473/57823050-be37c000-77c8-11e9-9b7e-071cc20c759b.png) 可以看到非阻塞IO一般需要轮询,不断检查是否有数据到来,比较“累”。如果没有数据到来,函数会返回一个特殊标记回来,比如`EWULDBLOCK`,也可能是`EAGAIN`。如果有数据到来那么也得卡在这里等待数据从内核数据缓冲区拷贝到用户缓冲区,所以这个复制阶段还是阻塞的。 ## 同步与异步IO 异步IO模型 ![image](https://user-images.githubusercontent.com/8001473/57823483-4cf90c80-77ca-11e9-846f-12b62d0842ca.png) 异步I/O:调用一个异步I/O函数时,我们要给这个函数指定一个接收缓冲区,还要给定一个回调函数;调用完一个异步I/O函数后,该函数会立即返回。 其余判断交给操作系统,操作系统会判断数据是否到来,如果数据到来了,操作系统会把数据拷贝到我们所提供的缓冲区里,然后调用指定的回调函数来通知我们。同步IO就是导致请求进程阻塞,直到I/O操作完成。 ## IO复用 ![image](https://user-images.githubusercontent.com/8001473/57824206-de697e00-77cc-11e9-8c75-84627495b9c8.png) 所谓I/O复用,就是我多个socket(多个TCP连接)可以弄成一捆,用select这种同步I/O函数在这等数据;select()的能力是等多条TCP连接上的任意一条有数据来,然后哪条TCP有数据来,我们再用具体的比如recvfrom()去收。所以,这种调用一个函数能够判断一堆TCP连接是否来数据的这种能力,叫I/O复用,英文I/O multiplexing。 ## 几种IO模型比较 ![image](https://user-images.githubusercontent.com/8001473/57824285-2c7e8180-77cd-11e9-9734-61ecec869d33.png) 可以看到,只有异步IO才是真正没有阻塞行为发生的。

Linux
TCP/IP

## listen函数 listen用于监听端口,一般用在TCP连接中的服务端 ```C #include int listen(int sockfd, int backlog); ``` sockfd很好理解,就是调用`socket`函数的返回值,backlog要复杂点,要理解backlog首先要知道TCP协议栈在TCP连接过程中会创建两个队列,分别是`已完成连接队列`和`未完成连接队列`,如下图所示 ![image](https://user-images.githubusercontent.com/8001473/57766877-bc272000-773a-11e9-8b6a-03a2bb4082f3.png) ### 监听套接字队列 对于一个调用listen()进行监听的套接字,操作系统会给这个套接字维护两个队列,如上所示。 - 未完成连接队列 当客户端发送TCP三次握手的第一个包(SYN)时,服务器就会在未完成队列中创建一个跟这个sync包对应的一项,其实我们也可以把这个连接看成是半连接。这个半连接的状态会从LISTEN变成SYN_RCVD状态,同时给客户端返回第二次握手包(syn,ack),这个时候服务器是在等待完成第三次握手。 - 已完成连接队列 当第三次握手完成了,这个连接就变成了ESTABLISHED状态,每个已经完成三次握手的客户端都放在这个队列中作为一项。 backlog参数之前的含义就是指这两个队列的和。 ### 客户端connect什么时候返回? 客户端其实是收到三次握手的第二次握手包(也就是收到服务器发回来的syn/ack)之后就返回了。 可以看看下面这个时序图。 ![connect时序](https://user-images.githubusercontent.com/8001473/57767707-969b1600-773c-11e9-9d04-bcd340bcc4ae.png) ![image](https://user-images.githubusercontent.com/8001473/57768831-06120500-773f-11e9-9960-234fe58c2aff.png) RTT是未完成队列中任意一项在未完成队列中留存的时间,这个时间取决于客户端和服务器。对于客户端,这个RTT时间是第一次和第二次握手加起来的时间;对于服务器,这个RTT时间实际上是第二次和第三次握手加起来的时间。如果这三次握手包传递速度特别快的话,大概187毫秒能够建立起来这个连接。...

Linux
TCP/IP