H264中SPS,PPS解析,seq_parameter_set_rbsp();

首先NALU的构成如下,图来自网上。

其中SPS的语法根据文档ITU-T H264中表格7.3.2.1.1可知

根据H264文档ITU-T H264中表格7.3.2.1.1 Sequence parameter set data syntax可知,SPS有以下信息:

表中的描述符Descriptor的含义如下,

下面用代码去解析,源码来自雷霄骅

首先将NAL转为RBSP

int nal_to_rbsp(const uint8_t* nal_buf, int* nal_size, uint8_t* rbsp_buf, int* rbsp_size) {
    int i;
    int j     = 0;
    int count = 0;
    for( i = 1; i < *nal_size; i++ ){ 
        // in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any byte-aligned position
        if( ( count == 2 ) && ( nal_buf[i] < 0x03) )
            return -1;

        if( ( count == 2 ) && ( nal_buf[i] == 0x03) ) {
            // check the 4th byte after 0x000003, except when cabac_zero_word is used, in which case the last three bytes of this NAL unit must be 0x000003
            if((i < *nal_size - 1) && (nal_buf[i+1] > 0x03))
                return -1;
            // if cabac_zero_word is used, the final byte of this NAL unit(0x03) is discarded, and the last two bytes of RBSP must be 0x0000
            if(i == *nal_size - 1)
                break;
            i++;
            count = 0;
        }

        if ( j >= *rbsp_size ) {
            // error, not enough space
            return -1;
        }

        rbsp_buf[j] = nal_buf[i];
        if(nal_buf[i] == 0x00)
            count++;
        else
            count = 0;
        j++;
    }

    *nal_size = i;
    *rbsp_size = j;
    return j;
}

转换出来的rbsp可以使用h264bitstream库来解析,bs_xxx这些是库的内容

void read_seq_parameter_set_rbsp(bs_t* b) {
    int i;
    // NOTE can't read directly into sps because seq_parameter_set_id not yet known and so sps is not selected

    int profile_idc = bs_read_u8(b);
    int constraint_set0_flag = bs_read_u1(b);
    int constraint_set1_flag = bs_read_u1(b);
    int constraint_set2_flag = bs_read_u1(b);
    int constraint_set3_flag = bs_read_u1(b);
    int constraint_set4_flag = bs_read_u1(b);
    int constraint_set5_flag = bs_read_u1(b);
    int reserved_zero_2bits  = bs_read_u(b,2);  /* all 0's */
    int level_idc = bs_read_u8(b);
    int seq_parameter_set_id = bs_read_ue(b);

    // select the correct sps
    h->sps = h->sps_table[seq_parameter_set_id];
    sps_t* sps = h->sps;
    memset(sps, 0, sizeof(sps_t));
    
    sps->chroma_format_idc = 1; 

    sps->profile_idc = profile_idc; // bs_read_u8(b);
    sps->constraint_set0_flag = constraint_set0_flag;//bs_read_u1(b);
    sps->constraint_set1_flag = constraint_set1_flag;//bs_read_u1(b);
    sps->constraint_set2_flag = constraint_set2_flag;//bs_read_u1(b);
    sps->constraint_set3_flag = constraint_set3_flag;//bs_read_u1(b);
    sps->constraint_set4_flag = constraint_set4_flag;//bs_read_u1(b);
    sps->constraint_set5_flag = constraint_set5_flag;//bs_read_u1(b);
    sps->reserved_zero_2bits = reserved_zero_2bits;//bs_read_u(b,2);
    sps->level_idc = level_idc; //bs_read_u8(b);
    sps->seq_parameter_set_id = seq_parameter_set_id; // bs_read_ue(b);
    if( sps->profile_idc == 100 || sps->profile_idc == 110 ||
        sps->profile_idc == 122 || sps->profile_idc == 144 ) {
        sps->chroma_format_idc = bs_read_ue(b);
        if( sps->chroma_format_idc == 3 ) {
            sps->residual_colour_transform_flag = bs_read_u1(b);
        }
        sps->bit_depth_luma_minus8 = bs_read_ue(b);
        sps->bit_depth_chroma_minus8 = bs_read_ue(b);
        sps->qpprime_y_zero_transform_bypass_flag = bs_read_u1(b);
        sps->seq_scaling_matrix_present_flag = bs_read_u1(b);
        if( sps->seq_scaling_matrix_present_flag ){
            for( i = 0; i < 8; i++ ){
                sps->seq_scaling_list_present_flag[ i ] = bs_read_u1(b);
                if( sps->seq_scaling_list_present_flag[ i ] ){
                    if( i < 6 ){
                        read_scaling_list( b, sps->ScalingList4x4[ i ], 16,
                                    sps->UseDefaultScalingMatrix4x4Flag[ i ]);
                    }else{
                        read_scaling_list( b, sps->ScalingList8x8[ i - 6 ], 64,
                                    sps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] );
                    }
                }
            }
        }
    }
    sps->log2_max_frame_num_minus4 = bs_read_ue(b);
    sps->pic_order_cnt_type = bs_read_ue(b);
    if( sps->pic_order_cnt_type == 0 ){
        sps->log2_max_pic_order_cnt_lsb_minus4 = bs_read_ue(b);
    }else if( sps->pic_order_cnt_type == 1 ){
        sps->delta_pic_order_always_zero_flag = bs_read_u1(b);
        sps->offset_for_non_ref_pic = bs_read_se(b);
        sps->offset_for_top_to_bottom_field = bs_read_se(b);
        sps->num_ref_frames_in_pic_order_cnt_cycle = bs_read_ue(b);
        for( i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++ ){
            sps->offset_for_ref_frame[ i ] = bs_read_se(b);
        }
    }
    sps->num_ref_frames = bs_read_ue(b);
    sps->gaps_in_frame_num_value_allowed_flag = bs_read_u1(b);
    sps->pic_width_in_mbs_minus1 = bs_read_ue(b);
    sps->pic_height_in_map_units_minus1 = bs_read_ue(b);
    sps->frame_mbs_only_flag = bs_read_u1(b);
    if( !sps->frame_mbs_only_flag ){
        sps->mb_adaptive_frame_field_flag = bs_read_u1(b);
    }
    sps->direct_8x8_inference_flag = bs_read_u1(b);
    sps->frame_cropping_flag = bs_read_u1(b);
    if( sps->frame_cropping_flag ){
        sps->frame_crop_left_offset = bs_read_ue(b);
        sps->frame_crop_right_offset = bs_read_ue(b);
        sps->frame_crop_top_offset = bs_read_ue(b);
        sps->frame_crop_bottom_offset = bs_read_ue(b);
    }
    sps->vui_parameters_present_flag = bs_read_u1(b);
    if( sps->vui_parameters_present_flag ){
        read_vui_parameters(h, b);
    }
    read_rbsp_trailing_bits(b);
}

更多详细的内容在视音频编解码学习工程:H.264分析器《雷霄骅》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在GStreamer 1.16.3版本,GST_QUERY_H264_SPS已经被移除,因此您需要使用其他方式来查询H.264视频流参数集(SPS)。您可以使用h264parse元素提取SPS信息,然后再以其他方式进行处理。下面是一个示例: ```c #include <gst/gst.h> #include <gst/video/video.h> #include <gst/video/gstvideometa.h> // 回调函数 static GstPadProbeReturn probe_callback(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { GstVideoInfo *vinfo; GstVideoCodecState *state; GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER(info); gint n_sps = 0; // 获取视频信息 vinfo = gst_video_info_new(); if (!gst_video_info_from_caps(vinfo, GST_BUFFER_CAPS(buf))) { g_printerr("Failed to get video info from caps\n"); return GST_PAD_PROBE_OK; } // 获取视频状态 state = gst_video_codec_state_new(); if (!gst_video_decoder_negotiate(GST_ELEMENT(GST_PAD_PARENT(pad)), vinfo, NULL, state)) { g_printerr("Failed to negotiate video codec state\n"); return GST_PAD_PROBE_OK; } // 提取SPS信息 GstVideoCodecFrame *frame = gst_video_codec_frame_new(); if (!gst_video_codec_state_frame_init(state, frame)) { g_printerr("Failed to initialize video codec frame\n"); gst_video_codec_state_unref(state); return GST_PAD_PROBE_OK; } n_sps = gst_video_codec_frame_get_n_sps(frame); if (n_sps > 0) { GstBuffer *sps_buf = gst_buffer_copy(gst_video_codec_frame_get_sps(frame, 0)); // 用sps_buf进行后续操作 g_print("SPS size: %d\n", GST_BUFFER_SIZE(sps_buf)); gst_buffer_unref(sps_buf); } // 清理 gst_video_codec_frame_unref(frame); gst_video_codec_state_unref(state); gst_video_info_free(vinfo); return GST_PAD_PROBE_OK; } int main(int argc, char *argv[]) { GstElement *pipeline, *src, *h264parse; GstPad *srcpad; gst_init(&argc, &argv); // 创建元素 pipeline = gst_pipeline_new("test-pipeline"); src = gst_element_factory_make("filesrc", "src"); h264parse = gst_element_factory_make("h264parse", "h264parse"); // 设置元素属性 g_object_set(G_OBJECT(src), "location", "/path/to/h264file", NULL); // 将元素添加到管道 gst_bin_add_many(GST_BIN(pipeline), src, h264parse, NULL); gst_element_link(src, h264parse); // 获取h264parse元素的源端口 srcpad = gst_element_get_static_pad(h264parse, "src"); // 添加探针 gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BUFFER, probe_callback, NULL, NULL); // 启动管道 gst_element_set_state(pipeline, GST_STATE_PLAYING); // 运行主循环 GstBus *bus = gst_element_get_bus(pipeline); GstMessage *msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); if (msg != NULL) { gst_message_unref(msg); } // 清理 gst_object_unref(bus); gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(pipeline); return 0; } ``` 上面的示例,我们使用了h264parse元素提取了SPS信息,并且通过回调函数的方式进行处理。您可以根据您的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值