Frage

I'm trying to program a video buffer in a std::deque in my OFX video plug-in. I would like to access previously processed images in order to process the current image. My idea is to push processed images to the front of the deque and pop them from the back if the buffer exceeds the maximum size. The plug-in crashes when I try to free the memory of an image using delete before removing it from the buffer. I found out that I can add one or several images to the buffer and delete and remove them immediately afterwards with no problem. However, if I try to delete an image which has been added in an earlier cycle, it crashes. The plug-in consists of the main class OFXPlugin and the processor class myplugin. The instance of OFXPlugin stays over time, but for every image to be processed it creates an instance of myplugin and destroys it after processing that frame.

I'm not sure if I'm doing something wrong in the way I use the deque, if I'm not allowed to free memory which has been allocated by another instance of myplugin or if I'm doing something illegal related to the OFX API.

The Code below shows the extracts of the plug-in related to the problem. It's based on the OFX Support examples. It crashes at delete videoBuffer_.back().img; in the function OFXPlugin::addToVBuff(OFX::Image *img, double t). I cannot catch an exception, apparently it is handled (ignored) in the OFX API.

Thanks a lot for your help!

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!");
    }
}
War es hilfreich?

Lösung

The statement

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

doesn't do what you expect it to.

The sizeof operation of a pointer returns the size of the pointer, not what it points to. This means that in this case, you are only copying 4 or 8 bytes (depending on if you are on a 32 or 64 bit platform).

However, there is another worse problem hidden in that memcpy call. If the OFX::Image contains data member pointers, copying the data will copy the pointers and not the data. It's a shallow copy, not a deep copy. This is a reason C++ has copy constructors and copy assignment operators.

What you should to is a simple assignment, and hope that OFX::Image follows the rule of three:

*e.img = *img;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top