radek-k/FFMediaToolkit

End of file copying frames - but number of output frames doesn't equal number of input frames

voltagex opened this issue · 5 comments

        public static void Convert(string inputFile)
        {
            FFmpegLoader.FFmpegPath = Path.Join(Directory.GetParent(Application.ExecutablePath).ToString(), "lib");
            string outputPath = Path.GetDirectoryName(inputFile);
            string outputFile = Path.GetFileNameWithoutExtension(inputFile) + ".mp4";
            outputFile = Path.Combine(outputPath, outputFile);
            var inputVideo = MediaFile.Open(inputFile);
            var outputContainer = MediaBuilder.CreateContainer(outputFile).WithVideo(new VideoEncoderSettings(1920, 1080, 30, VideoCodec.H264)).Create();
            int? inputFrameCount = inputVideo.Video.Info.NumberOfFrames;
            int i = 0;
            while (i != inputFrameCount)
            {
                outputContainer.Video.AddFrame(inputVideo.Video.GetNextFrame());
                i++;
            }
        }

I am trying to convert MJPEG in an AVI container (from a "wildlife camera") to H264 in an MP4 container

IMAG0020.zip

I get an exception about hitting the end of the file at frame 272, but inputVideo.Video.Info.NumberOfFrames says it has 330 frames.

Am I doing something wrong here? This does seem like a bit of a "long way round" for something equivalent to `ffmpeg -i video.avi -an video.mp4"

FFMediaToolkit doesn't use FFmpeg tool itself, but its low-level API. If you just want to convert a video file I recommend using a FFmpeg command-line wrapper library such as Xabe.FFmpeg It would be more reliable and easier to setup.

Sure, but I still think there's a bug with this library.

@voltagex Number of frames is provided by container and it's might be inaccurate anyway.

If look to ffprobe report, you got same values:

ffprobe.exe -i .\IMAG0020.AVI -print_format json -loglevel fatal -show_streams -count_frames -select_streams v

Output:

 "nb_frames": "330",
 "nb_read_frames": "272",

You should avoid leverages to nb_frames, because this value might be incorrect. Also, not all containers store their frame count.

Thanks, this makes more sense - I'd probably need to do two loops through the source video then to make sure I know how many frames to read.

@voltagex

You can do it in one loop:

while (inputVideo.Video.TryGetNextFrame(out var frame))
{
    outputContainer.Video.AddFrame(frame);
}