logo资料库

视频码率/分辨率/卡顿的计算方法参考.docx

第1页 / 共10页
第2页 / 共10页
第3页 / 共10页
第4页 / 共10页
第5页 / 共10页
第6页 / 共10页
第7页 / 共10页
第8页 / 共10页
资料共10页,剩余部分请下载后查看
你提到的从getInfo中取,只针对腾讯视频中的http请求中带有相关信息的时候,获取不到的时候就是
视频码率/分辨率/卡顿的计算方法参考: 1、 码率问题: 你们提到的客户给出的码率字段定义是视频文件的大小/视频播放时长.这个我们也是这么计算的, 只是有些细节的问题,需要说明一下,以免你对我们现有的定义有误解: 首先,码率的单位,一般为 kbps, 1B=8b B=byte(字节) b=bit(位) k=kilo 所以这里的 :kbps = kilo bits per second 其次,针对不同的视频格式又不同的码率算法, 不知道你有疑问的是哪一种,看描述,你应该是对 MP4 格式的码率计算有疑问,可以重点看一下 MP4 的码率算法: 1) MP4: 在数据流中通过 ftyp box 找到 moov box,进而在 moov box 中找到 mvhd box,mvhd box 包含 着该格式视频的一些基础信息,这里我们要用到的是 timescale 和 duration 这两个字段,timescale 字段表示该视频的时间尺度—即在其时间坐标系统中每秒传递的时间单位数,duration 字段表 示视频在时间尺度单元中的持续时间。 视频的时间长度由公式 duration / timescale 得到,单位为 s; 视频的大小 filesize 通过在 http response header 中解析 Content-Length 或者 Content-Range (Content-Range 取'/'后的部分)得到,单位为 Byte;一般情况下从两者中分析出的的值应该
一致,但是当视频分段传输,Content-Length 小于 Content-Range 时,以 Content-Range 中取得 的值为准。 所以视频的码率为: rate = 8 * filesize / (duration / timescale) ,码率的单位为 bits/s,一般输出的时候会进行单位转换 rate/1024,变成 kbps。 2) FLV: FLV 格式的视频数据中可以通过解析 videodatarate 字段直接得到码率,filesize 字段得到文件大 小。 3)TS: 找到 PAT 表(节目关联表),进而找到 PMT 表(节目映射表)对应的 PID,然后通过 PID 找 到 PMT 表,根据第二步找到的视频内容(H.264:stream_type =0x1B; H.265:stream_type =0x24) 对应的 TS 的 PID,将视频内容对应的 TS 找到,将其中的 payload 部分的结构(PES)拿出来, 找到视频内容对应的 PTS,1PTS 表示 1/90000 秒,只找 payload_unit_start_indicator 为 1 的包。 在前面查到一个含 PCR 字段的 TS 包,取出 PCR 值和 PID,然后在后续流量中查找这个 PID 的 TS 包,取出 PCR 值,将这两个包的位置之间的 BYTE 大小除 PCR 的差值再乘 90000 再乘 8, 即得该 TS 流的码率。 3、分辨率问题: 这个也是不同的格式算法不同: 1) MP4: 分析完码率之后继续分析,找到 tkhd box,可以直接分析得到 width 和 heigth: 2) FLV: FLV 格式的视频数据中可以通过解析 width 和 heigth 直接得到。 3)TS: TS 格式的视频,解析宽高需要找到视频的序列参数集 SPS,SPS 的内容大致可以分为几个部 分: 1、自引 ID; 2、解码相关信息,如档次级别、分辨率、子层数等; 3、某档次中的功能开关标识及该功能的参数;
4、对结构和变换系数编码灵活性的限制信息; 5、时域可分级信息; 6、VUI。 这里我们主要解析分辨率,即宽高,用到的信息为 pic_width_in_luma_samples 和 pic_height_in_luma_samples : 得到 pic_width_in_luma_samples 和 pic_height_in_luma_samples 值后即可通过以下公式得到视频 宽高(H.264 和 H.265 的计算方法还有一些差别): H.264 的宽高计算公式为: width = (sps.pic_width_in_mbs_minus1+1)*16; height= (sps.pic_height_in_map_units_minus1+1)*16; H.265 计算宽高的公式为: width = sps.pic_width_in_luma_samples; height = sps.pic_height_in_luma_samples; 编辑此区域 你提到的从 getInfo 中取,只针对腾讯视频中的 http 请求中带有相关信息的时候,获取不到的 时候就是用上面的方法分析得到的; 就我们看,分辨率和码率也有你说的这种分辨率等级和分辨率像素区间的关系, 你提到的 144P 以下的分辨率,视频码率也存在 2MB 以上的值,这应该是分析的有问题,如果有 相关的数据可以提供给我们进行进一步分析。 4、卡顿次数占比问题 我们的对卡顿的认定方式是根据 缓存数据是否足够一定数量的播放量来认定的,即,当视频缓存 到一定数量(一般为 2 秒的播放量,2*码率)之后,认为视频播放成功,之后: 当视频缓存不足一定数量(一般为 3 秒的播放量,3*码率)之后,认为出现卡顿,记一次卡顿,并 统计卡顿时间,当缓存够这些数据之后重新开始判定是否出现卡顿。 3、关于 TS 的分析, TS 是苹果系统里面用得非常多的一种格式,现在网络中也有 20%左右的量是 TS 格式的,和 Mp4、 Flv 合在一起占了绝大多数网络流量。
TS 的包是一个一个 188 字节的包组成,这 188 字节里面由一个 0x47 开头的包作为同步,也就是说, 如果你找到了 0x47,如果与它相隔 188 个字节的地方又是一个 0x47,基本上就是一个 TS 的包。另 外,对于我们实际上还有辅助判断办法,比如.TS 的文件一般 content_type 为 video/mp2t(但反 过来,video/mp2t 类型的有一小部分是 mp4);另外,访问的 url 里面一般都有".ts"或者".ts?"的 字段。 一般将“video/mp2t"和是否包含".ts"合并起来判断,基本上可以拿出绝大多数的 ts,如果再加上 0x47 这个判断,就更加准确了,基本上 100% TS 包的表结构如下: 第一步:找到 PAT 表(节目关联表),为的目的是找到 PMT 表对应的 PID PAT 表的 PID 为 0,一般它在整个 TS 的前几个(一般在 1,2 个)TS 结构中。我举的例子就是在第二 个 TS 结构中,如下:
0x47 和第一个 0x47 正好隔了 188 个,第一个 TS 包的 PID 不为 0( 0 0000 0001 0001),忽略,第二个 TS 包的 PID 为 0,为 PAT 表(注意 PID 后面还要跳过一个 8bit 的长度才是 PAT 表结构)。 PAT 表结构如下: N loop 那里就是标识后面多个表结构信息的地方,所以找到 PAT 之后,直接从它的结构的第 9 个字节 开始(如果从 0x47 算起,就是第 14 个字节),就是 N 个 program 的结构了,从这里面找 Program number 为 0x00 01 的结构,他的 Network PID 即为 PMT 对应的 PID。 这里我们看到,除掉最后 32 个字节的 CRC 外,只有一个 program 结构(4 个字节),其中 program number 为 0x01,PID 为 0xF0 的后 13 个 bit,即 0x 10 00, 第二步:根据第一步找到的 PMT 表的 PID(0x 10 10),找到 PMT 表 挺幸运,第三个 TS 结构实际上就是 PMT 表,如下图,找 PID 的办法,我第一步里面已经说了 pmt 的结构如下: 1. 2. typedef struct TS_PMT {
3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. : 8; //固定为 0x02, 表示 PMT 表 : 1; //固定为 0x01 unsigned table_id unsigned section_syntax_indicator unsigned zero unsigned reserved_1 unsigned section_length : 1; //0x01 : 2; //0x03 : 12;//首先两位 bit 置为 00,它指示段的 byte 数,由段长度域开始,包含 CRC。 unsigned program_number unsigned reserved_2 unsigned version_number unsigned current_next_indicator : 16;// 指出该节目对应于可应用的 Program map PID : 2; //0x03 : 5; //指出 TS 流中 Program map section 的版本号 : 1; //当该位置 1 时,当前传送的 Program map section 可用; //当该位置 0 时,指示当前传送的 Program map section 不可用,下一个 TS 流的 Program map section 有效。 unsigned section_number unsigned last_section_number unsigned reserved_3 unsigned PCR_PID : 8; //固定为 0x00 : 8; //固定为 0x00 : 3; //0x07 : 13; //指明 TS 包的 PID 值,该 TS 包含有 PCR 域, //该 PCR 值对应于由节目号指定的对应节目。 //如果对于私有数据流的节目定义与 PCR 无关,这个域的值将为 0x1FFF。 unsigned reserved_4 unsigned program_info_length 数。 : 4; //预留为 0x0F : 12; //前两位 bit 为 00。该域指出跟随其后对节目信息的描述的 byte std::vector PMT_Stream; //每个元素包含 8 位, 指示特定 PID 的节目元素包的类型。该处 PID 由 elementary PID 指定 unsigned reserved_5 unsigned reserved_6 unsigned CRC_32 23. 24. 25. 26. } TS_PMT; : 3; //0x07 : 4; //0x0F : 32; 我们主要在乎的是 PMT_Stream(第 13 个字节开始,从 0x47 开始为第 18 个字节)里面的内容, PMT_Stream 的结构如下(有多少个,由 program_info_length 决定) 1. 2. 3. 4. 5. 6. 7. typedef struct TS_PMT_Stream { unsigned stream_type unsigned elementary_PID 有相关的节目元素 unsigned ES_info_length 元素的 byte 数 unsigned descriptor; }TS_PMT_Stream; 我们还是看这个例子, : 8; //指示特定 PID 的节目元素包的类型。该处 PID 由 elementary PID 指定 :13; //3 个 bit reserved,后 13 个 bit 指示 TS 包的 PID 值。这些 TS 包含 : 12; //前 4 位 bit 为 reserved。后 12 个 bit 指示跟随其后的描述相关节目 //长度由 ES_info_length 决定
第一个 PMT_Stream stream_type =0x1B,查下表,后面为 H.264 格式的 video 的描述,它的 PID 为 E1 的后 13 个 bit,即 0x0100; 即后面所有的 TS 结构,PID 为 0x01 00 的,都是 H.264 的视频(我们第三步的目标出来了!),这个 stream 的 descriptor 长度为 0( ES_info_length 这里为 0),所以总共就 5 byte 长; 第二个 PMT_Stream stream_type =0x0F,查下表,为 audio,PID 为 0x0101,ES_info_length 为 6,所以总长度 11 个 byte(这 些都是后话,对于本次分析意义不大,说这些只是为了编程时好理解)
第三步:根据第二步找到的视频内容对应的 TS 的 PID,将视频内容对应的 TS 找到,将其中的 payload 部分的结构(PES)拿出来,找到视频内容对应的 PTS(相当重要啊,直接关系到视频播放时间) 还是那个包,很幸运,第五个 TS 的 PID 就是 0x10 00(把 0x47 41 00 的 41 00 拆开,取后面 13 个 bit), 我们只找 payload_unit_start_indicator 为 1 的包(标识这是 PES 的开头包) 但是要注意,TS 的 adaptation field control 字段为 11,表示后面接着有个 adaptation 结构,然 后才是 payload 部分,几个取值代表的意思见下: 00 reserved for future use by ISO/IEC 01 no adaptation_field, payload only 10 adaptation_field only, no payload 11 adaptation_field followed by payload 这个 adaptation 对于我们意义,不大,直接读取它的第一个字节(表示他的长度)然后跳过这个长 度的 byte,直接到 payload 部分即可
分享到:
收藏