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