popen 在进程之间传递二进制数据

Posted

技术标签:

【中文标题】popen 在进程之间传递二进制数据【英文标题】:popen to pass binary data between processes 【发布时间】:2011-03-14 17:37:48 【问题描述】:

我在进程之间传递二进制数据时遇到问题。我的程序使用 popen() 打开一个到 ffmpeg 的管道,并尝试捕获输出,然后将其作为 HTTP 服务器流式传输。

我正在做这样的事情

ffmpeg -i "input_video.avi" -ab 56 -ar 44100 -b 1500000 -r 25 -s 800x600 -f flv - 

(输出文件名“-”将输出转移到标准输出)

打开后,我使用 fread() 来读取管道。

我可以阅读它并且我的程序流式传输内容,当我在浏览器上下载文件时,它完成了,但输出文件不可播放!!!

我怀疑管道打开是“非二进制”句柄,因为我用 popen("", "r") 打开它,因为 fopen 中的 "r" 用于打开文本文件。

但是我不能像 fopen() 那样用“rb”打开它,因为 popen() 不能接受“rb”。

我该如何解决这个问题?

更新:

#define FFMPEG_COMMAND "ffmpeg -i %s -ab 56 -ar 44100 -b 1500000 -r 25 -s 800x600 -f flv -"

代码开启管道

Opening_pipe(filename)

    STREAMING_HANDLE *vfp = NULL;
    char command[512] =   0 ;


    vfp = (STREAMING_HANDLE *)malloc(sizeof(STREAMING_HANDLE));
    if(NULL != vfp)
    
        sprintf(command, FFMPEG_COMMAND, filename);
        vfp->ffmpeg_pipe = popen( command, 
                                  "r" );

        if( NULL == vfp->ffmpeg_pipe )
        
            free(vfp);
            vfp = NULL;
        
        
    printf("Virt_dir_fopen : vfp => 0x%X\n", vfp);
    return vfp;

从管道读取的代码

Reading_data_from_pipe(fileHnd, buff, buflen)

    STREAMING_HANDLE *vfp = (STREAMING_HANDLE *)fileHnd;
    int ret_code;
    printf("Virt_dir_fread : Asking for %d bytes \n", buflen);
    ret_code =  fread(buf, 1, buflen, vfp->ffmpeg_pipe );
    printf("Virt_dir_fread : Returning %d bytes \n", ret_code);

    return ret_code;

关闭管道的代码(为了完整性:))

Closing_pipe(fileHnd)

    STREAMING_HANDLE *vfp = (STREAMING_HANDLE *)fileHnd;
    pclose(vfp->ffmpeg_pipe);
    free(vfp);
    return 0;

更新 2:

比较文件

1) File-1 => 通过将数据从 ffmpeg 管道输出获得

2) File-2 => 直接从ffmpeg中获取,使用相同的配置

我可以看到一些差异, 1) File-1 中的 File_Duration_field 为 0,但 File-2 有一些值。 2) File-1 中的 File_size_field 为 0 但 File-2 有一些值 3) File-1 末尾有一些额外的 18 个字节,File-2 中不存在这些字节。看起来缺少有关 file_size 和 file_duration 的详细信息。

这看起来很自然,不是吗?由于 ffmpeg 不知道输出的确切 file_size 它可能将其作为 0 放在 file-1 的标头中(但仍然想知道为什么它必须在 file-1 的持续时间中放置 0)。

我的目标是将我的视频文件转码为 flv 并同时流式传输它们,这样我就不必等待转换或必须提前转换所有内容。但是以这种方式实现这一点看起来是不可能的。我有什么办法吗???

任何帮助/建议都将非常有帮助和赞赏。

问候,

微内核

【问题讨论】:

【参考方案1】:

我猜你正在使用 linux 或其他一些 unix。在这种情况下,以二进制模式或文本模式打开内容没有区别。您根本不需要“b”标志。您的问题出在其他地方。

来自fopen 联机帮助页:

模式字符串还可以包含字母“b”作为最后一个字符或作为上述任何两个字符串中的字符之间的字符。这完全是为了与 C8​​9 兼容,没有任何效果; ''b'' 在所有符合 POSIX 的系统上都被忽略,包括 Linux。 (其他系统可能会以不同的方式处理文本文件和二进制文件,如果您对二进制文件执行 I/O 并期望您的程序可以移植到非 Unix 环境,则添加“b”可能是个好主意。)

【讨论】:

嗨,保罗,是的,我正在使用 Ubuntu。更多代码 sn-p 会有所帮助吗?使用更多代码 sn-p 更新问题。 添加了更多代码 sn-ps 显示我如何打开和使用管道句柄。 为了调试它,我可能会尝试将我的文件与从命令行运行 ffmpeg 的输出进行比较。在您阅读时打印一个十六进制转储,并将其与已知良好文件的十六进制转储进行比较。将从管道读取数据的代码联系在一起可能是错误的来源。 您好 Paul,请查看帖子中 Update-2 下的文件比较结果。对我接下来可以做什么有什么建议吗?【参考方案2】:

输出可能是没有容器的原始数据。因此,应用程序无法知道如何解释文件中的二进制数据。

您可能还想尝试使用ffmpeg pipe option 看看这是否对输出有影响。

请注意,某些格式(通常 MOV),要求输出协议 是可搜索的,所以他们会失败 管道输出协议。

【讨论】:

嗨法官,嗯,但我直接使用 ffmpeg 和该命令要求它写入文件,输出文件不会有任何问题。但是如果我将它传送到我的应用程序并存储它,就会面临问题。那么,容器不应该有问题吗? 你可能是对的。我没有查找那些 ffmpeg 选项。您是否尝试过将输出与通过 HTTP 获得的文件进行比较? 嗯,我没做过,会做,看看有什么不同。感谢您的建议:) 法官您好,请看帖子中Update-2下的文件对比结果。对我接下来可以做什么有什么建议吗? 您是否使用完全相同的方法获取文件 2?换句话说,ffmpeg -i %s -ab 56 -ar 44100 -b 1500000 -r 25 -s 800x600 -f flv - > file2.flv.

以上是关于popen 在进程之间传递二进制数据的主要内容,如果未能解决你的问题,请参考以下文章

subprocess.Popen 和缓冲的进程输出

在 python 和 c++ 之间传递二进制数据

如何在 Linux 中的进程之间交换二进制数据

进程间通信:管道

使用队列在两个 BackgroundWorker 之间传递数据

如何加快与子进程的通信