我想从文件中提取视频的帧大小。为此,我通过bash shell启动了一个ffmpeg命令,我想提取输出。此命令在bash shell中运行良好,并根据需要返回输出。
ffprobe -v error -count_frames -of flat=s=_ -select_streams v:0 -show_entries stream=nb_read_frames /home/peter/DA/videos/IMG-2014-1-10-10-4-37.avi
我想通过C ++调用它并读出结果。我使用IDE Qt 4.8.6和GCC 4.8编译器。
对于我的代码,我使用此模板:
executing shell command with popen
并根据我的要求改为
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
FILE* pipe = popen("echo $(ffprobe -v error -count_frames -of flat=s=_ -select_streams v:0 -show_entries stream=nb_read_frames /home/peter/DA/videos/IMG-2014-1-10-10-4-37.avi)", "r");
if(!pipe)
{
cout << "error" << endl;
return 1;
}
char* buffer = new char[512];
string result;
fgets(buffer, sizeof(buffer), pipe) ;
while(!feof(pipe))
{
if(fgets(buffer, sizeof(buffer), pipe) != NULL)
{
cout << buffer << endl;
result += buffer;
}
}
pclose(pipe);
cout << result<< endl;
return 0;
}
Qt控制台向我发出了此警告,并且返回时返回0:
/home/peter/DA/videos/IMG-2014-1-10-10-4-37.avi: Invalid data found when processing input
和&#34; pipe&#34;是空的。
当我在shell中用g ++编译main.cpp文件时,它也很好用。
答案 0 :(得分:1)
旧帖子,但正如我所见,这里有两点:
错误&#34;处理输入时发现无效数据&#34;
这是ffprobe正常文件处理错误。通常它发生在媒体文件中有错误时,它与c ++程序无关。
ffprobe将警告/错误消息写入stderr
流,但popen
仅捕获stdout
个流,这就是为什么您的程序无法获取该错误消息的原因管道。
如何在程序中获取stdout + stderr
popen
允许执行任何shell命令,因此我们可以使用它将stderr
重定向到stdout
,因此您的程序也可以获得该输出,如下所示:
FILE *pipe = popen("ffprobe ... 2>&1");
2>
重定向句柄#2输出到当前&1
句柄#1输出(#1 = stdout
,#2 = stderr
)。
绝对不需要执行FILE *pipe = popen("echo $(ffprobe ...)");
,因为最终结果是相同的:请注意$(...)
返回带有stdout
命令输出的字符串,echo
1}}打印它。完全是多余的。
为了改进您的代码,需要进行一些观察:
当字符串太大而无法在一个屏幕宽度中显示时,最好将其分成多行(可能在某些逻辑中将每行内的文本分组),因为这样可以提高字符串的读数其他人的代码(最终由你自己在几个月内完成)。
您可以使用C / C ++编译器功能来连接由空格分隔的字符串(换行符,制表符等),例如。 "hi " "world"
与编译器的"hi world"
相同。
当您的程序必须编写错误消息时,请使用stderr
流。在c ++中std::cerr
代替std::cout
。
如果没有使用loger(每个new
必须有delete
)
避免使用using namespace std;
,而是对您将要使用的每个标准实例/类使用using std::name;
。防爆。 using std::string;
,避免了未来的问题,特别是在大型项目中。常见错误的一个示例是here。一般情况下,请避免使用using namespace xxxx;
。
重新组织代码,我们有:
#include <iostream>
#include <stdio.h>
using std::string;
using std::cout;
using std::cerr;
using std::endl;
int main() {
static char ffprobeCmd[] =
"ffprobe " // command
"-v error " // args
"-count_frames "
"-of flat=s=_ "
"-select_streams v:0 "
"-show_entries stream=nb_read_frames "
"/home/peter/DA/videos/IMG-2014-1-10-10-4-37.avi" // file
" 2>&1"; // Send stderr to stdout
FILE *pipe = popen(ffprobeCmd, "r");
if (!pipe) {
perror("Cannot open pipe.");
return 1;
}
char* buffer = new char[512];
string result;
while ((fgets(buffer, sizeof(buffer), pipe)) != NULL) {
result += buffer;
}
// See Note below
int retCode = pclose(pipe);
if (retCode != 0) {
// Program ends with error, and result has the error message
cerr << "retCode: " << retCode << "\nMessage: " << result << endl;
return retCode;
} else {
// Program ends normally, prints: streams_stream_0_nb_read_frames="xxx"
cout << result << endl;
}
delete buffer; // free memory
return 0;
}
<强> 注意 强>
pclose
并非用于返回已执行的程序状态代码,但如果您需要此值,则pclose会在某些c ++版本/系统中执行此操作,因此请检查它。无论如何,只有一切正常,它才会为零。