修改
我想我明白这里发生了什么,但不知道怎么回事。根据每次使用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