• Firstly, we need to create a directory for our module under modules directory. Copy folder dummy and name it imagemagick
  • We can use the module with name DummyModule, but for any real module, we probably want to give some beeter name. So the next few steps are optional, but recommended:
    • Rename DummyModule.cpp to ImageMagickSource.cpp and DummyModule.h to ImageMagickSource.h
    • Change DummyModule.h in #include in ImageMagickSource.cpp to ImageMagickSource.h
    • Rename the class: change all occurences of DummyModule class to ImageMagickSource
  • We're gonna use ImageMagick library, specifically it's C++ bindings called Magick++. CMake know about this packafe, so it's easy to add test for in. We add following line into CMakeLists.txt in modules directory:
find_package(ImageMagick COMPONENTS Magick++)
  • If we found ImageMagick, we can tell cmake to compile our module. So we add subdirectory imagemagic, if the test was successfull:
IF(${ImageMagick_Magick++_FOUND})
add_subdirectory(imagemagick)
ENDIF()
  • Now we have to edit CMakeLists.txt in imagemagick directory: change SET(MODULE dummy) to SET(MODULE imagemagick_source) and filenames in SET(SRC…. to ImageMagickSource.*
  • And lastly, we add the library to CMakeLists.txt in imagemagick directory: add following line for imagemagick includes:
include_directories(${ImageMagick_Magick++_INCLUDE_DIR})

and change linking to this:

target_link_libraries(${MODULE} ${LIBNAME} ${ImageMagick_Magick++_LIBRARY})
  • Now the module should compile under new name and link with libMagick++.so
  • So we can finally move to the code. Let's change the header file like this:
ImageMagickSource.h
#ifndef DUMMYMODULE_H_
#define DUMMYMODULE_H_
 
#include "yuri/io/BasicIOThread.h"
 
namespace yuri {
namespace imagemagick_module {
using yuri::log::Log;
using yuri::config::Parameter;
using yuri::config::Parameters;
using yuri::io::pThreadBase;
 
class ImageMagickSource: public yuri::io::BasicIOThread
{
public:
	IO_THREAD_GENERATOR_DECLARATION
	static shared_ptr<Parameters> configure();
	virtual ~ImageMagickSource();
private:
	ImageMagickSource(Log &log_,pThreadBase parent,Parameters &parameters);
	virtual bool step();
	virtual bool set_param(Parameter& param);
};
 
} /* namespace dummy_module */
} /* namespace yuri */

The only difference between this and the DummyModule.h is (except for the name) that we removed the attribute dummy_name.

Not for the cpp file:

ImageMagickSource.cpp
#include "ImageMagickSource.h"
#include "yuri/config/RegisteredClass.h"
#include "Magick++.h"
#include <map>
 
namespace yuri {
namespace imagemagick_module {
 
REGISTER("imagemagick_source",ImageMagickSource)
 
IO_THREAD_GENERATOR(ImageMagickSource)
 
using namespace yuri::io;
 
shared_ptr<Parameters> ImageMagickSource::configure()
{
	shared_ptr<Parameters> p = BasicIOThread::configure();
	p->set_description("Image loader based on ImageMagick.");
	p->set_max_pipes(1,1);
	return p;
}
 
ImageMagickSource::ImageMagickSource(Log &log_,pThreadBase parent,Parameters &parameters):
BasicIOThread(log_,parent,1,1,std::string("ImageMagickSource"))
{
	IO_THREAD_INIT("ImageMagickSource")
}
 
ImageMagickSource::~ImageMagickSource()
{
}
 
bool ImageMagickSource::step()
{
	pBasicFrame frame = in[0]->pop_frame();
	if (!frame) return true;
	if (frame->get_planes_count()>1) {
		log[warning] << "Input frame has more than 1 plane, ignoring them\n";
	}
	try {
		Magick::Blob blob(PLANE_RAW_DATA(frame,0),PLANE_SIZE(frame,0));
		Magick::Image image(blob);
		image.modifyImage();
		yuri::size_t width = image.columns();
		yuri::size_t height = image.rows();
		log[debug] << "Loaded image " << width << "x" <<height <<"\n";
		pBasicFrame out_frame = allocate_empty_frame(YURI_FMT_RGB24,width,height);
		image.write(0,0,width,height,"RGB",Magick::CharPixel,PLANE_RAW_DATA(out_frame,0));
		push_raw_video_frame(0,out_frame);
	}
	catch (std::exception& e) {
		log[error] << "Exception during decoding: " << e.what() << "\n";
	}
	return true;
}
bool ImageMagickSource::set_param(Parameter& param)
{
	return BasicIOThread::set_param(param);
}
 
} /* namespace dummy_module */
} /* namespace yuri */

The only relevant changes are in the step() method.

  • First we get input frame. If there's no frame available, we return. Always return true, unless some unrecoverable fatal error occurred. Returning false will most often terminate the program.
  • We support only frames with single plane, so we print a warning when we get more.
  • Then it's just using API of Magick++. Note how we use PLANE_RAW_DATA and PLANE_SIZE to get data and size of first (index 0) plane in the incoming frame.
  • Next important thing is the call to allocate_empty_frame, that allocates just enough data for a frame with given resolution and format.
  • Lastly, we call push_raw_video_frame to push the frame to the output pipe.

That's all, this is working code for imagemagick_source module! Look at the actual version in source distribution, there are some minor enhancements, but this was the first version.

 
yuri/module/tutorial.txt · Last modified: 2013/02/17 04:56 by neneko
 
Except where otherwise noted, content on this wiki is licensed under the following license: GNU Free Documentation License 1.3
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki