EasyRTMP视频直播推送H264 sps解析错误导致播放画面拉伸问题解决
EasyRTMP是将H264流以及AAC流以RTMP协议推送到RTMP服务器上进行直播。EasyRTMP推送库中会从H264流中提取中SPS、PPS进行解析,开发的时候遇到过有些SPS解析有误,获取到的宽高不正确,导致播放的时候画面被拉长的问题。下面给出一份比较完善的SPS解析
SPS解析
定义sps结构
typedef struct
{
int i_id;
int i_profile_idc;
int i_level_idc;
int b_constraint_set0;
int b_constraint_set1;
int b_constraint_set2;
int i_chroma_format_idc;
int i_log2_max_frame_num;
int i_poc_type;
/* poc 0 */
int i_log2_max_poc_lsb;
/* poc 1 */
int b_delta_pic_order_always_zero;
int i_offset_for_non_ref_pic;
int i_offset_for_top_to_bottom_field;
int i_num_ref_frames_in_poc_cycle;
int i_offset_for_ref_frame[256];
int i_num_ref_frames;
int b_gaps_in_frame_num_value_allowed;
int i_mb_width;
int i_mb_height;
int b_frame_mbs_only;
int b_mb_adaptive_frame_field;
int b_direct8x8_inference;
int b_crop;
struct
{
int i_left;
int i_right;
int i_top;
int i_bottom;
} crop;
int b_vui;
struct
{
int b_aspect_ratio_info_present;
int i_sar_width;
int i_sar_height;
int b_overscan_info_present;
int b_overscan_info;
int b_signal_type_present;
int i_vidformat;
int b_fullrange;
int b_color_description_present;
int i_colorprim;
int i_transfer;
int i_colmatrix;
int b_chroma_loc_info_present;
int i_chroma_loc_top;
int i_chroma_loc_bottom;
int b_timing_info_present;
int i_num_units_in_tick;
int i_time_scale;
int b_fixed_frame_rate;
int nal_hrd_parameters_present_flag;
int vcl_hrd_parameters_present_flag;
int pic_struct_present_flag;
int b_bitstream_restriction;
int b_motion_vectors_over_pic_boundaries;
int i_max_bytes_per_pic_denom;
int i_max_bits_per_mb_denom;
int i_log2_max_mv_length_horizontal;
int i_log2_max_mv_length_vertical;
int i_num_reorder_frames;
int i_max_dec_frame_buffering;
/* FIXME to complete */
} vui;
int b_qpprime_y_zero_transform_bypass;
int scaling_matrix_present;
uint8_t scaling_matrix4[6][16];
uint8_t scaling_matrix8[6][64];
} h264_sps_t;
解析SPS数据,得到h264_sps_t结构的数据
/* return -1 if invalid, else the id */
int h264_sps_read( unsigned char *nal, int nal_len, h264_sps_t *sps)
{
int i_profile_idc;
int i_level_idc;
int b_constraint_set0;
int b_constraint_set1;
int b_constraint_set2;
int id;
bs_t bs;
bs_t *s = &bs;
sps->scaling_matrix_present = 0;
bs_init( &bs, nal+1, nal_len-1 );
//P264_TRACE_ADDRESS();
i_profile_idc = bs_read( s, 8 );
//_TRACE2("SPS: profile_idc = %d\n", i_profile_idc);
b_constraint_set0 = bs_read( s, 1 );
b_constraint_set1 = bs_read( s, 1 );
b_constraint_set2 = bs_read( s, 1 );
bs_skip( s, 5 ); /* reserved */
//P264_TRACE_ADDRESS();
i_level_idc = bs_read( s, 8 );
//_TRACE2("SPS: level_idc = %d\n", i_level_idc);
id = bs_read_ue( s );
if( bs_eof( s ) || id >= 32 )
{
/* the sps is invalid, no need to corrupt sps_array[0] */
return -1;
}
sps->i_id = id;
/* put pack parsed value */
sps->i_profile_idc = i_profile_idc;
sps->i_level_idc = i_level_idc;
sps->b_constraint_set0 = b_constraint_set0;
sps->b_constraint_set1 = b_constraint_set1;
sps->b_constraint_set2 = b_constraint_set2;
if(sps->i_profile_idc >= 100){ //high profile
sps->i_chroma_format_idc= bs_read_ue( s );
if(sps->i_chroma_format_idc >= 32 )
return -1;
if(sps->i_chroma_format_idc == 3)
bs_read( s, 1 );//residual_color_transform_flag
//sps->bit_depth_luma = get_ue_golomb(&s->gb) + 8;
//sps->bit_depth_chroma = get_ue_golomb(&s->gb) + 8;
//sps->transform_bypass = get_bits1(&s->gb);
/* bit_depth_luma_minus8 */
bs_read_ue( s );
/* bit_depth_chroma_minus8 */
bs_read_ue( s );
/* qpprime_y_zero_transform_bypass_flag */
bs_skip( s, 1 );
/* seq_scaling_matrix_present_flag */
int seq_scaling_matrix_present_flag = bs_read( s, 1 );
//decode_scaling_matrices(s, sps, NULL, 1, sps->scaling_matrix4, sps->scaling_matrix8);
if (seq_scaling_matrix_present_flag)
{
for( int i = 0; i < ((3 != sps->i_chroma_format_idc) ? 8 : 12); i++ )
{
/* seq_scaling_list_present_flag[i] */
seq_scaling_matrix_present_flag = bs_read( s, 1 );
if( !seq_scaling_matrix_present_flag )
continue;
const int i_size_of_scaling_list = (i < 6 ) ? 16 : 64;
/* scaling_list (...) */
int i_lastscale = 8;
int i_nextscale = 8;
for( int j = 0; j < i_size_of_scaling_list; j++ )
{
if( i_nextscale != 0 )
{
/* delta_scale */
seq_scaling_matrix_present_flag = bs_read_se( s );
i_nextscale = ( i_lastscale + seq_scaling_matrix_present_flag + 256 ) % 256;
/* useDefaultScalingMatrixFlag = ... */
}
/* scalinglist[j] */
i_lastscale = ( i_nextscale == 0 ) ? i_lastscale : i_nextscale;
}
}
}
}
//sps->i_log2_max_frame_num = bs_read_ue( s ) + 4;
//sps->i_log2_max_frame_num = 2^(bs_read_ue( s ) + 4);
sps->i_log2_max_frame_num = bs_read_ue( s );
sps->i_poc_type = bs_read_ue( s );
if( sps->i_poc_type == 0 )
{
sps->i_log2_max_poc_lsb = bs_read_ue( s ) + 4;
}
else if( sps->i_poc_type == 1 )
{
int i;
sps->b_delta_pic_order_always_zero = bs_read( s, 1 );
sps->i_offset_for_non_ref_pic = bs_read_se( s );
sps->i_offset_for_top_to_bottom_field = bs_read_se( s );
sps->i_num_ref_frames_in_poc_cycle = bs_read_ue( s );
if( sps->i_num_ref_frames_in_poc_cycle > 256 )
{
/* FIXME what to do */
sps->i_num_ref_frames_in_poc_cycle = 256;
}
for( i = 0; i < sps->i_num_ref_frames_in_poc_cycle; i++ )
{
sps->i_offset_for_ref_frame[i] = bs_read_se( s );
}
}
else if( sps->i_poc_type > 2 )
{
goto error;
}
sps->i_num_ref_frames = bs_read_ue( s );
//_TRACE2("SPS: num_ref_frames = %d\n", sps->i_num_ref_frames);
sps->b_gaps_in_frame_num_value_allowed = bs_read( s, 1 );
sps->i_mb_width = bs_read_ue( s ) + 1;
//_TRACE2("SPS: mb_width = %d\n", sps->i_mb_width);
sps->i_mb_height= bs_read_ue( s ) + 1;
//_TRACE2("SPS: mb_height = %d\n", sps->i_mb_height);
sps->b_frame_mbs_only = bs_read( s, 1 );
if( !sps->b_frame_mbs_only )
{
sps->b_mb_adaptive_frame_field = bs_read( s, 1 );
}
else
{
sps->b_mb_adaptive_frame_field = 0;
}
sps->b_direct8x8_inference = bs_read( s, 1 );
sps->b_crop = bs_read( s, 1 );
if( sps->b_crop )
{
sps->crop.i_left = bs_read_ue( s );
sps->crop.i_right = bs_read_ue( s );
sps->crop.i_top = bs_read_ue( s );
sps->crop.i_bottom= bs_read_ue( s );
}
else
{
sps->crop.i_left = 0;
sps->crop.i_right = 0;
sps->crop.i_top = 0;
sps->crop.i_bottom= 0;
}
sps->b_vui = bs_read( s, 1 );
if( sps->b_vui )
{
/* FIXME */
//_TRACE2( "decode vui %d\n", bs_pos(s) );
decode_vui_parameters(s, sps);
}
if( bs_eof( s ) )
{
/* no rbsp trailing */
//_TRACE2( "incomplete SPS\n" );
sps->i_id = -1;
return -1000;
}
return id;
error:
/* invalidate this sps */
sps->i_id = -1;
return -1;
}
获取更多信息
Copyright © EasyDarwin.org 2012-2016

EasyRTMP视频直播推送H264 sps解析错误导致播放画面拉伸问题解决的更多相关文章
- EasyRTMP手机直播推送rtmp流flash无法正常播放问题
本文转自EasyDarwin团队Kim的博客:http://blog.csdn.net/jinlong0603/article/details/52960750 问题简介 EasyRTMP是EasyD ...
- EasyDarwin开源手机直播方案:EasyPusher手机直播推送,EasyDarwin流媒体服务器,EasyPlayer手机播放器
在不断进行EasyDarwin开源流媒体服务器的功能和性能完善的同时,我们也配套实现了目前在安防和移动互联网行业比较火热的移动端手机直播方案,主要就是我们的 EasyPusher直播推送项目 和 Ea ...
- EasyDarwin开源手机直播方案:EasyPusher手机直播推送,EasyDarwin流媒体server,EasyPlayer手机播放器
在不断进行EasyDarwin开源流媒体server的功能和性能完好的同一时候,我们也配套实现了眼下在安防和移动互联网行业比較火热的移动端手机直播方案,主要就是我们的 EasyPusher直播推送项目 ...
- EasyPusher安卓Android手机直播推送之MediaCodec 硬编码H264格式
本文转自Holo的博客:http://blog.csdn.net/u013758734/article/details/50834770 最近在研究EasyDarwin的Push库EasyPusher ...
- 手机Android音视频采集与直播推送,实现单兵、移动监控类应用
从安卓智能手机.平板,到可穿戴的Android Ware.眼镜.手表.再到Android汽车.智能家居.电视,甚至最近看新闻,日本出的几款机器人都是Android系统的,再把目光放回监控行业,传统监控 ...
- EasyRTMP实现RTMP异步直播推送之环形缓冲区设计
本文转自EasyDarwin团队kim的博客:http://blog.csdn.net/jinlong0603 EasyRTMP的推送缓冲区设计 EasyRTMP内部也同样采用的环形缓冲的设计方法,将 ...
- 手机Android音视频採集与直播推送,实现单兵、移动监控类应用
最新手机採集推送直播监控以及EasyDarwin开源流媒体平台的版本号及代码: EasyDarwin 开源流媒体云平台:https://github.com/easydarwin EasyClient ...
- 基于EasyDarwin EasyPusher实现Android手机直播推送功能
EasyPusher直播推送在之前就已经稳定支持了Windows.Linux.ARM上的RTSP直播推送功能,配合EasyDarwin开源流媒体服务器,延时基本在1s以内,这个技术方案经过一年多时间, ...
- EasyPusher直播推送中用到的缓冲区设计和丢帧原理
问题描述 我们在开发直播过程中,会需要用到直播推送端,推送端将直播的音视频数据推送到流媒体服务器或者cdn,再由流媒体服务器/CDN进行视频的转发和分发,提供给客户端进行观看.由于直播推送端会存在于各 ...
随机推荐
- 病毒(bzoj 2938)
Description 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码 ...
- 3 月 15 个有意思的 JavaScript 和 CSS 库
Tutorialzine 旨在让你了解最新最酷的 Web 发展趋势.这就是我们每个月为何都会发布一些我们偶然发现并认为值得你关注的优秀资源的原因. BasicScroll https://github ...
- Notepad++中常用的插件【转】
转自:http://www.crifan.com/files/doc/docbook/rec_soft_npp/release/htmls/npp_common_plugins.html 1.4. N ...
- Yii CDbCriteria的常用方法总结
查看代码 打印 01 $criteria=new CDbCriteria; 02 $criteria->addCondition("id=1");//查询条件,即wher ...
- 1076. Wifi密码 (15)【模拟】
1076. Wifi密码 (15) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 下面是微博上流传的一张照片:“ ...
- BZOJ1006神奇的国度 弦圖染色 最大勢算法
@[弦圖染色, 最大勢算法] Description K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA 相互认识,是简洁高效的.为了巩固三角 ...
- filter和spring 的interceptor都是单例的,都不是线程安全的
Filter 是在 Servlet 容器启动时就初始化的,因此可以认为是以单例对象存在的,如果一个请求线程对其中的成员变量修改的话,会影响到其他的请求线程,因此认为是多线程不安全的.
- 邁向IT專家成功之路的三十則鐵律 鐵律二十二:IT人升遷之道-無為
升遷管道是許多人求職時相當重要的考量之一,畢竟人除了很愛錢之外更愛顯赫的頭銜,然而在企業中越顯赫的頭銜,其背後通常有更多的罵名,因為許多人的高官厚爵都是踩著一群人的頭頂爬上去的,隨時哪一天跌了下來,都 ...
- 八卦某 G 的前端开发方式及流程--百度FEX前端nwind信息搜集神技能
他山之石,可以攻玉. 话说本人从毕业到现在一直在某 B 公司工作,前些年折腾过不少开发方式和工具,但总觉得或许有更好的方案,所以很好奇其它公司内部是如何工作的,我曾经浏览过某 Y 公司内部无所不包的 ...
- mac 下 virtualbox 配置全网通
mac下virtualbox实现主机和虚拟机.虚拟机和外网互访的方案 全局添加Host-Only网络 Adapter IPv4 Address:192.168.56.1 IPv4 Network Ma ...