Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 执行bash shell命令并提取输出-->;无效文件错误_C++_Bash_Shell_Ffmpeg_Qt5 - Fatal编程技术网

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

C++ 执行bash shell命令并提取输出-->;无效文件错误,c++,bash,shell,ffmpeg,qt5,C++,Bash,Shell,Ffmpeg,Qt5,我想从文件中提取视频的帧大小。为此,我通过bashshell启动了一个ffmpeg命令,并希望提取输出。该命令在bashshell中运行良好,并根据需要返回输出 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++调用它并读出结果。我使用I

我想从文件中提取视频的帧大小。为此,我通过bashshell启动了一个ffmpeg命令,并希望提取输出。该命令在bashshell中运行良好,并根据需要返回输出

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++调用它并读出结果。我使用IDEQt4.8.6和GCC4.8编译器

对于我的代码,我使用以下模板:

根据我的要求改成

#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;   
}
“管道”是空的


当我在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::CURR < /C> >而不是代码> STD::CUT .< /P>
  • 在未使用记录器时始终释放分配的内存(每个
    必须有一个
    删除

  • 避免使用
    名称空间std,而不是使用std::name使用
    用于您将使用的每个标准实例/类。例如,
    使用std::string,避免将来出现问题,特别是在大型程序中。常见错误的一个例子是。通常避免使用
    名称空间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;
}
#包括
#包括
使用std::string;
使用std::cout;
使用std::cerr;
使用std::endl;
int main(){
静态字符ffprobeCmd[]=
“ffprobe”//command
“-v错误”//args
“-计数\u帧”
“-of flat=s=u2;”
“-选择\u流v:0”
“-show_entries stream=nb_read_frames”
“/home/peter/DA/videos/IMG-2014-1-10-10-4-37.avi”//file
“2>&1”//将stderr发送到stdout
文件*pipe=popen(ffprobeCmd,“r”);
如果(!管道){
perror(“无法打开管道”);
返回1;
}
char*buffer=新字符[512];
字符串结果;
while((fgets(buffer,sizeof(buffer,pipe))!=NULL){
结果+=缓冲区;
}
//见下文注释
int-retCode=pclose(管道);
如果(retCode!=0){
//程序以错误结束,结果显示错误消息

cerr为什么不干脆执行
(fgets(…)!=nullptr)
?而
字符串是什么(大写
S
)?“处理输入时发现无效数据”是一个ffmpeg错误,它意味着读取文件很困难。该错误不应该与您的代码有关。此外,“echo”似乎是多余的。@criswell我很确定您需要
echo
到管道中。@erip:the
popen
从命令创建管道,写入管道的是
ffprobe
echo
是多余的,因为@criswell saysUppercase S已更改。Thx
#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;
}