merging 17300:17342
[blender-staging.git] / source / gameengine / VideoTexture / VideoFFmpeg.cpp
1 /* $Id$
2 -----------------------------------------------------------------------------
3 This source file is part of VideoTexture library
4
5 Copyright (c) 2007 The Zdeno Ash Miklas
6
7 This program is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the Free Software
9 Foundation; either version 2 of the License, or (at your option) any later
10 version.
11
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
19 http://www.gnu.org/copyleft/lesser.txt.
20 -----------------------------------------------------------------------------
21 */
22
23 // INT64_C fix for some linux machines (C99ism)
24 #define __STDC_CONSTANT_MACROS
25 #include <stdint.h>
26
27
28 #include "MEM_guardedalloc.h"
29 #include "PIL_time.h"
30
31 #include <string>
32
33 #include "Exception.h"
34 #include "VideoFFmpeg.h"
35
36 #ifdef WITH_FFMPEG
37
38 // default framerate
39 const double defFrameRate = 25.0;
40 // time scale constant
41 const long timeScale = 1000;
42
43 // macro for exception handling and logging
44 #define CATCH_EXCP catch (Exception & exp) \
45 { exp.report(); m_status = SourceError; }
46
47 extern "C" void do_init_ffmpeg();
48
49 // class RenderVideo
50
51 // constructor
52 VideoFFmpeg::VideoFFmpeg (HRESULT * hRslt) : VideoBase(), 
53 m_codec(NULL), m_formatCtx(NULL), m_codecCtx(NULL), 
54 m_frame(NULL), m_frameDeinterlaced(NULL), m_frameRGB(NULL), m_imgConvertCtx(NULL),
55 m_deinterlace(false), m_preseek(0),     m_videoStream(-1), m_baseFrameRate(25.0),
56 m_lastFrame(-1),  m_curPosition(-1), m_startTime(0), 
57 m_captWidth(0), m_captHeight(0), m_captRate(0.f), m_isImage(false)
58 {
59         // set video format
60         m_format = RGB24;
61         // force flip because ffmpeg always return the image in the wrong orientation for texture
62         setFlip(true);
63         // construction is OK
64         *hRslt = S_OK;
65 }
66
67 // destructor
68 VideoFFmpeg::~VideoFFmpeg () 
69 {
70 }
71
72
73 // release components
74 bool VideoFFmpeg::release()
75 {
76         // release
77         if (m_codecCtx)
78         {
79                 avcodec_close(m_codecCtx);
80                 m_codecCtx = NULL;
81         }
82         if (m_formatCtx)
83         {
84                 av_close_input_file(m_formatCtx);
85                 m_formatCtx = NULL;
86         }
87         if (m_frame)
88         {
89                 av_free(m_frame);
90                 m_frame = NULL;
91         }
92         if (m_frameDeinterlaced)
93         {
94                 MEM_freeN(m_frameDeinterlaced->data[0]);
95                 av_free(m_frameDeinterlaced);
96                 m_frameDeinterlaced = NULL;
97         }
98         if (m_frameRGB)
99         {
100                 MEM_freeN(m_frameRGB->data[0]);
101                 av_free(m_frameRGB);
102                 m_frameRGB = NULL;
103         }
104         if (m_imgConvertCtx)
105         {
106                 sws_freeContext(m_imgConvertCtx);
107                 m_imgConvertCtx = NULL;
108         }
109         m_codec = NULL;
110         m_status = SourceStopped;
111         return true;
112 }
113
114
115 // set initial parameters
116 void VideoFFmpeg::initParams (short width, short height, float rate, bool image)
117 {
118         m_captWidth = width;
119         m_captHeight = height;
120         m_captRate = rate;
121         m_isImage = image;
122 }
123
124 int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVFormatParameters *formatParams)
125 {
126         AVFormatContext *formatCtx;
127         int                             i, videoStream;
128         AVCodec                 *codec;
129         AVCodecContext  *codecCtx;
130
131         if(av_open_input_file(&formatCtx, filename, inputFormat, 0, formatParams)!=0)
132                 return -1;
133
134         if(av_find_stream_info(formatCtx)<0) 
135         {
136                 av_close_input_file(formatCtx);
137                 return -1;
138         }
139
140         /* Find the first video stream */
141         videoStream=-1;
142         for(i=0; i<formatCtx->nb_streams; i++)
143         {
144                 if(formatCtx->streams[i] &&
145                         get_codec_from_stream(formatCtx->streams[i]) && 
146                         (get_codec_from_stream(formatCtx->streams[i])->codec_type==CODEC_TYPE_VIDEO))
147                 {
148                         videoStream=i;
149                         break;
150                 }
151         }
152
153         if(videoStream==-1) 
154         {
155                 av_close_input_file(formatCtx);
156                 return -1;
157         }
158
159         codecCtx = get_codec_from_stream(formatCtx->streams[videoStream]);
160
161         /* Find the decoder for the video stream */
162         codec=avcodec_find_decoder(codecCtx->codec_id);
163         if(codec==NULL) 
164         {
165                 av_close_input_file(formatCtx);
166                 return -1;
167         }
168         codecCtx->workaround_bugs = 1;
169         if(avcodec_open(codecCtx, codec)<0) 
170         {
171                 av_close_input_file(formatCtx);
172                 return -1;
173         }
174
175 #ifdef FFMPEG_OLD_FRAME_RATE
176         if(codecCtx->frame_rate>1000 && codecCtx->frame_rate_base==1)
177                 codecCtx->frame_rate_base=1000;
178         m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
179 #else
180         m_baseFrameRate = av_q2d(formatCtx->streams[videoStream]->r_frame_rate);
181 #endif
182         if (m_baseFrameRate <= 0.0) 
183                 m_baseFrameRate = defFrameRate;
184
185         m_codec = codec;
186         m_codecCtx = codecCtx;
187         m_formatCtx = formatCtx;
188         m_videoStream = videoStream;
189         m_frame = avcodec_alloc_frame();
190         m_frameDeinterlaced = avcodec_alloc_frame();
191         m_frameRGB = avcodec_alloc_frame();
192
193
194         // allocate buffer if deinterlacing is required
195         avpicture_fill((AVPicture*)m_frameDeinterlaced, 
196                 (uint8_t*)MEM_callocN(avpicture_get_size(
197                 m_codecCtx->pix_fmt,
198                 m_codecCtx->width, m_codecCtx->height), 
199                 "ffmpeg deinterlace"), 
200                 m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height);
201
202         // allocate buffer to store final decoded frame
203         avpicture_fill((AVPicture*)m_frameRGB, 
204                 (uint8_t*)MEM_callocN(avpicture_get_size(
205                 PIX_FMT_RGB24,
206                 m_codecCtx->width, m_codecCtx->height),
207                 "ffmpeg rgb"),
208                 PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height);
209         // allocate sws context
210         m_imgConvertCtx = sws_getContext(
211                 m_codecCtx->width,
212                 m_codecCtx->height,
213                 m_codecCtx->pix_fmt,
214                 m_codecCtx->width,
215                 m_codecCtx->height,
216                 PIX_FMT_RGB24,
217                 SWS_FAST_BILINEAR,
218                 NULL, NULL, NULL);
219
220         if (!m_imgConvertCtx) {
221                 avcodec_close(m_codecCtx);
222                 av_close_input_file(m_formatCtx);
223                 av_free(m_frame);
224                 MEM_freeN(m_frameDeinterlaced->data[0]);
225                 av_free(m_frameDeinterlaced);
226                 MEM_freeN(m_frameRGB->data[0]);
227                 av_free(m_frameRGB);
228                 return -1;
229         }
230         return 0;
231 }
232
233 // open video file
234 void VideoFFmpeg::openFile (char * filename)
235 {
236         do_init_ffmpeg();
237
238         if (openStream(filename, NULL, NULL) != 0)
239                 return;
240
241         if (m_codecCtx->gop_size)
242                 m_preseek = (m_codecCtx->gop_size < 25) ? m_codecCtx->gop_size+1 : 25;
243         else if (m_codecCtx->has_b_frames)              
244                 m_preseek = 25; // should determine gopsize
245         else
246                 m_preseek = 0;
247
248         // get video time range
249         m_range[0] = 0.0;
250         m_range[1] = (double)m_formatCtx->duration / AV_TIME_BASE;
251
252         // open base class
253         VideoBase::openFile(filename);
254
255         if (
256 #ifdef FFMPEG_PB_IS_POINTER
257         m_formatCtx->pb && m_formatCtx->pb->is_streamed
258 #else
259         m_formatCtx->pb.is_streamed
260 #endif
261         )
262         {
263                 // the file is in fact a streaming source, prevent seeking
264                 m_isFile = false;
265                 // for streaming it is important to do non blocking read
266                 m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK;
267         }
268
269         if (m_isImage) 
270         {
271                 // the file is to be treated as an image, i.e. load the first frame only
272                 m_isFile = false;
273                 // in case of reload, the filename is taken from m_imageName, no need to change it
274                 if (m_imageName.Ptr() != filename)
275                         m_imageName = filename;
276                 m_preseek = 0;
277                 play();
278         }
279
280 }
281
282
283 // open video capture device
284 void VideoFFmpeg::openCam (char * file, short camIdx)
285 {
286         // open camera source
287         AVInputFormat           *inputFormat;
288         AVFormatParameters      formatParams;
289         AVRational                      frameRate;
290         char                            *p, filename[28], rateStr[20];
291
292         do_init_ffmpeg();
293
294         memset(&formatParams, 0, sizeof(formatParams));
295 #ifdef WIN32
296         // video capture on windows only through Video For Windows driver
297         inputFormat = av_find_input_format("vfwcap");
298         if (!inputFormat)
299                 // Video For Windows not supported??
300                 return;
301         sprintf(filename, "%d", camIdx);
302 #else
303         // In Linux we support two types of devices: VideoForLinux and DV1394. 
304         // the user specify it with the filename:
305         // [<device_type>][:<standard>]
306         // <device_type> : 'v4l' for VideoForLinux, 'dv1394' for DV1394. By default 'v4l'
307         // <standard>    : 'pal', 'secam' or 'ntsc'. By default 'ntsc'
308         // The driver name is constructed automatically from the device type:
309         // v4l   : /dev/video<camIdx>
310         // dv1394: /dev/dv1394/<camIdx>
311         // If you have different driver name, you can specify the driver name explicitely 
312         // instead of device type. Examples of valid filename:
313         //    /dev/v4l/video0:pal
314         //    /dev/ieee1394/1:ntsc
315         //    dv1394:secam
316         //    v4l:pal
317         if (file && strstr(file, "1394") != NULL) 
318         {
319                 // the user specifies a driver, check if it is v4l or d41394
320                 inputFormat = av_find_input_format("dv1394");
321                 sprintf(filename, "/dev/dv1394/%d", camIdx);
322         } else 
323         {
324                 inputFormat = av_find_input_format("video4linux");
325                 sprintf(filename, "/dev/video%d", camIdx);
326         }
327         if (!inputFormat)
328                 // these format should be supported, check ffmpeg compilation
329                 return;
330         if (file && strncmp(file, "/dev", 4) == 0) 
331         {
332                 // user does not specify a driver
333                 strncpy(filename, file, sizeof(filename));
334                 filename[sizeof(filename)-1] = 0;
335                 if ((p = strchr(filename, ':')) != 0)
336                         *p = 0;
337         }
338         if (file && (p = strchr(file, ':')) != NULL)
339                 formatParams.standard = p+1;
340 #endif
341         //frame rate
342         if (m_captRate <= 0.f)
343                 m_captRate = defFrameRate;
344         sprintf(rateStr, "%f", m_captRate);
345         av_parse_video_frame_rate(&frameRate, rateStr);
346         // populate format parameters
347         // need to specify the time base = inverse of rate
348         formatParams.time_base.num = frameRate.den;
349         formatParams.time_base.den = frameRate.num;
350         formatParams.width = m_captWidth;
351         formatParams.height = m_captHeight;
352
353         if (openStream(filename, inputFormat, &formatParams) != 0)
354                 return;
355
356         // for video capture it is important to do non blocking read
357         m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK;
358         // open base class
359         VideoBase::openCam(file, camIdx);
360 }
361
362 // play video
363 bool VideoFFmpeg::play (void)
364 {
365         try
366         {
367                 // if object is able to play
368                 if (VideoBase::play())
369                 {
370                         // set video position
371                         setPositions();
372                         // return success
373                         return true;
374                 }
375         }
376         CATCH_EXCP;
377         return false;
378 }
379
380
381 // stop video
382 bool VideoFFmpeg::stop (void)
383 {
384         try
385         {
386                 if (VideoBase::stop())
387                 {
388                         return true;
389                 }
390         }
391         CATCH_EXCP;
392         return false;
393 }
394
395
396 // set video range
397 void VideoFFmpeg::setRange (double start, double stop)
398 {
399         try
400         {
401                 // set range
402                 VideoBase::setRange(start, stop);
403                 // set range for video
404                 setPositions();
405         }
406         CATCH_EXCP;
407 }
408
409 // set framerate
410 void VideoFFmpeg::setFrameRate (float rate)
411 {
412         VideoBase::setFrameRate(rate);
413 }
414
415
416 // image calculation
417 void VideoFFmpeg::calcImage (unsigned int texId)
418 {
419         loadFrame();
420 }
421
422
423 // load frame from video
424 void VideoFFmpeg::loadFrame (void)
425 {
426         // get actual time
427         double actTime = PIL_check_seconds_timer() - m_startTime;
428         // if video has ended
429         if (m_isFile && actTime * m_frameRate >= m_range[1])
430         {
431                 // if repeats are set, decrease them
432                 if (m_repeat > 0) 
433                         --m_repeat;
434                 // if video has to be replayed
435                 if (m_repeat != 0)
436                 {
437                         // reset its position
438                         actTime -= (m_range[1] - m_range[0]) / m_frameRate;
439                         m_startTime += (m_range[1] - m_range[0]) / m_frameRate;
440                 }
441                 // if video has to be stopped, stop it
442                 else 
443                         m_status = SourceStopped;
444         }
445         // if video is playing
446         if (m_status == SourcePlaying)
447         {
448                 // actual frame
449                 long actFrame = m_isFile ? long(actTime * actFrameRate()) : m_lastFrame + 1;
450                 // if actual frame differs from last frame
451                 if (actFrame != m_lastFrame)
452                 {
453                         // get image
454                         if(grabFrame(actFrame))
455                         {
456                                 AVFrame* frame = getFrame();
457                                 // save actual frame
458                                 m_lastFrame = actFrame;
459                                 // init image, if needed
460                                 init(short(m_codecCtx->width), short(m_codecCtx->height));
461                                 // process image
462                                 process((BYTE*)(frame->data[0]));
463                                 // in case it is an image, automatically stop reading it
464                                 if (m_isImage)
465                                 {
466                                         m_status = SourceStopped;
467                                         // close the file as we don't need it anymore
468                                         release();
469                                 }
470                         }
471                 }
472         }
473 }
474
475
476 // set actual position
477 void VideoFFmpeg::setPositions (void)
478 {
479         // set video start time
480         m_startTime = PIL_check_seconds_timer();
481         // if file is played and actual position is before end position
482         if (m_isFile && m_lastFrame >= 0 && m_lastFrame < m_range[1] * actFrameRate())
483                 // continue from actual position
484                 m_startTime -= double(m_lastFrame) / actFrameRate();
485         else
486                 m_startTime -= m_range[0];
487 }
488
489 // position pointer in file, position in second
490 bool VideoFFmpeg::grabFrame(long position)
491 {
492         AVPacket packet;
493         int frameFinished;
494         int posFound = 1;
495         bool frameLoaded = false;
496         long long targetTs = 0;
497
498         // first check if the position that we are looking for is in the preseek range
499         // if so, just read the frame until we get there
500         if (position > m_curPosition + 1 
501                 && m_preseek 
502                 && position - (m_curPosition + 1) < m_preseek) 
503         {
504                 while(av_read_frame(m_formatCtx, &packet)>=0) 
505                 {
506                         if (packet.stream_index == m_videoStream) 
507                         {
508                                 avcodec_decode_video(
509                                         m_codecCtx, 
510                                         m_frame, &frameFinished, 
511                                         packet.data, packet.size);
512                                 if (frameFinished)
513                                         m_curPosition++;
514                         }
515                         av_free_packet(&packet);
516                         if (position == m_curPosition+1)
517                                 break;
518                 }
519         }
520         // if the position is not in preseek, do a direct jump
521         if (position != m_curPosition + 1) { 
522                 double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base);
523                 long long pos = (long long)
524                         ((long long) (position - m_preseek) * AV_TIME_BASE / m_baseFrameRate);
525                 long long startTs = m_formatCtx->streams[m_videoStream]->start_time;
526
527                 if (pos < 0)
528                         pos = 0;
529
530                 if (startTs != AV_NOPTS_VALUE)
531                         pos += (long long)(startTs * AV_TIME_BASE * timeBase);
532
533                 av_seek_frame(m_formatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
534                 // current position is now lost, guess a value. 
535                 // It's not important because it will be set at this end of this function
536                 m_curPosition = position - m_preseek - 1;
537                 // this is the timestamp of the frame we're looking for
538                 targetTs = (long long)(((double) position) / m_baseFrameRate / timeBase);
539                 if (startTs != AV_NOPTS_VALUE)
540                         targetTs += startTs;
541
542                 posFound = 0;
543                 avcodec_flush_buffers(m_codecCtx);
544         }
545
546         while(av_read_frame(m_formatCtx, &packet)>=0) 
547         {
548                 if(packet.stream_index == m_videoStream) 
549                 {
550                         avcodec_decode_video(m_codecCtx, 
551                                 m_frame, &frameFinished, 
552                                 packet.data, packet.size);
553
554                         if (frameFinished && !posFound) 
555                         {
556                                 if (packet.dts >= targetTs)
557                                         posFound = 1;
558                         } 
559
560                         if(frameFinished && posFound == 1) 
561                         {
562                                 AVFrame * input = m_frame;
563
564                                 /* This means the data wasnt read properly, 
565                                 this check stops crashing */
566                                 if (   input->data[0]==0 && input->data[1]==0 
567                                         && input->data[2]==0 && input->data[3]==0)
568                                 {
569                                         av_free_packet(&packet);
570                                         break;
571                                 }
572
573                                 if (m_deinterlace) 
574                                 {
575                                         if (avpicture_deinterlace(
576                                                 (AVPicture*) m_frameDeinterlaced,
577                                                 (const AVPicture*) m_frame,
578                                                 m_codecCtx->pix_fmt,
579                                                 m_codecCtx->width,
580                                                 m_codecCtx->height) >= 0)
581                                         {
582                                                 input = m_frameDeinterlaced;
583                                         }
584                                 }
585                                 // convert to RGB24
586                                 sws_scale(m_imgConvertCtx,
587                                         input->data,
588                                         input->linesize,
589                                         0,
590                                         m_codecCtx->height,
591                                         m_frameRGB->data,
592                                         m_frameRGB->linesize);
593                                 av_free_packet(&packet);
594                                 frameLoaded = true;
595                                 break;
596                         }
597                 }
598                 av_free_packet(&packet);
599         }
600         if (frameLoaded)
601                 m_curPosition = position;
602         return frameLoaded;
603 }
604
605
606 // python methods
607
608
609 // cast Image pointer to VideoFFmpeg
610 inline VideoFFmpeg * getVideoFFmpeg (PyImage * self)
611 { return static_cast<VideoFFmpeg*>(self->m_image); }
612
613
614 // object initialization
615 static int VideoFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
616 {
617         PyImage * self = reinterpret_cast<PyImage*>(pySelf);
618         // parameters - video source
619         // file name or format type for capture (only for Linux: video4linux or dv1394)
620         char * file = NULL;
621         // capture device number
622         short capt = -1;
623         // capture width, only if capt is >= 0
624         short width = 0;
625         // capture height, only if capt is >= 0
626         short height = 0;
627         // capture rate, only if capt is >= 0
628         float rate = 25.f;
629
630         static char *kwlist[] = {"file", "capture", "rate", "width", "height", NULL};
631
632         // get parameters
633         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|hfhh", kwlist, &file, &capt,
634                 &rate, &width, &height))
635                 return -1; 
636
637         try
638         {
639                 // create video object
640                 Video_init<VideoFFmpeg>(self);
641
642                 // set thread usage
643                 getVideoFFmpeg(self)->initParams(width, height, rate);
644
645                 // open video source
646                 Video_open(getVideo(self), file, capt);
647         }
648         catch (Exception & exp)
649         {
650                 exp.report();
651                 return -1;
652         }
653         // initialization succeded
654         return 0;
655 }
656
657 PyObject * VideoFFmpeg_getPreseek (PyImage *self, void * closure)
658 {
659         return Py_BuildValue("h", getFFmpeg(self)->getPreseek());
660 }
661
662 // set range
663 int VideoFFmpeg_setPreseek (PyImage * self, PyObject * value, void * closure)
664 {
665         // check validity of parameter
666         if (value == NULL || !PyInt_Check(value))
667         {
668                 PyErr_SetString(PyExc_TypeError, "The value must be an integer");
669                 return -1;
670         }
671         // set preseek
672         getFFmpeg(self)->setPreseek(PyInt_AsLong(value));
673         // success
674         return 0;
675 }
676
677 // get deinterlace
678 PyObject * VideoFFmpeg_getDeinterlace (PyImage * self, void * closure)
679 {
680         if (getFFmpeg(self)->getDeinterlace())
681                 Py_RETURN_TRUE;
682         else
683                 Py_RETURN_FALSE;
684 }
685
686 // set flip
687 int VideoFFmpeg_setDeinterlace (PyImage * self, PyObject * value, void * closure)
688 {
689         // check parameter, report failure
690         if (value == NULL || !PyBool_Check(value))
691         {
692                 PyErr_SetString(PyExc_TypeError, "The value must be a bool");
693                 return -1;
694         }
695         // set deinterlace
696         getFFmpeg(self)->setDeinterlace(value == Py_True);
697         // success
698         return 0;
699 }
700
701 // methods structure
702 static PyMethodDef videoMethods[] =
703 { // methods from VideoBase class
704         {"play", (PyCFunction)Video_play, METH_NOARGS, "Play video"},
705         {"stop", (PyCFunction)Video_stop, METH_NOARGS, "Stop (pause) video"},
706         {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh video - get its status"},
707         {NULL}
708 };
709 // attributes structure
710 static PyGetSetDef videoGetSets[] =
711 { // methods from VideoBase class
712         {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL},
713         {(char*)"range", (getter)Video_getRange, (setter)Video_setRange, (char*)"replay range", NULL},
714         {(char*)"repeat", (getter)Video_getRepeat, (setter)Video_setRepeat, (char*)"repeat count, -1 for infinite repeat", NULL},
715         {(char*)"framerate", (getter)Video_getFrameRate, (setter)Video_setFrameRate, (char*)"frame rate", NULL},
716         // attributes from ImageBase class
717         {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
718         {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
719         {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
720         {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
721         {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
722         {(char*)"preseek", (getter)VideoFFmpeg_getPreseek, (setter)VideoFFmpeg_setPreseek, (char*)"nb of frames of preseek", NULL},
723         {(char*)"deinterlace", (getter)VideoFFmpeg_getDeinterlace, (setter)VideoFFmpeg_setDeinterlace, (char*)"deinterlace image", NULL},
724         {NULL}
725 };
726
727 // python type declaration
728 PyTypeObject VideoFFmpegType =
729
730         PyObject_HEAD_INIT(NULL)
731         0,                         /*ob_size*/
732         "VideoTexture.VideoFFmpeg",   /*tp_name*/
733         sizeof(PyImage),          /*tp_basicsize*/
734         0,                         /*tp_itemsize*/
735         (destructor)Image_dealloc, /*tp_dealloc*/
736         0,                         /*tp_print*/
737         0,                         /*tp_getattr*/
738         0,                         /*tp_setattr*/
739         0,                         /*tp_compare*/
740         0,                         /*tp_repr*/
741         0,                         /*tp_as_number*/
742         0,                         /*tp_as_sequence*/
743         0,                         /*tp_as_mapping*/
744         0,                         /*tp_hash */
745         0,                         /*tp_call*/
746         0,                         /*tp_str*/
747         0,                         /*tp_getattro*/
748         0,                         /*tp_setattro*/
749         0,                         /*tp_as_buffer*/
750         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
751         "FFmpeg video source",       /* tp_doc */
752         0,                             /* tp_traverse */
753         0,                             /* tp_clear */
754         0,                             /* tp_richcompare */
755         0,                             /* tp_weaklistoffset */
756         0,                             /* tp_iter */
757         0,                             /* tp_iternext */
758         videoMethods,    /* tp_methods */
759         0,                   /* tp_members */
760         videoGetSets,          /* tp_getset */
761         0,                         /* tp_base */
762         0,                         /* tp_dict */
763         0,                         /* tp_descr_get */
764         0,                         /* tp_descr_set */
765         0,                         /* tp_dictoffset */
766         (initproc)VideoFFmpeg_init,     /* tp_init */
767         0,                         /* tp_alloc */
768         Image_allocNew,           /* tp_new */
769 };
770
771 // object initialization
772 static int ImageFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
773 {
774         PyImage * self = reinterpret_cast<PyImage*>(pySelf);
775         // parameters - video source
776         // file name or format type for capture (only for Linux: video4linux or dv1394)
777         char * file = NULL;
778
779         // get parameters
780         if (!PyArg_ParseTuple(args, "s", &file))
781                 return -1; 
782
783         try
784         {
785                 // create video object
786                 Video_init<VideoFFmpeg>(self);
787
788                 getVideoFFmpeg(self)->initParams(0, 0, 1.0, true);
789
790                 // open video source
791                 Video_open(getVideo(self), file, -1);
792         }
793         catch (Exception & exp)
794         {
795                 exp.report();
796                 return -1;
797         }
798         // initialization succeded
799         return 0;
800 }
801
802 PyObject * Image_reload (PyImage * self, PyObject *args)
803 {
804         char * newname = NULL;
805
806         if (self->m_image != NULL && PyArg_ParseTuple(args, "|s", &newname))
807         {
808                 VideoFFmpeg* video = getFFmpeg(self);
809                 // check type of object
810                 if (!newname)
811                         newname = video->getImageName();
812                 if (!newname) {
813                         // if not set, retport error
814                         PyErr_SetString(PyExc_RuntimeError, "No image file name given");
815                         return NULL;
816                 }
817                 // make sure the previous file is cleared
818                 video->release();
819                 // open the new file
820                 video->openFile(newname);
821         }
822         Py_RETURN_NONE;
823 }
824
825 // methods structure
826 static PyMethodDef imageMethods[] =
827 { // methods from VideoBase class
828         {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh image, i.e. load it"},
829         {"reload", (PyCFunction)Image_reload, METH_VARARGS, "Reload image, i.e. reopen it"},
830         {NULL}
831 };
832 // attributes structure
833 static PyGetSetDef imageGetSets[] =
834 { // methods from VideoBase class
835         {(char*)"status", (getter)Video_getStatus, NULL, (char*)"video status", NULL},
836         // attributes from ImageBase class
837         {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
838         {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
839         {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
840         {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
841         {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
842         {NULL}
843 };
844
845 // python type declaration
846 PyTypeObject ImageFFmpegType =
847
848         PyObject_HEAD_INIT(NULL)
849         0,                         /*ob_size*/
850         "VideoTexture.ImageFFmpeg",   /*tp_name*/
851         sizeof(PyImage),          /*tp_basicsize*/
852         0,                         /*tp_itemsize*/
853         (destructor)Image_dealloc, /*tp_dealloc*/
854         0,                         /*tp_print*/
855         0,                         /*tp_getattr*/
856         0,                         /*tp_setattr*/
857         0,                         /*tp_compare*/
858         0,                         /*tp_repr*/
859         0,                         /*tp_as_number*/
860         0,                         /*tp_as_sequence*/
861         0,                         /*tp_as_mapping*/
862         0,                         /*tp_hash */
863         0,                         /*tp_call*/
864         0,                         /*tp_str*/
865         0,                         /*tp_getattro*/
866         0,                         /*tp_setattro*/
867         0,                         /*tp_as_buffer*/
868         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
869         "FFmpeg image source",       /* tp_doc */
870         0,                             /* tp_traverse */
871         0,                             /* tp_clear */
872         0,                             /* tp_richcompare */
873         0,                             /* tp_weaklistoffset */
874         0,                             /* tp_iter */
875         0,                             /* tp_iternext */
876         imageMethods,    /* tp_methods */
877         0,                   /* tp_members */
878         imageGetSets,          /* tp_getset */
879         0,                         /* tp_base */
880         0,                         /* tp_dict */
881         0,                         /* tp_descr_get */
882         0,                         /* tp_descr_set */
883         0,                         /* tp_dictoffset */
884         (initproc)ImageFFmpeg_init,     /* tp_init */
885         0,                         /* tp_alloc */
886         Image_allocNew,           /* tp_new */
887 };
888
889 #endif  //WITH_FFMPEG
890
891