4
$\begingroup$

I am reading large AVI files and want to know the number of stored frames.

To do that in Mathematica 11.3 I use the following:

Needs["MediaTools`"]; 
numberImages = MediaTools`Private`$MFReadVideoFrameCount["movie.avi"];

This second line takes too much time (e.g. 205 sec for finding out that an AVI movie contains 4325 frames).

I am working with thousands of such and longer AVI files, and if I always have to wait for some minutes to find the total frame number it would sum up for thousand files to 3000 min = 50 hours!!! (In reality more.)

I there a possibility to read the value from the header?

For example VirtualDub (free Software for Windows) reads the information in a fraction of a second and the value is exact, not estimated! I tested this for hundreds of AVI files. My AVI files are experimental movie files where the correct number is written into the header.

Addendum

After the comments of Buddha_the_Scientist and C. M. I would like to provide some additional information:

Here is an example avi movie (named "20181203_01_movie.avi", only 1 MB in size): https://drive.google.com/open?id=1Wmp0YGZtKTYxBd2nGzgyglJKrNb_Uk0_

  • First step:

    Needs["MediaTools`"];

    numberImages = MediaToolsPrivate$MFReadVideoFrameCount[ "20181203_01_movie.avi"] // AbsoluteTiming

    {4.16492, 350}

  • Second step with restarted kernel:

    numberImages = Import["20181203_01_movie.avi", "FrameCount"] // AbsoluteTiming

    {3.96804, 350}

So for this very small avi file it takes about 4 sec to read the total number of images (350).

Now lets take exiftool: I downloaded the Windows Version from here: https://www.sno.phy.queensu.ca/~phil/exiftool/

On Windows command shell cmd:

"exiftool(-k).exe" lower_center.avi

That gives instantaneously the total frame count of 350 and many other data from the header:

enter image description here

Question to the Mathematica experts:

How can I read the meta information WITH Mathematica? I cannot believe that I have to use an external program to do that.

$\endgroup$
  • 2
    $\begingroup$ I think you can call VirtualDub through command line maybe you can run it as an external program in Mathematica and return the result. $\endgroup$ – Buddha_the_Scientist Dec 3 '18 at 10:23
  • 1
    $\begingroup$ You didn't mention Import["movie.avi", "FrameCount"] but I assume it is equally slow. $\endgroup$ – C. E. Dec 3 '18 at 10:43
  • $\begingroup$ @C. E. I compared the two different possibilities to read the number of frames for a certain AVI (10866 frames): your proposal: 279 sec, the solution that I used: 232 sec. This is in the same order of magnitude. $\endgroup$ – mrz Dec 3 '18 at 11:52
  • $\begingroup$ I tried using ffprobe, a companion tool to ffmpeg, to get the frame count of a 1330 frames long video, and that took 18 seconds. I used exiftool to look at what metadata the file held, and the frame count is not supplied as metadata. So maybe it actually has to go through all the frames, and that may be what's taking time. In that case, there may not be a very fast solution for an exact frame count, although frame rate and duration could be used to estimate. $\endgroup$ – C. E. Dec 3 '18 at 13:46
  • 1
    $\begingroup$ You say that your files have the frame count in the metadata, so you might try either exiftool or ffprobe and see if they find this. If you use ffprobe the command is this: ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 movie.avi It is easy to call ffprobe from Mathematica. See this and this. This is along the lines of Buddha_the_Scientist's suggestion of using VirtudalDub via the command line. $\endgroup$ – C. E. Dec 3 '18 at 13:53
4
$\begingroup$

In my comment, I pointed to how exiftool and ffprobe can be used to read the frame count. Apparently, VirtualDub can too. But, it turns out, these tools aren't doing anything we can't also do easily in Mathematica. The AVI metadata header is documented e.g. here. What this says is that we can retrieve the metadata by reading the bytes at the beginning of the file. We can do it like this:

video = "~/Downloads/20181203_01_movie.avi";
stream = OpenRead[video, BinaryFormat -> True];
Skip[stream, Byte, 32];
metadata = <|
   "TimeDelay" -> BinaryRead[stream, "Integer32"],
   "AVIDataRate" -> BinaryRead[stream, "Integer32"],
   "Padding" -> BinaryRead[stream, "Integer32"],
   "Flags" -> BinaryRead[stream, "Integer32"],
   "NumberOfFrames" -> BinaryRead[stream, "Integer32"],
   "NumberOfPreviewFrames" -> BinaryRead[stream, "Integer32"],
   "NumberOfDataStreams" -> BinaryRead[stream, "Integer32"],
   "BufferSize" -> BinaryRead[stream, "Integer32"],
   "Width" -> BinaryRead[stream, "Integer32"],
   "Height" -> BinaryRead[stream, "Integer32"],
   "TimeScale" -> BinaryRead[stream, "Integer32"],
   "DataRate" -> BinaryRead[stream, "Integer32"],
   "StartT" -> BinaryRead[stream, "Integer32"],
   "ChunkSize" -> BinaryRead[stream, "Integer32"]
   |>;
metadata["NumberOfFrames"]

350

And of course, it is instantaneous. A thank you goes to halirutan who showed me how to read the bytes with BinaryRead[stream, "Integer32"]. That was just what I needed to turn four consecutive bytes into an integer.

If you are going to read the metadata from multiple files, you might also want to Close the streams when you're done with them. Close[stream].

$\endgroup$
  • $\begingroup$ Thanks so much … and also to halirutan. $\endgroup$ – mrz Dec 4 '18 at 10:14

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.