所以我想抓取一个框架来自视频在特定时间 using libav用作缩略图。
我正在使用的是以下代码。它编译并运行良好(就检索图片而言),但我很难将其实现检索正确的图片.
我根本无法理解 libav 在每个视频中明显使用多个时基背后的所有清晰逻辑。具体找出哪些函数期望/返回哪种类型的时基。
不幸的是,这些文档基本上没有任何帮助。那么来救援吗?
#define ABORT(x) do {fprintf(stderr, x); exit(1);} while(0)
av_register_all();
AVFormatContext *format_context = ...;
AVCodec *codec = ...;
AVStream *stream = ...;
AVCodecContext *codec_context = ...;
int stream_index = ...;
// open codec_context, etc.
AVRational stream_time_base = stream->time_base;
AVRational codec_time_base = codec_context->time_base;
printf("stream_time_base: %d / %d = %.5f\n", stream_time_base.num, stream_time_base.den, av_q2d(stream_time_base));
printf("codec_time_base: %d / %d = %.5f\n\n", codec_time_base.num, codec_time_base.den, av_q2d(codec_time_base));
AVFrame *frame = avcodec_alloc_frame();
printf("duration: %lld @ %d/sec (%.2f sec)\n", format_context->duration, AV_TIME_BASE, (double)format_context->duration / AV_TIME_BASE);
printf("duration: %lld @ %d/sec (stream time base)\n\n", format_context->duration / AV_TIME_BASE * stream_time_base.den, stream_time_base.den);
printf("duration: %lld @ %d/sec (codec time base)\n", format_context->duration / AV_TIME_BASE * codec_time_base.den, codec_time_base.den);
double request_time = 10.0; // 10 seconds. Video's total duration is ~20sec
int64_t request_timestamp = request_time / av_q2d(stream_time_base);
printf("requested: %.2f (sec)\t-> %2lld (pts)\n", request_time, request_timestamp);
av_seek_frame(format_context, stream_index, request_timestamp, 0);
AVPacket packet;
int frame_finished;
do {
if (av_read_frame(format_context, &packet) < 0) {
break;
} else if (packet.stream_index != stream_index) {
av_free_packet(&packet);
continue;
}
avcodec_decode_video2(codec_context, frame, &frame_finished, &packet);
} while (!frame_finished);
// do something with frame
int64_t received_timestamp = frame->pkt_pts;
double received_time = received_timestamp * av_q2d(stream_time_base);
printf("received: %.2f (sec)\t-> %2lld (pts)\n\n", received_time, received_timestamp);
使用测试电影文件运行它,我得到以下输出:
stream_time_base: 1 / 30000 = 0.00003
codec_time_base: 50 / 2997 = 0.01668
duration: 20062041 @ 1000000/sec (20.06 sec)
duration: 600000 @ 30000/sec (stream time base)
duration: 59940 @ 2997/sec (codec time base)
requested: 10.00 (sec) -> 300000 (pts)
received: 0.07 (sec) -> 2002 (pts)
时代不相符。这里发生了什么?我究竟做错了什么?
在寻找线索时我偶然发现了这一点这个说法 http://libav-users.943685.n4.nabble.com/How-do-I-convert-dts-pts-values-into-seconds-tt945776.html#a945779来自 libav-users 邮件列表...
[...] 分组PTS/DTS单位为格式化上下文的 time_base,
哪里的AVFrame->pts值的单位为编解码器上下文的 time_base.
换句话说,容器可以(并且通常)有不同的
time_base 比编解码器。大多数 libav 玩家都懒得使用
编解码器的 time_base 或 pts 因为并非所有编解码器都有一个,但大多数
容器可以。 (这就是为什么danger教程说忽略AVFrame->pts)
…这让我更加困惑,因为我在官方文档中找不到任何此类提及。
反正我换了……
double received_time = received_timestamp * av_q2d(stream_time_base);
…with…
double received_time = received_timestamp * av_q2d(codec_time_base);
...输出变成这样...
...
requested: 10.00 (sec) -> 300000 (pts)
received: 33.40 (sec) -> 2002 (pts)
仍然没有比赛。怎么了?