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格式监控相关推荐

  1. AVPlayer支持的视频格式

    发现很多人对视频格式存在一些误解,之前写的一篇文章讲AVPlayer的支持格式也有一些问题,所以这里单独出一篇文章讲一下,希望大家能明白. 基本概念 一个在线视频能够播放,大致是经过了如下步骤: 可以 ...

  2. 计算机视频格式有哪些,在线视频网站支持的视频格式有哪些?

    在线视频网站支持的视频格式有哪些?网上冲浪也需要具备一定的上网技巧.大家都知道在线视频网站的精彩内容,大多数是网友上传上去的,如果我们也想上传视频文件到在线视频网站,希望和广大网友分享的话,就需要了解 ...

  3. [Rtsp]海康网络摄像头基于RTSP协议的windows平台监控

    [Rtsp]海康网络摄像头基于RTSP协议的windows平台监控 基于RTSP协议的windows平台监控. 1.  基于RTSP协议的windows平台监控. 1.1 选取海康网络摄像头(支持RT ...

  4. 万能视频格式转换器是一款功能强大的全能视频格式转换软件,支持多种视频格式转换。万能视频转换器可以将R...

    万能视频格式转换器是一款功能强大的全能视频格式转换软件,支持多种视频格式转换.万能视频转换器可以将RM.RMVB.AVI.WMV.MPG .MPEG.FLV.3GP.MP4.SWF.ASF.DIVX. ...

  5. VVf格式监控录像数据恢复软件

    VVF格式监控录像数据恢复软件 VVF格式监控数据恢复软件主要是恢复VVF格式的嵌入式监控录像.由于此监控硬盘格式并不普通的NTFS或FAT文件系统,用户把硬盘挂接在PC机上进行数据导出时,操作系统往 ...

  6. MCG格式监控录像数据恢复软件 1.0

    MCG格式监控录像数据恢复软件 MCG格式监控数据恢复软件主要是恢复MCG格式的嵌入式监控录像.由于此监控硬盘格式并不普通的NTFS或FAT文件系统,所以用户把硬盘挂接在PC机上进行数据导出时,往往会 ...

  7. HTML5支持的视频格式

    原来HTML5支持的视频压缩格式与封装格式都是有限制的,看来做一个BS结构的流媒体应用实用性不太强. 当前,video 元素支持三种视频格式: 格式 IE Firefox Opera Chrome S ...

  8. 在Tomcat中添加支持3GP/MP4格式文件的下载

    近日在工作中遇到3gp和mp4格式的文件问题.我用Nokia3250下载史莱克的视频(3gp)格式的.下载完后只给我提示一个text:内容有avc2.0.10.1110这样的内容. 原来Tomcat并 ...

  9. MCG格式监控录像数据恢复成功

    MCG格式监控录像数据恢复成功 [客户描述] 客户使用AVT779嵌入式监控录像机,因为要把监控录像资料导入到电脑上,所以把硬盘接在了Windows系统上,但监控录像的硬盘不是常用的Window格式, ...

  10. 『转』FFMPEG目前为止支持的所有格式列表

    FFMPEG目前为止支持的所有格式列表 1.文件格式: Supported File Format Encoding Decoding Comments MPEG audio X X MPEG-1 s ...

最新文章

  1. [c#]_ELVE_Message多功能用法
  2. ccflow如何实现自由流程的?
  3. 编码utf-8的不可映射字符_不要在 MySQL 中使用“utf8”,请使用“utf8mb4”
  4. setsockopt()和getsockopt()函数参数
  5. hash:奶牛看地图(洛谷P3405 [USACO16DEC]Cities and States S)
  6. 前端学习(1232):组件化开发开始
  7. git(7)---Git cherry-pick
  8. Oracle树查询(查询所有子节点,父节点等等)_转载
  9. 自动驾驶落地物流场景,嬴彻科技驶入快车道
  10. vivado 使用DDS IP方法
  11. sqlite3 小记
  12. EXCEL 数据透视表的制作
  13. 通过jacob实现office在线预览
  14. suse linux 飞信客户端,飞信 for linux
  15. 罗米欧与朱丽叶(徐志摩)
  16. Lipschitz函数相关
  17. 盘点那些互联网思维的餐饮新品牌
  18. Java中对两个对象进行比较大小
  19. python爬取谷歌学术参考文献的BibTex格式——基于selenium
  20. otf和ctf的意义_北京邮电大学出版社

热门文章

  1. errors and 0 warnings potentially fixable with the `--fix` option
  2. 尚硅谷kylin单机版之安装kylin
  3. 深入存储驱动:Overlay2
  4. beautifulsoup+requests链家(深圳)爬取及可视化分析
  5. npm install 提示 path .../node_modules/node-sass command failed
  6. linux attach 指令,Docker attach 命令
  7. 设置PyCharm背景图片
  8. 卡通人“小糊涂”就要登场亮相
  9. 雷军博客分享-日本的电饭煲到底好在哪?
  10. ubuntu 刷新频率 如何查看_Ubuntu 7.04救命啊!屏幕刷新频率只有50HZ眼不行啦!显示器是CRT...