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



我想从文件中提取视频的帧大小。为此,我通过bashshell启动了一个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编译器。

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

用popen 执行shell命令

并根据我的要求将其更改为

#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>将句柄#2输出重定向为当前&1句柄#1输出(#1=stdout,#2=stderr(。

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

为了改进您的代码,请注意以下几点:

  • 当一个字符串太大,无法在一个屏幕宽度内显示时,最好将其拆分为多行(可能在某些逻辑中对每行内的文本进行分组(,因为这将提高其他人(最终在几个月内提高自己(对代码的阅读能力。

    您可以使用C/C++编译器功能来实现这一点,该功能将由空格(换行符、制表符等(分隔的字符串连接起来。例如,对于编译器来说,"hi " "world""hi world"相同。

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

  • 未使用loger时总是分配空闲内存(每个new必须有一个delete(

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

相关内容

  • 没有找到相关文章

最新更新