Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to tell if ffmpeg errored or not?

Tags:

ffmpeg

The Situation: I'm using ffmpeg (via .net) to save video files. I can get the output from ffmpeg but I dont know how can I customize the output to have better result.

My Problem: My problem is, there is no certain difference between successful and failed operation.

last line of success:

video:1006kB audio:134kB subtitle:0 global headers:0kB muxing overhead 0.943510%

last lines from fails

c:\x\test-9-8/30/2012-9:29:56-AM.mp4: Invalid argument

rtmp://cdn.tv/cdn-live39/definst/stream01: Unknown error occurred

My Question: Is there an option (or command line parameter) to add some sort of return code (200: success, 500: error, etc)

Thanks!

PS: I saw this topic How to tell if ffmpeg errored? but there is no number before/after last line. I think the last version doesnt have number anymore.

like image 349
dvdmn Avatar asked Aug 30 '12 14:08

dvdmn


3 Answers

You could just check the exit code returned by ffmpeg. It should return 0 on success, anything else means it failed.

like image 199
sashoalm Avatar answered Nov 06 '22 09:11

sashoalm


I know this is very old but as i came across and found no other reliable answer and after some more testing:

The suggestion with checking for return of 0 is in general a good advice - but does not help in all cases. The other idea with checking if the file exists is also good - but again - does not help in all cases.

For example when the input file is a mp3 file that has an embedded cover - then ffmpeg does (in my tests) use this image and extracts that one as an (unusable) video file.

What i do now is to have debug level output and parse it for the number of muxed packets.

ffmpeg -i "wildlife.mp4" -c:v copy -an -sn "out.mp4" -y -loglevel debug 2> wildlife.txt

With a regex i search for this text:
Output stream .+ (video): [0-9][0-9]+ packets muxed \([0-9][0-9]+ bytes\)

(this assumes that every video has more than 9 packets - could of course be optimized for really short videos).

Of course for RTMP or other settings the output may differ but i think to parse the full output stream is the only option.

like image 45
Eleasar Avatar answered Nov 06 '22 11:11

Eleasar


You can run ffmpeg in -v error mode and have it return errors into a text file, see here: https://superuser.com/questions/100288/how-can-i-check-the-integrity-of-a-video-file-avi-mpeg-mp4 You can combine this with encoding without the null output but you will only be able to read the results from the text file.

Or you can have an additional script that will follow-up on the errors. Here is a Python example, which checks for file integrity, notice the if stdout clause. This will basically re-check encoded file if you need to see normal output first.

Solution 1:

import subprocess
import os
import sys
import re

def check_video(files):
    if type(files) == str:
        files = [files]

    for file in files:
        print(f"Checking {file}...")
        command_line = f'ffmpeg -v error -i "{file}" -map 0:v -map 0:a? -vcodec copy -acodec copy -f null -'
        base_name = os.path.splitext(file)[0]
        extension = os.path.splitext(file)[1]

        process = subprocess.Popen(command_line, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, stderr = process.communicate()
        return_code = process.returncode
        pid = process.pid

        print(f"Base: {base_name}")
        print(f"Extension: {extension}")
        print(f"RC: {return_code}")

        if stdout:
            allowed_errs = ["invalid as first byte of an EBML number"]
            stdout_detect = stdout.decode().split("\n")

            for error in allowed_errs:
                if error not in stdout_detect[0] or len(stdout_detect) > 2:
                    print(f"Errors!")
                    print(os.path.splitext(file)[1])
                    os.rename(file, f"{file}.error")
                    with open(f"{file}.error.log", "w") as errfile:
                        if stdout:
                            errfile.write(stdout.decode())
                        if stderr:
                            errfile.write(stderr.decode())
                else:
                    print("Minor problems detected.")
        else:
            print("File OK.")


        process.wait()

if __name__ == "__main__":
    files = sys.argv[1:]
    # files = ["a.mkv"]
    check_video(files)

Solution 2:

        with subprocess.Popen(command_line,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT,
                              universal_newlines=True) as self.process:

            for line in self.process.stdout:
                print(line, end='')

        return_code = self.process.wait()

From here, you can do whatever you like with each line, like checking for error keywords in them. I think ffmpeg has some standard of error reporting (https://ffmpeg.org/doxygen/trunk/group__lavu__error.html). With this solution, output will be displayed to you same as with directly running ffmpeg. Source: https://stackoverflow.com/a/4417735/1793606. Tested with Python 3.10

Solution 3: Also, you can set err_detect for ffmpeg itself, that should reflect in the return code

like image 1
HCLivess Avatar answered Nov 06 '22 10:11

HCLivess