H264(代码)---序列参数集(SPS)---解析并获取帧率

本文介绍了如何从H264的序列参数集(SPS)中解析并获取视频的帧率。通过分析sps->vui.vui_time_scale和sps->vui.vui_num_units_in_tic,以及考虑fixed_frame_rate_flag的影响,计算出准确的帧率。同时提供了H264ParseSPS.h和H264ParseSPS.c的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

H.264(H264)解码SPS获取分辨率和帧率 实例代码

获取H264帧率:
1、要解析sps->vui
关键得到两个值:1、sps->vui.vui_time_scale
        2、sps->vui.vui_num_units_in_tic
max_framerate = (float)(sps->vui.vui_time_scale) / (float)(sps->vui.vui_num_units_in_tick);

这个值是不准确的,网上查了各种资料说nuit_field_based_flag=1时要除以2,值=0时不用除,查了H.264官方中文版看了这个值和帧率貌似有点关系;
开始看ffmpeg源码如何解析nuit_field_based_flag,decode_picture_timing这个接口里根据sps->pic_struct_present_flag来确定有没有该值,测试文件该值为0,只能放弃;
记起来mplayer解析h264文件的帧率是对的,于是看mplayer源码,原来:
fixed_frame_rate_flag=1时fps才要除以2,于是从sps中解析出fixed_frame_rate_flag至此解决:

fps=time_scale/num_units_in_tick;
if (fixed_frame_rate_flag==1)
{
fps = fps/2;
}

H264ParseSPS.h

//  H264ParseSPS.h
#ifndef H264ParseSPS_h
#define H264ParseSPS_h
#include <stdio.h>    

typedef struct
{
   
    unsigned int profile_idc;
    unsigned int level_idc;
    
    unsigned int width;
    unsigned int height;
    unsigned int fps;       //SPS中可能不包含FPS信息
} sps_info_struct;
/**
 解析SPS数据信息
 @param data SPS数据内容,需要Nal类型为0x7数据的开始(比如:67 42 00 28 ab 40 22 01 e3 cb cd c0 80 80 a9 02)
 @param dataSize SPS数据的长度
 @param info SPS解析之后的信息数据结构体
 @return success:1,fail:0
 */
int h264_parse_sps(const unsigned char *data, unsigned int dataSize, sps_info_struct *info);

H264ParseSPS.c

//  H264ParseSPS.c
#include "H264ParseSPS.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>
 
typedef unsigned char BYTE;
typedef int INT;
typedef unsigned int UINT;
 
typedef struct
{
   
    const BYTE *data;   //sps数据
    UINT size;          //sps数据大小
    UINT index;         //当前计算位所在的位置标记
} sps_bit_stream;
 
/**
 移除H264的NAL防竞争码(0x03)
 @param data sps数据
 @param dataSize sps数据大小
 */
static void del_emulation_prevention(BYTE *data, UINT *dataSize)
{
   
    UINT dataSizeTemp = *dataSize;
    for (UINT i=0, j=0; i<(dataSizeTemp-2); i++) {
   
        int val = (data[i]^0x0) + (data[i+1]^0x0) + (data[i+2]^0x3);    //检测是否是竞争码
        if (val == 0) {
   
            for (j=i+2; j<dataSizeTemp-1; j++) {
       //移除竞争码
                data[j] = data[j+1];
            }
            
            (*dataSize)--;      //data size 减1
        }
    }
}
 
static void sps_bs_init(sps_bit_stream *bs, const BYTE *data, UINT size)
{
   
    if (bs) {
   
        bs->data = data;
        bs->size = size;
        bs->index = 0;
    }
}
 
/**
 是否已经到数据流最后
 
 @param bs sps_bit_stream数据
 @return 1:yes,0:no
 */
static INT eof(sps_bit_stream *bs)
{
   
    return (bs->index >= bs->size * 8);    //位偏移已经超出数据
}
 
/**
 读取从起始位开始的BitCount个位所表示的值
 
 @param bs sps_bit_stream数据
 @param bitCount bit位个数(从低到高)
 @return value
 */
static UINT u(sps_bit_stream *bs, BYTE bitCount)
{
   
    UINT val = 0;
    for (BYTE i=0; i<bitCount; i++) {
   
        val <<= 1;
        if (eof
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值