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