简体   繁体   English

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

[英]Executing bash shell command and extract output --> invalid file error

I want to extract the framesize of a video from a file. 我想从文件中提取视频的帧大小。 For this purpose, I have launched an ffmpeg command via bash shell, and I want to extract the output. 为此,我通过bash shell启动了ffmpeg命令,并且我想提取输出。 This command is working well in the bash shell, and returns the output as wanted. 该命令在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

I want to call it via C++ and read out the result. 我想通过C ++调用它并读出结果。 I use the IDE Qt 4.8.6 with GCC 4.8 compiler. 我使用带有GCC 4.8编译器的IDE Qt 4.8.6。

For my code, I use this template: 对于我的代码,我使用以下模板:

executing shell command with popen 用popen执行shell命令

and changed it for my demands to 并根据我的要求将其更改为

#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;   
}

The Qt console returned me this warning, and it is rending with return 0: Qt控制台向我返回此警告,并且正在返回0:

/home/peter/DA/videos/IMG-2014-1-10-10-4-37.avi: Invalid data found when processing input

and "pipe" is empty. 并且“管道”为空。

When I compile the main.cpp file above with g++ in the shell it works nice too. 当我在外壳中使用g ++编译上面的main.cpp文件时,它也很好用。

Old post, but as I see, there are two points here: 旧帖子,但据我所知,这里有两点:

Error "Invalid data found when processing input" 错误“处理输入时发现无效数据”

That's an ffprobe normal file processing error. 这是ffprobe正常的文件处理错误。 Usually it happens when there are errors inside media file, it is not related to c++ program. 通常,它发生在媒体文件中有错误时,它与c ++程序无关。

ffprobe writes warning/error messages into stderr stream, but popen only captures stdout stream, that's why your program couldn't get that error message trough the pipe. ffprobe将警告/错误消息写入stderr流,但是popen只捕获stdout流,这就是为什么您的程序无法通过管道获得该错误消息的原因。

How get the stdout+stderr in my program 如何在我的程序中获取stdout + stderr

popen allows execute any shell command, so we can use it to redirect stderr into stdout , so your program can get that output too, like this: popen允许执行任何shell命令,因此我们可以使用它将stderr重定向到stdout ,这样您的程序也可以获取该输出,如下所示:

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

The 2> redirect handle#2 output into current &1 handle#1 output (#1= stdout , #2= stderr ). 2>将handle#2输出重定向到当前的&1 handle#1输出中(#1 = stdout ,#2 = stderr )。

There's absolute no need to execute FILE *pipe = popen("echo $(ffprobe ...)"); 绝对不需要执行FILE *pipe = popen("echo $(ffprobe ...)"); , because the final result will be the same: Note that $(...) returns a string with stdout command output, and echo prints it. ,因为最终结果将是相同的:请注意, $(...)返回带有stdout命令输出的字符串,并用echo打印它。 Totally redundant. 完全多余。

A few observations in order to improve your code: 为了改善您的代码,一些观察:

  • When a string is too big to be displayed in one screen width, it's better split it into multiple lines (maybe grouping text inside each line within some logic), because that will improve the reading of your code by other people (and eventually by yourself in a few months). 当字符串太大而无法在一个屏幕宽度上显示时,最好将其分成多行(也许在逻辑中将每一行中的文本分组),因为这将提高其他人(最终由您自己)对代码的读取在几个月内)。

    You can do this with a C/C++ compiler feature that concatenates strings separated by spaces (newlines, tab, etc.), ex. 您可以使用C / C ++编译器功能来做到这一点,该功能将用空格(换行符,制表符等)分隔的字符串连接起来,例如。 "hi " "world" is the same as "hi world" to the compiler. 在编译器中, "hi " "world""hi world"相同。

  • When your program have to write error messages, use the stderr stream. 当程序必须编写错误消息时,请使用stderr流。 In c++ that's std::cerr instead std::cout . 在c ++中,它是std::cerr而不是std::cout

  • Always free memory allocated when it's no loger used (each new has to have a delete ) 不使用任何记录器时,总是释放已分配的内存(每个new都必须有一个delete

  • Avoid use using namespace std; 避免使用using namespace std; , instead use using std::name; ,而是使用using std::name; for each standard instance/class that you'll use. 对于您将使用的每个标准实例/类。 Ex. 防爆。 using std::string; , that avoids future problems, specially in big programs. ,这样可以避免将来出现问题,尤其是在大型程序中。 An example of a common error is here . 这里是一个常见错误的示例。 In general avoid using using namespace xxxx; 通常,避免using namespace xxxx; .

Reorganizing your code, we have: 重新组织您的代码,我们有:

#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;
}

Note 注意

pclose is not intended to return the executed program status code, but if you need this value, pclose does it in some c++ versions/systems, so check it. pclose并非旨在返回已执行的程序状态代码,但是如果需要此值,则pclose在某些c ++版本/系统中会执行此操作,因此请检查它。 Anyway it will be zero only if everything was OK. 无论如何,只有一切正常,它才会为零。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM