TheMickeyNick
TheMickeyNick

Reputation: 13

Traceback error with Python when using ffmpeg to convert a video

The simple way my script runs is the user provides a folder location and a filetype and glob.glob() finds the files with the filetype provided and adds them to a list. It then uses a for loop and goes through the list and converts each video. But it doesn't like when I try to run my ffmpeg command. Any help would be awesome. I'm also using Win 7 64 bit with 64 bit ffmpeg and Python 3.3 Here's the error:

OS Error
Traceback (most recent call last):
  File "C:\Python33\lib\subprocess.py", line 1106, in _execute_child
    startupinfo)
FileNotFoundError: [WinError 2] The system cannot find the file specified

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\user\Workspace\PythonConverter\HTMLandPythonConverter\Converter.py", line 77, in <module>
    massConvert(fileNames)
  File "C:\Users\user\Workspace\PythonConverter\HTMLandPythonConverter\Converter.py", line 47, in massConvert
    convertVideotoNewFormat('.mp4', x)
  File "C:\Users\user\Workspace\PythonConverter\HTMLandPythonConverter\Converter.py", line 61, in convertVideotoNewFormat
    myFile = subprocess.Popen(ffmpegString)#, stdout=subprocess.PIPE, stderr=subprocess.PIPE
  File "C:\Python33\lib\subprocess.py", line 820, in __init__
    restore_signals, start_new_session)
  File "C:\Python33\lib\subprocess.py", line 1112, in _execute_child
    raise WindowsError(*e.args)
FileNotFoundError: [WinError 2] The system cannot find the file specified

Here is my code:

import subprocess
from subprocess import call
import glob

fileNames = []
fileLocation = {}
filetype = {}
def convertString(location):
    s = list(location)
    for i in range(len(s)):
        if s[i] in '\\':
            s[i] = '/'

    if s[len(s)-1] != '/':
        s.append('/')
    location = "".join(s)
    return location

def convertStringBack(stringTo):
    s = list(stringTo)
    for i in range(len(s)):
        if s[i] in '/':
            s[i] = '\\'
    stringTo = "".join(s)
    return stringTo

def fileTypeTester():
    FieldType = '*' + input('What\'s the file type we are converting from?')
    typeSplit = list(FieldType)
    if typeSplit[1] != '.':
        typeSplit.insert(1,'.')
    FieldType = "".join(typeSplit)
    if FieldType not in ['*.flv','*.kdb']:
        print('Not a valid file type')
    else:
        return FieldType
    return None

def massConvert(listOfFiles):
    print('Starting Conversion')
    for x in listOfFiles:
        #x = convertStringBack(x)
        print('Converting ' + x + ' to .mp4')
        convertVideotoNewFormat('.mp4', x)
    print('Finished File Conversion')


def convertVideotoNewFormat(newFormat, fileLoc):
    newFilePath = fileLoc[0:len(fileLoc)-4]
    ffmpegString = ["ffmpeg64","-i", fileLoc,"-qscale","0","-ar","22050","-vcodec","libx264",newFilePath,newFormat]
    try:
        subprocess.check_call(newFilePath)
    except OSError:
        print('OS Error')
    except subprocess.CalledProcessError:
        print('Subprocess Error')
    myFile = subprocess.Popen(ffmpegString)
    print(myFile)

#This will replace old HTML flv object tag with new video tag, but it is yet to be implemented
def replaceHTML():
    pass

fileLocation = input('What is the path of the files you\'d like to convert?')
fileLocation = convertString(fileLocation)
fileType = fileTypeTester()
fileNames = glob.glob(fileLocation + fileType)
massConvert(fileNames)

I've looked around and most of the tutorials are in 2.7 the code is 3.3 and I can't find a tutorial to use ffmpeg for 3.3. My ffmpeg is set to 'ffmpeg64' on my PATH.

Thanks!

Upvotes: 1

Views: 2391

Answers (1)

abarnert
abarnert

Reputation: 366213

First:

def convertVideotoNewFormat(newFormat, fileLoc):
    newFilePath = fileLoc[0:len(fileLoc)-4]
    ffmpegString = ["ffmpeg64","-i", fileLoc,"-qscale","0","-ar","22050","-vcodec","libx264",newFilePath,newFormat]
    try:
        subprocess.check_call(newFilePath)
    except OSError:
        print('OS Error')
    except subprocess.CalledProcessError:
        print('Subprocess Error')

This part cannot possibly do anything useful. The newFilePath is a path you've made by stripping the last 4 characters off a video file. You can't run the program at that path, because (unless you get very, very unlucky) there is no such problem.

That explains the first OSError.


For the second error, it's telling you that ffmpeg64 isn't on your PATH. You say that it is on your PATH, but there is no other way that you could get that error from that line of code. You can look up what CreateProcess does if you want.

There are three common reasons for this:

  1. You've used SET to modify the PATH in a particular cmd.exe session (DOS prompt), but you're running code in a different DOS prompt, or running GUI code, or for some other reason have a different session.
  2. You've used the control panel to modify PATH for your user, but you're running the Python script as a different user (e.g., as part of a WSGI service).
  3. You haven't modified PATH at all; you're relying on the fact that you've cd'd into the same directory as ffmpeg64, and . is on the default PATH in Windows.

As a side note, this:

newFilePath = fileLoc[0:len(fileLoc)-4]

… is the same as:

newFilePath = fileLoc[:-4]

… except that it's harder to read, and less robust (it will raise an exception if fileLoc is under 4 characters wrong), and slower and easier to get wrong.

But really, if you want to strip off an extension, you don't want either. If you have foobar.mpeg, do you really want to turn that into foobar..mp4? Use the os.path module to munge paths:

newFilePath, ext = os.path.splitext(fileLoc)

While we're at it, you've got some other problems in your code:

myFile = subprocess.Popen(ffmpegString)
print(myFile)

subprocess.Popen creates a subprocess object, which you are eventually going to have to wait on. Printing it out won't do anything particularly useful.

If you want to do the conversions one at a time, waiting for each one to finish before doing the next, use check_call, not Popen here.

If you want to kick them all off in parallel, return myFile here, and then do something like this:

children = []
for x in listOfFiles:
    print('Converting ' + x + ' to .mp4')
    children.append(convertVideotoNewFormat('.mp4', x))
for child in children:
    child.wait()
print('Finished File Conversion')

Upvotes: 1

Related Questions