获取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