您的位置:首页 > 运维架构 > Linux

LinuxC/C++编程基础(17) 视频关键帧长度和宽度的解析

2012-12-05 15:47 851 查看
一.问题描述,如下:

在视频开发时,在视频播放之前,通常得确定该视频的原始长度和宽度,以这样的长度和宽度,才能得到最佳的视觉效果。

否则,长度或者宽度过大,就会造成失真,过小,则显然不必要。而视频的长度和宽度通常是通过相关算法变换后,存储

于视频的关键帧,因此,需要把它们解析出来,如下图给出了一些视频帧的数据:



比如,在网页YY的开发中,http://yy.com/#31499/81208043,其中的视频播放效果如下:



其中那美女的视频的长度和宽度,就需要解析出来,否则影响播放效果

转载请注明出处:山水间博客,/article/2317650.html

二.视频关键帧的解析,即sps-parse.cpp的实现,如下:

#include <stdlib.h>

#include <stdint.h>

#include <stdio.h>

typedef uint8_t byte, uint8, uint8_bitmask;

typedef uint16_t uint16, uint16_be, uint16_le;

typedef int16_t sint16, sint16_be, sint16_le;

typedef uint32_t uint32, uint32_be, uint32_le;

typedef int32_t sint32, sint32_be, sint32_le;

typedef struct __uint24 {

uint8 b[3];

} uint24, uint24_be, uint24_le;

typedef struct __bit_buffer {

byte * start;

size_t size;

byte * current;

uint8 read_bits;

} bit_buffer;

static void skip_bits(bit_buffer * bb, size_t nbits) {

bb->current = bb->current + ((nbits + bb->read_bits) / 8);

bb->read_bits = (uint8)((bb->read_bits + nbits) % 8);

}

/**

* 函数static uint8 get_bit(bit_buffer* bb)的功能是读取bb的某个字节的每一位,然后返回,实现很简单,这里略去。

*/

/**

* 函数static uint32 get_bits(bit_buffer* bb,size_t nbits)的功能相当于连续读取bb的nbits位,若nbits是8的整数倍,则相当于读取几个字节

*由uint32可知,nbits的取值范围为0~32,实现很简单,这里略去

*/

转载请注明出处:山水间博客,/article/2317650.html

static uint32 exp_golomb_ue(bit_buffer * bb) {

uint8 bit, significant_bits;

significant_bits = 0;

bit = get_bit(bb);

while (bit == 0) {

significant_bits++;

bit = get_bit(bb);

}

return (1 << significant_bits) + get_bits(bb, significant_bits) - 1;

}

static sint32 exp_golomb_se(bit_buffer * bb) {

sint32 ret;

ret = exp_golomb_ue(bb);

if ((ret & 0x1) == 0) {

return -(ret >> 1);

}

else {

return (ret + 1) >> 1;

}

}

static void parse_scaling_list(uint32 size, bit_buffer * bb) {

uint32 last_scale, next_scale, i;

sint32 delta_scale;

last_scale = 8;

next_scale = 8;

for (i = 0; i < size; i++) {

if (next_scale != 0) {

delta_scale = exp_golomb_se(bb);

next_scale = (last_scale + delta_scale + 256) % 256;

}

if (next_scale != 0) {

last_scale = next_scale;

}

}

}

/**

Parses a SPS NALU to retrieve video width and height

*/

static void parse_sps(byte * sps, size_t sps_size, uint32 * width, uint32 * height) {

bit_buffer bb;

uint32 profile, pic_order_cnt_type, width_in_mbs, height_in_map_units;

uint32 i, size, left, right, top, bottom;

uint8 frame_mbs_only_flag;

bb.start = sps;

bb.size = sps_size;

bb.current = sps;

bb.read_bits = 0;

/* skip first byte, since we already know we're parsing a SPS */

skip_bits(&bb, 8);

/* get profile */

profile = get_bits(&bb, 8);

/* skip 4 bits + 4 zeroed bits + 8 bits = 32 bits = 4 bytes */

skip_bits(&bb, 16);

/* read sps id, first exp-golomb encoded value */

exp_golomb_ue(&bb);

if (profile == 100 || profile == 110 || profile == 122 || profile == 144) {

/* chroma format idx */

if (exp_golomb_ue(&bb) == 3) {

skip_bits(&bb, 1);

}

/* bit depth luma minus8 */

exp_golomb_ue(&bb);

/* bit depth chroma minus8 */

exp_golomb_ue(&bb);

/* Qpprime Y Zero Transform Bypass flag */

skip_bits(&bb, 1);

/* Seq Scaling Matrix Present Flag */

if (get_bit(&bb)) {

for (i = 0; i < 8; i++) {

/* Seq Scaling List Present Flag */

if (get_bit(&bb)) {

parse_scaling_list(i < 6 ? 16 : 64, &bb);

}

}

}

}

/* log2_max_frame_num_minus4 */

exp_golomb_ue(&bb);

/* pic_order_cnt_type */

pic_order_cnt_type = exp_golomb_ue(&bb);

if (pic_order_cnt_type == 0) {

/* log2_max_pic_order_cnt_lsb_minus4 */

exp_golomb_ue(&bb);

}

else if (pic_order_cnt_type == 1) {

/* delta_pic_order_always_zero_flag */

skip_bits(&bb, 1);

/* offset_for_non_ref_pic */

exp_golomb_se(&bb);

/* offset_for_top_to_bottom_field */

exp_golomb_se(&bb);

size = exp_golomb_ue(&bb);

for (i = 0; i < size; i++) {

/* offset_for_ref_frame */

exp_golomb_se(&bb);

}

}

/* num_ref_frames */

exp_golomb_ue(&bb);

/* gaps_in_frame_num_value_allowed_flag */

skip_bits(&bb, 1);

/* pic_width_in_mbs */

width_in_mbs = exp_golomb_ue(&bb) + 1;

/* pic_height_in_map_units */

height_in_map_units = exp_golomb_ue(&bb) + 1;

/* frame_mbs_only_flag */

frame_mbs_only_flag = get_bit(&bb);

if (!frame_mbs_only_flag) {

/* mb_adaptive_frame_field */

skip_bits(&bb, 1);

}

/* direct_8x8_inference_flag */

skip_bits(&bb, 1);

/* frame_cropping */

left = right = top = bottom = 0;

if (get_bit(&bb)) {

left = exp_golomb_ue(&bb) * 2;

right = exp_golomb_ue(&bb) * 2;

top = exp_golomb_ue(&bb) * 2;

bottom = exp_golomb_ue(&bb) * 2;

if (!frame_mbs_only_flag) {

top *= 2;

bottom *= 2;

}

}

/* width */

*width = width_in_mbs * 16 - (left + right);

/* height */

*height = height_in_map_units * 16 - (top + bottom);

if (!frame_mbs_only_flag) {

*height *= 2;

}

}

转载请注明出处:山水间博客,/article/2317650.html

三.main函数实现,如下:

int main() {

FILE *fp = fopen("./pkt", "rb");//pkt即上图中给出的视频数据

int n = 0;

byte c = 0;

byte buf[256] = {0};

uint32 width, height;

fseek(fp, 0x0a, SEEK_SET);//set the offset 0x0a from the begining of the file

fread(&c, 1, 1, fp);

n |= (c << 8);

fread(&c, 1, 1, fp);

n |= c;

printf("sps len: 0x%x\n", n);

fread(buf, 1, n, fp);

parse_sps(buf, n, &width, &height);

printf("video width: %d\n", width);

printf("video height: %d\n", height);

return 0;

}

说明:代码简洁明了,该注意的地方,已经在注释中点出来了,这里不再赘述

四.运行结果,如下:



说明:由图可知,在视频关键帧中,视频的长度和宽度可以通过0x18个字节,即24个字节解析出来,具体哪24个字节呢?

从main函数里可以知道,是从第一行的第13个字节(即0x67)开始的24个字节,具体不再赘述

转载请注明出处:山水间博客,/article/2317650.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: