【问题标题】:Using delete in a std::deque image buffer (OFX Plug-in)在 std::deque 图像缓冲区中使用 delete(OFX 插件)
【发布时间】:2013-01-09 05:12:04
【问题描述】:

我正在尝试在我的 OFX​​ 视频插件中的 std::deque 中对视频缓冲区进行编程。我想访问以前处理的图像以处理当前图像。我的想法是将处理后的图像推送到双端队列的前面,如果缓冲区超过最大大小,则从后面弹出它们。 当我尝试在从缓冲区中删除图像之前使用 delete 释放图像的内存时,插件会崩溃。我发现我可以将一张或多张图像添加到缓冲区中,然后立即删除并删除它们,没有问题。但是,如果我尝试删除在较早周期中添加的图像,它会崩溃。 插件由主类OFXPlugin和处理器类myplugin组成。 OFXPlugin 的实例会随着时间的推移而保留,但是对于要处理的每个图像,它都会创建一个 myplugin 的实例并在处理完该帧后将其销毁。

我不确定我使用双端队列的方式是否有问题,是否不允许我释放已由另一个 myplugin 实例分配的内存,或者我是否在做与非法相关的事情到 OFX API。

下面的代码显示了与问题相关的插件的摘录。它基于 OFX 支持示例。它在函数OFXPlugin::addToVBuff(OFX::Image *img, double t) 中的delete videoBuffer_.back().img; 处崩溃。我无法捕获异常,显然它是在 OFX API 中处理(忽略)的。

非常感谢您的帮助!

myplugin.h

#include "ofxsImageEffect.h"
#include "ofxsMultiThread.h"
#include "../Support/Plugins/include/ofxsProcessing.H"

#include <deque>

// Video Buffer Element
typedef struct vBuffEl
{
    OFX::Image* img;
    double  time;
} vBuffEl;

inline
bool operator==(const vBuffEl &a, const double b)
{
    return a.time == b;
}


class myplugin : public OFX::ImageProcessor {
protected :
    OFX::Image *_srcImg;
    double   _time;
    OFXPlugin *_opInstance;

public :
    // ctor
    myplugin(OFX::ImageEffect &instance)
    : OFX::ImageProcessor(instance)
    , _srcImg(0)
    , _time(0)
    {}

    void multiThreadProcessImages(OfxRectI procWindow);

    void setOFXPlugin(OFXPlugin* opInstance) {_opInstance = opInstance;}

    OFXPlugin* getOFXPlugin() {return _opInstance;}

    void setTime(double argsTime) {_time = argsTime;}

    double getTime() {return _time;}

    void setSrcImg(OFX::Image *v) {_srcImg = v;}

    OFX::Image* getSrcImg() {return _srcImg;}

};


class OFXPlugin : public OFX::ImageEffect {
protected :
    OFX::Clip *dstClip_;
    OFX::Clip *srcClip_;

    double time_;
    std::deque<vBuffEl> videoBuffer_;

public :

  /** @brief ctor */
  OFXPlugin(OfxImageEffectHandle handle);

  /** @brief dtor */
  ~OFXPlugin();

  /* Override the render */
  virtual void render(const OFX::RenderArguments &args);

  /* get the source Clip */
  OFX::Clip* getSrcClip();

  /* get the current time */
  double getTime();

  /* set up and run a processor */
  void setupAndProcess(myplugin &, const OFX::RenderArguments &args);

  /* add to video buffer */
  void addToVBuff(OFX::Image *img, double t);

  /* fetch a dst image from buffer */
  void fetchDstImageBuff(double t, OFX::Image* &img, bool &buff);
};

myplugin.cpp

#include "myplugin.h"
#include <algorithm>


void myplugin::multiThreadProcessImages(OfxRectI procWindow)
{
    // Do some filtering of the source image and store result in destination image
    myfiltering(_dstImg, _srcImg, procWindow);

    // add to buffer
    _opInstance->addToVBuff(_dstImg, _time);

}


/* set up and run a processor */
void
OFXPlugin::setupAndProcess(myplugin &processor, const OFX::RenderArguments &args)
{
  // get a dst image
  std::auto_ptr<OFX::Image> dst(dstClip_->fetchImage(args.time));
  OFX::BitDepthEnum dstBitDepth       = dst->getPixelDepth();
  OFX::PixelComponentEnum dstComponents  = dst->getPixelComponents();

  // fetch main input image
  std::auto_ptr<OFX::Image> src(srcClip_->fetchImage(args.time));

  // set the images
  processor.setDstImg(dst.get());
  processor.setSrcImg(src.get());

  // set the render window
  processor.setRenderWindow(args.renderWindow);

  // set time
  processor.setTime(args.time);
  time_ = args.time;

  // set OFXPlugin instance
  processor.setOFXPlugin(this);

  // Call the base class process member, this will call the derived templated process code
  processor.process();
}


OFX::Clip* OFXPlugin::getSrcClip()
{
    return srcClip_;
}

/* get the current time */
double
OFXPlugin::getTime()
{
    return time_;
}

// the overridden render function
void
OFXPlugin::render(const OFX::RenderArguments &args)
{
    try {
          myplugin fred(*this);
          setupAndProcess(fred, args);
    } catch (...) {
      outputMessage("ERROR: An unknown error happened!");
    }
}

/* add to video buffer */
void
OFXPlugin::addToVBuff(OFX::Image *img, double t)
{
    try {
        // if frame already exists in buffer, remove
        std::deque<vBuffEl>::iterator it;
        it = find(videoBuffer_.begin(), videoBuffer_.end(), t);
        if(it != videoBuffer_.end())
        {
            delete it->img;
            videoBuffer_.erase(it);
        }

        // add new frame to the front
        vBuffEl e;
        e.time = t;
        e.img = new OFX::Image(img->getPropertySet().propSetHandle());
        memcpy(e.img, img, sizeof(img));
        videoBuffer_.push_front(e);

        // remove elements at the end, if the buffer exceeds the max size
        int LASTIMG_ARRAY_SIZE = 10;
        while(videoBuffer_.size() > LASTIMG_ARRAY_SIZE)
        {
            delete videoBuffer_.back().img;
            videoBuffer_.erase(--(videoBuffer_.end()));
        }
    } catch (...) {
      outputMessage("ERROR: An unknown error happened!");
    }
}

/* fetch a dst image from buffer */
void
OFXPlugin::fetchDstImageBuff(double t, OFX::Image* &img, bool &buff)
{
    try {
        std::deque<vBuffEl>::iterator it;
        it = find(videoBuffer_.begin(), videoBuffer_.end(), t);
        if(it != videoBuffer_.end())
        {
            img = it->img;      // return buffered dst image
            buff = true;
        }
        else
        {
            img = getSrcClip()->fetchImage(t);  // fetch and return src image
            buff = false;
        }
    } catch (...) {
      outputMessage("ERROR: An unknown error happened!");
    }
}

【问题讨论】:

    标签: c++ video ofx


    【解决方案1】:

    声明

    memcpy(e.img, img, sizeof(img));
    

    没有按照你的预期去做。

    指针的sizeof 操作返回指针的大小,而不是它指向的内容。这意味着在这种情况下,您只复制 4 或 8 个字节(取决于您是在 32 位还是 64 位平台上)。

    然而,memcpy 调用中隐藏着另一个更糟糕的问题。如果OFX::Image 包含数据成员指针,则复制数据将复制指针而不是数据。是浅拷贝,不是深拷贝。这就是 C++ 具有复制构造函数和复制赋值运算符的原因。

    你应该做的是一个简单的作业,希望OFX::Image跟随the rule of three

    *e.img = *img;
    

    【讨论】:

    • 非常感谢您的提示,我在代码中更改了它。但是,删除的问题仍然存在。即使我完全离开 *e.img = *img;memcpy(e.img, img, sizeof(img)); 行,在缓冲区中只存储空图像,它也会发生!
    • @StefanScheidegger 那么它可能是OFX::Image 类中的一个错误。尝试制作一个展示此错误的最小示例,并将其报告给创建者。有关一些提示,请参阅sscce.org。也不是说这样做时,您可能会发现这是代码中的错误,因此请学习如何自己修复它。
    • 非常感谢您的支持。在制作 sscce 时,我发现了问题:new OFX::Image(img-&gt;getPropertySet().propSetHandle()); 实际上并没有为新图像分配内存,而是返回一个带有指向现有图像数据的指针的 OFX​​::Image。当我试图在以后的循环中删除它时,该图像不再存在于内存中。
    猜你喜欢
    • 2017-08-08
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 2020-05-14
    • 2018-05-31
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    相关资源
    最近更新 更多