18

I needed a library to perform basic functions such as length, size, etc of a video file (i'm guessing through the metadata or tags) so I chose ffmpeg. Valid video formats are primarily those prevalent in movie files viz. wmv, wmvhd, avi, mpeg, mpeg-4, etc. If you can, please help me with the method(s) to be used for knowing the duration the video file. I'm on a Linux platform.

Kunal Vyas
  • 1,499
  • 1
  • 23
  • 40

4 Answers4

38

libavcodec is pretty hard to program against, and it's also hard to find documentation, so I feel your pain. This tutorial is a good start. Here is the main API docs.

The main data structure for querying video files is AVFormatContext. In the tutorial, it's the first thing you open, using av_open_input_file -- the docs for that say it's deprecated and you should use avformat_open_input instead.

From there, you can read properties out of the AVFormatContext: duration in some fractions of a second (see the docs), file_size in bytes, bit_rate, etc.

So putting it together should look something like:

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);

If you have a file format with no headers, like MPEG, you may need to add this line after avformat_open_input to read information from the packets (which might be slower):

avformat_find_stream_info(pFormatCtx, NULL);

Edit:

  • Added allocation and de-allocation of pFormatCtx in the code example.
  • Added avformat_find_stream_info(pFormatCtx, NULL) to work with video types that have no headers such as MPEG
mgiuca
  • 20,958
  • 7
  • 54
  • 70
  • 2
    It seems to me that pFormatCtx should be initialized to NULL? Otherwise, avformat_open_input assumes that the caller has already allocated the context. – jpa Sep 19 '11 at 12:12
  • @jpa Good spotting. My bad. I decided to change the code to explicitly allocate and de-allocate, rather than simply initialising it to NULL and letting avformat_open_input allocate it (this way is clearer that you need to de-allocate as well). – mgiuca Sep 21 '11 at 02:47
  • Which part of the libav are you linking against the program in order to use avformat_open_input? I installed the most recent libav library version from the git and link all of them against my code. I still get the error undefined reference to avformat_open_input... so this function is somehow not existent in the library. Am I doing anything wrong? – mmoment Jan 13 '12 at 19:30
  • 1
    @mmoment It still works for me (using apt get, libavformat 0.7.2). I am linking with `-lavformat -lavcodec`. You need to make sure that your C files appear BEFORE the linker files on the command line -- [this recently changed and I was bitten by it](http://stackoverflow.com/questions/8640642/gcc-link-order-changed/8640681). If that doesn't work, use objdump to find out if the function is actually in the library: `objdump -T /usr/lib/libavformat.so | grep avformat_open_input`. – mgiuca Jan 13 '12 at 23:05
  • Didn't help, objdump was a good hint though. Apparently I'm missing the function in both the new and the old version. how can that be possible?! – mmoment Jan 13 '12 at 23:45
  • @mmoment No idea... is there a reason you're compiling from git and not just installing the packaged version? – mgiuca Jan 14 '12 at 01:16
  • @mgiuca My supervisor told me to after the apt version didn't work for me. We're working with Ubuntu Unitiy for LTS Reasons, but I don't think that this would have any affect on the packages though? – mmoment Jan 17 '12 at 18:50
  • 1
    @mgiuca I found out what happened. Apparently the installer strayed the libs and headers all over the place. That's why I had to face problems like not matching headers etc. Thanks for your effort, objdump really helped me realizing this! – mmoment Jan 17 '12 at 21:51
  • @mmoment Ah, I imagine that you didn't remove the apt-get version before you installed the git version. You probably were using the headers from one and the libs from another. It shouldn't have to be this way, but in general, it's best to make sure you only have _one_ version of any given library installed. Glad you sorted it out. – mgiuca Jan 18 '12 at 00:54
  • Link to tutorial in answer is dead - *"400 Bad Request"*. – Pang Aug 01 '17 at 09:25
14

I had to add a call to

avformat_find_stream_info(pFormatCtx,NULL)

after avformat_open_input to get mgiuca's answer to work. (can't comment on it)

#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);

The duration is in uSeconds, divide by AV_TIME_BASE to get seconds.

kritzikratzi
  • 19,662
  • 1
  • 29
  • 40
seeseac
  • 151
  • 1
  • 2
1

used this function its working :

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);
}

When I m using (jint) (duration / AV_TIME_BASE) this video duration is getting wrong.

axita.savani
  • 406
  • 1
  • 6
  • 21
-2
AVFormatContext* pFormatCtx = avformat_alloc_context();

will cause memory leak.

it should be AVFormatContext* pFormatCtx = NULL

Billal Begueradj
  • 20,717
  • 43
  • 112
  • 130
John Li
  • 21
  • 2
  • "Pointer to user-supplied AVFormatContext (**allocated by avformat_alloc_context**). **May be a pointer to NULL**, in which case an AVFormatContext is allocated by this function and written into ps. Note that a user-supplied AVFormatContext will be freed on failure." ffmpeg docs – mip Aug 14 '16 at 20:01