Search code examples
powershellffmpegsyntax

Check mutliple mxf files for errors


Im trying to do a powershell to test all the files in a folder for any errors using ffmpeg, as follows.

Get-ChildItem -Filter "*.mxf" -Recurse | ForEach-Object {
    ffmpeg -v error -i $_.FullName -map 0:1 -f null 2>$($_.FullName + '.log') E:\$_.FullName.mxf
}

I get an error as follows

ffmpeg : At least one output file must be specified At line:2 char:5
+     ffmpeg -v error -i $_.FullName -map 0:1 -f null }
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (At least one ou...st be specified:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

I actually dont need the output here, just want to check the file for any errors.


Solution

  • Preface:

    • Your error message - unlike your command - implies that you did not also pass E:\$_.FullName.mxf to your ffmpeg command as the last argument.

    • If you had, your command would have worked, for the reasons explained below.

    • As an aside: As an actual output file path E:\$_.FullName.mxf wouldn't work, because $_ (alone) would expand to the input file's full path, so you'd get a path such as E:\C:\path\to\..., which is invalid; also .FullName would be retained verbatim, because the argument is implicitly treated as if it were enclosed in "...", i.e. as an expandable string, inside of which expressions (as opposed to stand-alone variable references such as $_), such as accessing a property, must be enclosed in $(...).


    • -f null means that you're using the so-called null muxer, whose express purpose is not to write an output file (but the input file's data is still processed).
    • Despite that, ffmpeg nonetheless requires you to specify an output-file operand - even though it is effectively ignored.
    • Therefore, you can pass a dummy operand to satisfy this syntax requirement, in the simplest case -:
    # Note the "-" as the dummy output-file operand.
    Get-ChildItem -Filter "*.mxf" -Recurse | ForEach-Object {
      ffmpeg -v error -i $_.FullName -map 0:1 -f null - 2>($_.FullName + '.log')
    }
    

    Note:

    • If you were to specify an actual video format with -f, e.g, -f mov, yet still wanted to discard the output, you'd have to use /dev/null (on Unix) / NUL (on Windows) as the output-file operand, Additionally, use -y on Unix-like platforms to suppress a spurious prompt for "overwriting" /dev/null (observed with v6 of ffmpeg).

    • In Windows PowerShell, ffmpeg's first stderr line (if any) is mistakenly recorded in the output file as if it were a PowerShell error, i.e. in a noisy, multiline format (fortunately, this problem has been fixed in PowerShell (Core) 7+).

      • This is simply a cosmetic problem and can be ignored.

      • If you want to prevent the problem, use the following workaround (for an explanation of the technique, see this answer):

        Get-ChildItem -Filter "*.mxf" -Recurse | ForEach-Object {
          $stdErrLines = [System.Collections.Generic.List[string]] @()
          ffmpeg -v error -i $_.FullName -map 0:1 -f null - 2>&1 |
            ForEach-Object {
              if ($_ -is [System.Management.Automation.ErrorRecord]) {
                $stdErrLines.Add($_.ToString())
              } else {
                $_
              }
            }
          $stdErrLines >($_.FullName + '.log')
        }