通过AVPacket中的flags来判断。具体的代码参考如下:
#include "stdafx.h"
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include<libswresample/swresample.h>
}
using namespace std;
int main(int argc, _TCHAR* argv[])
{
char *url = "D:/video/sliph264/111.flv";
AVFormatContext *ic;
ic = avformat_alloc_context();
av_register_all();
AVPacket *pkt = (AVPacket *)malloc(sizeof(AVPacket));
av_init_packet(pkt);
int videostream, audiostream;
int j = 0,i;
int reference_stream_index;
int ret = avformat_open_input(&ic, url, NULL, 0);
if (avformat_find_stream_info(ic, NULL) < 0)
{
cout << "dont find stram" << endl;
system("pause");
return -1;
}
if (ret != 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf)-1);
cout << "open " << url << " failed! :" << buf << endl;
system("pause");
return -1;
}
cout << "open scucess" << url << endl;
cout << "ic->nb_streams:" << ic->nb_streams << endl;
for (int i = 0; i < ic->nb_streams; i++)
{
if (ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videostream = i;
}
if (ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
audiostream = i;
}
}
cout << "videostream:" << videostream << "audiostream:" << audiostream << endl;
while (1)
{
if (av_read_frame(ic, pkt) >= 0)
{
if (pkt->stream_index == videostream && (pkt->flags & AV_PKT_FLAG_KEY))
{
j++;
printf("该帧为关键帧\n j = %d\n", j);
}
}
}
system("pause");
return 0;
}
上述需要注意的问题是,打开mp4文件时,只需要avformat函数就可以得到ic->nb_streams值是2,但是打开flv格式文件时,仅仅avformat_open_input函数是不够的,还需要avformat_find_stream_info函数,才能得到ic->nb_streams的值为2.
在一些格式当中没有头部信息,如flv格式,h264格式,这个时候调用avformat_open_input()在打开文件之后就没有参数,也就无法获取到里面的信息。这个时候就可以调用avformat_find_stream_info此函数,因为它会试着去探测文件的格式,但是如果格式当中没有头部信息,那么它只能获取到编码、宽高这些信息,还是无法获得总时长。如果总时长无法获取到,则仍需要把整个文件读一遍,计算一下它的总帧数。
avformat_open_input函数会读文件头,对mp4文件而言,它会解析所有的box。但它知识把读到的结果保存在对应的数据结构下。这个时候,AVStream中的很多字段都是空白的。
avformat_find_stream_info则检测这些重要字段,如果是空白的,就设法填充它们。因为我们解析文件头的时候,已经掌握了大量的信息,avformat_find_stream_info就是通过这些信息来填充自己的成员,当重要的成员都填充完毕后,该函数就返回了。这中情况下,该函数效率很高。但对于某些文件,单纯的从文件头中获取信息是不够的,比如vidoe的pix_fmt是需要调用h264_decode_frame才可以获取其pix_fmt的。因此,这个时候这个函数就会读一些数据进来,然后分析这些数据,并尝试解码这些数据,最终从中提取到所需要的信息。在所有的信息都已经获取到以后,avformat_find_stream_info函数会计算start_time,波特率等信息