Playback.cpp
上传用户:lusi_8715
上传日期:2007-01-08
资源大小:199k
文件大小:22k
- /**************************************************************************************
- * *
- * This application contains code from OpenDivX and is released as a "Larger Work" *
- * under that license. Consistant with that license, this application is released *
- * under the GNU General Public License. *
- * *
- * The OpenDivX license can be found at: http://www.projectmayo.com/opendivx/docs.php *
- * The GPL can be found at: http://www.gnu.org/copyleft/gpl.html *
- * *
- * Copyright (c) 2001 - Project Mayo *
- * *
- * Authors: Damien Chavarria <adrc at projectmayo.com> *
- * *
- **************************************************************************************/
- #include "Playback.h"
- /*
- * Main Class
- */
- /*
- * Internal audio callback
- * for audio streams in AVIs
- *
- */
- void audio_callback(void *lpData, void *buffer, unsigned int size)
- {
- Playback *playback = (Playback *) lpData;
- if(playback && playback->playing && !playback->paused) {
- playback->audio_bytes += size;
- if(playback->audioCodec)
- playback->audioCodec->Decompress(buffer, size);
- }
- else {
- memset(buffer, 0, size);
- }
- }
- /*
- * Constructor : Does nothing
- *
- */
- Playback::Playback()
- {
- this->ok = 0;
- this->codec = NULL;
- this->decaps = NULL;
- this->audioCodec = NULL;
- this->videoRenderer = NULL;
- this->audioRenderer = NULL;
- this->subtitles = NULL;
- this->playing = 0;
- this->paused = 0;
- this->use_bilinear = 0;
- this->fullscreen = 0;
- this->fast_forward = 0;
- this->rewind = 0;
- this->volume = 100;
- this->has_subtitles = 0;
- this->use_subtitles = 0;
- this->playbackMutex = CreateMutex (NULL, FALSE, NULL);
- }
- /*
- * Open : Tries to open a Playback
- *
- */
- int Playback::Open(char *lpFilename, int type, HWND hwnd)
- {
- /*
- * Init everything
- */
- this->ok = 0;
- this->codec = NULL;
- this->decaps = NULL;
- this->audioCodec = NULL;
- this->videoRenderer = NULL;
- this->audioRenderer = NULL;
- this->videoBuffer = NULL;
- this->subtitles = NULL;
- this->playing = 0;
- this->paused = 0;
- this->use_bilinear = 0;
- this->fullscreen = 0;
- this->fast_forward = 0;
- this->rewind = 0;
- this->volume = 100;
- this->has_subtitles = 0;
- this->use_subtitles = 0;
- if(lpFilename) {
- this->hwnd = hwnd;
-
- decaps = new AviDecaps();
- if(decaps->Open(lpFilename, type)) {
- /*
- * Audio
- */
- this->audioCodec = new AudioCodec(decaps, decaps->WaveFormatEx());
-
- if(audioCodec->IsOK()) {
- audioRenderer = new AudioRenderer(audioCodec->GetFormat(), hwnd);
- audioRenderer->SetCallback(this, audio_callback);
- }
- /*
- * Video
- */
- codec = new Codec(decaps->BitmapInfoHeader());
- if(codec->IsOK()) {
- videoRenderer = new VideoRenderer();
- videoRenderer->SetBilinear(this->use_bilinear);
- if(videoRenderer->Open(hwnd, decaps->BitmapInfoHeader())) {
- /*
- * get the video mode and try
- * to set the codec into the same one.
- */
- codec->SetVideoMode(videoRenderer->GetVideoMode());
- videoRenderer->SetCodecVideoMode(codec->GetVideoMode());
- this->fullscreen = 0;
- this->ok = TRUE;
- this->videoBuffer = new VideoBuffer(this->decaps, this->codec);
- this->videoBuffer->Start();
- /*
- * Try to find subtitles
- */
- this->subtitles = new Subtitles();
- if(subtitles->Open(lpFilename)) {
-
- this->has_subtitles = 1;
- }
-
- }
- else {
- this->ok = 0;
- MessageBox(NULL, "Couldn't init video, make sure you have DirectX 7.0 installed",
- "Fatal Error", MB_OK);
- return 0;
- }
- playing = 0;
- paused = 0;
-
- if(this->ok == TRUE) {
- return 1;
- }
- }
- else {
- MessageBox(NULL, "Could not initialize Codec", "Error", MB_OK);
- return 0;
- }
- }
- }
- return 0;
- }
- /*
- * Destructor : CleanUp.
- *
- */
- Playback::~Playback()
- {
- CloseHandle(this->playbackMutex);
- }
- /*
- * Return TRUE is object
- * is ready for playing.
- *
- */
- int Playback::OK()
- {
- return this->ok;
- }
- /*
- * Return the current
- * video time in ms
- *
- */
- unsigned long Playback::VideoTime()
- {
- /*
- * time is in ms
- */
- if(this->decaps && this->decaps->FrameRate() != 0) {
- return (unsigned long) ((double) this->video_frames * 1000.0 / (double) this->decaps->FrameRate());
- }
- else {
- return 0;
- }
- }
- /*
- * Wrapper against the renderer call
- * do not affect video only AVIs
- *
- */
- unsigned long Playback::AudioTime()
- {
- if(this->audioRenderer && this->audioCodec) {
-
- return this->audioRenderer->AudioTime();
- }
- else {
- return this->VideoTime();
- }
- }
- /*
- * Gives Global Time
- *
- */
- int Playback::GetTime()
- {
-
- return VideoTime()/1000;
- }
- int Playback::GetTotalTime()
- {
-
- if(this->decaps) {
- return (int) (this->decaps->TotalFrames() / (double) this->decaps->FrameRate());
- }
- else {
- return 0;
- }
- }
- /*
- * Internal Video
- * Only Thread
- *
- */
- DWORD WINAPI VideoThreadFunc( LPVOID lpData)
- {
- Playback *playback = (Playback *) lpData;
- int time, timeDiff;
- char *frame = NULL;
-
- if(playback != NULL)
- {
- playback->baseTime = GetTickCount();
- while(playback->playing) {
- debut:
- frame = NULL;
- PM_DEBUG("One Framen", NULL);
- if(!playback->paused) {
- if(playback->fast_forward) {
- playback->decaps->NextKeyFrame();
- }
- else {
- if(playback->rewind) {
-
- playback->decaps->PreviousKeyFrame();
- }
- }
- /*
- * synchro here
- *
- */
- if(!playback->fast_forward && !playback->rewind) {
- timeDiff = playback->VideoTime() - (GetTickCount() - playback->baseTime);
- if(timeDiff > 10) {
- Sleep(timeDiff/2);
- }
- if(timeDiff < -150) {
-
- /*
- * drop here
- */
-
- playback->videoBuffer->Drop();
- playback->video_frames++;
- }
- if(timeDiff < -230) {
-
- /*
- * drop here
- */
-
- playback->videoBuffer->Drop();
- playback->video_frames++;
- }
- }
- else {
- Sleep(80);
- }
- PM_DEBUG("Decodingn", NULL);
- frame = playback->videoBuffer->GiveMeAFrame();
- playback->video_frames++;
- if(frame == NULL) {
- PM_DEBUG("NULL FRAME! Stoppingn", NULL);
- if(!playback->loop)
- playback->Stop(TRUE);
- else {
- playback->decaps->Rewind();
-
- playback->displayed_frames = 0;
- playback->audio_bytes = 0;
- playback->video_frames = 0;
-
- playback->baseTime = GetTickCount();
-
- goto debut;
- }
- break;
- }
- WaitForSingleObject(playback->playbackMutex, INFINITE);
- if(!playback->paused) {
- if(playback->fullscreen) {
- playback->videoRenderer->DrawFullscreen(frame);
- playback->displayed_frames++;
- }
- else {
- playback->videoRenderer->Draw(frame, playback->has_subtitles && playback->use_subtitles);
- playback->displayed_frames++;
- }
- if(playback->has_subtitles && playback->use_subtitles) {
- playback->subtitles->Apply(playback->hwnd, playback->video_frames,
- playback->decaps->FrameRate(), playback->fullscreen);
- }
- }
- ReleaseMutex(playback->playbackMutex);
- PM_DEBUG("Frame Done!n", NULL);
- }
- }
- }
- else {
- MessageBox(NULL, "Playing : NULL playback engine!", "", MB_OK);
- }
- PM_DEBUG("Stop Playing Threadn", NULL);
- return 0;
- }
- /*
- * Internal Video synced
- * on Audio thread
- *
- */
- DWORD WINAPI ThreadFunc( LPVOID lpData)
- {
- Playback *playback = (Playback *) lpData;
- long timeDiff;
- char *frame = NULL;
-
- DWORD time;
- PM_DEBUG("Start Playing Threadn", NULL);
- if(playback != NULL)
- {
- while(playback->playing) {
- debut_audio:
- frame = NULL;
- if(!playback->paused) {
- if(playback->fast_forward) {
- playback->decaps->NextKeyFrame();
- }
- else {
- if(playback->rewind) {
-
- playback->decaps->PreviousKeyFrame();
- }
- }
- /*
- * synchro here
- *
- */
- if(!playback->fast_forward && !playback->rewind) {
- timeDiff = playback->VideoTime() - playback->AudioTime() - 100;
- if(timeDiff == -100) {
-
- /*
- * Nothing to do
- */
- }
- else {
- if(timeDiff > 10) {
- Sleep(timeDiff/2);
- }
- if(timeDiff < -150) {
-
- /*
- * drop here
- */
-
- playback->videoBuffer->Drop();
- playback->video_frames++;
- }
- if(timeDiff < -230) {
-
- /*
- * drop here
- */
- playback->videoBuffer->Drop();
- playback->video_frames++;
- }
- }
- }
- else {
- Sleep(80);
- }
- frame = playback->videoBuffer->GiveMeAFrame();
- playback->video_frames++;
- if(frame == NULL) {
- /*
- * We're at the end of the file
- */
- if(!playback->loop) {
-
- if(playback->audioRenderer)
- playback->audioRenderer->Stop();
- playback->Stop(TRUE);
- }
- else {
- playback->decaps->Rewind();
-
- if(playback->audioRenderer)
- playback->audioRenderer->Stop();
- playback->displayed_frames = 0;
- playback->audio_bytes = 0;
- playback->video_frames = 0;
-
- if(playback->audioRenderer)
- playback->audioRenderer->Start();
-
- goto debut_audio;
- }
- break;
- }
- WaitForSingleObject(playback->playbackMutex, INFINITE);
- if(!playback->paused) {
- if(playback->fullscreen) {
- playback->videoRenderer->DrawFullscreen(frame);
- playback->displayed_frames++;
- }
- else {
- playback->videoRenderer->Draw(frame, playback->has_subtitles && playback->use_subtitles);
- playback->displayed_frames++;
- }
- if(playback->has_subtitles && playback->use_subtitles) {
- playback->subtitles->Apply(playback->hwnd, playback->video_frames,
- playback->decaps->FrameRate(), playback->fullscreen);
- }
- }
- ReleaseMutex(playback->playbackMutex);
- }
- }
- }
- else {
- MessageBox(NULL, "Playing : NULL playback engine!", "", MB_OK);
- }
- PM_DEBUG("Stop Playing Threadn", NULL);
- return 0;
- }
- /*
- * Returns the video width
- *
- */
- int Playback::Width()
- {
- if(this->decaps) {
- return this->decaps->Width();
- }
- else {
- return 0;
- }
- }
- /*
- * Returns the video height
- *
- */
- int Playback::Height()
- {
- if(this->decaps) {
- return this->decaps->Height();
- }
- else {
- return 0;
- }
- }
- /*
- * Tells if we're paused
- *
- */
- BOOL Playback::isPaused()
- {
- return this->paused;
- }
- BOOL Playback::isPlaying()
- {
- return this->playing;
- }
- /*
- * Starts playing
- *
- */
- int Playback::Play()
- {
- if(this->ok == TRUE) {
- if(this->fast_forward) {
-
- this->fast_forward = 0;
- this->playing = 1;
- this->paused = 0;
- this->video_frames = 0;
- this->displayed_frames = 0;
- this->audio_bytes = 0;
- if(this->decaps) {
-
- this->decaps->ReSeekAudio();
- }
- if(this->audioCodec)
- this->audioCodec->EmptyBuffers();
- if(this->audioCodec && this->audioCodec->IsOK() && this->audioRenderer) {
-
- this->audioRenderer->SetVolume(0);
- this->audioRenderer->Start();
- }
- if(this->paused)
- Pause();
- Sleep(600);
- if(this->audioCodec && this->audioCodec->IsOK() && this->audioRenderer) {
- this->audioRenderer->SetVolume(this->volume);
- }
- }
- else {
- if(this->rewind) {
-
- this->rewind = 0;
- this->playing = 1;
- this->paused = 0;
- this->video_frames = 0;
- this->displayed_frames = 0;
- this->audio_bytes = 0;
- if(this->decaps) {
-
- this->decaps->ReSeekAudio();
- }
- if(this->audioCodec)
- this->audioCodec->EmptyBuffers();
- if(this->audioCodec && this->audioCodec->IsOK() && this->audioRenderer) {
-
- this->audioRenderer->SetVolume(0);
- this->audioRenderer->Start();
- }
- if(this->paused)
- Pause();
- Sleep(600);
- if(this->audioCodec && this->audioCodec->IsOK() && this->audioRenderer) {
- this->audioRenderer->SetVolume(this->volume);
- }
- }
- else {
- if(this->playing)
- return 0;
- this->playing = 1;
- this->paused = 0;
- this->video_frames = 0;
- this->displayed_frames = 0;
- this->audio_bytes = 0;
- if(this->audioCodec && this->audioCodec->IsOK() && this->audioRenderer) {
-
- this->audioRenderer->SetVolume(this->volume);
- this->audioRenderer->Start();
- this->videoThread = CreateThread( NULL, 0, ThreadFunc, (LPVOID) this, 0, &id );
- }
- else {
- this->videoThread = CreateThread( NULL, 0, VideoThreadFunc, (LPVOID) this, 0, &id );
- }
- }
- }
- }
- return 1;
- }
- /*
- * Pause video and audio
- *
- */
- int Playback::Pause()
- {
- /*
- * Toggle Pause
- */
- if(this->playing) {
- if(this->paused) {
- if(this->audioRenderer) {
- this->audioRenderer->Pause();
- }
- this->paused = 0;
- ReleaseMutex(this->playbackMutex);
- this->baseTime += (GetTickCount() - this->stopTime);
- ResumeThread(this->videoThread);
- }
- else {
-
- WaitForSingleObject(this->playbackMutex, INFINITE);
- if(!this->fast_forward && !this->rewind) {
- if(this->audioRenderer) {
- this->audioRenderer->Pause();
- }
- }
- else {
-
- this->decaps->ReSeekAudio();
- this->audioCodec->EmptyBuffers();
-
- this->video_frames = 0;
- this->displayed_frames = 0;
- this->audio_bytes = 0;
- this->audioRenderer->Stop();
- this->audioRenderer->Start();
- this->audioRenderer->Pause();
- }
- this->fast_forward = 0;
- this->rewind = 0;
- this->stopTime = GetTickCount();
- SuspendThread(this->videoThread);
- this->paused = 1;
-
- }
- }
- return 1;
- }
- /*
- * Starts the Fast Forward Display
- *
- */
- int Playback::FastForward()
- {
- if(this->paused) {
- this->fast_forward = 1;
-
- this->paused = 0;
- ReleaseMutex(this->playbackMutex);
- this->baseTime += (GetTickCount() - this->stopTime);
- ResumeThread(this->videoThread);
- return 0;
- }
- if(this->ok && this->playing && !this->rewind && !this->fast_forward) {
- if(this->audioRenderer) {
- this->audioRenderer->Pause();
- }
- this->fast_forward = 1;
- }
- return 1;
- }
- int Playback::Rewind()
- {
- if(this->paused) {
- this->rewind = 1;
- this->paused = 0;
- ReleaseMutex(this->playbackMutex);
- this->baseTime += (GetTickCount() - this->stopTime);
- ResumeThread(this->videoThread);
- return 0;
- }
- if(this->ok && this->playing && !this->fast_forward && !this->rewind) {
- if(this->audioRenderer) {
- this->audioRenderer->Pause();
- }
- this->rewind = 1;
- }
- return 1;
- }
- /*
- * Only display the next frame
- *
- *
- */
- int Playback::NextFrame()
- {
- if(this->paused) {
- /*
- long image_size;
-
- image_size = this->decaps->NextVideoFrame(this->video_in);
-
- this->codec->Decompress(this->video_in, image_size, (char *) this->videoRenderer->GetSurface());
- this->video_frames++;
- this->videoRenderer->Draw();
- this->displayed_frames++;
- */
- }
- return 1;
- }
- /*
- * Set/UnSet Looping
- *
- */
- Playback::SetLoop(int loop)
- {
- this->loop = loop;
- return 0;
- }
- /*
- * Stops the playback
- * TODO : rewind the stream
- *
- */
- int Playback::Stop(int redraw)
- {
- if(this->playing) {
- WaitForSingleObject(this->playbackMutex, INFINITE);
-
- TerminateThread(this->videoThread, 0);
- this->playing = 0;
- if(this->audioCodec && this->audioCodec->IsOK() && this->audioRenderer != NULL) {
- this->audioRenderer->Stop();
- }
- }
- this->fast_forward = 0;
- this->rewind = 0;
- this->displayed_frames = 0;
- this->audio_bytes = 0;
- this->video_frames = 0;
- if(this->decaps)
- this->decaps->Rewind();
- if(this->audioCodec)
- this->audioCodec->EmptyBuffers();
- ReleaseMutex(this->playbackMutex);
- /*
- * Do redraw here!
- */
- RECT rect;
- if(redraw) {
-
- GetClientRect(this->hwnd, &rect);
- InvalidateRect(this->hwnd, &rect, TRUE);
- UpdateWindow(this->hwnd);
- }
- return 1;
- }
- /*
- * Performs Seeking
- *
- *
- */
- int Playback::Seek(int percent)
- {
- int has_to_play = 0;
-
- if(this->ok) {
-
- if(this->playing) {
- Stop(FALSE);
- has_to_play = 1;
- }
- this->decaps->Seek(percent);
- if(this->audioCodec)
- this->audioCodec->EmptyBuffers();
- if(has_to_play) {
-
- this->playing = 1;
- this->paused = 0;
- this->video_frames = 0;
- this->displayed_frames = 0;
- this->audio_bytes = 0;
- if(this->audioCodec && this->audioCodec->IsOK() && this->audioRenderer) {
-
- this->audioRenderer->SetVolume(0);
- this->audioRenderer->Start();
- this->videoThread = CreateThread( NULL, 0, ThreadFunc, (LPVOID) this, 0, &id );
- }
- else {
- this->videoThread = CreateThread( NULL, 0, VideoThreadFunc, (LPVOID) this, 0, &id );
- }
- }
- Sleep(500);
-
- if(this->audioCodec && this->audioCodec->IsOK() && this->audioRenderer) {
- this->audioRenderer->SetVolume(this->volume);
- }
- }
- return 1;
- }
- /*
- * Sets the volume
- *
- */
- int Playback::SetVolume(int volume)
- {
- this->volume = volume;
- if(this->audioRenderer) {
- this->audioRenderer->SetVolume(this->volume);
- }
- return 1;
- }
- /*
- * Gives the current displayed FPS
- *
- */
- double Playback::GetCurrentFps()
- {
- double time;
- time = AudioTime() / 1000;
- if(time != 0) {
- return this->displayed_frames / time;
- }
- else {
- return 0;
- }
- }
- /*
- * Gives the progress of the buffering
- */
- int Playback::GetBufferingState() {
- if(this->decaps) {
- return this->decaps->GetBufferingState();
- }
- return 0;
- }
- /*
- * Gives the video
- * position
- *
- */
- double Playback::GetProgress()
- {
- if(this->decaps) {
- return this->decaps->GetProgress();
- }
- return 0.0;
- }
- /*
- * Set/Unset Forcing of fullscreen resolution
- */
- int Playback::SetChangeFullscreenRes(int change) {
- if(this->videoRenderer != NULL) {
-
- this->videoRenderer->SetChangeFullscreenRes(change);
- return 1;
- }
- return 0;
- }
- /*
- * use or not the subtitles
- */
- int Playback::SetUseSubtitles(int useSubtitles) {
- this->use_subtitles = useSubtitles;
- return 1;
- }
- /*
- * Set/unset the use of
- * bilinear filtering
- *
- */
- int Playback::SetBilinear(int use_bilinear)
- {
- if(this->use_bilinear != use_bilinear) {
- PM_DEBUG("Changing Bilinear Staten", NULL);
- this->use_bilinear = use_bilinear;
- if(this->ok) {
-
- int has_to_play = 0;
- if(this->playing) {
- WaitForSingleObject(this->playbackMutex, INFINITE);
-
- SuspendThread(this->videoThread);
- this->playing = 0;
- ReleaseMutex(this->playbackMutex);
- has_to_play = 1;
- }
- this->videoRenderer->Close();
- this->videoRenderer->SetBilinear(this->use_bilinear);
- if(this->fullscreen) {
- this->videoRenderer->OpenFullscreen(this->hwnd, this->decaps->BitmapInfoHeader());
- }
- else {
- this->videoRenderer->Open(this->hwnd, this->decaps->BitmapInfoHeader());
- }
- if(has_to_play) {
- this->playing = 1;
- ResumeThread(this->videoThread);
- }
- }
- }
- return 0;
- }
- /*
- * Switch to Fullscreen
- * mode...
- */
- int Playback::Fullscreen(int active)
- {
- if(active) {
- if(this->ok && this->playing && !this->paused) {
-
- int has_to_play = 0;
- if(this->playing) {
-
- this->Pause();
- has_to_play = 1;
- }
- this->videoRenderer->Fullscreen(TRUE);
- this->fullscreen = 1;
-
- if(has_to_play) {
- this->Pause();
- }
- }
- }
- else {
-
- if(this->ok && this->playing && !this->paused) {
-
- int has_to_play = 0;
- if(this->playing) {
-
- this->Pause();
- has_to_play = 1;
- }
- this->videoRenderer->Fullscreen(FALSE);
- this->fullscreen = 0;
-
- if(has_to_play) {
- this->Pause();
- }
- }
- }
- return 1;
- }
- /*
- *
- *
- *
- */
- int Playback::isInFullscreen()
- {
- return this->fullscreen;
- }
- /*
- * Closes the playback
- * (definitive)
- *
- */
- int Playback::Close()
- {
- if(this->ok == TRUE) {
- this->ok = FALSE;
- Stop(TRUE);
- if(this->codec != NULL) {
- this->codec->Close();
- delete this->codec;
- }
- if(this->audioCodec != NULL) {
- this->audioCodec->Close();
- delete this->audioCodec;
- }
- if(this->videoRenderer != NULL) {
- this->videoRenderer->Close();
- delete this->videoRenderer;
- }
- if(this->videoBuffer != NULL) {
- this->videoBuffer->Stop();
- delete this->videoBuffer;
- }
- if(this->audioRenderer != NULL) {
- this->audioRenderer->Close();
- delete this->audioRenderer;
- }
-
- if(this->decaps != NULL) {
- this->decaps->Close();
- delete this->decaps;
- }
- if(this->subtitles != NULL) {
- this->subtitles->Close();
- delete this->subtitles;
- }
- return 1;
- }
- else {
- return 0;
- }
- }