解析问题H.264序列参数设置数据

如何解决解析问题H.264序列参数设置数据

我需要从原始H.264数据解析图像大小。以下测试代码适用于我测试过的情况,但现在在\“ Z0IAIOKQCgDLYC3AQEBpB4kRUA == \”上失败时。结果应该是1280x800,但它却可以显示640x1616:
public static void main(String[] args) {
    decode(StringUtils.fromBase64(\"Z0IAKeKQCgDLYC3AQEBpB4kRUA==\"));
    decode(StringUtils.fromBase64(\"Z0IAIOKQCgDLYC3AQEBpB4kRUA==\"));
    decode(StringUtils.fromBase64(\"Z0IAHuNQFAe2AtwEBAaQeJEV\"));
}

static int pos;
static byte[] data;

private static void decode(byte[] data) {
    try {
        System.out.println();
        System.out.println(StringUtils.toHex(data));
        System.out.println(StringUtils.toBin(data,data.length,true));
        System.out.println();
        pos = 0;
        T.data = data;
        int profile_idc = getU(8);
        int constraint_set0_flag = getU(1);
        int constraint_set1_flag = getU(1);
        int constraint_set2_flag = getU(1);
        int constraint_set3_flag = getU(1);
        int reserved_zero_4bits = getU(4);
        int level_idc = getU(8);
        int seq_parameter_set_id = uev();
        int log2_max_frame_num_minus4 = uev();
        int pict_order_cnt_type = uev();
        System.out.println(\"pict_order_cnt_type=\" + pict_order_cnt_type);
        if (pict_order_cnt_type == 0) {
            uev();
        } else if (pict_order_cnt_type == 1) {
            getU(1);
            sev();
            sev();
            int n = uev();
            System.out.println(\"n*sev,n=\" + n);
            for (int i = 0; i < n; i++)
                sev();
        }
        int num_ref_frames = uev();
        getU(1);
        int pic_width = (uev() + 1) * 16;
        int pic_height = (uev() + 1) * 16;
        int frame_mbs_only_flag = getU(1);
        System.out.println(pic_width + \" x \" + pic_height);
    } catch (Exception e) {
        e.printStackTrace(System.out);
    }
}

private static int ev(boolean signed) {
    int bitcount = 0;
    StringBuilder expGolomb = new StringBuilder();
    while (getBit() == 0) {
        expGolomb.append(\'0\');
        bitcount++;
    }
    expGolomb.append(\"/1\");
    int result = 1;
    for (int i = 0; i < bitcount; i++) {
        int b = getBit();
        expGolomb.append(b);
        result = result * 2 + b;
    }
    result--;
    if (signed) {
        result = (result + 1) / 2 * (result % 2 == 0 ? -1 : 1);
        System.out.println(\"getSe(v) = \" + (result) + \" \" + expGolomb);
    } else {
        System.out.println(\"getUe(v) = \" + (result) + \" \" + expGolomb);
    }
    return result;
}

private static int uev() {
    return ev(false);
}

private static int sev() {
    return ev(true);
}

private static int getU(int bits) {
    int result = 0;
    for (int i = 0; i < bits; i++) {
        result = result * 2 + getBit();
    }
    System.out.println(\"getU(\" + bits + \") = \" + result);
    return result;
}

private static int getBit() {
    int mask = 1 << (7 - (pos & 7));
    int idx = pos >> 3;
    pos++;
    return ((data[idx] & mask) == 0) ? 0 : 1;
}
失败案例的输出:
67420020E2900A00CB602DC040406907891150
01100111 01000010 00000000 00100000 11100010 10010000 00001010 00000000 11001011 01100000 00101101 11000000 01000000 01000000 01101001 00000111 10001001 00010001 01010000 

getU(8) = 103
getU(1) = 0
getU(1) = 1
getU(1) = 0
getU(1) = 0
getU(4) = 2   << shouldn\'t this be 0 ? is same with correct parsing!
getU(8) = 0
getUe(v) = 3 00/100
getUe(v) = 13 000/1110   << log2_max_frame_num_minus4 shall be 0-12,inclusive.
getUe(v) = 4 00/101    
pict_order_cnt_type=4    << pic_order_cnt_type shall be 0-2,inclusive.
getUe(v) = 3 00/100       
getU(1) = 0
getUe(v) = 39 00000/101000
getUe(v) = 100 000000/1100101
getU(1) = 1
640 x 1616
    

解决方法

        也许不是您要的,但是请看一下参考实现,以了解它们如何进行解析... 从http://www.w6rz.net/h264_parse.zip下载h.264解析器(从该线程@ doom9 http://forum.doom9.org/archive/index.php/t-133070.html) 从http://iphome.hhi.de/suehring/tml/下载H.264参考SW。 这应该使您入门。 BTW比特流在附件中描述。 B.在规格。从ITU http://www.itu.int/rec/T-REC-H.264-201003-I/en下载     ,        代码中确实存在一个错误(实际上有三个)。 第一个错误是第一个字节是NAL标头(包含::2ѭ(1位),
nal_ref_idc
(2位)和a4ѭ(5位),值应为7表示SPS单位。 第二个错误是总共有5个5而不是3个(占错误3中描述的两位)。 第三个错误是在当前规格中
reserved_zero_#bits
的数量为2。我猜这在过去可能有所不同,但是我不确定。 因此,我对解码方法进行了一些更改,并提出了适用于我的版本(顺便说一句,我的类称为H264Parser,因此语句为
H264Parser.data = data;
):
private static void decode(byte[] data) {
    try {
        System.out.println();
            System.out.println(StringUtils.toHex(data));
            System.out.println(StringUtils.toBin(data,data.length,true));
            System.out.println();
        pos = 0;
        H264Parser.data = data;

        int forbidden_zero_bit = getU(1);
        System.out.println(\"forbidden_zero_bit \" + forbidden_zero_bit);
        int nal_ref_idc = getU(2);
        int nal_unit_type = getU(5);
        System.out.println(\"nal_unit_type (should be 7 for SPS) \" + nal_unit_type);
        //END of NAL_header

        //Start of SPS data
        int profile_idc = getU(8);
        int constraint_set0_flag = getU(1);
        int constraint_set1_flag = getU(1);
        int constraint_set2_flag = getU(1);
        int constraint_set3_flag = getU(1);
        int constraint_set4_flag = getU(1);
        int constraint_set5_flag = getU(1);
        //The current version of the spec states that there are two reserved bits
        int reserved_zero_2bits = getU(2);
        System.out.println(\"reserved_zero_2bits\" + reserved_zero_2bits);
        int level_idc = getU(8);
        int seq_parameter_set_id = uev();
        int log2_max_frame_num_minus4 = uev();
        int pict_order_cnt_type = uev();
        System.out.println(\"pict_order_cnt_type=\" + pict_order_cnt_type);
        if (pict_order_cnt_type == 0) {
            uev();
        } else if (pict_order_cnt_type == 1) {
            getU(1);
            sev();
            sev();
            int n = uev();
            System.out.println(\"n*sev,n=\" + n);
            for (int i = 0; i < n; i++)
                sev();
        }
        int num_ref_frames = uev();
        getU(1);
        int pic_width = (uev() + 1) * 16;
        int pic_height = (uev() + 1) * 16;
        int frame_mbs_only_flag = getU(1);
        System.out.println(pic_width + \" x \" + pic_height);
    } catch (Exception e) {
        e.printStackTrace(System.out);
    }
}
    ,        您的代码中有一个错误,应该丢弃第一个字节,即NAL单元类型:
67 - NAL unit type ( SPS )
42 - Profile Idc ( Baseline profile in your case )
00 - reserved zero
29 - level ( 41 )
e2 - SPS id ( 0 ),max frame num - 4 ( 0 ),POC type ( 0 ),90 - uev ( 5 ),num ref frames ( 1 ),u ( 0 )
etc
实际上,您可以将JCodec类https://github.com/jcodec/jcodec/blob/master/src/main/java/org/jcodec/codecs/h264/io/model/SeqParameterSet.java使用为框SPS解析例程。     ,        对于某些配置文件,您还应该在seq_parameter_set_id之后读取比例矩阵:
        int seq_parameter_set_id = uev();

        if (profile_idc == 100 || profile_idc == 110 ||
                profile_idc == 122 || profile_idc == 244 || profile_idc == 44 ||
                profile_idc == 83 || profile_idc == 86 || profile_idc == 118 ||
                profile_idc == 128) {
            int chroma_format_idc = uev();
            if( chroma_format_idc == 3 ){
                int separate_colour_plane_flag = getU(1);
            }

            int bit_depth_luma_minus8 = uev();
            int bit_depth_chroma_minus8 = uev();
            int qpprime_y_zero_transform_bypass_flag = getU(1);
            int seq_scaling_matrix_present_flag = getU(1);
            if( seq_scaling_matrix_present_flag == 1) {
                int count = (chroma_format_idc != 3) ? 8 : 12;
                for (int i = 0; i <count; i++) {
                    int seq_scaling_list_present_flag_i_ = getU(1);
                    if (seq_scaling_list_present_flag_i_ == 1) {
                        if (i < 6)
                            scaling_list(16);

                        else
                            scaling_list(64);
                    }
                }
            }
        }


        int log2_max_frame_num_minus4 = uev();
其中缩放列表定义为以下内容:
int[] scaling_list(int sizeOfScalingList){
    int lastScale = 8;
    int nextScale = 8;
    int delta_scale;
    boolean useDefaultScalingMatrixFlag;
    int[] scalingList = new int[sizeOfScalingList];
    for(int j = 0; j < sizeOfScalingList; j++ ) {
        if( nextScale != 0 ) {
            delta_scale = sev();
            nextScale = ( lastScale + delta_scale + 256 ) % 256;
            useDefaultScalingMatrixFlag = ( j == 0 && nextScale == 0 );
        }
        scalingList[ j ] = ( nextScale == 0 ) ? lastScale : nextScale;
        lastScale = scalingList[ j ];
    }
    return scalingList;
}
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-