Commits

pygame  committed 0e01b51

ffmpeg movies moved to movieext

  • Participants
  • Parent commits db86733

Comments (0)

Files changed (7)

 NUMERIC = -I/usr/include/python2.0/Numeric
 #--EndConfig
 
-#Movie needs libavcodec and friends, must hand configure
-#movie src/movie.c  src/ffmovie.c $(SDL) -lavcodec -lavformat
 
 
 
 mixer_music src/music.c $(SDL) $(MIXER)
 surfarray src/surfarray.c $(SDL) $(NUMERIC)
 sndarray src/sndarray.c $(SDL) $(NUMERIC) $(MIXER)
+movie src/movie.c $(SDL) $(SMPEG)
 
+#experimental new movie movie. requires libavcodec and libavformat.
+#add any necessary compile flags to this line and uncomment.
+#movieext src/movie.c  src/ffmovie.c $(SDL) -lavcodec -lavformat
 
 
 #these modules are required for pygame to run. they only require
 # BREAK = change breaks existing code
 # BUG	= fixed a bug that was (or could have been) crashing
 
+June 19, 2004
+    ffmpeg movie backend renamed to movieext, experimental
+    v1.6 movie module restored
+
 May 1, 2004
     updated sprite module, Joe Wresching
 

File lib/__init__.py

 try: import pygame.movie
 except (ImportError,IOError), msg:movie=MissingModule("movie", msg, 0)
 
+try: import pygame.movieext
+except (ImportError,IOError), msg:movie=MissingModule("movieext", msg, 0)
+
 try: import pygame.surfarray
 except (ImportError,IOError), msg:surfarray=MissingModule("surfarray", msg, 0)
 

File src/ffmovie.c

     movie->frame_count = 0;
     movie->time_offset = 0.0;
     movie->paused = 1;
+    movie->sourcename = strdup(filename);
 
     Global_num_active++;
     movie->decode_thread = SDL_CreateThread(decode_thread, movie);
 void ffmovie_close(FFMovie *movie)
 {
 /*MAIN THREAD*/
-   movie->abort_request = 1;
-printf("ffmovie_close, wait thread %p\n", movie);
+    movie->abort_request = 1;
     SDL_WaitThread(movie->decode_thread, NULL);
-printf("ffmovie_close, freemem %p\n", movie);
+    if(movie->sourcename) {
+        free((void*)movie->sourcename);
+    }
     av_free(movie);
-printf("ffmovie_close, finished\n");
 }
 
 void ffmovie_play(FFMovie *movie) {
 
 void ffmovie_abortall() {
     Global_abort_all = 1;
-printf("Movie abort all waiting for %d movies...\n", Global_num_active);
     while(Global_num_active > 0) {
         SDL_Delay(200);
     }
-printf("Movie abort all, finished\n");
     Global_abort_all = 0;
 }
+
+
+FFMovie *ffmovie_reopen(FFMovie *movie) {
+    const char* filename;
+    SDL_Overlay *dest_overlay;
+    SDL_Surface *dest_surface;
+    SDL_Rect dest_rect;
+    int waspaused = movie->paused;
+
+    filename = movie->sourcename;
+    movie->sourcename = NULL;
+    if(!filename) {
+        return NULL;
+    }
+
+    SDL_LockMutex(movie->dest_mutex);
+    dest_overlay = movie->dest_overlay;
+    dest_surface = movie->dest_surface;
+    dest_rect = movie->dest_rect;
+    movie->dest_overlay = NULL;
+    movie->dest_surface = NULL;
+    SDL_UnlockMutex(movie->dest_mutex);
+
+    ffmovie_close(movie);
+    
+    movie = ffmovie_open(filename);
+    free((void*)filename);
+    
+    if(movie) {
+        if(dest_overlay) {
+            SDL_LockMutex(movie->dest_mutex);
+            movie->dest_overlay = dest_overlay;
+            movie->dest_surface = dest_surface;
+            movie->dest_rect = dest_rect;
+            SDL_UnlockMutex(movie->dest_mutex);
+        }
+        if(!waspaused) {
+            ffmovie_play(movie);
+        }
+    }
+   
+    return movie;
+}

File src/ffmovie.h

 
 
 
-
+#define MAX_SOURCENAME 1024
 #define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
 
 /* SDL audio buffer size, in samples. Should be small to have precise
     double time_offset; /*track paused time*/
     
     int audio_disable;
+    
+    const char *sourcename;
 } FFMovie;
 
 
 
 
 FFMovie *ffmovie_open(const char *filename);
+FFMovie *ffmovie_reopen(FFMovie *movie);
 void ffmovie_close(FFMovie *movie);
 void ffmovie_play(FFMovie *movie);
 void ffmovie_stop(FFMovie *movie);
  *  movie playback for pygame
  */
 #include "pygame.h"
-#include "ffmovie.h"
-
+#include "smpeg.h"
 
 
 typedef struct {
   PyObject_HEAD
-  FFMovie* movie;
+  SMPEG* movie;
   PyObject* surftarget;
   PyObject* filesource;
 } PyMovieObject;
-#define PyMovie_AsFFMovie(x) (((PyMovieObject*)x)->movie)
+#define PyMovie_AsSMPEG(x) (((PyMovieObject*)x)->movie)
 
 
 staticforward PyTypeObject PyMovie_Type;
-static PyObject* PyMovie_New(FFMovie*);
+static PyObject* PyMovie_New(SMPEG*);
 #define PyMovie_Check(x) ((x)->ob_type == &PyMovie_Type)
 
 
 
-static void autoquit(void)
-{
-    ffmovie_abortall();
-}
 
 
 /* movie object methods */
     /*DOC*/    "number of times the movie loops while playing.\n"
     /*DOC*/ ;
 
-/*FIX, needs looping, which needs a 'rewind'*/
-
 static PyObject* movie_play(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
 	int loops=0;
 	if(!PyArg_ParseTuple(args, "|i", &loops))
 		return NULL;
         Py_BEGIN_ALLOW_THREADS
-	ffmovie_play(movie);
+	SMPEG_loop(movie, loops);
+	SMPEG_play(movie);
         Py_END_ALLOW_THREADS
 	RETURN_NONE
 }
 
 static PyObject* movie_stop(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
         Py_BEGIN_ALLOW_THREADS
-	ffmovie_stop(movie);
+	SMPEG_stop(movie);
         Py_END_ALLOW_THREADS
 	RETURN_NONE
 }
 
 static PyObject* movie_pause(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
         Py_BEGIN_ALLOW_THREADS
-	ffmovie_pause(movie);
+	SMPEG_pause(movie);
         Py_END_ALLOW_THREADS
 	RETURN_NONE
 }
     /*DOC*/    "set playback position to the beginning of the movie\n"
     /*DOC*/    "\n"
     /*DOC*/    "Sets the movie playback position to the start of\n"
-    /*DOC*/    "the movie. This can raise a ValueError if the movie\n"
-    /*DOC*/    "cannot be rewound.\n"
-    /*DOC*/    "\n"
-    /*DOC*/    "The movie will automatically start playing if the movie\n"
-    /*DOC*/    "is currently playing.\n"
+    /*DOC*/    "the movie.\n"
     /*DOC*/ ;
-/*need something for this, if anything reinit a new movie and start*/
 
 static PyObject* movie_rewind(PyObject* self, PyObject* args)
 {
-        PyObject* source;
-        char* sourcename = NULL;
-	FFMovie* movie = PyMovie_AsFFMovie(self);
-        SDL_Surface* dest = NULL;
-        int waspaused = movie->paused;
+	SMPEG* movie = PyMovie_AsSMPEG(self);
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
-        
-        source = ((PyMovieObject*)self)->filesource;
-        if(source && PyString_Check(source))
-            sourcename = PyString_AsString(source);
-        if(((PyMovieObject*)self)->surftarget)
-            dest = PySurface_AsSurface(((PyMovieObject*)self)->surftarget);
-        
-        if(!sourcename) {
-            return RAISE(PyExc_ValueError, "Unable to rewind movie source");
-        }
-        
         Py_BEGIN_ALLOW_THREADS
-        ffmovie_close(movie);
-        movie = ffmovie_open(sourcename);
-        ffmovie_setdisplay(movie, dest, NULL); /*need to set rect!*/
-        if(!waspaused) {
-            ffmovie_play(movie);
-        }
+	SMPEG_rewind(movie);
+        Py_END_ALLOW_THREADS
+	RETURN_NONE
+}
+
+    /*DOC*/ static char doc_movie_skip[] =
+    /*DOC*/    "Movie.skip(seconds) -> None\n"
+    /*DOC*/    "skip the movie playback position forward\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Sets the movie playback position ahead by the given\n"
+    /*DOC*/    "amount of seconds. the seconds value is a floating\n"
+    /*DOC*/    "point value\n"
+    /*DOC*/ ;
+
+static PyObject* movie_skip(PyObject* self, PyObject* args)
+{
+	SMPEG* movie = PyMovie_AsSMPEG(self);
+	float seconds;
+	if(!PyArg_ParseTuple(args, "f", &seconds))
+		return NULL;
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_skip(movie, seconds);
         Py_END_ALLOW_THREADS
 	RETURN_NONE
 }
 
 static PyObject* movie_set_volume(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
 	float value;
+	int volume;
 	if(!PyArg_ParseTuple(args, "f", &value))
 		return NULL;
 
         Py_BEGIN_ALLOW_THREADS
-        ffmovie_setvolume(movie, (int)(value*128));
+	volume = (int)(value * 100);
+	if(volume<0) volume = 0;
+	if(volume>100) volume = 100;
+	SMPEG_setvolume(movie, volume);
         Py_END_ALLOW_THREADS
 
 	RETURN_NONE
 
 
     /*DOC*/ static char doc_movie_set_display[] =
-    /*DOC*/    "Movie.set_display(Surface, [rect]) -> None\n"
+    /*DOC*/    "Movie.set_display(Surface, [pos]) -> None\n"
     /*DOC*/    "change the video output surface\n"
     /*DOC*/    "\n"
     /*DOC*/    "Set the output surface for the Movie's video. You may\n"
     /*DOC*/    "also specify a position for the topleft corner of the\n"
-    /*DOC*/    "video.\n"
+    /*DOC*/    "video. The position defaults to (0,0) if not given.\n"
     /*DOC*/    "\n"
-    /*DOC*/    "The position argument must be a rectstyle if given.\n"
-    /*DOC*/    "The video will be stretched to fill the rectangular area.\n"
+    /*DOC*/    "The position argument can optionally be a rectangle,\n"
+    /*DOC*/    "in which case the video will be stretched to fill the\n"
+    /*DOC*/    "rectangular area.\n"
     /*DOC*/    "\n"
     /*DOC*/    "You may also pass None as the destination Surface, and\n"
     /*DOC*/    "no video will be rendered for the movie playback.\n"
 
 static PyObject* movie_set_display(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
 	PyObject* surfobj, *posobj=NULL;
-        SDL_Rect* sdlrect, sdltemp;
 	GAME_Rect *rect, temp;
+	int x=0, y=0;
 	if(!PyArg_ParseTuple(args, "O|O", &surfobj, &posobj))
 		return NULL;
 
 
 	if(PySurface_Check(surfobj))
 	{
-       SDL_Surface* surf = PySurface_AsSurface(surfobj);
-
-	   ((PyMovieObject*)self)->surftarget = surfobj;
-       Py_INCREF(surfobj);
+	    SMPEG_Info info;
+	    SDL_Surface* surf;
 
 		if(posobj == NULL)
 		{
-			sdlrect = NULL;
+			SMPEG_Info info;
+			SMPEG_getinfo(movie, &info);
+			SMPEG_scaleXY(movie, info.width, info.height);
+			x = y = 0;
+		}
+		else if(TwoIntsFromObj(posobj, &x, &y))
+		{
+			SMPEG_Info info;
+			SMPEG_getinfo(movie, &info);
+			SMPEG_scaleXY(movie, info.width, info.height);
 		}
 		else if((rect = GameRect_FromObject(posobj, &temp)))
-                {
-                        sdlrect = &sdltemp;
-                        sdltemp.x = rect->x;
-                        sdltemp.y = rect->y;
-                        sdltemp.w = rect->w;
-                        sdltemp.h = rect->h;
-                }
-                else
+		{
+			x = rect->x;
+			y = rect->y;
+			SMPEG_scaleXY(movie, rect->w, rect->h);
+		}
+		else
 			return RAISE(PyExc_TypeError, "Invalid position argument");
 
-            Py_BEGIN_ALLOW_THREADS            
-            ffmovie_setdisplay(movie, surf, sdlrect);
-            Py_END_ALLOW_THREADS
+	    surf = PySurface_AsSurface(surfobj);
+
+            SMPEG_getinfo(movie, &info);
+	    SMPEG_enablevideo(movie, 1);
+	    SMPEG_setdisplay(movie, surf, NULL, NULL);
+	    SMPEG_move(movie, x, y);
 	}
 	else
 	{
             Py_BEGIN_ALLOW_THREADS
-	    ffmovie_setdisplay(movie, NULL, NULL);
+	    SMPEG_enablevideo(movie, 0);
             Py_END_ALLOW_THREADS
 	    if(surfobj != Py_None)
 		       return RAISE(PyExc_TypeError, "destination must be a Surface");
 
 static PyObject* movie_has_video(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
+	SMPEG_Info info;
 
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
 
-	return PyInt_FromLong(movie->video_st != NULL);
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_getinfo(movie, &info);
+        Py_END_ALLOW_THREADS
+	return PyInt_FromLong(info.has_video);
 }
 
     /*DOC*/ static char doc_movie_has_audio[] =
 
 static PyObject* movie_has_audio(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
+	SMPEG_Info info;
 
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
 
-	return PyInt_FromLong(movie->audio_st != NULL);
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_getinfo(movie, &info);
+        Py_END_ALLOW_THREADS
+	return PyInt_FromLong(info.has_audio);
 }
 
     /*DOC*/ static char doc_movie_get_size[] =
 
 static PyObject* movie_get_size(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
-        int w=0, h=0;
+	SMPEG* movie = PyMovie_AsSMPEG(self);
+	SMPEG_Info info;
 
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
 
-	if(movie->video_st != NULL) {
-                w = movie->video_st->codec.width;
-                h = movie->video_st->codec.height;
-        }
-	return Py_BuildValue("(ii)", w, h);
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_getinfo(movie, &info);
+        Py_END_ALLOW_THREADS
+	return Py_BuildValue("(ii)", info.width, info.height);
 }
 
     /*DOC*/ static char doc_movie_get_frame[] =
 
 static PyObject* movie_get_frame(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
+	SMPEG_Info info;
 
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
 
-	return PyInt_FromLong(movie->frame_count);
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_getinfo(movie, &info);
+        Py_END_ALLOW_THREADS
+	return PyInt_FromLong(info.current_frame);
 }
 
     /*DOC*/ static char doc_movie_get_time[] =
     /*DOC*/    "query the current time in the movie\n"
     /*DOC*/    "\n"
     /*DOC*/    "Gets the current time (in seconds) for the movie.\n"
+    /*DOC*/    "(currently not working? SMPEG always reports 0)\n"
     /*DOC*/ ;
 
 static PyObject* movie_get_time(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
+	SMPEG_Info info;
 
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
 
-	return PyFloat_FromDouble(movie->frame_last_pts);
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_getinfo(movie, &info);
+        Py_END_ALLOW_THREADS
+	return PyFloat_FromDouble(info.current_time);
 }
 
     /*DOC*/ static char doc_movie_get_length[] =
     /*DOC*/    "\n"
     /*DOC*/    "Returns the total time (in seconds) of the movie.\n"
     /*DOC*/ ;
-/*FIX, currently a no op*/
+
 static PyObject* movie_get_length(PyObject* self, PyObject* args)
 {
-/*	FFMovie* movie = PyMovie_AsFFMovie(self);*/
+	SMPEG* movie = PyMovie_AsSMPEG(self);
+	SMPEG_Info info;
 
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
 
-	return PyFloat_FromDouble(0.0);
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_getinfo(movie, &info);
+        Py_END_ALLOW_THREADS
+	return PyFloat_FromDouble(info.total_time);
 }
 
-
     /*DOC*/ static char doc_movie_get_busy[] =
     /*DOC*/    "Movie.get_busy() -> bool\n"
     /*DOC*/    "query the playback state\n"
 
 static PyObject* movie_get_busy(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
 
 	if(!PyArg_ParseTuple(args, ""))
 		return NULL;
 
-	return PyInt_FromLong(movie->context != NULL);
+	return PyInt_FromLong(SMPEG_status(movie) == SMPEG_PLAYING);
 }
 
-    /*DOC*/ static char doc_movie_skip[] =
-    /*DOC*/    "Movie.skip(seconds) -> None\n"
-    /*DOC*/    "skip ahead a given amount of time\n"
+
+
+    /*DOC*/ static char doc_movie_render_frame[] =
+    /*DOC*/    "Movie.render_frame(framenum) -> int\n"
+    /*DOC*/    "Render a specfic numbered frame.\n"
     /*DOC*/    "\n"
-    /*DOC*/    "Skips ahead in the movie a given number of seconds.\n"
+    /*DOC*/    "Returns the current frame number.\n"
     /*DOC*/ ;
 
-static PyObject* movie_skip(PyObject* self, PyObject* args)
+static PyObject* movie_render_frame(PyObject* self, PyObject* args)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
-        float seconds;
+        SMPEG* movie = PyMovie_AsSMPEG(self);
+        SMPEG_Info info;
+        int framenum;
 
-	if(!PyArg_ParseTuple(args, "f", &seconds))
-		return NULL;
-
-printf("Skipping: %.3f\n", seconds);
-        movie->time_offset -= seconds;
-        
-	return PyInt_FromLong(movie->context != NULL);
+        if(!PyArg_ParseTuple(args, "i", &framenum))
+                return NULL;
+        Py_BEGIN_ALLOW_THREADS
+        SMPEG_renderFrame(movie, framenum);
+        SMPEG_getinfo(movie, &info);
+        Py_END_ALLOW_THREADS
+        return PyInt_FromLong(info.current_frame);
 }
 
 
-static PyObject* movie_noop(PyObject* self, PyObject* args)
-{
-	return PyInt_FromLong(0);
-}
-
-
-
 static PyMethodDef movie_builtins[] =
 {
 	{ "play", movie_play, 1, doc_movie_play },
 	{ "stop", movie_stop, 1, doc_movie_stop },
 	{ "pause", movie_pause, 1, doc_movie_pause },
 	{ "rewind", movie_rewind, 1, doc_movie_rewind },
+	{ "skip", movie_skip, 1, doc_movie_skip },
 
 	{ "set_volume", movie_set_volume, 1, doc_movie_set_volume },
 	{ "set_display", movie_set_display, 1, doc_movie_set_display },
 	{ "get_time", movie_get_time, 1, doc_movie_get_time },
 	{ "get_length", movie_get_length, 1, doc_movie_get_length },
 	{ "get_busy", movie_get_busy, 1, doc_movie_get_busy },
-
-	{ "skip", movie_skip, 1, doc_movie_skip },
-        { "render_frame", movie_noop, 1, "obsolete, does nothing"},
+        { "render_frame", movie_render_frame, 1, doc_movie_render_frame},
 
 	{ NULL, NULL }
 };
 
 static void movie_dealloc(PyObject* self)
 {
-	FFMovie* movie = PyMovie_AsFFMovie(self);
- 
-       Py_BEGIN_ALLOW_THREADS
-	ffmovie_close(movie);
+	SMPEG* movie = PyMovie_AsSMPEG(self);
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_delete(movie);
         Py_END_ALLOW_THREADS
 	Py_XDECREF(((PyMovieObject*)self)->surftarget);
 	Py_XDECREF(((PyMovieObject*)self)->filesource);
 {
 	PyObject* file, *final, *filesource=NULL;
 	char* name = NULL;
-	FFMovie* movie=NULL;
+	SMPEG* movie=NULL;
+	SMPEG_Info info;
 	SDL_Surface* screen;
+	char* error;
+	int audioavail = 0;
 	if(!PyArg_ParseTuple(arg, "O", &file))
 		return NULL;
 
+	if(!SDL_WasInit(SDL_INIT_AUDIO))
+		audioavail = 1;
+
 	if(PyString_Check(file) || PyUnicode_Check(file))
 	{
 		if(!PyArg_ParseTuple(arg, "s", &name))
 			return NULL;
+		movie = SMPEG_new(name, &info, audioavail);
+	}
+	else if(PyFile_Check(file))
+	{
+		SDL_RWops *rw = SDL_RWFromFP(PyFile_AsFile(file), 0);
+		movie = SMPEG_new_rwops(rw, &info, audioavail);
+		filesource = file;
+		Py_INCREF(file);
+	}
+	else
+	{
+		SDL_RWops *rw;
+                if(!(rw = RWopsFromPythonThreaded(file)))
+			return NULL;
+                Py_BEGIN_ALLOW_THREADS
+		movie = SMPEG_new_rwops(rw, &info, audioavail);
+                Py_END_ALLOW_THREADS
+	}
 
-printf("  ^opening movie %s\n", name);fflush(stdout);
-		movie = ffmovie_open(name);
-printf("  ^done %p\n", movie);fflush(stdout);
-	}
-        
 	if(!movie)
 		return RAISE(PyExc_SDLError, "Cannot create Movie object");
 
-      	screen = SDL_GetVideoSurface();
+	error = SMPEG_error(movie);
+	if(error)
+	{
+/* while this would seem correct, it causes a crash, so don't delete */
+/*	    SMPEG_delete(movie);*/
+	    return RAISE(PyExc_SDLError, error);
+	}
 
+        Py_BEGIN_ALLOW_THREADS
+	SMPEG_enableaudio(movie, audioavail);
+
+	screen = SDL_GetVideoSurface();
+	if(screen)
+		SMPEG_setdisplay(movie, screen, NULL, NULL);
+
+	SMPEG_scaleXY(movie, info.width, info.height);
+        Py_END_ALLOW_THREADS
 
 	final = PyMovie_New(movie);
-	if(!final) {
-		ffmovie_close(movie);
-        } else {
-            filesource = PyString_FromString(name);
-            ((PyMovieObject*)final)->filesource = filesource;
-        }
+	if(!final)
+		SMPEG_delete(movie);
+	((PyMovieObject*)final)->filesource = filesource;
 
 	return final;
 }
 
 
 
-
-static PyMethodDef moviemod_builtins[] =
+static PyMethodDef mixer_builtins[] =
 {
 	{ "Movie", Movie, 1, doc_Movie },
 
 
 
 
-static PyObject* PyMovie_New(FFMovie* movie)
+static PyObject* PyMovie_New(SMPEG* movie)
 {
 	PyMovieObject* movieobj;
 
 	PyType_Init(PyMovie_Type);
 
 	/* create the module */
-	module = Py_InitModule3("movie", moviemod_builtins, doc_pygame_movie_MODULE);
+	module = Py_InitModule3("movie", mixer_builtins, doc_pygame_movie_MODULE);
 	dict = PyModule_GetDict(module);
 
 	PyDict_SetItemString(dict, "MovieType", (PyObject *)&PyMovie_Type);
 
-        /*imported needed apis*/
+	/*imported needed apis*/
 	import_pygame_base();
 	import_pygame_surface();
 	import_pygame_rwobject();
 	import_pygame_rect();
-
-    PyGame_RegisterQuit(autoquit);
 }
 

File src/movieext.c

+/*
+    pygame - Python Game Library
+    Copyright (C) 2000-2001  Pete Shinners
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Pete Shinners
+    pete@shinners.org
+*/
+
+/*
+ *  movie playback for pygame
+ */
+#include "pygame.h"
+#include "ffmovie.h"
+
+
+
+typedef struct {
+  PyObject_HEAD
+  FFMovie* movie;
+  PyObject* surftarget;
+} PyMovieObject;
+#define PyMovie_AsFFMovie(x) (((PyMovieObject*)x)->movie)
+
+
+staticforward PyTypeObject PyMovie_Type;
+static PyObject* PyMovie_New(FFMovie*);
+#define PyMovie_Check(x) ((x)->ob_type == &PyMovie_Type)
+
+
+
+static void autoquit(void)
+{
+    ffmovie_abortall();
+}
+
+
+/* movie object methods */
+
+    /*DOC*/ static char doc_movie_play[] =
+    /*DOC*/    "Movie.play() -> None\n"
+    /*DOC*/    "start movie playback\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Starts playback of a movie. If audio or video is enabled\n"
+    /*DOC*/    "for the Movie, those outputs will be created. \n"
+    /*DOC*/ ;
+
+static PyObject* movie_play(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+	int loops=0;
+
+        if(!PyArg_ParseTuple(args, "|i", &loops))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+        Py_BEGIN_ALLOW_THREADS
+	ffmovie_play(movie);
+        Py_END_ALLOW_THREADS
+	RETURN_NONE
+}
+
+
+
+    /*DOC*/ static char doc_movie_stop[] =
+    /*DOC*/    "Movie.stop() -> None\n"
+    /*DOC*/    "stop movie playback\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Stops playback of a movie. If sound and video are being\n"
+    /*DOC*/    "rendered, both will be stopped at their current position.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_stop(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+        Py_BEGIN_ALLOW_THREADS
+	ffmovie_stop(movie);
+        Py_END_ALLOW_THREADS
+	RETURN_NONE
+}
+
+
+    /*DOC*/ static char doc_movie_pause[] =
+    /*DOC*/    "Movie.pause() -> None\n"
+    /*DOC*/    "pause/resume movie playback\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "This will temporarily stop playback of the movie. When called\n"
+    /*DOC*/    "a second time, playback will resume where it left off.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_pause(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+        Py_BEGIN_ALLOW_THREADS
+	ffmovie_pause(movie);
+        Py_END_ALLOW_THREADS
+	RETURN_NONE
+}
+
+
+    /*DOC*/ static char doc_movie_rewind[] =
+    /*DOC*/    "Movie.rewind() -> None\n"
+    /*DOC*/    "set playback position to the beginning of the movie\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Sets the movie playback position to the start of\n"
+    /*DOC*/    "the movie. This can raise a ValueError if the movie\n"
+    /*DOC*/    "cannot be rewound.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "The movie will automatically start playing if the movie\n"
+    /*DOC*/    "is currently playing.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "If rewinding the movie fails, it will invalidate this Movie\n"
+    /*DOC*/    "object.\n"
+    /*DOC*/ ;
+/*need something for this, if anything reinit a new movie and start*/
+
+static PyObject* movie_rewind(PyObject* self, PyObject* args)
+{
+        PyMovieObject* movieobj = (PyMovieObject*)self;
+        if(!movieobj->movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+        Py_BEGIN_ALLOW_THREADS
+        movieobj->movie = ffmovie_reopen(movieobj->movie);        
+        Py_END_ALLOW_THREADS
+        
+        if(!movieobj->movie)
+            RAISE(PyExc_SDLError, "Error handling movie source for rewind");
+	RETURN_NONE
+}
+
+
+    /*DOC*/ static char doc_movie_set_volume[] =
+    /*DOC*/    "Movie.set_volume(val) -> None\n"
+    /*DOC*/    "change volume for sound\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Set the play volume for this Movie. The volume value is between\n"
+    /*DOC*/    "0.0 and 1.0.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_set_volume(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+	float value;
+    
+	if(!PyArg_ParseTuple(args, "f", &value))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+        Py_BEGIN_ALLOW_THREADS
+        ffmovie_setvolume(movie, (int)(value*128));
+        Py_END_ALLOW_THREADS
+
+	RETURN_NONE
+}
+
+
+    /*DOC*/ static char doc_movie_set_display[] =
+    /*DOC*/    "Movie.set_display(Surface, [rect]) -> None\n"
+    /*DOC*/    "change the video output surface\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Set the output surface for the Movie's video. You may\n"
+    /*DOC*/    "also specify a position for the topleft corner of the\n"
+    /*DOC*/    "video.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "The position argument must be a rectstyle if given.\n"
+    /*DOC*/    "The video will be stretched to fill the rectangular area.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "You may also pass None as the destination Surface, and\n"
+    /*DOC*/    "no video will be rendered for the movie playback.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_set_display(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+	PyObject* surfobj, *posobj=NULL;
+        SDL_Rect* sdlrect, sdltemp;
+	GAME_Rect *rect, temp;
+    
+	if(!PyArg_ParseTuple(args, "O|O", &surfobj, &posobj))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+	Py_XDECREF(((PyMovieObject*)self)->surftarget);
+	((PyMovieObject*)self)->surftarget = NULL;
+
+	if(PySurface_Check(surfobj))
+	{
+       SDL_Surface* surf = PySurface_AsSurface(surfobj);
+
+	   ((PyMovieObject*)self)->surftarget = surfobj;
+       Py_INCREF(surfobj);
+
+		if(posobj == NULL)
+		{
+			sdlrect = NULL;
+		}
+		else if((rect = GameRect_FromObject(posobj, &temp)))
+                {
+                        sdlrect = &sdltemp;
+                        sdltemp.x = rect->x;
+                        sdltemp.y = rect->y;
+                        sdltemp.w = rect->w;
+                        sdltemp.h = rect->h;
+                }
+                else
+			return RAISE(PyExc_TypeError, "Invalid position argument");
+
+            Py_BEGIN_ALLOW_THREADS            
+            ffmovie_setdisplay(movie, surf, sdlrect);
+            Py_END_ALLOW_THREADS
+	}
+	else
+	{
+            Py_BEGIN_ALLOW_THREADS
+	    ffmovie_setdisplay(movie, NULL, NULL);
+            Py_END_ALLOW_THREADS
+	    if(surfobj != Py_None)
+		       return RAISE(PyExc_TypeError, "destination must be a Surface");
+	}
+
+	RETURN_NONE;
+}
+
+
+    /*DOC*/ static char doc_movie_has_video[] =
+    /*DOC*/    "Movie.has_video() -> bool\n"
+    /*DOC*/    "query if movie stream has video\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Returns a true value when the Movie object has a valid\n"
+    /*DOC*/    "video stream.\n"
+    /*DOC*/ ;
+
+
+static PyObject* movie_has_video(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+	return PyInt_FromLong(movie->video_st != NULL);
+}
+
+    /*DOC*/ static char doc_movie_has_audio[] =
+    /*DOC*/    "Movie.has_audio() -> bool\n"
+    /*DOC*/    "query if movie stream has audio\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Returns a true value when the Movie object has a valid\n"
+    /*DOC*/    "audio stream.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_has_audio(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+
+	return PyInt_FromLong(movie->audio_st != NULL);
+}
+
+    /*DOC*/ static char doc_movie_get_size[] =
+    /*DOC*/    "Movie.get_size() -> width,height\n"
+    /*DOC*/    "query the size of the video image\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Returns the size of the video image the mpeg provides.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_get_size(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+        int w=0, h=0;
+
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+	if(movie->video_st != NULL) {
+                w = movie->video_st->codec.width;
+                h = movie->video_st->codec.height;
+        }
+	return Py_BuildValue("(ii)", w, h);
+}
+
+    /*DOC*/ static char doc_movie_get_frame[] =
+    /*DOC*/    "Movie.get_frame() -> int\n"
+    /*DOC*/    "query the current frame in the movie\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Gets the current video frame number for the movie.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_get_frame(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+	return PyInt_FromLong(movie->frame_count);
+}
+
+    /*DOC*/ static char doc_movie_get_time[] =
+    /*DOC*/    "Movie.get_time() -> float\n"
+    /*DOC*/    "query the current time in the movie\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Gets the current time (in seconds) for the movie.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_get_time(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+	return PyFloat_FromDouble(movie->frame_last_pts);
+}
+
+    /*DOC*/ static char doc_movie_get_length[] =
+    /*DOC*/    "Movie.get_length() -> float\n"
+    /*DOC*/    "query playback time of the movie\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Returns the total time (in seconds) of the movie.\n"
+    /*DOC*/ ;
+/*FIX, currently a no op*/
+static PyObject* movie_get_length(PyObject* self, PyObject* args)
+{
+/*	FFMovie* movie = PyMovie_AsFFMovie(self);*/
+
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+
+	return PyFloat_FromDouble(0.0);
+}
+
+
+    /*DOC*/ static char doc_movie_get_busy[] =
+    /*DOC*/    "Movie.get_busy() -> bool\n"
+    /*DOC*/    "query the playback state\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Returns true if the movie is currently playing.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_get_busy(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+
+	if(!PyArg_ParseTuple(args, ""))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+	return PyInt_FromLong(movie->context != NULL);
+}
+
+    /*DOC*/ static char doc_movie_skip[] =
+    /*DOC*/    "Movie.skip(seconds) -> None\n"
+    /*DOC*/    "skip ahead a given amount of time\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Skips ahead in the movie a given number of seconds.\n"
+    /*DOC*/    "Totally experimental, and doesn't work very foos.\n"
+    /*DOC*/ ;
+
+static PyObject* movie_skip(PyObject* self, PyObject* args)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+        float seconds;
+
+	if(!PyArg_ParseTuple(args, "f", &seconds))
+		return NULL;
+        if(!movie)
+            RAISE(PyExc_SDLError, "Movie object invalid");
+
+        movie->time_offset -= seconds;
+        
+	return PyInt_FromLong(movie->context != NULL);
+}
+
+
+static PyObject* movie_noop(PyObject* self, PyObject* args)
+{
+	return PyInt_FromLong(0);
+}
+
+
+
+static PyMethodDef movie_builtins[] =
+{
+	{ "play", movie_play, 1, doc_movie_play },
+	{ "stop", movie_stop, 1, doc_movie_stop },
+	{ "pause", movie_pause, 1, doc_movie_pause },
+	{ "rewind", movie_rewind, 1, doc_movie_rewind },
+
+	{ "set_volume", movie_set_volume, 1, doc_movie_set_volume },
+	{ "set_display", movie_set_display, 1, doc_movie_set_display },
+
+	{ "has_video", movie_has_video, 1, doc_movie_has_video },
+	{ "has_audio", movie_has_audio, 1, doc_movie_has_audio },
+	{ "get_size", movie_get_size, 1, doc_movie_get_size },
+	{ "get_frame", movie_get_frame, 1, doc_movie_get_frame },
+	{ "get_time", movie_get_time, 1, doc_movie_get_time },
+	{ "get_length", movie_get_length, 1, doc_movie_get_length },
+	{ "get_busy", movie_get_busy, 1, doc_movie_get_busy },
+
+	{ "skip", movie_skip, 1, doc_movie_skip },
+        { "render_frame", movie_noop, 1, "obsolete, does nothing"},
+
+	{ NULL, NULL }
+};
+
+
+/*sound object internals*/
+
+static void movie_dealloc(PyObject* self)
+{
+	FFMovie* movie = PyMovie_AsFFMovie(self);
+ 
+        if(movie) {
+            Py_BEGIN_ALLOW_THREADS
+            ffmovie_close(movie);
+            Py_END_ALLOW_THREADS
+        }
+	Py_XDECREF(((PyMovieObject*)self)->surftarget);
+	PyObject_DEL(self);
+}
+
+
+static PyObject* movie_getattr(PyObject* self, char* attrname)
+{
+	return Py_FindMethod(movie_builtins, self, attrname);
+}
+
+
+    /*DOC*/ static char doc_Movie_MODULE[] =
+    /*DOC*/    "The Movie object represents an opened MPEG file.\n"
+    /*DOC*/    "You control playback similar to a Sound object.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Movie objects have a target display Surface.\n"
+    /*DOC*/    "The movie is rendered to this Surface in a background\n"
+    /*DOC*/    "thread. If the Surface is the display surface, and\n"
+    /*DOC*/    "the system supports it, the movie will render into a\n"
+    /*DOC*/    "Hardware YUV overlay plane. If you don't set a display\n"
+    /*DOC*/    "Surface, it will default to the display Surface.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Movies are played back in background threads, so there\n"
+    /*DOC*/    "is very little management needed on the user end. Just\n"
+    /*DOC*/    "load the Movie, set the destination, and Movie.play()\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Movies will only playback audio if the pygame.mixer\n"
+    /*DOC*/    "module is not initialized. It is easy to temporarily\n"
+    /*DOC*/    "call pygame.mixer.quit() to disable audio, then create\n"
+    /*DOC*/    "and play your movie. Finally calling pygame.mixer.init()\n"
+    /*DOC*/    "again when finished with the Movie.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "NOTE: When disabling the mixer so a movie may play audio,\n"
+    /*DOC*/    "you must disable the audio before calling pygame.movie.Movie\n"
+    /*DOC*/    "or the movie will not realise that it may access the audio.\n"
+    /*DOC*/    "Before reinitialising the mixer, You must remove all\n"
+    /*DOC*/    "references to the movie before calling pygame.mixer.init()\n"
+    /*DOC*/    "or the init will fail, leading to errors when you attempt to\n"
+    /*DOC*/    "use the mixer.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "eg.\n"
+    /*DOC*/    "pygame.mixer.quit()\n"
+    /*DOC*/    "movie=pygame.movie.Movie(\"my.mpg\")\n"
+    /*DOC*/    "movie.play()\n"
+    /*DOC*/    "# process events until movie finished here\n"
+    /*DOC*/    "movie.stop()\n"
+    /*DOC*/    "movie=None # if you don't do this bit the init will fail\n"
+    /*DOC*/    "pygame.mixer.init()\n"
+    /*DOC*/ ;
+
+static PyTypeObject PyMovie_Type =
+{
+	PyObject_HEAD_INIT(NULL)
+	0,
+	"Movie",
+	sizeof(PyMovieObject),
+	0,
+	movie_dealloc,
+	0,
+	movie_getattr,
+	NULL,					/*setattr*/
+	NULL,					/*compare*/
+	NULL,					/*repr*/
+	NULL,					/*as_number*/
+	NULL,					/*as_sequence*/
+	NULL,					/*as_mapping*/
+	(hashfunc)NULL, 		/*hash*/
+	(ternaryfunc)NULL,		/*call*/
+	(reprfunc)NULL, 		/*str*/
+	0L,0L,0L,0L,
+	doc_Movie_MODULE /* Documentation string */
+};
+
+
+
+
+/*movie module methods*/
+
+
+    /*DOC*/ static char doc_Movie[] =
+    /*DOC*/    "pygame.movie.Movie(file) -> Movie\n"
+    /*DOC*/    "load a new MPEG stream\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Loads a new movie stream from a MPEG file. The file\n"
+    /*DOC*/    "argument is either a filename, or any python file-like object\n"
+    /*DOC*/ ;
+
+static PyObject* Movie(PyObject* self, PyObject* arg)
+{
+	PyObject* file, *final;
+	char* name = NULL;
+	FFMovie* movie=NULL;
+	SDL_Surface* screen;
+	if(!PyArg_ParseTuple(arg, "O", &file))
+		return NULL;
+
+	if(PyString_Check(file) || PyUnicode_Check(file))
+	{
+		if(!PyArg_ParseTuple(arg, "s", &name))
+			return NULL;
+
+		movie = ffmovie_open(name);
+	}
+        
+	if(!movie)
+		return RAISE(PyExc_SDLError, "Cannot create Movie object");
+
+      	screen = SDL_GetVideoSurface();
+
+
+	final = PyMovie_New(movie);
+	if(!final) {
+		ffmovie_close(movie);
+        }
+
+	return final;
+}
+
+
+
+
+
+static PyMethodDef moviemod_builtins[] =
+{
+	{ "Movie", Movie, 1, doc_Movie },
+
+	{ NULL, NULL }
+};
+
+
+
+static PyObject* PyMovie_New(FFMovie* movie)
+{
+	PyMovieObject* movieobj;
+
+	if(!movie)
+		return RAISE(PyExc_RuntimeError, "unable to create movie.");
+
+	movieobj = PyObject_NEW(PyMovieObject, &PyMovie_Type);
+	if(movieobj)
+		movieobj->movie = movie;
+
+	movieobj->surftarget = NULL;
+
+	return (PyObject*)movieobj;
+}
+
+
+
+    /*DOC*/ static char doc_pygame_movie_MODULE[] =
+    /*DOC*/    "The movie module is an optional pygame module that\n"
+    /*DOC*/    "allows for decoding and playback of MPEG movie files.\n"
+    /*DOC*/    "The module only contains a single function, Movie()\n"
+    /*DOC*/    "which creates a new Movie object.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Movies are played back in background threads, so there\n"
+    /*DOC*/    "is very little management needed on the user end. Just\n"
+    /*DOC*/    "load the Movie, set the destination, and Movie.play()\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Movies will only playback audio if the pygame.mixer\n"
+    /*DOC*/    "module is not initialized. It is easy to temporarily\n"
+    /*DOC*/    "call pygame.mixer.quit() to disable audio, then create\n"
+    /*DOC*/    "and play your movie. Finally calling pygame.mixer.init()\n"
+    /*DOC*/    "again when finished with the Movie.\n"
+    /*DOC*/ ;
+
+PYGAME_EXPORT
+void initmovieext(void)
+{
+	PyObject *module, *dict;
+
+	PyType_Init(PyMovie_Type);
+
+	/* create the module */
+	module = Py_InitModule3("movieext", moviemod_builtins, doc_pygame_movie_MODULE);
+	dict = PyModule_GetDict(module);
+
+	PyDict_SetItemString(dict, "MovieType", (PyObject *)&PyMovie_Type);
+
+        /*imported needed apis*/
+	import_pygame_base();
+	import_pygame_surface();
+	import_pygame_rwobject();
+	import_pygame_rect();
+
+    PyGame_RegisterQuit(autoquit);
+}
+