ffmpeg mp4解码管道输出的问题

时间:2022-07-26
本文章向大家介绍ffmpeg mp4解码管道输出的问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

测试代码:

HANDLE hReadPipe, hWritePipe;
SECURITY_ATTRIBUTES sa;
int testFfmpegPipe()        // 测试ffmpeg管道io
{
    char cmdString[200]{ "ffmpeg -i D:\vc\images\small.mp4 -f image2pipe -pix_fmt bgr24 -vcodec rawvideo -" };

    // 创建管道
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;             //使用系统默认的安全描述符
    sa.bInheritHandle = TRUE;                   //一定要为TRUE,不然句柄不能被继承。
    CreatePipe(&hReadPipe, &hWritePipe, &sa, 0); //创建pipe内核对象,设置好hReadPipe,hWritePipe.

    // 创建dos子进程
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    si.cb = sizeof(STARTUPINFO);
    GetStartupInfo(&si);
    si.hStdError = hWritePipe; //设定其标准错误输出为hWritePipe
    si.hStdOutput = hWritePipe; //设定其标准输出为hWritePipe
    si.wShowWindow = SW_HIDE;
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    if (!CreateProcess(NULL, cmdString
        , NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi)) {
        //MessageBox("Error on CreateProcess()");
        return 1;
    }
    CloseHandle(hWritePipe);

    Mat rgba = Mat::zeros(cv::Size(560,320), CV_8UC3);
    const uint32_t framebytes = 560 * 320 * 3 * 1.1;
    char buffer[framebytes] = { 0 };
    DWORD bytesRead;
    uint32_t a = 0;
    while (true) {
        if (ReadFile(hReadPipe, buffer, framebytes, &bytesRead, NULL) == NULL)//从hReadPipe中读出数据.
            break;
        if (bytesRead<5000) {
            cout << buffer << endl;
        }
        cout << bytesRead << endl;
    }

    return 0;
}

视频是 560*320,166帧

上面主进程读取的字节数如下:共,2834行,与理想的166帧166行相差甚远,每帧560*320*3=537600也和下面的不一样。

44
1686
67
701
17
93
34
391
32768
32768
32768
32768
32768
32768
32768
32768
32768
32768
32768
32768
32768
32768
32768
32768
13312
...
32768
32768
32768
32768
13312
100
104

开头和结果这些小字节的都是解码的什么鬼哦

打印出来才发现,是ffmpeg的各种提示信息。。。。

ffmpeg version 4.3.1-full_build-www.gyan.dev
 Copyright (c) 2000-2020 the FFmpeg developers

  built with gcc 10.2.0 (Rev1, Built by MSYS2 project)

  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libwavpack --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint

  libavutil      56. 51.100 / 56. 51.100

  libavcodec     58. 91.100 / 58. 91.100

  libavformat    58. 45.100 / 58. 45.100

  libavdevice    58. 10.100 / 58. 10.100

  libavfilter     7. 85.100 /  7. 85.100

  libswscale      5.  7.100 /  5.  7.100

  libswresample   3.  7.100 /  3.  7.100

  libpostproc    55.  7.100 / 55.  7.100

把头尾的这些小字节去掉,总数刚好对的上,看来这个buffer是固定了32768=2^15不够一帧,要自己循环处理。

上面16个32768 + 13312 刚好等于一帧大小。

好了,需要ffmpeg屏蔽中间提示信息,加上这个就好了:

 -loglevel quiet 

加上帧大小,循环读出,满足一帧容量后输出,最终代码如下:

HANDLE hReadPipe, hWritePipe;
SECURITY_ATTRIBUTES sa;
int testFfmpegPipe()        // 测试ffmpeg管道io
{
    char cmdString[200]{ "ffmpeg -loglevel quiet -i D:\vc\images\small.mp4 -f image2pipe -pix_fmt bgr24 -vcodec rawvideo -" };

    // 创建管道
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;             //使用系统默认的安全描述符
    sa.bInheritHandle = TRUE;                   //一定要为TRUE,不然句柄不能被继承。
    CreatePipe(&hReadPipe, &hWritePipe, &sa, 0); //创建pipe内核对象,设置好hReadPipe,hWritePipe.

    // 创建dos子进程
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    si.cb = sizeof(STARTUPINFO);
    GetStartupInfo(&si);
    si.hStdError = hWritePipe; //设定其标准错误输出为hWritePipe
    si.hStdOutput = hWritePipe; //设定其标准输出为hWritePipe
    si.wShowWindow = SW_HIDE;
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    if (!CreateProcess(NULL, cmdString
        , NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi)) {
        //MessageBox("Error on CreateProcess()");
        return 1;
    }
    CloseHandle(hWritePipe);

    Mat rgba = Mat::zeros(cv::Size(560,320), CV_8UC3);
    const uint32_t framebytes = 560 * 320 * 3;
    char buffer[framebytes] = { 0 };
    uint32_t readCount = 0;
    DWORD bytesRead;
    
    while (true) {
        if (ReadFile(hReadPipe, buffer, framebytes, &bytesRead, NULL) == NULL) { //从hReadPipe中读出数据.
            break;
        }
        memcpy(rgba.data + readCount, buffer, bytesRead);
        readCount += bytesRead;
        if (readCount == framebytes) {  // 拿到完整一帧了
            cout << "frame finished." << endl;
            readCount = 0;
            waitKey(100);
            imshow("frame", rgba);
            //imwrite("D:\vc\images\xx.bmp", rgba);
        }
    }

    return 0;
}