如何使用libavcodec/ffmpeg查找视频文件的时长

19

我需要一个库来执行基本函数,比如视频文件的长度、大小等(我猜是通过元数据或标签),所以我选择了ffmpeg。有效的视频格式主要是电影文件中常见的,例如wmv,wmvhd,avi,mpeg,mpeg-4等。如果可以,请帮我找到用于了解视频文件持续时间的方法。我是在Linux平台上操作。

4个回答

38

libavcodec编程相当困难,而且查找文档也很困难,所以我理解你的痛苦。 这篇教程 是一个不错的开始。主要的API文档在 这里

查询视频文件的主要数据结构是 AVFormatContext 。在教程中,它是使用 av_open_input_file 打开的第一件事--该函数已被弃用,应该使用 avformat_open_input 代替。

从那里,您可以从AVFormatContext中读取属性:duration以某些秒分数表示(请参阅文档),file_size以字节为单位,bit_rate等。

因此,将它们整合起来应该看起来像:

AVFormatContext* pFormatCtx = avformat_alloc_context();
avformat_open_input(&pFormatCtx, filename, NULL, NULL);
int64_t duration = pFormatCtx->duration;
// etc
avformat_close_input(&pFormatCtx);
avformat_free_context(pFormatCtx);

如果你有一个没有头文件的文件格式,比如MPEG,你可能需要在avformat_open_input之后添加这行代码来读取数据包中的信息(这可能会更慢):

avformat_find_stream_info(pFormatCtx, NULL);

编辑

  • 在代码示例中添加了pFormatCtx的分配和释放操作。
  • 添加了avformat_find_stream_info(pFormatCtx, NULL),以便处理没有头文件的视频类型,例如MPEG。

2
在我看来,pFormatCtx 应该被初始化为 NULL 吗?否则,avformat_open_input 将假定调用者已经分配了上下文。 - jpa
你在链接程序时使用了 libav 的哪一部分才能使用 avformat_open_input 函数?我从 git 安装了最新的 libav 库版本,并将它们全部与我的代码链接。但我仍然遇到“undefined reference to avformat_open_input”错误,所以这个函数在库中似乎不存在。我错在哪里了吗? - mmoment
1
@mmoment 对我来说仍然有效(使用apt-get,libavformat 0.7.2)。我正在链接-lavformat -lavcodec。您需要确保在命令行上将C文件放在链接器文件之前--最近发生了变化,我被咬了一口。如果这样不起作用,请使用objdump查找函数是否实际上在库中:objdump -T /usr/lib/libavformat.so | grep avformat_open_input - mgiuca
没什么帮助,不过 objdump 是一个好的提示。显然,我在新版和旧版中都缺失该函数。这怎么可能?! - mmoment
1
@mgiuca 我找到了问题所在。显然,安装程序将库和头文件散落在各个地方。这就是为什么我会遇到诸如头文件不匹配等问题。感谢你的努力,objdump 真的帮助我意识到了这一点! - mmoment
显示剩余5条评论

14

我不得不添加一个调用

avformat_find_stream_info(pFormatCtx,NULL)

avformat_open_input之后,才能让mgiuca的答案起作用。(无法对其进行评论)

#include <libavformat/avformat.h>
...
av_register_all();
AVFormatContext* pFormatCtx = avformat_alloc_context();
avformat_open_input(&pFormatCtx, filename, NULL, NULL);
avformat_find_stream_info(pFormatCtx,NULL)
int64_t duration = pFormatCtx->duration;
// etc
avformat_close_input(&pFormatCtx);
avformat_free_context(pFormatCtx);

持续时间以微秒为单位,除以AV_TIME_BASE可得到秒数。


1
谢谢!你的添加对我很有用。如果没有这个调用,它就不会返回持续时间。 - Sergey Stasishin
1
时长以微秒为单位,除以AV_TIME_BASE可得到秒数。当我除以它时,视频时长出现错误。@seeseac - axita.savani

3

使用了这个函数,它正常工作:

extern "C"
JNIEXPORT jint JNICALL
Java_com_ffmpegjni_videoprocessinglibrary_VideoProcessing_getDuration(JNIEnv *env,
                                                                      jobject instance,
                                                                      jstring input_) {
    av_register_all();
    AVFormatContext *pFormatCtx = NULL;
    if (avformat_open_input(&pFormatCtx, jStr2str(env, input_), NULL, NULL) < 0) {
        throwException(env, "Could not open input file");
        return 0;
    }


    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        throwException(env, "Failed to retrieve input stream information");
        return 0;
    }

    int64_t duration = pFormatCtx->duration;

    avformat_close_input(&pFormatCtx);
    avformat_free_context(pFormatCtx);
    return (jint) (duration / AV_TIME_BASE);
}

当我使用 (jint) (duration / AV_TIME_BASE) 时,视频的持续时间会出错。


-3
AVFormatContext* pFormatCtx = avformat_alloc_context();

会导致内存泄漏。

应该是 AVFormatContext* pFormatCtx = NULL


指向用户提供的 AVFormatContext 的指针(由 avformat_alloc_context 分配)。可能是一个指向 NULL 的指针,在这种情况下,该函数将分配一个 AVFormatContext 并写入 ps。请注意,如果失败,用户提供的 AVFormatContext 将被释放。 - mip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接