cv :: VideoWriter是双极的

时间:2011-02-23 22:09:06

标签: c++ compiler-construction assembly opencv memory-alignment

修改

我想我明白这里发生了什么,但不知道怎么回事。根据每次使用ffmpeg时显示的消息(下面的消息),OpenCV 2.1附带的libavcoded不会对齐堆栈变量。根据在调用ffmpeg之前代码中的局部变量的位置,变量将会或者不会在libavcodec所期望的位置。

  

编译器没有对齐堆栈变量。 Libavcodec被错误编译   并且可能非常慢或崩溃。这不是libavcodec中的错误,   但在编译器中。您可以尝试使用gcc> = 4.2重新编译。   不要向FFmpeg开发人员报告崩溃事件。

为了能够完全解释和理解这种情况的发生,需要更好地理解我目前拥有的x86程序集。也许在这个论坛上有人可以对这种情况有所了解吗?

以下是一个更简洁的源代码版本,用于演示此问题:

#include <opencv/highgui.h>
#include <iostream>

int main(int argc, char* argv[])
{
    if (argc < 3) { return -1; }

    cv::VideoCapture cap(argv[1]);

    std::string str = argv[2];

    int fourcc = CV_FOURCC('j', 'p', 'e', 'g');
    double fps = cap.get(CV_CAP_PROP_FPS);
    int width  = int(cap.get(CV_CAP_PROP_FRAME_WIDTH));
    int height = int(cap.get(CV_CAP_PROP_FRAME_HEIGHT));

    // COMMENT OUT THIS BLOCK TO MAKE THE PROGRAM CRASH
    // This code creates a variable on the stack and preforms
    // some operations with it.  This somehow alligns the memory
    // for the call "cv::VideoWriter vw(...)" in a way that
    // libavcoded expects and makes the call "vw << img" not crash.
    // Note that these variables are never used outside of this block.
    char * name_c = new char[100];
    strcpy(name_c, str.c_str());
    delete[] name_c;
    // END COMMENT OUT THIS BLOCK TO MAKE THE PROGRAM CRASH

    cv::VideoWriter vw(
        str,
        fourcc,
        fps,
        cv::Size(width, height));

    int fnum = 0;
    cv::Mat img;
    while(cap.grab() && cap.retrieve(img) && fnum < 30)
    {
        cv::imshow("img", img);
        vw << img;
        ++fnum;
    }

    return 0;
}

当块未被注释掉时,对视频编写器的调用将编译到此程序集中:

cv::VideoWriter vw(
        str,
        fourcc,
        fps,
        cv::Size(width, height));
00401290  fld         qword ptr [esp+50h] 
00401294  add         esp,4 
00401297  push        1    
00401299  sub         esp,8 
0040129C  mov         eax,esp 
0040129E  mov         dword ptr [esp+60h],esp 
004012A2  sub         esp,8 
004012A5  fstp        qword ptr [esp] 
004012A8  mov         dword ptr [eax],edi 
004012AA  mov         dword ptr [eax+4],ebp 
004012AD  push        6765706Ah 
004012B2  lea         eax,[esp+0A8h] 
004012B9  push        eax  
004012BA  lea         ecx,[esp+5Ch] 
004012BE  call        cv::VideoWriter::VideoWriter (401454h) 

...

vw << img;
00401353  mov         edx,dword ptr [esp+40h] 
00401357  mov         eax,dword ptr [edx+0Ch] 
0040135A  lea         ecx,[esp+20h] 
0040135E  push        ecx  
0040135F  lea         ecx,[esp+44h] 
00401363  call        eax  
00401365  lea         ecx,[esp+14h] 

当块被注释掉时,程序集是这样的:

cv::VideoWriter vw(
        str,
        fourcc,
        fps,
        cv::Size(width, height));
00401253  fld         qword ptr [esp+44h] 
00401257  push        1    
00401259  sub         esp,8 
0040125C  mov         ecx,esp 
0040125E  mov         dword ptr [esp+58h],esp 
00401262  sub         esp,8 
00401265  fstp        qword ptr [esp] 
00401268  mov         dword ptr [ecx+4],eax 
0040126B  push        6765706Ah 
00401270  lea         eax,[esp+0A0h] 
00401277  mov         dword ptr [ecx],edi 
00401279  push        eax  
0040127A  lea         ecx,[esp+54h] 
0040127E  call        cv::VideoWriter::VideoWriter (401454h) 

...

vw << img;
00401313  mov         edx,dword ptr [esp+38h] 
00401317  mov         eax,dword ptr [edx+0Ch] 
0040131A  lea         ecx,[esp+18h] 
0040131E  push        ecx  
0040131F  lea         ecx,[esp+3Ch] 
00401323  call        eax  
00401325  lea         ecx,[esp+0Ch] 

主要区别在于对cv::VideoWriter vw()的调用:

       // Working (with extra block)                       Crashes (without extra block)
    00401290  fld         qword ptr [esp+50h]      00401253  fld         qword ptr [esp+44h] 
*** 00401294  add         esp,4                  
    00401297  push        1                        00401257  push        1 
    ...
    004012A5  fstp        qword ptr [esp]          00401265  fstp        qword ptr [esp] 
*** 004012A8  mov         dword ptr [eax],edi      00401268  mov         dword ptr [ecx+4],eax
*** 004012AA  mov         dword ptr [eax+4],ebp    0040126B  push        6765706Ah 
*** 004012AD  push        6765706Ah                00401270  lea         eax,[esp+0A0h]
    004012B2  lea         eax,[esp+0A8h]           00401277  mov         dword ptr [ecx],edi 
    004012B9  push        eax                      00401279  push        eax  

这如何改变堆栈变量的对齐方式?为什么编译器会在这两种情况下为同一个调用生成不同的代码?

同样,我使用OpenCV 2.1和Visual Studio 2008在Windows XP上运行。

结束编辑

ORIGINAL

为什么这个简单的小程序在写入时会崩溃,但如果取消注释该块(并注释掉save(...)语句),则可以正常工作?

当您尝试写入vw时实际出现问题 - 它构造得很好,在文件系统中创建指定的文件(如果没有正确传递文件名,则不会这样做),以及当你第一次尝试写vw << img时,只会崩溃。

但是,如果您在main函数中执行所有操作,则输出文件将按原样打开,写入和关闭。

#include <opencv/highgui.h>

void save(const std::string & str, cv::VideoCapture & cap)
{
    int fourcc = int(cap.get(CV_CAP_PROP_FOURCC));
    double fps = cap.get(CV_CAP_PROP_FPS);
    int width  = int(cap.get(CV_CAP_PROP_FRAME_WIDTH));
    int height = int(cap.get(CV_CAP_PROP_FRAME_HEIGHT));

    cv::VideoWriter  vw(
        str,
        fourcc,
        fps,
        cv::Size(width, height));

    int fnum = 0;
    cv::Mat img;
    while(cap.grab() && cap.retrieve(img) && fnum < 30)
    {
        cv::imshow("img", img);
        cv::waitKey(1);
        vw << img;
        ++fnum;
    }
}

int main(int argc, char* argv[])
{
    if (argc < 3) { return -1; }

    cv::VideoCapture cap(argv[1]);

    std::string str = argv[2];
    save(str, cap);
/*
    int fourcc = int(cap.get(CV_CAP_PROP_FOURCC));
    double fps = cap.get(CV_CAP_PROP_FPS);
    int width  = int(cap.get(CV_CAP_PROP_FRAME_WIDTH));
    int height = int(cap.get(CV_CAP_PROP_FRAME_HEIGHT));

    cv::VideoWriter  vw(
        str,
        fourcc,
        fps,
        cv::Size(width, height));

    int fnum = 0;
    cv::Mat img;
    while(cap.grab() && cap.retrieve(img) && fnum < 30)
    {
        cv::imshow("img", img);
        cv::waitKey(1);
        vw << img;
        ++fnum;
    }
*/
    return 0;
}

我正在使用OpenCV 2.1和Visual Studio 2008在Windows XP上运行。

END ORIGINAL

0 个答案:

没有答案