QProcess start filename args
-
I'm creating audio files out of my mkv music movies. The command to do this is:
ffmpeg -i infile.mkv -vn -c:a copy outfile.aac
No problem manually typing that for each file, so I made a drag/drop widget to capture the file url. Ffmpeg output is to stderr, which is connected to a plaintext widget's append(). I'm having a spot of bother getting that command into QProcess::start(). Ffmpeg complains about the " -i "; unknown option, but it is supposed to identify the input file. I put a debug break at the start command, the args list is 4 strings for the four arguments. They look fine. What does start() do with the command? Is there a way to examine the final string sent to the bash shell? Why can't ffmpeg recognize a standard option? Something seems to get scrozzled somewhere. Are the args parsed FIFO?``` outFileName = filename.chopped(3) + "aac"; QString program("/usr/bin/ffmpeg"); QStringList args; args << " -i " << filename << " -vn -c:a copy " << outFileName; myProcess->setProgram(program); myProcess->setArguments(args); myProcess->start();
-
Two things:
I believe each argument needs to be a separate element in the args list, and what happens if filename contains spaces? It would a really good idea to quote the filenames.
I count six distinct args in your example. You make them into four.
Finally, args beginning with a space may cause problems. if it is passing " -i " as arg[1] then the command line parse isn't going to understand because it expect the first char to be "-".
-
@Psnarf said in QProcess start filename args:
Is there a way to examine the final string sent to the bash shell?
This question can be answered experimentally with a simple shell script:
#!/bin/sh for arg in "$@"; do echo arg: \"$arg\" >> /tmp/test done
Augment it to print the working directory, environment variables, open file descriptors, or anything else you might want to know about the process.
-
-
args << " -i " << filename << " -vn -c:a copy " << outFileName;
Your arguments look wrong in a couple of ways.
For the
-i
issue, I would presume that is because you have included spaces in the argument. When you pass" -i "
you are passing a single argument which is space-hyphen-i-space. This is going to upsetffmpeg
. Look very carefully at the error message you have copied. I paste it here from your post:"Unable to find a suitable output format for ' -i '
Note the spaces in the
' -i '
in that message.When you pass that to a shell it splits arguments on (non-quoted) spaces, so the situation is different.
For the
" -vn -c:a copy "
, you are passing that as a single argument, which again looks as though it will be incorrect for whatffmpeg
expects, in addition to the same issue of its leading and trailing spaces.I suspect your
args
should look like this:args << "-i" << filename << "-vn" << "-c:a" << "copy" << outFileName;
?
-
@Psnarf said in QProcess start filename args:
Thank you for your reply. Things work as advertised in a bash shell. It is the argument in QProcess::start() as that is passed to the shell I'm trying to get at. "ffmpeg -i file" - it is only from qprocess that it does not recognize the -i option.
Rather than attempting to guess what QProcess is passing to ffmpeg, have QProcess execute the above script with the same arguments. Look at the output file, and adjust as necessary.
outFileName = filename.chopped(3) + "aac"; QString program("/tmp/test.sh"); QStringList args; args << " -i " << filename << " -vn -c:a copy " << outFileName; myProcess->setProgram(program); myProcess->setArguments(args); myProcess->start(); myProcess->waitForFinished(); // Examine /tmp/test
-
@JonB
args << "-i" << filename << "-vn" << "-c:a" << "copy" << outFileName;It never gets to the other arguments, it throws an error at " -i ". I added the spaces because without them, the dashes get dropped somewhere, so the error is "i" unknown option.
-
You must not add spaces around the arguments.
-
@jeremy_k Thank you for this idea! Excellent troubleshooting tip.
The args appear as they do in debug, a list of strings. I assume QProcess::start() appends them to program with a space before between each.
Using Jeremy's argument list: "Failed to set value '-c:a' for option 'vn': Option not found " . If I truncate the args toargs << "-i" << filename;
, everything works as advertised. There is no value for -vn (no video stream). "-c:a copy" (audio codec is 'copy') is one option-value pair, not two separate options. This command takes two file arguments, "-i infile" and "outfile". Everything after the infile specifies how to build the outfile. The outfile extension specifies the format of the output file. The entire command is supposed to convert an audio/video Matroska container into an audio AAC file. I have never seen the '-c:a' option taken as the value for 'vn'. -
@Psnarf said in QProcess start filename args:
I assume QProcess::start() appends them to program with a space before between each
No, it does not modify them but pass them as separate arguments as needed.
-
@Christian-Ehrlicher said in QProcess start filename args:
No, it does not modify
"...as needed"? Recall the command I'm trying to build:
/usr/bin/ffmpeg -i infile -vn -c:a copy outfile
- I need the entire command. How is-c:a
taken as the value of the 'vn' option?? It is a separate option.Failed to set value '-c:a' for option 'vn': Option not found
If I enter "/usr/bin/ffmpeg -i infile -vn -c:a", the expected error appears: Missing argument for option 'c:a'. Like I said, everything works in a konsole bash shell. QProcess::start() somehow does something it shouldn't.
-
This is how QProcess builds argv for linux:
argv[0] = ::strdup(encodedProgramName.constData()); // Add every argument to the list for (int i = 0; i < arguments.count(); ++i) argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData());
It then forks argv. Perhaps something in encodeName, which changes everything to local 8-bit? The documentation for encodeName says:
File names hard-coded into the application should only use 7-bit ASCII filename characters.
If that is the case, why are the filenames in the argument list converted to 8-bit? Should not that be an option? How can QProcess deal with this command:ffmpeg -i input.mp4 -c:v libx265 -preset medium -crf 28 -pix_fmt yuv420p12le -c:a aac -b:a 128k output_12bit.mp4
-
As already said - add every parameter to a QStringList, pass it to QProcess::exec()
-
@Psnarf said in QProcess start filename args:
This is how QProcess builds argv for linux:
argv[0] = ::strdup(encodedProgramName.constData()); // Add every argument to the list for (int i = 0; i < arguments.count(); ++i) argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData());
It then forks argv. Perhaps something in encodeName, which changes everything to local 8-bit?
Going back to test.sh, its output should answer this question for you. Look at the file it generates. It will tell you exactly what the child process receives, because it is that child process. QProcess isn't going to alter them based on which program it is executing.
The documentation for encodeName says:
File names hard-coded into the application should only use 7-bit ASCII filename characters.
If that is the case, why are the filenames in the argument list converted to 8-bit? Should not that be an option?QProcess invokes execve in the unix implementation, which accepts
char *const argv[]
consisting of null byte terminated strings. Not converting from utf-16 is unlikely to behave as expected. -
I had copied my ffprobe wrapper project to create the ffmpeg wrapper. When I stepped through the program line by line, I discovered a 'ffprobe' where a 'ffmpeg' should be. Made the substitution, problem solved.
Cause: IBK - Idiot Behind KeyboardI thank everyone who tried to help me. I learned a lot from this exercise in futility.