Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/gameengine/VideoTexture/VideoFFmpeg.cpp')
-rw-r--r--source/gameengine/VideoTexture/VideoFFmpeg.cpp927
1 files changed, 927 insertions, 0 deletions
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
new file mode 100644
index 00000000000..02798c7e596
--- /dev/null
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
@@ -0,0 +1,927 @@
+/* $Id$
+-----------------------------------------------------------------------------
+This source file is part of VideoTexture library
+
+Copyright (c) 2007 The Zdeno Ash Miklas
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307, USA, or go to
+http://www.gnu.org/copyleft/lesser.txt.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef WITH_FFMPEG
+
+// INT64_C fix for some linux machines (C99ism)
+#define __STDC_CONSTANT_MACROS
+#include <stdint.h>
+
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include <string>
+
+#include "Exception.h"
+#include "VideoFFmpeg.h"
+
+
+// default framerate
+const double defFrameRate = 25.0;
+// time scale constant
+const long timeScale = 1000;
+
+// macro for exception handling and logging
+#define CATCH_EXCP catch (Exception & exp) \
+{ exp.report(); m_status = SourceError; }
+
+extern "C" void do_init_ffmpeg();
+
+// class RenderVideo
+
+// constructor
+VideoFFmpeg::VideoFFmpeg (HRESULT * hRslt) : VideoBase(),
+m_codec(NULL), m_formatCtx(NULL), m_codecCtx(NULL),
+m_frame(NULL), m_frameDeinterlaced(NULL), m_frameRGB(NULL), m_imgConvertCtx(NULL),
+m_deinterlace(false), m_preseek(0), m_videoStream(-1), m_baseFrameRate(25.0),
+m_lastFrame(-1), m_eof(false), m_curPosition(-1), m_startTime(0),
+m_captWidth(0), m_captHeight(0), m_captRate(0.f), m_isImage(false)
+{
+ // set video format
+ m_format = RGB24;
+ // force flip because ffmpeg always return the image in the wrong orientation for texture
+ setFlip(true);
+ // construction is OK
+ *hRslt = S_OK;
+}
+
+// destructor
+VideoFFmpeg::~VideoFFmpeg ()
+{
+}
+
+
+// release components
+bool VideoFFmpeg::release()
+{
+ // release
+ if (m_codecCtx)
+ {
+ avcodec_close(m_codecCtx);
+ m_codecCtx = NULL;
+ }
+ if (m_formatCtx)
+ {
+ av_close_input_file(m_formatCtx);
+ m_formatCtx = NULL;
+ }
+ if (m_frame)
+ {
+ av_free(m_frame);
+ m_frame = NULL;
+ }
+ if (m_frameDeinterlaced)
+ {
+ MEM_freeN(m_frameDeinterlaced->data[0]);
+ av_free(m_frameDeinterlaced);
+ m_frameDeinterlaced = NULL;
+ }
+ if (m_frameRGB)
+ {
+ MEM_freeN(m_frameRGB->data[0]);
+ av_free(m_frameRGB);
+ m_frameRGB = NULL;
+ }
+ if (m_imgConvertCtx)
+ {
+ sws_freeContext(m_imgConvertCtx);
+ m_imgConvertCtx = NULL;
+ }
+ m_codec = NULL;
+ m_status = SourceStopped;
+ return true;
+}
+
+
+// set initial parameters
+void VideoFFmpeg::initParams (short width, short height, float rate, bool image)
+{
+ m_captWidth = width;
+ m_captHeight = height;
+ m_captRate = rate;
+ m_isImage = image;
+}
+
+int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVFormatParameters *formatParams)
+{
+ AVFormatContext *formatCtx;
+ int i, videoStream;
+ AVCodec *codec;
+ AVCodecContext *codecCtx;
+
+ if(av_open_input_file(&formatCtx, filename, inputFormat, 0, formatParams)!=0)
+ return -1;
+
+ if(av_find_stream_info(formatCtx)<0)
+ {
+ av_close_input_file(formatCtx);
+ return -1;
+ }
+
+ /* Find the first video stream */
+ videoStream=-1;
+ for(i=0; i<formatCtx->nb_streams; i++)
+ {
+ if(formatCtx->streams[i] &&
+ get_codec_from_stream(formatCtx->streams[i]) &&
+ (get_codec_from_stream(formatCtx->streams[i])->codec_type==CODEC_TYPE_VIDEO))
+ {
+ videoStream=i;
+ break;
+ }
+ }
+
+ if(videoStream==-1)
+ {
+ av_close_input_file(formatCtx);
+ return -1;
+ }
+
+ codecCtx = get_codec_from_stream(formatCtx->streams[videoStream]);
+
+ /* Find the decoder for the video stream */
+ codec=avcodec_find_decoder(codecCtx->codec_id);
+ if(codec==NULL)
+ {
+ av_close_input_file(formatCtx);
+ return -1;
+ }
+ codecCtx->workaround_bugs = 1;
+ if(avcodec_open(codecCtx, codec)<0)
+ {
+ av_close_input_file(formatCtx);
+ return -1;
+ }
+
+#ifdef FFMPEG_OLD_FRAME_RATE
+ if(codecCtx->frame_rate>1000 && codecCtx->frame_rate_base==1)
+ codecCtx->frame_rate_base=1000;
+ m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
+#else
+ m_baseFrameRate = av_q2d(formatCtx->streams[videoStream]->r_frame_rate);
+#endif
+ if (m_baseFrameRate <= 0.0)
+ m_baseFrameRate = defFrameRate;
+
+ m_codec = codec;
+ m_codecCtx = codecCtx;
+ m_formatCtx = formatCtx;
+ m_videoStream = videoStream;
+ m_frame = avcodec_alloc_frame();
+ m_frameDeinterlaced = avcodec_alloc_frame();
+ m_frameRGB = avcodec_alloc_frame();
+
+ // allocate buffer if deinterlacing is required
+ avpicture_fill((AVPicture*)m_frameDeinterlaced,
+ (uint8_t*)MEM_callocN(avpicture_get_size(
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width, m_codecCtx->height),
+ "ffmpeg deinterlace"),
+ m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height);
+
+ // check if the pixel format supports Alpha
+ if (m_codecCtx->pix_fmt == PIX_FMT_RGB32 ||
+ m_codecCtx->pix_fmt == PIX_FMT_BGR32 ||
+ m_codecCtx->pix_fmt == PIX_FMT_RGB32_1 ||
+ m_codecCtx->pix_fmt == PIX_FMT_BGR32_1)
+ {
+ // allocate buffer to store final decoded frame
+ m_format = RGBA32;
+ avpicture_fill((AVPicture*)m_frameRGB,
+ (uint8_t*)MEM_callocN(avpicture_get_size(
+ PIX_FMT_RGBA,
+ m_codecCtx->width, m_codecCtx->height),
+ "ffmpeg rgba"),
+ PIX_FMT_RGBA, m_codecCtx->width, m_codecCtx->height);
+ // allocate sws context
+ m_imgConvertCtx = sws_getContext(
+ m_codecCtx->width,
+ m_codecCtx->height,
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width,
+ m_codecCtx->height,
+ PIX_FMT_RGBA,
+ SWS_FAST_BILINEAR,
+ NULL, NULL, NULL);
+ } else
+ {
+ // allocate buffer to store final decoded frame
+ m_format = RGB24;
+ avpicture_fill((AVPicture*)m_frameRGB,
+ (uint8_t*)MEM_callocN(avpicture_get_size(
+ PIX_FMT_RGB24,
+ m_codecCtx->width, m_codecCtx->height),
+ "ffmpeg rgb"),
+ PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height);
+ // allocate sws context
+ m_imgConvertCtx = sws_getContext(
+ m_codecCtx->width,
+ m_codecCtx->height,
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width,
+ m_codecCtx->height,
+ PIX_FMT_RGB24,
+ SWS_FAST_BILINEAR,
+ NULL, NULL, NULL);
+ }
+ if (!m_imgConvertCtx) {
+ avcodec_close(m_codecCtx);
+ av_close_input_file(m_formatCtx);
+ av_free(m_frame);
+ MEM_freeN(m_frameDeinterlaced->data[0]);
+ av_free(m_frameDeinterlaced);
+ MEM_freeN(m_frameRGB->data[0]);
+ av_free(m_frameRGB);
+ return -1;
+ }
+ return 0;
+}
+
+// open video file
+void VideoFFmpeg::openFile (char * filename)
+{
+ do_init_ffmpeg();
+
+ if (openStream(filename, NULL, NULL) != 0)
+ return;
+
+ if (m_codecCtx->gop_size)
+ m_preseek = (m_codecCtx->gop_size < 25) ? m_codecCtx->gop_size+1 : 25;
+ else if (m_codecCtx->has_b_frames)
+ m_preseek = 25; // should determine gopsize
+ else
+ m_preseek = 0;
+
+ // get video time range
+ m_range[0] = 0.0;
+ m_range[1] = (double)m_formatCtx->duration / AV_TIME_BASE;
+
+ // open base class
+ VideoBase::openFile(filename);
+
+ if (
+#ifdef FFMPEG_PB_IS_POINTER
+ m_formatCtx->pb && m_formatCtx->pb->is_streamed
+#else
+ m_formatCtx->pb.is_streamed
+#endif
+ )
+ {
+ // the file is in fact a streaming source, prevent seeking
+ m_isFile = false;
+ // for streaming it is important to do non blocking read
+ m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK;
+ }
+
+ if (m_isImage)
+ {
+ // the file is to be treated as an image, i.e. load the first frame only
+ m_isFile = false;
+ // in case of reload, the filename is taken from m_imageName, no need to change it
+ if (m_imageName.Ptr() != filename)
+ m_imageName = filename;
+ m_preseek = 0;
+ m_avail = false;
+ play();
+ }
+
+}
+
+
+// open video capture device
+void VideoFFmpeg::openCam (char * file, short camIdx)
+{
+ // open camera source
+ AVInputFormat *inputFormat;
+ AVFormatParameters formatParams;
+ AVRational frameRate;
+ char *p, filename[28], rateStr[20];
+
+ do_init_ffmpeg();
+
+ memset(&formatParams, 0, sizeof(formatParams));
+#ifdef WIN32
+ // video capture on windows only through Video For Windows driver
+ inputFormat = av_find_input_format("vfwcap");
+ if (!inputFormat)
+ // Video For Windows not supported??
+ return;
+ sprintf(filename, "%d", camIdx);
+#else
+ // In Linux we support two types of devices: VideoForLinux and DV1394.
+ // the user specify it with the filename:
+ // [<device_type>][:<standard>]
+ // <device_type> : 'v4l' for VideoForLinux, 'dv1394' for DV1394. By default 'v4l'
+ // <standard> : 'pal', 'secam' or 'ntsc'. By default 'ntsc'
+ // The driver name is constructed automatically from the device type:
+ // v4l : /dev/video<camIdx>
+ // dv1394: /dev/dv1394/<camIdx>
+ // If you have different driver name, you can specify the driver name explicitely
+ // instead of device type. Examples of valid filename:
+ // /dev/v4l/video0:pal
+ // /dev/ieee1394/1:ntsc
+ // dv1394:secam
+ // v4l:pal
+ if (file && strstr(file, "1394") != NULL)
+ {
+ // the user specifies a driver, check if it is v4l or d41394
+ inputFormat = av_find_input_format("dv1394");
+ sprintf(filename, "/dev/dv1394/%d", camIdx);
+ } else
+ {
+ inputFormat = av_find_input_format("video4linux");
+ sprintf(filename, "/dev/video%d", camIdx);
+ }
+ if (!inputFormat)
+ // these format should be supported, check ffmpeg compilation
+ return;
+ if (file && strncmp(file, "/dev", 4) == 0)
+ {
+ // user does not specify a driver
+ strncpy(filename, file, sizeof(filename));
+ filename[sizeof(filename)-1] = 0;
+ if ((p = strchr(filename, ':')) != 0)
+ *p = 0;
+ }
+ if (file && (p = strchr(file, ':')) != NULL)
+ formatParams.standard = p+1;
+#endif
+ //frame rate
+ if (m_captRate <= 0.f)
+ m_captRate = defFrameRate;
+ sprintf(rateStr, "%f", m_captRate);
+ av_parse_video_frame_rate(&frameRate, rateStr);
+ // populate format parameters
+ // need to specify the time base = inverse of rate
+ formatParams.time_base.num = frameRate.den;
+ formatParams.time_base.den = frameRate.num;
+ formatParams.width = m_captWidth;
+ formatParams.height = m_captHeight;
+
+ if (openStream(filename, inputFormat, &formatParams) != 0)
+ return;
+
+ // for video capture it is important to do non blocking read
+ m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK;
+ // open base class
+ VideoBase::openCam(file, camIdx);
+}
+
+// play video
+bool VideoFFmpeg::play (void)
+{
+ try
+ {
+ // if object is able to play
+ if (VideoBase::play())
+ {
+ // set video position
+ setPositions();
+ // return success
+ return true;
+ }
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+
+// stop video
+bool VideoFFmpeg::stop (void)
+{
+ try
+ {
+ if (VideoBase::stop())
+ {
+ return true;
+ }
+ }
+ CATCH_EXCP;
+ return false;
+}
+
+
+// set video range
+void VideoFFmpeg::setRange (double start, double stop)
+{
+ try
+ {
+ // set range
+ VideoBase::setRange(start, stop);
+ // set range for video
+ setPositions();
+ }
+ CATCH_EXCP;
+}
+
+// set framerate
+void VideoFFmpeg::setFrameRate (float rate)
+{
+ VideoBase::setFrameRate(rate);
+}
+
+
+// image calculation
+void VideoFFmpeg::calcImage (unsigned int texId)
+{
+ loadFrame();
+}
+
+
+// load frame from video
+void VideoFFmpeg::loadFrame (void)
+{
+ // get actual time
+ double actTime = PIL_check_seconds_timer() - m_startTime;
+ // if video has ended
+ if (m_isFile && actTime * m_frameRate >= m_range[1])
+ {
+ // if repeats are set, decrease them
+ if (m_repeat > 0)
+ --m_repeat;
+ // if video has to be replayed
+ if (m_repeat != 0)
+ {
+ // reset its position
+ actTime -= (m_range[1] - m_range[0]) / m_frameRate;
+ m_startTime += (m_range[1] - m_range[0]) / m_frameRate;
+ }
+ // if video has to be stopped, stop it
+ else
+ m_status = SourceStopped;
+ }
+ // if video is playing
+ if (m_status == SourcePlaying)
+ {
+ // actual frame
+ long actFrame = m_isFile ? long(actTime * actFrameRate()) : m_lastFrame + 1;
+ // if actual frame differs from last frame
+ if (actFrame != m_lastFrame)
+ {
+ // get image
+ if(grabFrame(actFrame))
+ {
+ AVFrame* frame = getFrame();
+ // save actual frame
+ m_lastFrame = actFrame;
+ // init image, if needed
+ init(short(m_codecCtx->width), short(m_codecCtx->height));
+ // process image
+ process((BYTE*)(frame->data[0]));
+ // in case it is an image, automatically stop reading it
+ if (m_isImage)
+ {
+ m_status = SourceStopped;
+ // close the file as we don't need it anymore
+ release();
+ }
+ }
+ }
+ }
+}
+
+
+// set actual position
+void VideoFFmpeg::setPositions (void)
+{
+ // set video start time
+ m_startTime = PIL_check_seconds_timer();
+ // if file is played and actual position is before end position
+ if (m_isFile && !m_eof && m_lastFrame >= 0 && m_lastFrame < m_range[1] * actFrameRate())
+ // continue from actual position
+ m_startTime -= double(m_lastFrame) / actFrameRate();
+ else
+ m_startTime -= m_range[0];
+}
+
+// position pointer in file, position in second
+bool VideoFFmpeg::grabFrame(long position)
+{
+ AVPacket packet;
+ int frameFinished;
+ int posFound = 1;
+ bool frameLoaded = false;
+ long long targetTs = 0;
+
+ // first check if the position that we are looking for is in the preseek range
+ // if so, just read the frame until we get there
+ if (position > m_curPosition + 1
+ && m_preseek
+ && position - (m_curPosition + 1) < m_preseek)
+ {
+ while(av_read_frame(m_formatCtx, &packet)>=0)
+ {
+ if (packet.stream_index == m_videoStream)
+ {
+ avcodec_decode_video(
+ m_codecCtx,
+ m_frame, &frameFinished,
+ packet.data, packet.size);
+ if (frameFinished)
+ m_curPosition++;
+ }
+ av_free_packet(&packet);
+ if (position == m_curPosition+1)
+ break;
+ }
+ }
+ // if the position is not in preseek, do a direct jump
+ if (position != m_curPosition + 1)
+ {
+ double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base);
+ long long pos = (long long)
+ ((long long) (position - m_preseek) * AV_TIME_BASE / m_baseFrameRate);
+ long long startTs = m_formatCtx->streams[m_videoStream]->start_time;
+
+ if (pos < 0)
+ pos = 0;
+
+ if (startTs != AV_NOPTS_VALUE)
+ pos += (long long)(startTs * AV_TIME_BASE * timeBase);
+
+ if (position <= m_curPosition || !m_eof)
+ {
+ // no need to seek past the end of the file
+ if (av_seek_frame(m_formatCtx, -1, pos, AVSEEK_FLAG_BACKWARD) >= 0)
+ {
+ // current position is now lost, guess a value.
+ // It's not important because it will be set at this end of this function
+ m_curPosition = position - m_preseek - 1;
+ }
+ }
+ // this is the timestamp of the frame we're looking for
+ targetTs = (long long)(((double) position) / m_baseFrameRate / timeBase);
+ if (startTs != AV_NOPTS_VALUE)
+ targetTs += startTs;
+
+ posFound = 0;
+ avcodec_flush_buffers(m_codecCtx);
+ }
+
+ while(av_read_frame(m_formatCtx, &packet)>=0)
+ {
+ if(packet.stream_index == m_videoStream)
+ {
+ avcodec_decode_video(m_codecCtx,
+ m_frame, &frameFinished,
+ packet.data, packet.size);
+
+ if (frameFinished && !posFound)
+ {
+ if (packet.dts >= targetTs)
+ posFound = 1;
+ }
+
+ if(frameFinished && posFound == 1)
+ {
+ AVFrame * input = m_frame;
+
+ /* This means the data wasnt read properly,
+ this check stops crashing */
+ if ( input->data[0]==0 && input->data[1]==0
+ && input->data[2]==0 && input->data[3]==0)
+ {
+ av_free_packet(&packet);
+ break;
+ }
+
+ if (m_deinterlace)
+ {
+ if (avpicture_deinterlace(
+ (AVPicture*) m_frameDeinterlaced,
+ (const AVPicture*) m_frame,
+ m_codecCtx->pix_fmt,
+ m_codecCtx->width,
+ m_codecCtx->height) >= 0)
+ {
+ input = m_frameDeinterlaced;
+ }
+ }
+ // convert to RGB24
+ sws_scale(m_imgConvertCtx,
+ input->data,
+ input->linesize,
+ 0,
+ m_codecCtx->height,
+ m_frameRGB->data,
+ m_frameRGB->linesize);
+ av_free_packet(&packet);
+ frameLoaded = true;
+ break;
+ }
+ }
+ av_free_packet(&packet);
+ }
+ m_eof = !frameLoaded;
+ if (frameLoaded)
+ m_curPosition = position;
+ return frameLoaded;
+}
+
+
+// python methods
+
+
+// cast Image pointer to VideoFFmpeg
+inline VideoFFmpeg * getVideoFFmpeg (PyImage * self)
+{ return static_cast<VideoFFmpeg*>(self->m_image); }
+
+
+// object initialization
+static int VideoFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
+{
+ PyImage * self = reinterpret_cast<PyImage*>(pySelf);
+ // parameters - video source
+ // file name or format type for capture (only for Linux: video4linux or dv1394)
+ char * file = NULL;
+ // capture device number
+ short capt = -1;
+ // capture width, only if capt is >= 0
+ short width = 0;
+ // capture height, only if capt is >= 0
+ short height = 0;
+ // capture rate, only if capt is >= 0
+ float rate = 25.f;
+
+ static char *kwlist[] = {"file", "capture", "rate", "width", "height", NULL};
+
+ // get parameters
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|hfhh", kwlist, &file, &capt,
+ &rate, &width, &height))
+ return -1;
+
+ try
+ {
+ // create video object
+ Video_init<VideoFFmpeg>(self);
+
+ // set thread usage
+ getVideoFFmpeg(self)->initParams(width, height, rate);
+
+ // open video source
+ Video_open(getVideo(self), file, capt);
+ }
+ catch (Exception & exp)
+ {
+ exp.report();
+ return -1;
+ }
+ // initialization succeded
+ return 0;
+}
+
+PyObject * VideoFFmpeg_getPreseek (PyImage *self, void * closure)
+{
+ return Py_BuildValue("h", getFFmpeg(self)->getPreseek());
+}
+
+// set range
+int VideoFFmpeg_setPreseek (PyImage * self, PyObject * value, void * closure)
+{
+ // check validity of parameter
+ if (value == NULL || !PyInt_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be an integer");
+ return -1;
+ }
+ // set preseek
+ getFFmpeg(self)->setPreseek(PyInt_AsLong(value));
+ // success
+ return 0;
+}
+
+// get deinterlace
+PyObject * VideoFFmpeg_getDeinterlace (PyImage * self, void * closure)
+{
+ if (getFFmpeg(self)->getDeinterlace())
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+// set flip
+int VideoFFmpeg_setDeinterlace (PyImage * self, PyObject * value, void * closure)
+{
+ // check parameter, report failure
+ if (value == NULL || !PyBool_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "The value must be a bool");
+ return -1;
+ }
+ // set deinterlace
+ getFFmpeg(self)->setDeinterlace(value == Py_True);
+ // success
+ return 0;
+}
+
+// methods structure
+static PyMethodDef videoMethods[] =
+{ // methods from VideoBase class
+ {"play", (PyCFunction)Video_play, METH_NOARGS, "Play video"},
+ {"stop", (PyCFunction)Video_stop, METH_NOARGS, "Stop (pause) video"},
+ {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh video - get its status"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef videoGetSets[] =
+{ // methods from VideoBase class
+ {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL},
+ {(char*)"range", (getter)Video_getRange, (setter)Video_setRange, (char*)"replay range", NULL},
+ {(char*)"repeat", (getter)Video_getRepeat, (setter)Video_setRepeat, (char*)"repeat count, -1 for infinite repeat", NULL},
+ {(char*)"framerate", (getter)Video_getFrameRate, (setter)Video_setFrameRate, (char*)"frame rate", NULL},
+ // attributes from ImageBase class
+ {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
+ {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
+ {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
+ {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
+ {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
+ {(char*)"preseek", (getter)VideoFFmpeg_getPreseek, (setter)VideoFFmpeg_setPreseek, (char*)"nb of frames of preseek", NULL},
+ {(char*)"deinterlace", (getter)VideoFFmpeg_getDeinterlace, (setter)VideoFFmpeg_setDeinterlace, (char*)"deinterlace image", NULL},
+ {NULL}
+};
+
+// python type declaration
+PyTypeObject VideoFFmpegType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.VideoFFmpeg", /*tp_name*/
+ sizeof(PyImage), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Image_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "FFmpeg video source", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ videoMethods, /* tp_methods */
+ 0, /* tp_members */
+ videoGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)VideoFFmpeg_init, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
+// object initialization
+static int ImageFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
+{
+ PyImage * self = reinterpret_cast<PyImage*>(pySelf);
+ // parameters - video source
+ // file name or format type for capture (only for Linux: video4linux or dv1394)
+ char * file = NULL;
+
+ // get parameters
+ if (!PyArg_ParseTuple(args, "s", &file))
+ return -1;
+
+ try
+ {
+ // create video object
+ Video_init<VideoFFmpeg>(self);
+
+ getVideoFFmpeg(self)->initParams(0, 0, 1.0, true);
+
+ // open video source
+ Video_open(getVideo(self), file, -1);
+ }
+ catch (Exception & exp)
+ {
+ exp.report();
+ return -1;
+ }
+ // initialization succeded
+ return 0;
+}
+
+PyObject * Image_reload (PyImage * self, PyObject *args)
+{
+ char * newname = NULL;
+
+ if (self->m_image != NULL && PyArg_ParseTuple(args, "|s", &newname))
+ {
+ VideoFFmpeg* video = getFFmpeg(self);
+ // check type of object
+ if (!newname)
+ newname = video->getImageName();
+ if (!newname) {
+ // if not set, retport error
+ PyErr_SetString(PyExc_RuntimeError, "No image file name given");
+ return NULL;
+ }
+ // make sure the previous file is cleared
+ video->release();
+ // open the new file
+ video->openFile(newname);
+ }
+ Py_RETURN_NONE;
+}
+
+// methods structure
+static PyMethodDef imageMethods[] =
+{ // methods from VideoBase class
+ {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh image, i.e. load it"},
+ {"reload", (PyCFunction)Image_reload, METH_VARARGS, "Reload image, i.e. reopen it"},
+ {NULL}
+};
+// attributes structure
+static PyGetSetDef imageGetSets[] =
+{ // methods from VideoBase class
+ {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL},
+ // attributes from ImageBase class
+ {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
+ {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
+ {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
+ {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
+ {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
+ {NULL}
+};
+
+// python type declaration
+PyTypeObject ImageFFmpegType =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "VideoTexture.ImageFFmpeg", /*tp_name*/
+ sizeof(PyImage), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Image_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ "FFmpeg image source", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ imageMethods, /* tp_methods */
+ 0, /* tp_members */
+ imageGetSets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ImageFFmpeg_init, /* tp_init */
+ 0, /* tp_alloc */
+ Image_allocNew, /* tp_new */
+};
+
+#endif //WITH_FFMPEG
+
+