在一些格式信息中可能没有头部信息,比如:FLV 可以用avformat_find_stream_info探测文件信息:编码宽高,但不能获取总时长。
尝试打印视频时长和流信息:可以发现FLV 里面是没有读到的
尝试添加 avformat_find_stream_info
//获取流信息 读取部分视频做探测
avformat_open_input_result = avformat_find_stream_info(avformat_context, 0);
if (avformat_open_input_result != 0) {
NSLog(@"avformat_find_stream_info failed!");
}
读取成功,如果有些文件读取不出时长,用遍历帧的方式计算时长
av_find_best_stream()
// ====================================
/**
获取音视频流的索引
@param ic#> 上下文 description#>
@param type#> 音频/视频流信息类型 description#>
@param wanted_stream_nb#> 指定取的流的信息(传 -1) description#>
@param related_stream#> 想关流信息(-1) description#>
@param decoder_ret#> 解码器 (NULL) description#>
@param flags#> 暂时无用 description#>
@return <#return value description#>
*/
audioStream = av_find_best_stream(avformat_context, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
NSLog(@" av_find_best_stream : %d ",audioStream);
//关闭输入的上下文 释放内存
avformat_close_input(&avformat_context);
av_read_frame AVPacket AVPacket flags
AVPacket 结构体
• AVBufferRef *buf 指针指向buf空间 存储引用计数
• int64_t pts // pts * (num/den) 显示时间
• int64_t dts 解码时间(没有B帧的话和pts是一致的)
• uint8_t *data int size
• int stream_index
• int flags //关键帧
方法
av_packet_allc(void) 创建并初始化 内存自己管理
av_packet_clone(const AVPacket *src)创建对象,对象指向的空间的引用计数+1
int av_packet_ref 引用计数+1 av_packet_unref 引用计数 -1
void av_packet_free (AVPacket **pkt)情况对象并引用计数 -1
void av_init_packet(AVPacket **pkt) 初始化
int av_packet_from_data(AVPackt *pkt,uint8_t *data,ini size);把数据转为AVPackt 包
av_seek_frame
• int av_seek_frame(AVFormatContext *s 上下文
• int stream_index, //-1 default(视频) 索引
• int64_t timestamp, //AVStream.time_base 移动到哪个时间位置
• int flags); 标识位,移动的方法
一般选择视频来移,因为视频存在B帧的概念,音频没有,视频移都要一道关键帧的位置
• #define AVSEEK_FLAG_BACKWARD 1 ///< seek backward
• #define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes
• #define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes
• #define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number
一般往后找 找到关键帧(当前时间以前叫往后)
• AVSEEK_FLAG_FRAME|AVSEEK_FLAG_BACKWARD
//读取帧数据
AVPacket *pkt = av_packet_alloc();//创建一个对象空间,初始化
for (; ; ) {//无线循环
int re = av_read_frame(ic, pkt);
if (re != 0) {
NSLog(@"读取到结尾处!");
int pos = 3 * r2d(ic->streams[videoStream]->time_base);;
av_seek_frame(ic, videoStream, pos, AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME);
continue;
}
NSLog(@"stream = %d size = %d pts = %lld flag = %d",pkt->stream_index,
pkt->size,pkt->pts,pkt->flags);
/////操作
av_packet_unref(pkt);
}