H264 SPS解析

ijkplayer中解析sps的代码,加上ffmpeg中的一部分处理
使用get_resolution_from_sps来获取获取解析到的视频宽高信息
或者其他什么sps中的字段值,在sps_info_struct结构中定义

/*
 * h264_sps_parser.h
 *
 * Copyright (c) 2014 Zhou Quan <zhouqicy@gmail.com>
 *
 * This file is part of ijkPlayer.
 *
 * ijkPlayer is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * ijkPlayer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with ijkPlayer; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
#ifndef IJKMediaPlayer_h264_sps_parser_h
#define IJKMediaPlayer_h264_sps_parser_h
#include <inttypes.h>
#include <stdbool.h>
static const uint8_t default_scaling4[2][16] = {
    {  6, 13, 20, 28, 13, 20, 28, 32,
        20, 28, 32, 37, 28, 32, 37, 42 },
    { 10, 14, 20, 24, 14, 20, 24, 27,
        20, 24, 27, 30, 24, 27, 30, 34 }
};
static const uint8_t default_scaling8[2][64] = {
    {  6, 10, 13, 16, 18, 23, 25, 27,
        10, 11, 16, 18, 23, 25, 27, 29,
        13, 16, 18, 23, 25, 27, 29, 31,
        16, 18, 23, 25, 27, 29, 31, 33,
        18, 23, 25, 27, 29, 31, 33, 36,
        23, 25, 27, 29, 31, 33, 36, 38,
        25, 27, 29, 31, 33, 36, 38, 40,
        27, 29, 31, 33, 36, 38, 40, 42 },
    {  9, 13, 15, 17, 19, 21, 22, 24,
        13, 13, 17, 19, 21, 22, 24, 25,
        15, 17, 19, 21, 22, 24, 25, 27,
        17, 19, 21, 22, 24, 25, 27, 28,
        19, 21, 22, 24, 25, 27, 28, 30,
        21, 22, 24, 25, 27, 28, 30, 32,
        22, 24, 25, 27, 28, 30, 32, 33,
        24, 25, 27, 28, 30, 32, 33, 35 }
};
static const uint8_t ff_zigzag_direct[64] = {
    0,   1,  8, 16,  9,  2,  3, 10,
    17, 24, 32, 25, 18, 11,  4,  5,
    12, 19, 26, 33, 40, 48, 41, 34,
    27, 20, 13,  6,  7, 14, 21, 28,
    35, 42, 49, 56, 57, 50, 43, 36,
    29, 22, 15, 23, 30, 37, 44, 51,
    58, 59, 52, 45, 38, 31, 39, 46,
    53, 60, 61, 54, 47, 55, 62, 63
};
static const uint8_t ff_zigzag_scan[16+1] = {
    0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
    1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
    1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4,
    3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4,
};
typedef struct
{
    const uint8_t *data;
    const uint8_t *end;
    int head;
    uint64_t cache;
} nal_bitstream;
static void
nal_bs_init(nal_bitstream *bs, const uint8_t *data, size_t size)
{
    bs->data = data;
    bs->end  = data + size;
    bs->head = 0;
    // fill with something other than 0 to detect
    //  emulation prevention bytes
    bs->cache = 0xffffffff;
}
static uint64_t
nal_bs_read(nal_bitstream *bs, int n)
{
    uint64_t res = 0;
    int shift;
    
    if (n == 0)
        return res;
    
    // fill up the cache if we need to
    while (bs->head < n) {
        uint8_t a_byte;
        bool check_three_byte;
        
        check_three_byte = true;
    next_byte:
        if (bs->data >= bs->end) {
            // we're at the end, can't produce more than head number of bits
            n = bs->head;
            break;
        }
        // get the byte, this can be an emulation_prevention_three_byte that we need
        // to ignore.
        a_byte = *bs->data++;
        if (check_three_byte && a_byte == 0x03 && ((bs->cache & 0xffff) == 0)) {
            // next byte goes unconditionally to the cache, even if it's 0x03
            check_three_byte = false;
            goto next_byte;
        }
        // shift bytes in cache, moving the head bits of the cache left
        bs->cache = (bs->cache << 8) | a_byte;
        bs->head += 8;
    }
    
    // bring the required bits down and truncate
    if ((shift = bs->head - n) > 0)
        res = bs->cache >> shift;
    else
        res = bs->cache;
    
    // mask out required bits
    if (n < 32)
        res &= (1 << n) - 1;
    
    bs->head = shift;
    
    return res;
}
static bool
nal_bs_eos(nal_bitstream *bs)
{
    return (bs->data >= bs->end) && (bs->head == 0);
}
// read unsigned Exp-Golomb code
static int64_t
nal_bs_read_ue(nal_bitstream *bs)
{
    int i = 0;
    
    while (nal_bs_read(bs, 1) == 0 && !nal_bs_eos(bs) && i < 32)
        i++;
    
    return ((1 << i) - 1 + nal_bs_read(bs, i));
}
//解码有符号的指数哥伦布编码
static int64_t
nal_bs_read_se(nal_bitstream *bs)
{
    int64_t ueVal = nal_bs_read_ue(bs);
    double k = ueVal;
    int64_t nValue = ceil(k/2);
    if(ueVal%2 == 0)
    {
        nValue = -nValue;
    }
    return nValue;
}
typedef struct
{
    uint64_t profile_idc;
    uint64_t level_idc;
    uint64_t sps_id;
    
    uint64_t chroma_format_idc;
    uint64_t separate_colour_plane_flag;
    uint64_t bit_depth_luma_minus8;
    uint64_t bit_depth_chroma_minus8;
    uint64_t qpprime_y_zero_transform_bypass_flag;
    uint64_t seq_scaling_matrix_present_flag;
    
    uint64_t log2_max_frame_num_minus4;
    uint64_t pic_order_cnt_type;
    uint64_t log2_max_pic_order_cnt_lsb_minus4;
    
    uint64_t max_num_ref_frames;
    uint64_t gaps_in_frame_num_value_allowed_flag;
    uint64_t pic_width_in_mbs_minus1;
    uint64_t pic_height_in_map_units_minus1;
    
    uint64_t frame_mbs_only_flag;
    uint64_t mb_adaptive_frame_field_flag;
    
    uint64_t direct_8x8_inference_flag;
    
    uint64_t frame_cropping_flag;
    uint64_t frame_crop_left_offset;
    uint64_t frame_crop_right_offset;
    uint64_t frame_crop_top_offset;
    uint64_t frame_crop_bottom_offset;
} sps_info_struct;
static void decode_scaling_list(nal_bitstream *bs, uint8_t *factors, int size,
                                const uint8_t *jvt_list,
                                const uint8_t *fallback_list)
{
    int i, last = 8, next = 8;
    const uint8_t *scan = size == 16 ? ff_zigzag_scan : ff_zigzag_direct;
    if (!nal_bs_read(bs, 1)) /* matrix not written, we use the predicted one */
        memcpy(factors, fallback_list, size * sizeof(uint8_t));
    else
        for (i = 0; i < size; i++) {
            if (next)
                next = (last + nal_bs_read_se(bs)) & 0xff;
            if (!i && !next) { /* matrix not written, we use the preset one */
                memcpy(factors, jvt_list, size * sizeof(uint8_t));
                break;
            }
            last = factors[scan[i]] = next ? next : last;
        }
}
static void decode_scaling_matrices(nal_bitstream *bs, sps_info_struct *sps,
                                    void* pps, int is_sps,
                                    uint8_t(*scaling_matrix4)[16],
                                    uint8_t(*scaling_matrix8)[64])
{
    int fallback_sps = !is_sps && sps->seq_scaling_matrix_present_flag;
    const uint8_t *fallback[4] = {
        fallback_sps ? scaling_matrix4[0] : default_scaling4[0],
        fallback_sps ? scaling_matrix4[3] : default_scaling4[1],
        fallback_sps ? scaling_matrix8[0] : default_scaling8[0],
        fallback_sps ? scaling_matrix8[3] : default_scaling8[1]
    };
    if (nal_bs_read(bs, 1)) {
        sps->seq_scaling_matrix_present_flag |= is_sps;
        decode_scaling_list(bs, scaling_matrix4[0], 16, default_scaling4[0], fallback[0]);        // Intra, Y
        decode_scaling_list(bs, scaling_matrix4[1], 16, default_scaling4[0], scaling_matrix4[0]); // Intra, Cr
        decode_scaling_list(bs, scaling_matrix4[2], 16, default_scaling4[0], scaling_matrix4[1]); // Intra, Cb
        decode_scaling_list(bs, scaling_matrix4[3], 16, default_scaling4[1], fallback[1]);        // Inter, Y
        decode_scaling_list(bs, scaling_matrix4[4], 16, default_scaling4[1], scaling_matrix4[3]); // Inter, Cr
        decode_scaling_list(bs, scaling_matrix4[5], 16, default_scaling4[1], scaling_matrix4[4]); // Inter, Cb
        if (is_sps) {
            decode_scaling_list(bs, scaling_matrix8[0], 64, default_scaling8[0], fallback[2]); // Intra, Y
            decode_scaling_list(bs, scaling_matrix8[3], 64, default_scaling8[1], fallback[3]); // Inter, Y
            if (sps->chroma_format_idc == 3) {
                decode_scaling_list(bs, scaling_matrix8[1], 64, default_scaling8[0], scaling_matrix8[0]); // Intra, Cr
                decode_scaling_list(bs, scaling_matrix8[4], 64, default_scaling8[1], scaling_matrix8[3]); // Inter, Cr
                decode_scaling_list(bs, scaling_matrix8[2], 64, default_scaling8[0], scaling_matrix8[1]); // Intra, Cb
                decode_scaling_list(bs, scaling_matrix8[5], 64, default_scaling8[1], scaling_matrix8[4]); // Inter, Cb
            }
        }
    }
}
static void parseh264_sps(sps_info_struct* sps_info, uint8_t* sps_data, uint32_t sps_size)
{
    if(sps_info == NULL)
        return;
    memset(sps_info, 0, sizeof(sps_info_struct));
    
    uint8_t scaling_matrix4[6][16];
    uint8_t scaling_matrix8[6][64];
    memset(scaling_matrix4, 16, sizeof(scaling_matrix4));
    memset(scaling_matrix8, 16, sizeof(scaling_matrix8));
    
    nal_bitstream bs;
    nal_bs_init(&bs, sps_data, sps_size);
    
    sps_info->profile_idc  = nal_bs_read(&bs, 8);
    nal_bs_read(&bs, 1);  // constraint_set0_flag
    nal_bs_read(&bs, 1);  // constraint_set1_flag
    nal_bs_read(&bs, 1);  // constraint_set2_flag
    nal_bs_read(&bs, 1);  // constraint_set3_flag
    nal_bs_read(&bs, 4);  // reserved
    sps_info->level_idc    = nal_bs_read(&bs, 8);
    sps_info->sps_id      = nal_bs_read_ue(&bs);
    
    if (sps_info->profile_idc == 100 ||
        sps_info->profile_idc == 110 ||
        sps_info->profile_idc == 122 ||
        sps_info->profile_idc == 244 ||
        sps_info->profile_idc == 44  ||
        sps_info->profile_idc == 83  ||
        sps_info->profile_idc == 86  ||
        sps_info->profile_idc == 118 ||
        sps_info->profile_idc == 128 ||
        sps_info->profile_idc == 138 ||
        sps_info->profile_idc == 144)
    {
        sps_info->chroma_format_idc                    = nal_bs_read_ue(&bs);
        if (sps_info->chroma_format_idc == 3)
            sps_info->separate_colour_plane_flag        = nal_bs_read(&bs, 1);
        sps_info->bit_depth_luma_minus8                = nal_bs_read_ue(&bs);
        sps_info->bit_depth_chroma_minus8              = nal_bs_read_ue(&bs);
        sps_info->qpprime_y_zero_transform_bypass_flag = nal_bs_read(&bs, 1);
        
        //        sps_info->seq_scaling_matrix_present_flag = nal_bs_read (&bs, 1);
        decode_scaling_matrices(&bs, sps_info, NULL, 1, scaling_matrix4, scaling_matrix8);
        
    }
    sps_info->log2_max_frame_num_minus4 = nal_bs_read_ue(&bs);
    if (sps_info->log2_max_frame_num_minus4 > 12) {
        // must be between 0 and 12
        // don't early return here - the bits we are using (profile/level/interlaced/ref frames)
        // might still be valid - let the parser go on and pray.
        //return;
    }
    
    sps_info->pic_order_cnt_type = nal_bs_read_ue(&bs);
    if (sps_info->pic_order_cnt_type == 0) {
        sps_info->log2_max_pic_order_cnt_lsb_minus4 = nal_bs_read_ue(&bs);
    }
    else if (sps_info->pic_order_cnt_type == 1) {
        nal_bs_read(&bs, 1); //delta_pic_order_always_zero_flag
        nal_bs_read_se(&bs); //offset_for_non_ref_pic
        nal_bs_read_se(&bs); //offset_for_top_to_bottom_field
        
        int64_t num_ref_frames_in_pic_order_cnt_cycle = nal_bs_read_ue(&bs);
        for(int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
        {
            nal_bs_read_se(&bs); //int offset_for_ref_frame =
        }
    }
    
    sps_info->max_num_ref_frames            = nal_bs_read_ue(&bs);
    sps_info->gaps_in_frame_num_value_allowed_flag = nal_bs_read(&bs, 1);
    sps_info->pic_width_in_mbs_minus1        = nal_bs_read_ue(&bs);
    sps_info->pic_height_in_map_units_minus1 = nal_bs_read_ue(&bs);
    
    sps_info->frame_mbs_only_flag            = nal_bs_read(&bs, 1);
    if (!sps_info->frame_mbs_only_flag)
        sps_info->mb_adaptive_frame_field_flag = nal_bs_read(&bs, 1);
    
    sps_info->direct_8x8_inference_flag      = nal_bs_read(&bs, 1);
    
    sps_info->frame_cropping_flag            = nal_bs_read(&bs, 1);
    if (sps_info->frame_cropping_flag) {
        sps_info->frame_crop_left_offset      = nal_bs_read_ue(&bs);
        sps_info->frame_crop_right_offset      = nal_bs_read_ue(&bs);
        sps_info->frame_crop_top_offset        = nal_bs_read_ue(&bs);
        sps_info->frame_crop_bottom_offset    = nal_bs_read_ue(&bs);
    }
}
static void get_resolution_from_sps(uint8_t* sps, uint32_t sps_size, uint64_t* width, uint64_t* height)
{
    sps_info_struct sps_info = {0};
    
    parseh264_sps(&sps_info, sps, sps_size);
    
    *width = (sps_info.pic_width_in_mbs_minus1 + 1) * 16 - sps_info.frame_crop_left_offset * 2 - sps_info.frame_crop_right_offset * 2;
    *height = ((2 - sps_info.frame_mbs_only_flag) * (sps_info.pic_height_in_map_units_minus1 + 1) * 16) - sps_info.frame_crop_top_offset * 2 - sps_info.frame_crop_bottom_offset * 2;
    
}
#endif
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352