zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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
    ", 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
    ", sps->i_mb_width);
        sps->i_mb_height= bs_read_ue( s ) + 1;
        //_TRACE2("SPS: mb_height = %d
    ", 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
    ", bs_pos(s) );
            decode_vui_parameters(s, sps);
        }
    
        if( bs_eof( s ) )
        {
            /* no rbsp trailing */
            //_TRACE2( "incomplete SPS
    " );
            sps->i_id = -1;
            return -1000;
        }
    
        return id;
    
    error:
        /* invalidate this sps */
        sps->i_id = -1;
        return -1;
    }

    获取更多信息

    邮件:support@easydarwin.org

    WEB:www.EasyDarwin.org

    Copyright © EasyDarwin.org 2012-2016

    EasyDarwin

  • 相关阅读:
    opstack 笔记 (一) 概念
    Redis学习汇总
    MongoDB添加删除节点
    Redis主从及Cluster区别及注意事项
    叶问18
    Redis慢日志取出来
    Redis的AOF重写脚本
    使用Python比较MySQL数据库中两个数据库的表结构--转载
    关于InnoDB存储引擎 text blob 大字段的存储和优化
    MongoDB进阶之路:不仅仅是技术研究,还有优化和最佳实践--转载
  • 原文地址:https://www.cnblogs.com/babosa/p/9217864.html
Copyright © 2011-2022 走看看