LiveRTMP

LiveRTMP是将H264流以及AAC流以RTMP协议推送到RTMP服务器上进行直播。LiveRTMP推送库中会从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;
}

LiveRTMP之H264 SPS解析宽高不正确导致播放时画面拉伸的问题修复(五)的更多相关文章

  1. EasyRTMP视频直播推送H264 sps解析错误导致播放画面拉伸问题解决

    EasyRTMP是将H264流以及AAC流以RTMP协议推送到RTMP服务器上进行直播.EasyRTMP推送库中会从H264流中提取中SPS.PPS进行解析,开发的时候遇到过有些SPS解析有误,获取到 ...

  2. android中加载的html获取的宽高不正确

    wap页面使用 js库是zepto,按照惯例在$(function(){})中,来获取当前可视区的宽高,但得到的宽高却与预想的相差十万八千里. 原本android手机的浏览器设定的宽高基本是360*6 ...

  3. H5 canvas的 width、height 与style中宽高的区别

    Canvas 的width height属性 1.当使用width height属性时,显示正常不会被拉伸:如下 <canvas id="mycanvas" width=&q ...

  4. 用addOnGlobalLayoutListener获取View的宽高

    首先,我们在onCreate方法里调用getHeight()和 getWidth()是不能正确获取View的宽高的,因为onCreate方法执行完了,我们定义的控件才会被onMeasure()度量,所 ...

  5. 【经验总结】关于使用某些第三方插件库元素设置display:none后重新show不显示的问题;(display、opacity、宽高0的使用场景)

    display:none 直接取消元素所占用的位置(但是元素还是存在的),后面元素看他就相当于不存在了: opacity:0  隐藏,但是其依旧占用位置: height.width:0 和displa ...

  6. 从H264码流中获取视频宽高 (SPS帧) 升级篇

    之前写过 <从H264码流中获取视频宽高 (SPS帧)> . 但发现很多局限性,而且有时解出来是错误的. 所以重新去研究了. 用了 官方提供的代码库来解析. 花了点时间,从代码库里单独把解 ...

  7. 从H264码流中获取视频宽高 (SPS帧)

    获取.h264视频宽高的方法 花了2个通宵终于搞定.(后面附上完整代码) http://write.blog.csdn.net/postedit/7852406 图像的高和宽在H264的SPS帧中.在 ...

  8. 一步一步解析H.264码流的NALU(SPS,PSS,IDR)获取宽高和帧率

    分析H.264码流的工具 CodecVisa,StreamEye以及VM Analyzer NALU是由NALU头和RBSP数据组成,而RBSP可能是SPS,PPS,Slice或SEI 而且SPS位于 ...

  9. H.264从SPS中提取视频宽高

    H.264有两种封装模式: (1)annexb模式:传统模式,使用start code来分隔NAL, SPS和PPS是在ES流的头部: (2)mp4模式:没有start code,使用NALU长度(固 ...

  10. 多媒体开发之h264中的sps---sps信息提取之分辨率宽高提取2

    -------------------author:pkf -----------------------------time:2015-8-20 -------------------------- ...

随机推荐

  1. AAAI 2025-FEI: 频率掩码嵌入推理:一种非对比学习的时间序列表示学习

    title:Frequency-Masked Embedding Inference: A Non-Contrastive Approach for Time Series Representatio ...

  2. AGC021E ball Eat chamelemons

    E - Ball Eat Chameleons 设颜色序列中有\(R\)个红球,\(B\)个蓝球,且有\(B+R=k\) 然后分类讨论: \(R<B\) 无解 \(R>B\) 这时有一种合 ...

  3. FastAPI权限配置:你的系统真的安全吗?

    url: /posts/96b6ede65030daa4613ab92da1d739a6/ title: FastAPI权限配置:你的系统真的安全吗? date: 2025-06-26T07:35:3 ...

  4. DataGridView绑定BindingList 中的 DataGridViewCheckBoxColumn 无法点击排序问题

    参考文档 DataGridView绑定BindingList<T>带数据排序的类 - 腾讯云开发者社区-腾讯云 (tencent.com) DataGridView使用技巧十三:点击列头实 ...

  5. PLC通过lora网关采集温室大棚温湿度数据

    概述: 运用lora网关远程控制大棚内风机,日光灯,温湿度传感器等设备.可以实现远程获取现场环境的空气温湿度.土壤水分温度.二氧化碳浓度.光照强度可以自动控制温室湿帘风机.喷淋滴灌.加温补光等设备,并 ...

  6. Oracle数据一致性与事务管理

    数据一致性和事务 Oracle中的数据一致性 当从A表取一条数据添加到B表时,需先删除A表数据,再新增B表数据, 如果第二条操作出异常时,就造成了数据不一致. Oracle中的事务 事务是保证数据一致 ...

  7. MySQL 核心内容

    1.文件类型 .frm 表结构 .myd 表数据 .myi 表索引 .logbin 主从复制 .errlog 错误日志 2.架构 A.连接层(连接驱动,常用JDBC) B.服务层(拦截器.分析器.优化 ...

  8. CF1990D Grid Puzzle 题解

    CF1990D Grid Puzzle DP 好题.考虑分析两种操作的性质,不难发现操作 \(1\) 至多只能涂白 \(4\) 个方格,而操作 \(2\) 可以涂白的方格取决于这一行的方格数,几乎无上 ...

  9. audio 小记

    简介 音频的样式更改,其实说难不难,如果用 方法 https://stackoverflow.com/questions/4126708/is-it-possible-to-style-html5-a ...

  10. 如何通过iPaaS对数据作预警监控

    通过iPaaS的企业级API网关的预警设置功能即可实现监控,预警设置功能可配置多种预警机制,如API超时发送通知.调用错误发送通知.速率异常通知.业务数据异常通知等多场景监测预警.也可使用邮件.企业微 ...