#include "SDL.h" #include "MPEG.h" #ifdef WIN32 #include #else #include #endif #include #include #include #ifndef O_BINARY #define O_BINARY 0 #endif MPEG::MPEG(const char * name, bool SDLaudio) : MPEGerror() { SDL_RWops *source; mpeg_mem = 0; source = SDL_RWFromFile(name, "rb"); if (!source) { InitErrorState(); SetError(SDL_GetError()); return; } Init(source, SDLaudio); } MPEG::MPEG(int Mpeg_FD, bool SDLaudio) : MPEGerror() { SDL_RWops *source; mpeg_mem = 0; // *** FIXME we're leaking a bit of memory for the FILE * // best solution would be to have SDL_RWFromFD FILE *file = fdopen(Mpeg_FD, "rb"); if (!file) { InitErrorState(); SetError(strerror(errno)); return; } source = SDL_RWFromFP(file,false); if (!source) { InitErrorState(); SetError(SDL_GetError()); return; } Init(source, SDLaudio); } MPEG::MPEG(void *data, int size, bool SDLaudio) : MPEGerror() { SDL_RWops *source; // The semantics are that the data passed in should be copied // (?) mpeg_mem = new char[size]; memcpy(mpeg_mem, data, size); source = SDL_RWFromMem(mpeg_mem, size); if (!source) { InitErrorState(); SetError(SDL_GetError()); return; } Init(source, SDLaudio); } MPEG::MPEG(SDL_RWops *mpeg_source, bool SDLaudio) : MPEGerror() { mpeg_mem = 0; Init(mpeg_source, SDLaudio); } void MPEG::Init(SDL_RWops *mpeg_source, bool SDLaudio) { source = mpeg_source; sdlaudio = SDLaudio; /* Create the system that will parse the MPEG stream */ system = new MPEGsystem(source); /* Initialize everything to invalid values for cleanup */ error = NULL; audiostream = videostream = NULL; audioaction = NULL; videoaction = NULL; audio = NULL; video = NULL; audioaction_enabled = SDLaudio; videoaction_enabled = false; loop = false; pause = false; parse_stream_list(); EnableAudio(audioaction_enabled); EnableVideo(videoaction_enabled); if ( ! audiostream && ! videostream ) { SetError("No audio/video stream found in MPEG"); } if ( system && system->WasError() ) { SetError(system->TheError()); } if ( audio && audio->WasError() ) { SetError(audio->TheError()); } if ( video && video->WasError() ) { SetError(video->TheError()); } if ( WasError() ) { SetError(TheError()); } } void MPEG::InitErrorState() { audio = NULL; video = NULL; system = NULL; error = NULL; source = NULL; audiostream = videostream = NULL; audioaction = NULL; videoaction = NULL; audio = NULL; video = NULL; audioaction_enabled = videoaction_enabled = false; loop = false; pause = false; } MPEG::~MPEG() { Stop(); if(video) delete video; if(audio) delete audio; if(system) delete system; if(source) SDL_RWclose(source); if ( mpeg_mem ) delete[] mpeg_mem; } bool MPEG::AudioEnabled(void) { return(audioaction_enabled); } void MPEG::EnableAudio(bool enabled) { if ( enabled && ! audioaction ) { enabled = false; } audioaction_enabled = enabled; /* Stop currently playing stream, if necessary */ if ( audioaction && ! audioaction_enabled ) { audioaction->Stop(); } /* Set the video time source */ if ( videoaction ) { if ( audioaction_enabled ) { videoaction->SetTimeSource(audioaction); } else { videoaction->SetTimeSource(NULL); } } if(audiostream) audiostream->enable(enabled); } bool MPEG::VideoEnabled(void) { return(videoaction_enabled); } void MPEG::EnableVideo(bool enabled) { if ( enabled && ! videoaction ) { enabled = false; } videoaction_enabled = enabled; /* Stop currently playing stream, if necessary */ if ( videoaction && ! videoaction_enabled ) { videoaction->Stop(); } if(videostream) videostream->enable(enabled); } /* MPEG actions */ void MPEG::Loop(bool toggle) { loop = toggle; } void MPEG::Play(void) { if ( AudioEnabled() ) { audioaction->Play(); } if ( VideoEnabled() ) { videoaction->Play(); } } void MPEG::Stop(void) { if ( VideoEnabled() ) { videoaction->Stop(); } if ( AudioEnabled() ) { audioaction->Stop(); } } void MPEG::Rewind(void) { seekIntoStream(0); } void MPEG::Pause(void) { pause = !pause; if ( VideoEnabled() ) { videoaction->Pause(); } if ( AudioEnabled() ) { audioaction->Pause(); } } /* Michel Darricau from eProcess conflict name with popcorn */ MPEGstatus MPEG::GetStatus(void) { MPEGstatus status; status = MPEG_STOPPED; if ( VideoEnabled() ) { /* Michel Darricau from eProcess conflict name with popcorn */ switch (videoaction->GetStatus()) { case MPEG_PLAYING: status = MPEG_PLAYING; break; default: break; } } if ( AudioEnabled() ) { /* Michel Darricau from eProcess conflict name with popcorn */ switch (audioaction->GetStatus()) { case MPEG_PLAYING: status = MPEG_PLAYING; break; default: break; } } if(status == MPEG_STOPPED && loop && !pause) { /* Here we go again */ Rewind(); Play(); if ( VideoEnabled() ) { /* Michel Darricau from eProcess conflict name with popcorn */ switch (videoaction->GetStatus()) { case MPEG_PLAYING: status = MPEG_PLAYING; break; default: break; } } if ( AudioEnabled() ) { /* Michel Darricau from eProcess conflict name with popcorn */ switch (audioaction->GetStatus()) { case MPEG_PLAYING: status = MPEG_PLAYING; break; default: break; } } } return(status); } /* MPEG audio actions */ bool MPEG::GetAudioInfo(MPEG_AudioInfo *info) { if ( AudioEnabled() ) { return(audioaction->GetAudioInfo(info)); } return(false); } void MPEG::Volume(int vol) { if ( AudioEnabled() ) { audioaction->Volume(vol); } } bool MPEG::WantedSpec(SDL_AudioSpec *wanted) { if( audiostream ) { return(GetAudio()->WantedSpec(wanted)); } return(false); } void MPEG::ActualSpec(const SDL_AudioSpec *actual) { if( audiostream ) { GetAudio()->ActualSpec(actual); } } MPEGaudio *MPEG::GetAudio(void) { // Simple accessor used in the C interface return audio; } /* MPEG video actions */ bool MPEG::GetVideoInfo(MPEG_VideoInfo *info) { if ( VideoEnabled() ) { return(videoaction->GetVideoInfo(info)); } return(false); } bool MPEG::SetDisplay(SDL_Surface *dst, SDL_mutex *lock, MPEG_DisplayCallback callback) { if ( VideoEnabled() ) { return(videoaction->SetDisplay(dst, lock, callback)); } return(false); } void MPEG::MoveDisplay(int x, int y) { if ( VideoEnabled() ) { videoaction->MoveDisplay(x, y); } } void MPEG::ScaleDisplayXY(int w, int h) { if ( VideoEnabled() ) { videoaction->ScaleDisplayXY(w, h); } } void MPEG::SetDisplayRegion(int x, int y, int w, int h) { if ( VideoEnabled() ) { videoaction->SetDisplayRegion(x, y, w, h); } } void MPEG::RenderFrame(int frame) { if ( VideoEnabled() ) { videoaction->RenderFrame(frame); } } void MPEG::RenderFinal(SDL_Surface *dst, int x, int y) { Stop(); if ( VideoEnabled() ) { videoaction->RenderFinal(dst, x, y); } Rewind(); } SMPEG_Filter * MPEG::Filter(SMPEG_Filter * filter) { if ( VideoEnabled() ) { return(videoaction->Filter(filter)); } return 0; } void MPEG::Seek(int position) { int was_playing = 0; /* Cannot seek past end of file */ if((Uint32)position > system->TotalSize()) return; /* Michel Darricau from eProcess conflict name with popcorn */ /* get info whrether we need to restart playing at the end */ if( GetStatus() == MPEG_PLAYING ) was_playing = 1; if(!seekIntoStream(position)) return; /* If we were playing and not rewind then play again */ if (was_playing) Play(); if (VideoEnabled() && !was_playing) videoaction->RenderFrame(0); if ( pause && VideoEnabled() ) { videoaction->Pause(); } if ( pause && AudioEnabled() ) { audioaction->Pause(); } } bool MPEG::seekIntoStream(int position) { /* First we stop everything */ Stop(); /* Go to the desired position into file */ if(!system->Seek(position)) return(false); /* Seek first aligned data */ if(audiostream && audioaction_enabled) while(audiostream->time() == -1) if ( ! audiostream->next_packet() ) return false; if(videostream && videoaction_enabled) while(videostream->time() == -1) if ( ! videostream->next_packet() ) return false; /* Calculating current play time on audio only makes sense when there is no video */ if ( audioaction && !videoaction) { audioaction->Rewind(); audioaction->ResetSynchro(system->TimeElapsedAudio(position)); } /* And forget what we previouly buffered */ else if ( audioaction ) { audioaction->Rewind(); audioaction->ResetSynchro(audiostream->time()); } if ( videoaction ) { videoaction->Rewind(); videoaction->ResetSynchro(videostream->time()); } return(true); } void MPEG::Skip(float seconds) { if(system->get_stream(SYSTEM_STREAMID)) { system->Skip(seconds); } else { /* No system information in MPEG */ if( VideoEnabled() ) videoaction->Skip(seconds); if( AudioEnabled() ) audioaction->Skip(seconds); } } void MPEG::GetSystemInfo(MPEG_SystemInfo * sinfo) { sinfo->total_size = system->TotalSize(); sinfo->current_offset = system->Tell(); sinfo->total_time = system->TotalTime(); /* Get current time from audio or video decoder */ /* TODO: move timing reference in MPEGsystem */ sinfo->current_time = 0; if( videoaction ) sinfo->current_time = videoaction->Time(); if( audioaction ) sinfo->current_time = audioaction->Time(); } void MPEG::parse_stream_list() { MPEGstream ** stream_list; register int i; /* A new thread is created for each video and audio */ /* stream */ /* TODO: support MPEG systems containing more than */ /* one audio or video stream */ i = 0; do { /* Retreive the list of streams */ stream_list = system->GetStreamList(); switch(stream_list[i]->streamid) { case SYSTEM_STREAMID: break; case AUDIO_STREAMID: audiostream = stream_list[i]; audioaction_enabled = true; audiostream->next_packet(); audio = new MPEGaudio(audiostream, sdlaudio); audioaction = audio; break; case VIDEO_STREAMID: videostream = stream_list[i]; videoaction_enabled = true; videostream->next_packet(); video = new MPEGvideo(videostream); videoaction = video; break; } i++; } while(stream_list[i]); }