RTSP支持MPEG-4格式监控
RTSP支持MPEG-4格式监控
- 1 前沿
- 2 RTSP客户端支持MPEG4
- 2.1 rtsp协议支持
- 2.2 MPEG-4头部解析
- 3 解码渲染
1 前沿
基本定义:MPEG-4 标准是一种基于对象的编解码方式,它以帧重建技术为基础实现了影像压缩。
技术要点:MPEG-4第二代的视频编码技术,提出了基于人眼生物特征的视频编码方法。提出了把人眼感兴趣的元素放在一起,即视频对象面的概念VOP 面。VOP 的分割也简单,按照一定的语义,0 表示在视频对象面内部,1 表示在视频对象面对象外部;在混合视频场景中,判断方法较复杂。
MPEG基本组成:MPEG-4 视频码流包括:视觉对象序列VS、视觉对象VO、视频对象层VOL、视频对象平面组GOV、视频对象平面VOP。其中VOP包括3种类型:帧内编码VOP(I-VOP)、预测编码VOP(P-VOP)和双向预测编码VOP(B-VOP) 。
MPEG优势:MPEG-4 标准在以下三方面具有明显优势:第一MPEG-4 压缩标准的视频传输效率比
H.264 高,且更适用于无线传输;第二基于MPEG-4 压缩标准的视频采用的是通用存储格式;第三H.264 压缩编码标准占用的CPU 和内存较大。
2 RTSP客户端支持MPEG4
2.1 rtsp协议支持
首先是在SDP协议协商时候需要提取几个关键信息:一个是协议格式:MP4V-ES;第二个是协议Payload:96;第三是分辨率等级:profile-level-id=4;当然这个还是以实际MPEG-4头解析为准;
第四是最为重要的MPEG-4头:config=000001b004000001b59113000001000000012000c888800f514043c14103;头部存放了MPEG-4分辨率信息,解码相关信息非常重要。
DESCRIBE URL RTSP/1.0
CSeq: 3
Accept: application/sdp
RTSP/1.0 200 OK
CSeq: 3
Content-Type: application/sdp
Content-Base: URL
Server: GStreamer RTSP server
Date: Wed, 01 Sep 2021 02:45:00 GMT
Content-Length: 360
v=0
o=- 1188340656180883 1 IN IP4 IP
s=Session streamed with GStreamer
i=rtsp-server
t=0 0
a=tool:GStreamer
a=type:broadcast
a=control:*
a=range:npt=now-
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
a=rtpmap:96 MP4V-ES/90000
a=control:stream=0
a=fmtp:96 profile-level-id=4;config=000001b004000001b59113000001000000012000c888800f514043c14103
2.2 MPEG-4头部解析
这里采用的是xvidcore库中的bitestream.c进行头部解析。头部解析分为几个步骤:
1.十六进制字符串转为二进制流
static void hex_str_to_byte(char *in, int len, unsigned char *out)
{char *str = (char *)malloc(len);memset(str, 0, len);memcpy(str, in, len);for (int i = 0; i < len; i+=2){if(str[i] >= 'a' && str[i] <= 'f') str[i] = str[i] - 0x20;if(str[i+1] >= 'a' && str[i] <= 'f') str[i+1] = str[i+1] - 0x20;if(str[i] >= 'A' && str[i] <= 'F')out[i/2] = (str[i]-'A'+10)<<4;elseout[i/2] = (str[i] & ~0x30)<<4;if(str[i+1] >= 'A' && str[i+1] <= 'F')out[i/2] |= (str[i+1]-'A'+10);elseout[i/2] |= (str[i+1] & ~0x30);}free(str);
}
2.第二是将数据导入xvidcore解析
解析的过程比较简单其实就是调用库函数API接口,这里只用到了流处理,即将头部赋给bs内部的流管理结构,进行初始化;然后调用头部解析,头部解析过程比较简单,就是协议的解析,分为三个部分:vos,vo,vop解析过程。
需要注意的是大小端的转换,一开始裁剪的太严重把大小端处理函数裁剪了,解析出来都是错乱的。
//这里对BitstreamReadHeaders函数参数进行了裁剪,主要是目的是为了获取视频分辨率
int mpeg4_parse(Mpeg4Context* cxt, const uint8_t* buf, size_t buf_len)
{if(!cxt || !buf) return -1;Bitstream bs;BitstreamReset(&bs);BitstreamInit(&bs, buf, buf_len);BitstreamReadHeaders(&bs, &cxt->width, &cxt->height);printf("[%s %d]:width(%d)higth(%d)\n", __FUNCTION__, __LINE__, cxt->width, cxt->height);return 0;
}//大小端处理函数
#define BSWAP(x) \x = ((((x) & 0xff000000) >> 24) | \(((x) & 0x00ff0000) >> 8) | \(((x) & 0x0000ff00) << 8) | \(((x) & 0x000000ff) << 24))
这里采用源码进行基本介绍
int
BitstreamReadHeaders(Bitstream * bs,DECODER * dec,uint32_t * rounding,uint32_t * reduced_resolution,uint32_t * quant,uint32_t * fcode_forward,uint32_t * fcode_backward,uint32_t * intra_dc_threshold,WARPPOINTS *gmc_warp)
{uint32_t vol_ver_id;uint32_t coding_type;uint32_t start_code;uint32_t time_incr = 0;int32_t time_increment = 0;int resize = 0;do {BitstreamByteAlign(bs);start_code = BitstreamShowBits(bs, 32);//VOS起始头部解析:0x000001b0if (start_code == VISOBJSEQ_START_CODE) {int profile;DPRINTF(XVID_DEBUG_STARTCODE, "<visual_object_sequence>\n");BitstreamSkip(bs, 32); /* visual_object_sequence_start_code */profile = BitstreamGetBits(bs, 8); /* profile_and_level_indication */DPRINTF(XVID_DEBUG_HEADER, "profile_and_level_indication %i\n", profile);} else if (start_code == VISOBJSEQ_STOP_CODE) {BitstreamSkip(bs, 32); /* visual_object_sequence_stop_code */DPRINTF(XVID_DEBUG_STARTCODE, "</visual_object_sequence>\n");//vo信息解析:0x000001b5} else if (start_code == VISOBJ_START_CODE) {int visobj_ver_id;DPRINTF(XVID_DEBUG_STARTCODE, "<visual_object>\n");BitstreamSkip(bs, 32); /* visual_object_start_code */if (BitstreamGetBit(bs)) /* is_visual_object_identified */{visobj_ver_id = BitstreamGetBits(bs, 4); /* visual_object_ver_id */DPRINTF(XVID_DEBUG_HEADER,"visobj_ver_id %i\n", visobj_ver_id);BitstreamSkip(bs, 3); /* visual_object_priority */} else {visobj_ver_id = 1;}if (BitstreamShowBits(bs, 4) != VISOBJ_TYPE_VIDEO) /* visual_object_type */{DPRINTF(XVID_DEBUG_ERROR, "visual_object_type != video\n");return -1;}BitstreamSkip(bs, 4);/* video_signal_type */if (BitstreamGetBit(bs)) /* video_signal_type */{DPRINTF(XVID_DEBUG_HEADER,"+ video_signal_type\n");BitstreamSkip(bs, 3); /* video_format */BitstreamSkip(bs, 1); /* video_range */if (BitstreamGetBit(bs)) /* color_description */{DPRINTF(XVID_DEBUG_HEADER,"+ color_description");BitstreamSkip(bs, 8); /* color_primaries */BitstreamSkip(bs, 8); /* transfer_characteristics */BitstreamSkip(bs, 8); /* matrix_coefficients */}}} else if ((start_code & ~VIDOBJ_START_CODE_MASK) == VIDOBJ_START_CODE) {DPRINTF(XVID_DEBUG_STARTCODE, "<video_object>\n");DPRINTF(XVID_DEBUG_HEADER, "vo id %i\n", start_code & VIDOBJ_START_CODE_MASK);BitstreamSkip(bs, 32); /* video_object_start_code *///vol解析:0x00000120} else if ((start_code & ~VIDOBJLAY_START_CODE_MASK) == VIDOBJLAY_START_CODE) {DPRINTF(XVID_DEBUG_STARTCODE, "<video_object_layer>\n");DPRINTF(XVID_DEBUG_HEADER, "vol id %i\n", start_code & VIDOBJLAY_START_CODE_MASK);BitstreamSkip(bs, 32); /* video_object_layer_start_code */BitstreamSkip(bs, 1); /* random_accessible_vol */BitstreamSkip(bs, 8); /* video_object_type_indication */if (BitstreamGetBit(bs)) /* is_object_layer_identifier */{DPRINTF(XVID_DEBUG_HEADER, "+ is_object_layer_identifier\n");vol_ver_id = BitstreamGetBits(bs, 4); /* video_object_layer_verid */DPRINTF(XVID_DEBUG_HEADER,"ver_id %i\n", vol_ver_id);BitstreamSkip(bs, 3); /* video_object_layer_priority */} else {vol_ver_id = 1;}dec->aspect_ratio = BitstreamGetBits(bs, 4);if (dec->aspect_ratio == VIDOBJLAY_AR_EXTPAR) /* aspect_ratio_info */{DPRINTF(XVID_DEBUG_HEADER, "+ aspect_ratio_info\n");dec->par_width = BitstreamGetBits(bs, 8); /* par_width */dec->par_height = BitstreamGetBits(bs, 8); /* par_height */}if (BitstreamGetBit(bs)) /* vol_control_parameters */{DPRINTF(XVID_DEBUG_HEADER, "+ vol_control_parameters\n");BitstreamSkip(bs, 2); /* chroma_format */dec->low_delay = BitstreamGetBit(bs); /* low_delay */DPRINTF(XVID_DEBUG_HEADER, "low_delay %i\n", dec->low_delay);if (BitstreamGetBit(bs)) /* vbv_parameters */{unsigned int bitrate;unsigned int buffer_size;unsigned int occupancy;DPRINTF(XVID_DEBUG_HEADER,"+ vbv_parameters\n");bitrate = BitstreamGetBits(bs,15) << 15; /* first_half_bit_rate */READ_MARKER();bitrate |= BitstreamGetBits(bs,15); /* latter_half_bit_rate */READ_MARKER();buffer_size = BitstreamGetBits(bs, 15) << 3; /* first_half_vbv_buffer_size */READ_MARKER();buffer_size |= BitstreamGetBits(bs, 3); /* latter_half_vbv_buffer_size */occupancy = BitstreamGetBits(bs, 11) << 15; /* first_half_vbv_occupancy */READ_MARKER();occupancy |= BitstreamGetBits(bs, 15); /* latter_half_vbv_occupancy */READ_MARKER();DPRINTF(XVID_DEBUG_HEADER,"bitrate %d (unit=400 bps)\n", bitrate);DPRINTF(XVID_DEBUG_HEADER,"buffer_size %d (unit=16384 bits)\n", buffer_size);DPRINTF(XVID_DEBUG_HEADER,"occupancy %d (unit=64 bits)\n", occupancy);}}else{dec->low_delay = dec->low_delay_default;}dec->shape = BitstreamGetBits(bs, 2); /* video_object_layer_shape */DPRINTF(XVID_DEBUG_HEADER, "shape %i\n", dec->shape);if (dec->shape != VIDOBJLAY_SHAPE_RECTANGULAR){DPRINTF(XVID_DEBUG_ERROR,"non-rectangular shapes are not supported\n");}if (dec->shape == VIDOBJLAY_SHAPE_GRAYSCALE && vol_ver_id != 1) {BitstreamSkip(bs, 4); /* video_object_layer_shape_extension */}READ_MARKER();/********************** for decode B-frame time ***********************/dec->time_inc_resolution = BitstreamGetBits(bs, 16); /* vop_time_increment_resolution */DPRINTF(XVID_DEBUG_HEADER,"vop_time_increment_resolution %i\n", dec->time_inc_resolution);#if 0dec->time_inc_resolution--;
#endifif (dec->time_inc_resolution > 0) {dec->time_inc_bits = MAX(log2bin(dec->time_inc_resolution-1), 1);} else {#if 0dec->time_inc_bits = 0;
#endif/* for "old" xvid compatibility, set time_inc_bits = 1 */dec->time_inc_bits = 1;}READ_MARKER();if (BitstreamGetBit(bs)) /* fixed_vop_rate */{DPRINTF(XVID_DEBUG_HEADER, "+ fixed_vop_rate\n");BitstreamSkip(bs, dec->time_inc_bits); /* fixed_vop_time_increment */}if (dec->shape != VIDOBJLAY_SHAPE_BINARY_ONLY) {if (dec->shape == VIDOBJLAY_SHAPE_RECTANGULAR) {uint32_t width, height;READ_MARKER();width = BitstreamGetBits(bs, 13); /* video_object_layer_width */READ_MARKER();height = BitstreamGetBits(bs, 13); /* video_object_layer_height */READ_MARKER();//获取视频分辨率DPRINTF(XVID_DEBUG_HEADER, "width %i\n", width);DPRINTF(XVID_DEBUG_HEADER, "height %i\n", height);if (dec->width != width || dec->height != height){if (dec->fixed_dimensions){DPRINTF(XVID_DEBUG_ERROR, "decoder width/height does not match bitstream\n");return -1;}resize = 1;dec->width = width;dec->height = height;}}dec->interlacing = BitstreamGetBit(bs);DPRINTF(XVID_DEBUG_HEADER, "interlacing %i\n", dec->interlacing);if (!BitstreamGetBit(bs)) /* obmc_disable */{DPRINTF(XVID_DEBUG_ERROR, "obmc_disabled==false not supported\n");/* TODO *//* fucking divx4.02 has this enabled */}dec->sprite_enable = BitstreamGetBits(bs, (vol_ver_id == 1 ? 1 : 2)); /* sprite_enable */if (dec->sprite_enable == SPRITE_STATIC || dec->sprite_enable == SPRITE_GMC){int low_latency_sprite_enable;if (dec->sprite_enable != SPRITE_GMC){int sprite_width;int sprite_height;int sprite_left_coord;int sprite_top_coord;sprite_width = BitstreamGetBits(bs, 13); /* sprite_width */READ_MARKER();sprite_height = BitstreamGetBits(bs, 13); /* sprite_height */READ_MARKER();sprite_left_coord = BitstreamGetBits(bs, 13); /* sprite_left_coordinate */READ_MARKER();sprite_top_coord = BitstreamGetBits(bs, 13); /* sprite_top_coordinate */READ_MARKER();}dec->sprite_warping_points = BitstreamGetBits(bs, 6); /* no_of_sprite_warping_points */dec->sprite_warping_accuracy = BitstreamGetBits(bs, 2); /* sprite_warping_accuracy */dec->sprite_brightness_change = BitstreamGetBits(bs, 1); /* brightness_change */if (dec->sprite_enable != SPRITE_GMC){low_latency_sprite_enable = BitstreamGetBits(bs, 1); /* low_latency_sprite_enable */}}if (vol_ver_id != 1 &&dec->shape != VIDOBJLAY_SHAPE_RECTANGULAR) {BitstreamSkip(bs, 1); /* sadct_disable */}if (BitstreamGetBit(bs)) /* not_8_bit */{DPRINTF(XVID_DEBUG_HEADER, "not_8_bit==true (ignored)\n");dec->quant_bits = BitstreamGetBits(bs, 4); /* quant_precision */BitstreamSkip(bs, 4); /* bits_per_pixel */} else {dec->quant_bits = 5;}if (dec->shape == VIDOBJLAY_SHAPE_GRAYSCALE) {BitstreamSkip(bs, 1); /* no_gray_quant_update */BitstreamSkip(bs, 1); /* composition_method */BitstreamSkip(bs, 1); /* linear_composition */}dec->quant_type = BitstreamGetBit(bs); /* quant_type */DPRINTF(XVID_DEBUG_HEADER, "quant_type %i\n", dec->quant_type);if (dec->quant_type) {if (BitstreamGetBit(bs)) /* load_intra_quant_mat */{uint8_t matrix[64];DPRINTF(XVID_DEBUG_HEADER, "load_intra_quant_mat\n");bs_get_matrix(bs, matrix);set_intra_matrix(dec->mpeg_quant_matrices, matrix);} elseset_intra_matrix(dec->mpeg_quant_matrices, get_default_intra_matrix());if (BitstreamGetBit(bs)) /* load_inter_quant_mat */{uint8_t matrix[64];DPRINTF(XVID_DEBUG_HEADER, "load_inter_quant_mat\n");bs_get_matrix(bs, matrix);set_inter_matrix(dec->mpeg_quant_matrices, matrix);} elseset_inter_matrix(dec->mpeg_quant_matrices, get_default_inter_matrix());if (dec->shape == VIDOBJLAY_SHAPE_GRAYSCALE) {DPRINTF(XVID_DEBUG_ERROR, "greyscale matrix not supported\n");return -1;}}if (vol_ver_id != 1) {dec->quarterpel = BitstreamGetBit(bs); /* quarter_sample */DPRINTF(XVID_DEBUG_HEADER,"quarterpel %i\n", dec->quarterpel);}elsedec->quarterpel = 0;dec->complexity_estimation_disable = BitstreamGetBit(bs); /* complexity estimation disable */if (!dec->complexity_estimation_disable){read_vol_complexity_estimation_header(bs, dec);}BitstreamSkip(bs, 1); /* resync_marker_disable */if (BitstreamGetBit(bs)) /* data_partitioned */{DPRINTF(XVID_DEBUG_ERROR, "data_partitioned not supported\n");BitstreamSkip(bs, 1); /* reversible_vlc */}if (vol_ver_id != 1) {dec->newpred_enable = BitstreamGetBit(bs);if (dec->newpred_enable) /* newpred_enable */{DPRINTF(XVID_DEBUG_HEADER, "+ newpred_enable\n");BitstreamSkip(bs, 2); /* requested_upstream_message_type */BitstreamSkip(bs, 1); /* newpred_segment_type */}dec->reduced_resolution_enable = BitstreamGetBit(bs); /* reduced_resolution_vop_enable */DPRINTF(XVID_DEBUG_HEADER, "reduced_resolution_enable %i\n", dec->reduced_resolution_enable);}else{dec->newpred_enable = 0;dec->reduced_resolution_enable = 0;}dec->scalability = BitstreamGetBit(bs); /* scalability */if (dec->scalability){DPRINTF(XVID_DEBUG_ERROR, "scalability not supported\n");BitstreamSkip(bs, 1); /* hierarchy_type */BitstreamSkip(bs, 4); /* ref_layer_id */BitstreamSkip(bs, 1); /* ref_layer_sampling_direc */BitstreamSkip(bs, 5); /* hor_sampling_factor_n */BitstreamSkip(bs, 5); /* hor_sampling_factor_m */BitstreamSkip(bs, 5); /* vert_sampling_factor_n */BitstreamSkip(bs, 5); /* vert_sampling_factor_m */BitstreamSkip(bs, 1); /* enhancement_type */if(dec->shape == VIDOBJLAY_SHAPE_BINARY /* && hierarchy_type==0 */) {BitstreamSkip(bs, 1); /* use_ref_shape */BitstreamSkip(bs, 1); /* use_ref_texture */BitstreamSkip(bs, 5); /* shape_hor_sampling_factor_n */BitstreamSkip(bs, 5); /* shape_hor_sampling_factor_m */BitstreamSkip(bs, 5); /* shape_vert_sampling_factor_n */BitstreamSkip(bs, 5); /* shape_vert_sampling_factor_m */}return -1;}} else /* dec->shape == BINARY_ONLY */{if (vol_ver_id != 1) {dec->scalability = BitstreamGetBit(bs); /* scalability */if (dec->scalability){DPRINTF(XVID_DEBUG_ERROR, "scalability not supported\n");BitstreamSkip(bs, 4); /* ref_layer_id */BitstreamSkip(bs, 5); /* hor_sampling_factor_n */BitstreamSkip(bs, 5); /* hor_sampling_factor_m */BitstreamSkip(bs, 5); /* vert_sampling_factor_n */BitstreamSkip(bs, 5); /* vert_sampling_factor_m */return -1;}}BitstreamSkip(bs, 1); /* resync_marker_disable */}return (resize ? -3 : -2 ); /* VOL */} else if (start_code == GRPOFVOP_START_CODE) {DPRINTF(XVID_DEBUG_STARTCODE, "<group_of_vop>\n");BitstreamSkip(bs, 32);{int hours, minutes, seconds;hours = BitstreamGetBits(bs, 5);minutes = BitstreamGetBits(bs, 6);READ_MARKER();seconds = BitstreamGetBits(bs, 6);DPRINTF(XVID_DEBUG_HEADER, "time %ih%im%is\n", hours,minutes,seconds);}BitstreamSkip(bs, 1); /* closed_gov */BitstreamSkip(bs, 1); /* broken_link */} else if (start_code == VOP_START_CODE) {DPRINTF(XVID_DEBUG_STARTCODE, "<vop>\n");BitstreamSkip(bs, 32); /* vop_start_code */coding_type = BitstreamGetBits(bs, 2); /* vop_coding_type */DPRINTF(XVID_DEBUG_HEADER, "coding_type %i\n", coding_type);/*********************** for decode B-frame time ***********************/while (BitstreamGetBit(bs) != 0) /* time_base */time_incr++;READ_MARKER();if (dec->time_inc_bits) {time_increment = (BitstreamGetBits(bs, dec->time_inc_bits)); /* vop_time_increment */}DPRINTF(XVID_DEBUG_HEADER, "time_base %i\n", time_incr);DPRINTF(XVID_DEBUG_HEADER, "time_increment %i\n", time_increment);DPRINTF(XVID_DEBUG_TIMECODE, "%c %i:%i\n",coding_type == I_VOP ? 'I' : coding_type == P_VOP ? 'P' : coding_type == B_VOP ? 'B' : 'S',time_incr, time_increment);if (coding_type != B_VOP) {dec->last_time_base = dec->time_base;dec->time_base += time_incr;dec->time = dec->time_base*dec->time_inc_resolution + time_increment;dec->time_pp = (int32_t)(dec->time - dec->last_non_b_time);dec->last_non_b_time = dec->time;} else {dec->time = (dec->last_time_base + time_incr)*dec->time_inc_resolution + time_increment;dec->time_bp = dec->time_pp - (int32_t)(dec->last_non_b_time - dec->time);}DPRINTF(XVID_DEBUG_HEADER,"time_pp=%i\n", dec->time_pp);DPRINTF(XVID_DEBUG_HEADER,"time_bp=%i\n", dec->time_bp);READ_MARKER();if (!BitstreamGetBit(bs)) /* vop_coded */{DPRINTF(XVID_DEBUG_HEADER, "vop_coded==false\n");return N_VOP;}if (dec->newpred_enable){int vop_id;int vop_id_for_prediction;vop_id = BitstreamGetBits(bs, MIN(dec->time_inc_bits + 3, 15));DPRINTF(XVID_DEBUG_HEADER, "vop_id %i\n", vop_id);if (BitstreamGetBit(bs)) /* vop_id_for_prediction_indication */{vop_id_for_prediction = BitstreamGetBits(bs, MIN(dec->time_inc_bits + 3, 15));DPRINTF(XVID_DEBUG_HEADER, "vop_id_for_prediction %i\n", vop_id_for_prediction);}READ_MARKER();}/* fix a little bug by MinChen <chenm002@163.com> */if ((dec->shape != VIDOBJLAY_SHAPE_BINARY_ONLY) &&( (coding_type == P_VOP) || (coding_type == S_VOP && dec->sprite_enable == SPRITE_GMC) ) ) {*rounding = BitstreamGetBit(bs); /* rounding_type */DPRINTF(XVID_DEBUG_HEADER, "rounding %i\n", *rounding);}if (dec->reduced_resolution_enable &&dec->shape == VIDOBJLAY_SHAPE_RECTANGULAR &&(coding_type == P_VOP || coding_type == I_VOP)) {*reduced_resolution = BitstreamGetBit(bs);DPRINTF(XVID_DEBUG_HEADER, "reduced_resolution %i\n", *reduced_resolution);}else{*reduced_resolution = 0;}if (dec->shape != VIDOBJLAY_SHAPE_RECTANGULAR) {if(!(dec->sprite_enable == SPRITE_STATIC && coding_type == I_VOP)) {uint32_t width, height;uint32_t horiz_mc_ref, vert_mc_ref;width = BitstreamGetBits(bs, 13);READ_MARKER();height = BitstreamGetBits(bs, 13);READ_MARKER();horiz_mc_ref = BitstreamGetBits(bs, 13);READ_MARKER();vert_mc_ref = BitstreamGetBits(bs, 13);READ_MARKER();DPRINTF(XVID_DEBUG_HEADER, "width %i\n", width);DPRINTF(XVID_DEBUG_HEADER, "height %i\n", height);DPRINTF(XVID_DEBUG_HEADER, "horiz_mc_ref %i\n", horiz_mc_ref);DPRINTF(XVID_DEBUG_HEADER, "vert_mc_ref %i\n", vert_mc_ref);}BitstreamSkip(bs, 1); /* change_conv_ratio_disable */if (BitstreamGetBit(bs)) /* vop_constant_alpha */{BitstreamSkip(bs, 8); /* vop_constant_alpha_value */}}if (dec->shape != VIDOBJLAY_SHAPE_BINARY_ONLY) {if (!dec->complexity_estimation_disable){read_vop_complexity_estimation_header(bs, dec, coding_type);}/* intra_dc_vlc_threshold */*intra_dc_threshold =intra_dc_threshold_table[BitstreamGetBits(bs, 3)];dec->top_field_first = 0;dec->alternate_vertical_scan = 0;if (dec->interlacing) {dec->top_field_first = BitstreamGetBit(bs);DPRINTF(XVID_DEBUG_HEADER, "interlace top_field_first %i\n", dec->top_field_first);dec->alternate_vertical_scan = BitstreamGetBit(bs);DPRINTF(XVID_DEBUG_HEADER, "interlace alternate_vertical_scan %i\n", dec->alternate_vertical_scan);}}if ((dec->sprite_enable == SPRITE_STATIC || dec->sprite_enable== SPRITE_GMC) && coding_type == S_VOP) {int i;for (i = 0 ; i < dec->sprite_warping_points; i++){int length;int x = 0, y = 0;/* sprite code borowed from ffmpeg; thx Michael Niedermayer <michaelni@gmx.at> */length = bs_get_spritetrajectory(bs);if(length){x= BitstreamGetBits(bs, length);if ((x >> (length - 1)) == 0) /* if MSB not set it is negative*/x = - (x ^ ((1 << length) - 1));}READ_MARKER();length = bs_get_spritetrajectory(bs);if(length){y = BitstreamGetBits(bs, length);if ((y >> (length - 1)) == 0) /* if MSB not set it is negative*/y = - (y ^ ((1 << length) - 1));}READ_MARKER();gmc_warp->duv[i].x = x;gmc_warp->duv[i].y = y;DPRINTF(XVID_DEBUG_HEADER,"sprite_warping_point[%i] xy=(%i,%i)\n", i, x, y);}if (dec->sprite_brightness_change){/* XXX: brightness_change_factor() */}if (dec->sprite_enable == SPRITE_STATIC){/* XXX: todo */}}if ((*quant = BitstreamGetBits(bs, dec->quant_bits)) < 1) /* vop_quant */*quant = 1;DPRINTF(XVID_DEBUG_HEADER, "quant %i\n", *quant);if (coding_type != I_VOP) {*fcode_forward = BitstreamGetBits(bs, 3); /* fcode_forward */DPRINTF(XVID_DEBUG_HEADER, "fcode_forward %i\n", *fcode_forward);}if (coding_type == B_VOP) {*fcode_backward = BitstreamGetBits(bs, 3); /* fcode_backward */DPRINTF(XVID_DEBUG_HEADER, "fcode_backward %i\n", *fcode_backward);}if (!dec->scalability) {if ((dec->shape != VIDOBJLAY_SHAPE_RECTANGULAR) &&(coding_type != I_VOP)) {BitstreamSkip(bs, 1); /* vop_shape_coding_type */}}return coding_type;} else if (start_code == USERDATA_START_CODE) {char tmp[256];int i, version, build;char packed;BitstreamSkip(bs, 32); /* user_data_start_code */tmp[0] = BitstreamShowBits(bs, 8);for(i = 1; i < 256; i++){tmp[i] = (BitstreamShowBits(bs, 16) & 0xFF);if(tmp[i] == 0)break;BitstreamSkip(bs, 8);}DPRINTF(XVID_DEBUG_STARTCODE, "<user_data>: %s\n", tmp);/* read xvid bitstream version */if(strncmp(tmp, "XviD", 4) == 0) {if (tmp[strlen(tmp)-1] == 'C') { sscanf(tmp, "XviD%dC", &dec->bs_version);dec->cartoon_mode = 1;}elsesscanf(tmp, "XviD%d", &dec->bs_version);DPRINTF(XVID_DEBUG_HEADER, "xvid bitstream version=%i\n", dec->bs_version);}/* divx detection */i = sscanf(tmp, "DivX%dBuild%d%c", &version, &build, &packed);if (i < 2)i = sscanf(tmp, "DivX%db%d%c", &version, &build, &packed);if (i >= 2){dec->packed_mode = (i == 3 && packed == 'p');DPRINTF(XVID_DEBUG_HEADER, "divx version=%i, build=%i packed=%i\n",version, build, dec->packed_mode);}} else /* start_code == ? */{if (BitstreamShowBits(bs, 24) == 0x000001) {DPRINTF(XVID_DEBUG_STARTCODE, "<unknown: %x>\n", BitstreamShowBits(bs, 32));}BitstreamSkip(bs, 8);}}while ((BitstreamPos(bs) >> 3) < bs->length);#if 0DPRINTF("*** WARNING: no vop_start_code found");
#endifreturn -1; /* ignore it */
}
3 解码渲染
解码选择比较多一个是设备平台本身支持硬解,这个比较好办,直接将头部数据和第一个I帧数据绑定丢到解码器,后面的数据也是直接丢掉解码器即可;最终拿到视频YUV数据走正常视频播放渲染流程即可。
另一种比较麻烦需要自己实现软解码,也有比较多种选择,比如这个xvid-core本身支持MPEG-4的编解码,也可以采用通用的视频框架比如ffmpeg也是支持软解MPEG-4格式。很遗憾我的设备没有硬件采用的是ffmpeg进行软解。
下面介绍下ffmpeg初始化一种编码格式过程,注意不同版本存在一些差异:
//MPEG-4 codecId:AV_CODEC_ID_MPEG4
//1. 初始化获取解码器:avcodec_find_decoder//初始化环境变量avcodec_alloc_context3//启动解码器avcodec_open2//申请帧空间av_frame_alloc//2. 释放帧空间//关闭解码器avcodec_close//释放帧空间av_frame_free//3. 解码过程//解码视频帧avcodec_decode_video2
需要注意点是解码后帧如何转成你想要的YUV格式:
AVFrame结构体,其中data是一个数组,data[0]存放的是Y数据它是按行存放,data[1]存放的是UV数据,也是按行存放;linesize表示的是data一行数据大小。
static void* get_yuv420_data(int h, int w)
{//申请内存 int height = h;int width = w;//写入数据 int a=0,i; for (i=0; i<height; i++) { memcpy(yuv_buf + a, pFrame->data[0] + i * pFrame->linesize[0], width); a+=width; } for (i=0; i<height/2; i++) { memcpy(yuv_buf + a, pFrame->data[1] + i * pFrame->linesize[1], width/2); a+=width/2; } for (i=0; i<height/2; i++) { memcpy(yuv_buf + a, pFrame->data[2] + i * pFrame->linesize[2], width/2); a+=width/2; } return yuv_buf;
}
渲染这边是送到硬件平台显示不做展开。
RTSP支持MPEG-4格式监控相关推荐
- AVPlayer支持的视频格式
发现很多人对视频格式存在一些误解,之前写的一篇文章讲AVPlayer的支持格式也有一些问题,所以这里单独出一篇文章讲一下,希望大家能明白. 基本概念 一个在线视频能够播放,大致是经过了如下步骤: 可以 ...
- 计算机视频格式有哪些,在线视频网站支持的视频格式有哪些?
在线视频网站支持的视频格式有哪些?网上冲浪也需要具备一定的上网技巧.大家都知道在线视频网站的精彩内容,大多数是网友上传上去的,如果我们也想上传视频文件到在线视频网站,希望和广大网友分享的话,就需要了解 ...
- [Rtsp]海康网络摄像头基于RTSP协议的windows平台监控
[Rtsp]海康网络摄像头基于RTSP协议的windows平台监控 基于RTSP协议的windows平台监控. 1. 基于RTSP协议的windows平台监控. 1.1 选取海康网络摄像头(支持RT ...
- 万能视频格式转换器是一款功能强大的全能视频格式转换软件,支持多种视频格式转换。万能视频转换器可以将R...
万能视频格式转换器是一款功能强大的全能视频格式转换软件,支持多种视频格式转换.万能视频转换器可以将RM.RMVB.AVI.WMV.MPG .MPEG.FLV.3GP.MP4.SWF.ASF.DIVX. ...
- VVf格式监控录像数据恢复软件
VVF格式监控录像数据恢复软件 VVF格式监控数据恢复软件主要是恢复VVF格式的嵌入式监控录像.由于此监控硬盘格式并不普通的NTFS或FAT文件系统,用户把硬盘挂接在PC机上进行数据导出时,操作系统往 ...
- MCG格式监控录像数据恢复软件 1.0
MCG格式监控录像数据恢复软件 MCG格式监控数据恢复软件主要是恢复MCG格式的嵌入式监控录像.由于此监控硬盘格式并不普通的NTFS或FAT文件系统,所以用户把硬盘挂接在PC机上进行数据导出时,往往会 ...
- HTML5支持的视频格式
原来HTML5支持的视频压缩格式与封装格式都是有限制的,看来做一个BS结构的流媒体应用实用性不太强. 当前,video 元素支持三种视频格式: 格式 IE Firefox Opera Chrome S ...
- 在Tomcat中添加支持3GP/MP4格式文件的下载
近日在工作中遇到3gp和mp4格式的文件问题.我用Nokia3250下载史莱克的视频(3gp)格式的.下载完后只给我提示一个text:内容有avc2.0.10.1110这样的内容. 原来Tomcat并 ...
- MCG格式监控录像数据恢复成功
MCG格式监控录像数据恢复成功 [客户描述] 客户使用AVT779嵌入式监控录像机,因为要把监控录像资料导入到电脑上,所以把硬盘接在了Windows系统上,但监控录像的硬盘不是常用的Window格式, ...
- 『转』FFMPEG目前为止支持的所有格式列表
FFMPEG目前为止支持的所有格式列表 1.文件格式: Supported File Format Encoding Decoding Comments MPEG audio X X MPEG-1 s ...
最新文章
- [c#]_ELVE_Message多功能用法
- ccflow如何实现自由流程的?
- 编码utf-8的不可映射字符_不要在 MySQL 中使用“utf8”,请使用“utf8mb4”
- setsockopt()和getsockopt()函数参数
- hash:奶牛看地图(洛谷P3405 [USACO16DEC]Cities and States S)
- 前端学习(1232):组件化开发开始
- git(7)---Git cherry-pick
- Oracle树查询(查询所有子节点,父节点等等)_转载
- 自动驾驶落地物流场景,嬴彻科技驶入快车道
- vivado 使用DDS IP方法
- sqlite3 小记
- EXCEL 数据透视表的制作
- 通过jacob实现office在线预览
- suse linux 飞信客户端,飞信 for linux
- 罗米欧与朱丽叶(徐志摩)
- Lipschitz函数相关
- 盘点那些互联网思维的餐饮新品牌
- Java中对两个对象进行比较大小
- python爬取谷歌学术参考文献的BibTex格式——基于selenium
- otf和ctf的意义_北京邮电大学出版社
热门文章
- errors and 0 warnings potentially fixable with the `--fix` option
- 尚硅谷kylin单机版之安装kylin
- 深入存储驱动:Overlay2
- beautifulsoup+requests链家(深圳)爬取及可视化分析
- npm install 提示 path .../node_modules/node-sass command failed
- linux attach 指令,Docker attach 命令
- 设置PyCharm背景图片
- 卡通人“小糊涂”就要登场亮相
- 雷军博客分享-日本的电饭煲到底好在哪?
- ubuntu 刷新频率 如何查看_Ubuntu 7.04救命啊!屏幕刷新频率只有50HZ眼不行啦!显示器是CRT...