前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ffmpeg mp4解码管道输出的问题

ffmpeg mp4解码管道输出的问题

原创
作者头像
shirishiyue
发布2020-10-13 18:54:53
2.1K0
发布2020-10-13 18:54:53
举报
文章被收录于专栏:全栈码

测试代码:

代码语言:javascript
复制
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也和下面的不一样。

代码语言:javascript
复制
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的各种提示信息。。。。

代码语言:javascript
复制
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屏蔽中间提示信息,加上这个就好了:

代码语言:javascript
复制
 -loglevel quiet 

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

代码语言:javascript
复制
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;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com