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