272d2695c4b38e3e099f47c2b882e91d70149433
[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 (
252 #ifdef FFMPEG_PB_IS_POINTER
253         m_formatCtx->pb->is_streamed
254 #else
255         m_formatCtx->pb.is_streamed
256 #endif
257         )
258         {
259                 // the file is in fact a streaming source, prevent seeking
260                 m_isFile = false;
261                 // for streaming it is important to do non blocking read
262                 m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK;
263         }
264 }
265
266
267 // open video capture device
268 void VideoFFmpeg::openCam (char * file, short camIdx)
269 {
270         // open camera source
271         AVInputFormat           *inputFormat;
272         AVFormatParameters      formatParams;
273         AVRational                      frameRate;
274         char                            *p, filename[28], rateStr[20];
275
276         do_init_ffmpeg();
277
278         memset(&formatParams, 0, sizeof(formatParams));
279 #ifdef WIN32
280         // video capture on windows only through Video For Windows driver
281         inputFormat = av_find_input_format("vfwcap");
282         if (!inputFormat)
283                 // Video For Windows not supported??
284                 return;
285         sprintf(filename, "%d", camIdx);
286 #else
287         // In Linux we support two types of devices: VideoForLinux and DV1394. 
288         // the user specify it with the filename:
289         // [<device_type>][:<standard>]
290         // <device_type> : 'v4l' for VideoForLinux, 'dv1394' for DV1394. By default 'v4l'
291         // <standard>    : 'pal', 'secam' or 'ntsc'. By default 'ntsc'
292         // The driver name is constructed automatically from the device type:
293         // v4l   : /dev/video<camIdx>
294         // dv1394: /dev/dv1394/<camIdx>
295         // If you have different driver name, you can specify the driver name explicitely 
296         // instead of device type. Examples of valid filename:
297         //    /dev/v4l/video0:pal
298         //    /dev/ieee1394/1:ntsc
299         //    dv1394:secam
300         //    v4l:pal
301         if (file && strstr(file, "1394") != NULL) 
302         {
303                 // the user specifies a driver, check if it is v4l or d41394
304                 inputFormat = av_find_input_format("dv1394");
305                 sprintf(filename, "/dev/dv1394/%d", camIdx);
306         } else 
307         {
308                 inputFormat = av_find_input_format("video4linux");
309                 sprintf(filename, "/dev/video%d", camIdx);
310         }
311         if (!inputFormat)
312                 // these format should be supported, check ffmpeg compilation
313                 return;
314         if (file && strncmp(file, "/dev", 4) == 0) 
315         {
316                 // user does not specify a driver
317                 strncpy(filename, file, sizeof(filename));
318                 filename[sizeof(filename)-1] = 0;
319                 if ((p = strchr(filename, ':')) != 0)
320                         *p = 0;
321         }
322         if (file && (p = strchr(file, ':')) != NULL)
323                 formatParams.standard = p+1;
324 #endif
325         //frame rate
326         if (m_captRate <= 0.f)
327                 m_captRate = defFrameRate;
328         sprintf(rateStr, "%f", m_captRate);
329         av_parse_video_frame_rate(&frameRate, rateStr);
330         // populate format parameters
331         // need to specify the time base = inverse of rate
332         formatParams.time_base.num = frameRate.den;
333         formatParams.time_base.den = frameRate.num;
334         formatParams.width = m_captWidth;
335         formatParams.height = m_captHeight;
336
337         if (openStream(filename, inputFormat, &formatParams) != 0)
338                 return;
339
340         // for video capture it is important to do non blocking read
341         m_formatCtx->flags |= AVFMT_FLAG_NONBLOCK;
342         // open base class
343         VideoBase::openCam(file, camIdx);
344 }
345
346
347 // play video
348 bool VideoFFmpeg::play (void)
349 {
350         try
351         {
352                 // if object is able to play
353                 if (VideoBase::play())
354                 {
355                         // set video position
356                         setPositions();
357                         // return success
358                         return true;
359                 }
360         }
361         CATCH_EXCP;
362         return false;
363 }
364
365
366 // stop video
367 bool VideoFFmpeg::stop (void)
368 {
369         try
370         {
371                 if (VideoBase::stop())
372                 {
373                         return true;
374                 }
375         }
376         CATCH_EXCP;
377         return false;
378 }
379
380
381 // set video range
382 void VideoFFmpeg::setRange (double start, double stop)
383 {
384         try
385         {
386                 // set range
387                 VideoBase::setRange(start, stop);
388                 // set range for video
389                 setPositions();
390         }
391         CATCH_EXCP;
392 }
393
394 // set framerate
395 void VideoFFmpeg::setFrameRate (float rate)
396 {
397         VideoBase::setFrameRate(rate);
398 }
399
400
401 // image calculation
402 void VideoFFmpeg::calcImage (unsigned int texId)
403 {
404         loadFrame();
405 }
406
407
408 // load frame from video
409 void VideoFFmpeg::loadFrame (void)
410 {
411         // get actual time
412         double actTime = PIL_check_seconds_timer() - m_startTime;
413         // if video has ended
414         if (m_isFile && actTime * m_frameRate >= m_range[1])
415         {
416                 // if repeats are set, decrease them
417                 if (m_repeat > 0) 
418                         --m_repeat;
419                 // if video has to be replayed
420                 if (m_repeat != 0)
421                 {
422                         // reset its position
423                         actTime -= (m_range[1] - m_range[0]) / m_frameRate;
424                         m_startTime += (m_range[1] - m_range[0]) / m_frameRate;
425                 }
426                 // if video has to be stopped, stop it
427                 else 
428                         m_status = SourceStopped;
429         }
430         // if video is playing
431         if (m_status == SourcePlaying)
432         {
433                 // actual frame
434                 long actFrame = m_isFile ? long(actTime * actFrameRate()) : m_lastFrame + 1;
435                 // if actual frame differs from last frame
436                 if (actFrame != m_lastFrame)
437                 {
438                         // get image
439                         if(grabFrame(actFrame))
440                         {
441                                 AVFrame* frame = getFrame();
442                                 // save actual frame
443                                 m_lastFrame = actFrame;
444                                 // init image, if needed
445                                 init(short(m_codecCtx->width), short(m_codecCtx->height));
446                                 // process image
447                                 process((BYTE*)(frame->data[0]));
448                         }
449                 }
450         }
451 }
452
453
454 // set actual position
455 void VideoFFmpeg::setPositions (void)
456 {
457         // set video start time
458         m_startTime = PIL_check_seconds_timer();
459         // if file is played and actual position is before end position
460         if (m_isFile && m_lastFrame >= 0 && m_lastFrame < m_range[1] * actFrameRate())
461                 // continue from actual position
462                 m_startTime -= double(m_lastFrame) / actFrameRate();
463         else
464                 m_startTime -= m_range[0];
465 }
466
467 // position pointer in file, position in second
468 bool VideoFFmpeg::grabFrame(long position)
469 {
470         AVPacket packet;
471         int frameFinished;
472         int posFound = 1;
473         bool frameLoaded = false;
474         long long targetTs = 0;
475
476         // first check if the position that we are looking for is in the preseek range
477         // if so, just read the frame until we get there
478         if (position > m_curPosition + 1 
479                 && m_preseek 
480                 && position - (m_curPosition + 1) < m_preseek) 
481         {
482                 while(av_read_frame(m_formatCtx, &packet)>=0) 
483                 {
484                         if (packet.stream_index == m_videoStream) 
485                         {
486                                 avcodec_decode_video(
487                                         m_codecCtx, 
488                                         m_frame, &frameFinished, 
489                                         packet.data, packet.size);
490                                 if (frameFinished)
491                                         m_curPosition++;
492                         }
493                         av_free_packet(&packet);
494                         if (position == m_curPosition+1)
495                                 break;
496                 }
497         }
498         // if the position is not in preseek, do a direct jump
499         if (position != m_curPosition + 1) { 
500                 double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base);
501                 long long pos = (long long)
502                         ((long long) (position - m_preseek) * AV_TIME_BASE / m_baseFrameRate);
503                 long long startTs = m_formatCtx->streams[m_videoStream]->start_time;
504
505                 if (pos < 0)
506                         pos = 0;
507
508                 if (startTs != AV_NOPTS_VALUE)
509                         pos += (long long)(startTs * AV_TIME_BASE * timeBase);
510
511                 av_seek_frame(m_formatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
512                 // current position is now lost, guess a value. 
513                 // It's not important because it will be set at this end of this function
514                 m_curPosition = position - m_preseek - 1;
515                 // this is the timestamp of the frame we're looking for
516                 targetTs = (long long)(((double) position) / m_baseFrameRate / timeBase);
517                 if (startTs != AV_NOPTS_VALUE)
518                         targetTs += startTs;
519
520                 posFound = 0;
521                 avcodec_flush_buffers(m_codecCtx);
522         }
523
524         while(av_read_frame(m_formatCtx, &packet)>=0) 
525         {
526                 if(packet.stream_index == m_videoStream) 
527                 {
528                         avcodec_decode_video(m_codecCtx, 
529                                 m_frame, &frameFinished, 
530                                 packet.data, packet.size);
531
532                         if (frameFinished && !posFound) 
533                         {
534                                 if (packet.dts >= targetTs)
535                                         posFound = 1;
536                         } 
537
538                         if(frameFinished && posFound == 1) 
539                         {
540                                 AVFrame * input = m_frame;
541
542                                 /* This means the data wasnt read properly, 
543                                 this check stops crashing */
544                                 if (   input->data[0]==0 && input->data[1]==0 
545                                         && input->data[2]==0 && input->data[3]==0)
546                                 {
547                                         av_free_packet(&packet);
548                                         break;
549                                 }
550
551                                 if (m_deinterlace) 
552                                 {
553                                         if (avpicture_deinterlace(
554                                                 (AVPicture*) m_frameDeinterlaced,
555                                                 (const AVPicture*) m_frame,
556                                                 m_codecCtx->pix_fmt,
557                                                 m_codecCtx->width,
558                                                 m_codecCtx->height) >= 0)
559                                         {
560                                                 input = m_frameDeinterlaced;
561                                         }
562                                 }
563                                 // convert to BGR24
564                                 sws_scale(m_imgConvertCtx,
565                                         input->data,
566                                         input->linesize,
567                                         0,
568                                         m_codecCtx->height,
569                                         m_frameBGR->data,
570                                         m_frameBGR->linesize);
571                                 av_free_packet(&packet);
572                                 frameLoaded = true;
573                                 break;
574                         }
575                 }
576                 av_free_packet(&packet);
577         }
578         if (frameLoaded)
579                 m_curPosition = position;
580         return frameLoaded;
581 }
582
583
584 // python methods
585
586
587 // cast Image pointer to VideoFFmpeg
588 inline VideoFFmpeg * getVideoFFmpeg (PyImage * self)
589 { return static_cast<VideoFFmpeg*>(self->m_image); }
590
591
592 // object initialization
593 static int VideoFFmpeg_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
594 {
595         PyImage * self = reinterpret_cast<PyImage*>(pySelf);
596         // parameters - video source
597         // file name or format type for capture (only for Linux: video4linux or dv1394)
598         char * file = NULL;
599         // capture device number
600         short capt = -1;
601         // capture width, only if capt is >= 0
602         short width = 0;
603         // capture height, only if capt is >= 0
604         short height = 0;
605         // capture rate, only if capt is >= 0
606         float rate = 25.f;
607
608         static char *kwlist[] = {"file", "capture", "rate", "width", "height", NULL};
609
610         // get parameters
611         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|hfhh", kwlist, &file, &capt,
612                 &rate, &width, &height))
613                 return -1; 
614
615         try
616         {
617                 // create video object
618                 Video_init<VideoFFmpeg>(self);
619
620                 // set thread usage
621                 getVideoFFmpeg(self)->initParams(width, height, rate);
622
623                 // open video source
624                 Video_open(getVideo(self), file, capt);
625         }
626         catch (Exception & exp)
627         {
628                 exp.report();
629                 return -1;
630         }
631         // initialization succeded
632         return 0;
633 }
634
635 PyObject * VideoFFmpeg_getPreseek (PyImage *self, void * closure)
636 {
637         return Py_BuildValue("h", getFFmpeg(self)->getPreseek());
638 }
639
640 // set range
641 int VideoFFmpeg_setPreseek (PyImage * self, PyObject * value, void * closure)
642 {
643         // check validity of parameter
644         if (value == NULL || !PyInt_Check(value))
645         {
646                 PyErr_SetString(PyExc_TypeError, "The value must be an integer");
647                 return -1;
648         }
649         // set preseek
650         getFFmpeg(self)->setPreseek(PyInt_AsLong(value));
651         // success
652         return 0;
653 }
654
655 // get deinterlace
656 PyObject * VideoFFmpeg_getDeinterlace (PyImage * self, void * closure)
657 {
658         if (getFFmpeg(self)->getDeinterlace())
659                 Py_RETURN_TRUE;
660         else
661                 Py_RETURN_FALSE;
662 }
663
664 // set flip
665 int VideoFFmpeg_setDeinterlace (PyImage * self, PyObject * value, void * closure)
666 {
667         // check parameter, report failure
668         if (value == NULL || !PyBool_Check(value))
669         {
670                 PyErr_SetString(PyExc_TypeError, "The value must be a bool");
671                 return -1;
672         }
673         // set deinterlace
674         getFFmpeg(self)->setDeinterlace(value == Py_True);
675         // success
676         return 0;
677 }
678
679 // methods structure
680 static PyMethodDef videoMethods[] =
681 { // methods from VideoBase class
682         {"play", (PyCFunction)Video_play, METH_NOARGS, "Play video"},
683         {"stop", (PyCFunction)Video_stop, METH_NOARGS, "Stop (pause) video"},
684         {"refresh", (PyCFunction)Video_refresh, METH_NOARGS, "Refresh video - get its status"},
685         {NULL}
686 };
687 // attributes structure
688 static PyGetSetDef videoGetSets[] =
689 { // methods from VideoBase class
690         {"status", (getter)Video_getStatus, NULL, "video status", NULL},
691         {"range", (getter)Video_getRange, (setter)Video_setRange, "replay range", NULL},
692         {"repeat", (getter)Video_getRepeat, (setter)Video_setRepeat, "repeat count, -1 for infinite repeat", NULL},
693         {"framerate", (getter)Video_getFrameRate, (setter)Video_setFrameRate, "frame rate", NULL},
694         // attributes from ImageBase class
695         {"image", (getter)Image_getImage, NULL, "image data", NULL},
696         {"size", (getter)Image_getSize, NULL, "image size", NULL},
697         {"scale", (getter)Image_getScale, (setter)Image_setScale, "fast scale of image (near neighbour)", NULL},
698         {"flip", (getter)Image_getFlip, (setter)Image_setFlip, "flip image vertically", NULL},
699         {"filter", (getter)Image_getFilter, (setter)Image_setFilter, "pixel filter", NULL},
700         {"preseek", (getter)VideoFFmpeg_getPreseek, (setter)VideoFFmpeg_setPreseek, "nb of frames of preseek", NULL},
701         {"deinterlace", (getter)VideoFFmpeg_getDeinterlace, (setter)VideoFFmpeg_setDeinterlace, "deinterlace image", NULL},
702         {NULL}
703 };
704
705 // python type declaration
706 PyTypeObject VideoFFmpegType =
707
708         PyObject_HEAD_INIT(NULL)
709         0,                         /*ob_size*/
710         "VideoTexture.VideoFFmpeg",   /*tp_name*/
711         sizeof(PyImage),          /*tp_basicsize*/
712         0,                         /*tp_itemsize*/
713         (destructor)Image_dealloc, /*tp_dealloc*/
714         0,                         /*tp_print*/
715         0,                         /*tp_getattr*/
716         0,                         /*tp_setattr*/
717         0,                         /*tp_compare*/
718         0,                         /*tp_repr*/
719         0,                         /*tp_as_number*/
720         0,                         /*tp_as_sequence*/
721         0,                         /*tp_as_mapping*/
722         0,                         /*tp_hash */
723         0,                         /*tp_call*/
724         0,                         /*tp_str*/
725         0,                         /*tp_getattro*/
726         0,                         /*tp_setattro*/
727         0,                         /*tp_as_buffer*/
728         Py_TPFLAGS_DEFAULT,        /*tp_flags*/
729         "FFmpeg video source",       /* tp_doc */
730         0,                             /* tp_traverse */
731         0,                             /* tp_clear */
732         0,                             /* tp_richcompare */
733         0,                             /* tp_weaklistoffset */
734         0,                             /* tp_iter */
735         0,                             /* tp_iternext */
736         videoMethods,    /* tp_methods */
737         0,                   /* tp_members */
738         videoGetSets,          /* tp_getset */
739         0,                         /* tp_base */
740         0,                         /* tp_dict */
741         0,                         /* tp_descr_get */
742         0,                         /* tp_descr_set */
743         0,                         /* tp_dictoffset */
744         (initproc)VideoFFmpeg_init,     /* tp_init */
745         0,                         /* tp_alloc */
746         Image_allocNew,           /* tp_new */
747 };
748
749
750
751 #endif  //WITH_FFMPEG
752
753