在Windows中使用OpenCV 2.4.4和FFmpeg

aar*_*rkk 7 windows opencv ffmpeg codec

我知道在OpenCV中还有其他问题涉及FFmpeg的使用,但是大多数问题似乎已经过时了.

通过在CMake中打开makefile,我可以验证我已经WITH_FFMPEG开启了标志.我的OpenCV版本的输出文件夹包含一个bin文件夹,其中包含文件夹DebugRelease文件夹,每个文件夹都包含一个名为的.dll文件的副本opencv_ffmpeg244.dll.当我创建一个VideoWriter并验证指向.dll的函数指针是否正确填充时,我可以进入OpenCV的源代码.这似乎很有效.

如果我使用CV_FOURCC_PROMPT的FOURCC代码,则以下编解码器正常工作:

  • 微软视频1
  • 英特尔IYUV编解码器
  • 罗技视频(I420)
  • Radius的Cinepak编解码器
  • 全帧(未压缩)

以下编解码器无法正常工作(即生成0kb视频文件):

  • 微软RLE

如果我的理解是正确的,使用FFMPEG应该允许使用一大堆新的编解码器(x264,DIVX,XVID等)编码视频.但是,这些都不会出现在提示中.使用宏通过FOURCC代码手动设置它们CV_FOURCC(...)也不起作用.例如,使用此:CV_FOURCC('X','2','6','4')生成消息:

Could not find encoder for codec id 28: Encoder not found

并制作一个大小为0kb的视频文件.

使用此方法:不CV_FOURCC('X','V','I','D')产生任何错误消息,并生成6kb的视频文件,该文件无法在Windows Media Player或VLC中播放.

我尝试从Xvid.org手动下载Xvid编解码器.安装完成后,它会出现在提示符下的VFW选项下,并且编码正常.所以它接近一个解决方案,但如果我尝试直接设置FOURCC代码,它仍然会失败,如上所述!我每次都必须从提示中选择它.是不是FFmpeg应该包含一大堆编解码器?如果是这样,为什么我手动下载编解码器而不是使用FFmpeg内置的编解码器?

我在这里错过了什么?有没有办法检查FFMPEG是"启用"的?似乎提示中唯一可用的编解码器是VFW编解码器,而不是FFMPEG编解码器.在.dll已建成和正坐在同一文件夹中的可执行文件,但它似乎它不以任何方式使用.

这里有很多相关的问题.希望找到一些了解OpenCV中FFmpeg实现的人,并了解所有这些部分是如何组合在一起的.

Zaw*_*Lin 1

单独运行 ffmpeg 和您的应用程序并使用管道数据传输图像怎么样?

将视频输入 opencv 程序,

ffmpeg -i input.mp4 -vcodec mjpeg -f image2pipe -pix_fmt yuvj420p -r 10 -|program.exe
Run Code Online (Sandbox Code Playgroud)

以及录音等

program.exe|ffmpeg -r 10 -vcodec mjpeg -f image2pipe -i - -vcodec h264 output.mp4
Run Code Online (Sandbox Code Playgroud)

program.exe 应该能够从标准输入读取串联的 jpeg 图像并将其写入标准输出,并且上述工作流程将起作用。这是一些从标准输入读取并显示视频的代码。

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;

#if defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
    || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)
# include <io.h>
# include <fcntl.h>
# define SET_BINARY_MODE(handle) setmode(handle, O_BINARY)
#else
# define SET_BINARY_MODE(handle) ((void)0)
#endif

#define BUFSIZE 10240
int main ( int argc, char **argv )
{

    SET_BINARY_MODE(fileno(stdin));
    std::vector<char> data;
    bool skip=true;
    bool imgready=false;
    bool ff=false;
    int readbytes=-1;
    while (1)
    {   
        char ca[BUFSIZE];
        uchar c;
        if (readbytes!=0)
        {
            readbytes=read(fileno(stdin),ca,BUFSIZE);
            for(int i=0;i<readbytes;i++)
            {
                c=ca[i];
                if(ff && c==(uchar)0xd8)
                {
                    skip=false;
                    data.push_back((uchar)0xff);
                }
                if(ff && c==0xd9)
                {
                    imgready=true;
                    data.push_back((uchar)0xd9);
                    skip=true;
                }
                ff=c==0xff;
                if(!skip)
                {
                    data.push_back(c);
                }
                if(imgready)
                {
                    if(data.size()!=0)
                    {
                        cv::Mat data_mat(data);
                        cv::Mat frame(imdecode(data_mat,1));

                        imshow("frame",frame);
                        waitKey(1);
                    }else
                    {
                        printf("warning");
                    }
                    imgready=false;
                    skip=true;
                    data.clear();
                }
            }
        }
        else
        {
            throw std::string("zero byte read");
        }
    }
}    
Run Code Online (Sandbox Code Playgroud)

写入输出这样的东西应该可以工作。

void saveFramestdout(cv::Mat& frame,int compression)
{
    SET_BINARY_MODE(fileno(stdout));
    cv::Mat towrite;
    if(frame.type()==CV_8UC1)
    {
        cvtColor(frame,towrite,CV_GRAY2BGR);
    }else if(frame.type()==CV_32FC3)
    {
        double minVal, maxVal;
        minMaxLoc(frame, &minVal, &maxVal);
        frame.convertTo(towrite, CV_8U, 255.0/(maxVal - minVal), -minVal * 255.0/(maxVal - minVal));
    }
    else{
        towrite=frame;
    }
    std::vector<uchar> buffer;
    std::vector<int> param(2);
    param[0]=CV_IMWRITE_JPEG_QUALITY;
    param[1]=compression;//default(95) 0-100
    imencode(".jpg",towrite,buffer,param);
    uchar* a = &buffer[0];
    ::write(fileno(stdout),a,buffer.size());
}
Run Code Online (Sandbox Code Playgroud)

上述问题是 jpeg 的多重编码/解码,可以通过链接 libjpeg-turbo 部分解决。或者可以去弄清楚如何直接从 ffmpeg 和 opencv 传递原始数据。就我而言,这是完全可以接受的,因为大部分开销都在编码或视频处理中。