gpt4 book ai didi

c++ - 执行 bash shell 命令并提取输出 --> 无效文件错误

转载 作者:行者123 更新时间:2023-11-30 05:40:05 26 4
gpt4 key购买 nike

我想从文件中提取视频的帧大小。为此,我通过 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++调用它并读出结果。我使用带有 GCC 4.8 编译器的 IDE Qt 4.8.6。

对于我的代码,我使用这个模板:

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

并且“管道”是空的。

当我在 shell 中使用 g++ 编译上面的 main.cpp 文件时,它也工作得很好。

最佳答案

旧帖子,但据我所知,这里有两点:

错误“处理输入时发现无效数据”

这是一个 ffprobe 正常的文件处理错误。通常发生在媒体文件中有错误时,它与 c++ 程序无关。

ffprobe 将警告/错误消息写入 stderr 流,但 popen 仅捕获 stdout 流,这就是您的程序无法获取的原因通过管道的错误消息。

如何在我的程序中获取stdout+stderr

popen 允许执行任何 shell 命令,因此我们可以使用它将 stderr 重定向到 stdout,这样您的程序也可以获得该输出,像这样:

FILE *pipe = popen("ffprobe ... 2>&1");

2> 将 handle#2 输出重定向到当前 &1 handle#1 输出(#1=stdout,#2=标准错误).

绝对不需要执行 FILE *pipe = popen("echo $(ffprobe ...)");,因为最终结果是一样的:注意 $ (...) 返回带有 stdout 命令输出的字符串,echo 打印它。完全多余。

一些改进代码的观察:

  • 当一个字符串太大而无法在一个屏幕宽度内显示时,最好将其分成多行(也许在某种逻辑中将每行内的文本分组),因为这将提高其他人对您代码的阅读能力人(并最终在几个月后由你自己)。

    您可以使用 C/C++ 编译器功能执行此操作,该功能连接由空格(换行符、制表符等)分隔的字符串,例如。 "hi ""world" 与编译器的 "hi world" 相同。

  • 当您的程序必须写入错误消息时,请使用 stderr 流。在 C++ 中,它是 std::cerr 而不是 std::cout

  • 总是在没有记录器使用时分配空闲内存(每个 new 都必须有一个 delete)

  • 避免使用 using namespace std;,而是对您将使用的每个标准实例/类使用 using std::name;。前任。 using std::string;,这避免了 future 的问题,特别是在大型程序中。常见错误的示例是 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++ 版本/系统中会这样做,所以检查一下。无论如何,只有在一切正常的情况下它才会为零。

关于c++ - 执行 bash shell 命令并提取输出 --> 无效文件错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31919172/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com