diff --git a/src/apps/mediaplayer/Controller.cpp b/src/apps/mediaplayer/Controller.cpp index c1d96da98a..43c3bc8a52 100644 --- a/src/apps/mediaplayer/Controller.cpp +++ b/src/apps/mediaplayer/Controller.cpp @@ -261,6 +261,9 @@ Controller::SetTo(const PlaylistItemRef& item) fDuration = 0; fVideoFrameRate = 25.0; + fSeekFrame = -1; + fSeekRequested = false; + if (fItem.Get() == NULL) return B_BAD_VALUE; @@ -369,7 +372,6 @@ Controller::SetTo(const PlaylistItemRef& item) _NotifyFileChanged(item.Get(), B_OK); - SetPosition(0.0); if (fAutoplay) StartPlaying(true); @@ -1080,7 +1082,7 @@ Controller::NotifyFPSChanged(float fps) const void -Controller::NotifyCurrentFrameChanged(int32 frame) const +Controller::NotifyCurrentFrameChanged(int64 frame) const { // check if we are still waiting to reach the seekframe, // don't pass the event on to the listeners in that case diff --git a/src/apps/mediaplayer/Controller.h b/src/apps/mediaplayer/Controller.h index 08570f261a..cbd5e3f3cd 100644 --- a/src/apps/mediaplayer/Controller.h +++ b/src/apps/mediaplayer/Controller.h @@ -168,7 +168,7 @@ private: bool enabled) const; virtual void NotifyVideoBoundsChanged(BRect bounds) const; virtual void NotifyFPSChanged(float fps) const; - virtual void NotifyCurrentFrameChanged(int32 frame) const; + virtual void NotifyCurrentFrameChanged(int64 frame) const; virtual void NotifySpeedChanged(float speed) const; virtual void NotifyFrameDropped() const; virtual void NotifyStopFrameReached() const; diff --git a/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp b/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp index 230fb8ecac..b49ec1b55a 100644 --- a/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp +++ b/src/apps/mediaplayer/media_node_framework/PlaybackManager.cpp @@ -323,7 +323,7 @@ PlaybackManager::IsLoopingEnabled() const } -int32 +int64 PlaybackManager::CurrentFrame() const { return PlaylistFrameAtFrame(FrameForTime(fPerformanceTime)); @@ -940,11 +940,11 @@ PlaybackManager::SetPerformanceFrame(int64 frame) void PlaybackManager::SetPerformanceTime(bigtime_t time) { - int32 oldCurrentFrame = CurrentFrame(); + int64 oldCurrentFrame = CurrentFrame(); fPerformanceTime = time; _UpdateStates(); _UpdateSpeedInfos(); - int32 currentFrame = CurrentFrame(); + int64 currentFrame = CurrentFrame(); //printf("PlaybackManager::SetPerformanceTime(%lld): %ld -> %ld\n", // time, oldCurrentFrame, currentFrame); @@ -1049,7 +1049,7 @@ PlaybackManager::NotifyFPSChanged(float fps) const void -PlaybackManager::NotifyCurrentFrameChanged(int32 frame) const +PlaybackManager::NotifyCurrentFrameChanged(int64 frame) const { for (int32 i = 0; PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i); @@ -1123,6 +1123,9 @@ PlaybackManager::PrintStateAtFrame(int64 frame) } +// #pragma mark - + + /*! Appends the supplied state to the list of states. If the state would become active at the same time as _LastState() the latter is removed and deleted. However, the activation time for the new state is adjusted, @@ -1150,18 +1153,23 @@ TRACE("PlaybackManager::_PushState()\n"); int64 activationFrame = max(max(state->activation_frame, lastState->activation_frame), NextFrame()); -TRACE(" state activation frame: %lld, last state activation frame: %lld, " -"NextFrame(): %lld\n", state->activation_frame, lastState->activation_frame, -NextFrame()); - int64 currentFrame = 0; // remember the current frame, if necessary - if (adjustCurrentFrame) + if (adjustCurrentFrame) { currentFrame = PlaylistFrameAtFrame(activationFrame); - // check whether it is active + if (currentFrame == CurrentFrame()) { + // Seems to be paused, force using the next frame + currentFrame++; + } + } + // Check whether the last state has already become active // (NOTE: We may want to keep the last state, if it is not active, // but then the new state should become active after the last one. // Thus we had to replace `NextFrame()' with `activationFrame'.) +TRACE(" state activation frame: %lld, last state activation frame: %lld, " +"NextFrame(): %lld, currentFrame: %lld, next currentFrame: %lld\n", +state->activation_frame, lastState->activation_frame, NextFrame(), +CurrentFrame(), currentFrame); if (lastState->activation_frame >= NextFrame()) { // it isn't -- remove it fStates.RemoveItem(fStates.CountItems() - 1); diff --git a/src/apps/mediaplayer/media_node_framework/PlaybackManager.h b/src/apps/mediaplayer/media_node_framework/PlaybackManager.h index 1b779c6e96..513fa2fe75 100644 --- a/src/apps/mediaplayer/media_node_framework/PlaybackManager.h +++ b/src/apps/mediaplayer/media_node_framework/PlaybackManager.h @@ -71,7 +71,7 @@ public: int32 PlayMode() const; int32 LoopMode() const; bool IsLoopingEnabled() const; - int32 CurrentFrame() const; + int64 CurrentFrame() const; float Speed() const; virtual void SetFramesPerSecond(float framesPerSecond); @@ -165,7 +165,7 @@ public: bool enabled) const; virtual void NotifyVideoBoundsChanged(BRect bounds) const; virtual void NotifyFPSChanged(float fps) const; - virtual void NotifyCurrentFrameChanged(int32 frame) const; + virtual void NotifyCurrentFrameChanged(int64 frame) const; virtual void NotifySpeedChanged(float speed) const; virtual void NotifyFrameDropped() const; virtual void NotifyStopFrameReached() const; diff --git a/src/apps/mediaplayer/media_node_framework/video/VideoProducer.cpp b/src/apps/mediaplayer/media_node_framework/video/VideoProducer.cpp index 9d66b81155..cc7cbcfd82 100644 --- a/src/apps/mediaplayer/media_node_framework/video/VideoProducer.cpp +++ b/src/apps/mediaplayer/media_node_framework/video/VideoProducer.cpp @@ -797,15 +797,13 @@ h->start_time = 0; h->u.raw_video.line_count = fConnectedFormat.display.line_count; // Fill in a frame - media_format mf; - mf.type = B_MEDIA_RAW_VIDEO; - mf.u.raw_video = fConnectedFormat; TRACE("_FrameGeneratorThread: frame: %Ld, " "playlistFrame: %Ld\n", fFrame, playlistFrame); bool forceOrWasCached = forceSendingBuffer; err = fSupplier->FillBuffer(playlistFrame, - buffer->Data(), &mf, forceOrWasCached); + buffer->Data(), fConnectedFormat, + forceOrWasCached); // clean the buffer if something went wrong if (err != B_OK) { // TODO: should use "back value" according diff --git a/src/apps/mediaplayer/media_node_framework/video/VideoSupplier.h b/src/apps/mediaplayer/media_node_framework/video/VideoSupplier.h index 9a895580ea..7f6a77e201 100644 --- a/src/apps/mediaplayer/media_node_framework/video/VideoSupplier.h +++ b/src/apps/mediaplayer/media_node_framework/video/VideoSupplier.h @@ -10,7 +10,7 @@ #include -struct media_format; +struct media_raw_video_format; class VideoSupplier { @@ -19,7 +19,7 @@ class VideoSupplier { virtual ~VideoSupplier(); virtual status_t FillBuffer(int64 startFrame, void* buffer, - const media_format* format, + const media_raw_video_format& format, bool& wasCached) = 0; virtual void DeleteCaches(); diff --git a/src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.cpp b/src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.cpp index 5322e8b827..c136958e6d 100644 --- a/src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.cpp +++ b/src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.cpp @@ -85,7 +85,7 @@ MediaTrackVideoSupplier::GetCodecInfo(media_codec_info* info) const status_t MediaTrackVideoSupplier::ReadFrame(void* buffer, bigtime_t* performanceTime, - const media_format* format, bool& wasCached) + const media_raw_video_format& format, bool& wasCached) { if (!fVideoTrack) return B_NO_INIT; @@ -93,12 +93,12 @@ MediaTrackVideoSupplier::ReadFrame(void* buffer, bigtime_t* performanceTime, return B_BAD_VALUE; status_t ret = B_OK; - if (format->u.raw_video.display.format + if (format.display.format != fFormat.u.raw_video.display.format || fFormat.u.raw_video.display.bytes_per_row - != format->u.raw_video.display.bytes_per_row) { - ret = _SwitchFormat(format->u.raw_video.display.format, - format->u.raw_video.display.bytes_per_row); + != format.display.bytes_per_row) { + ret = _SwitchFormat(format.display.format, + format.display.bytes_per_row); if (ret < B_OK) { fprintf(stderr, "MediaTrackVideoSupplier::ReadFrame() - " "unable to switch media format: %s\n", strerror(ret)); @@ -200,8 +200,10 @@ MediaTrackVideoSupplier::SeekToFrame(int64* frame) int64 nextWantFrame = wantFrame + 1; if (fVideoTrack->FindKeyFrameForFrame(&nextWantFrame, B_MEDIA_SEEK_CLOSEST_BACKWARD) == B_OK) { - if (nextWantFrame == wantFrame) - *frame = wantFrame + 1; + if (nextWantFrame == wantFrame) { + wantFrame++; + *frame = wantFrame; + } } } @@ -209,7 +211,7 @@ MediaTrackVideoSupplier::SeekToFrame(int64* frame) // printf("keyframe for frame: %lld -> %lld\n", wantFrame, *frame); //} - if (*frame <= fCurrentFrame && wantFrame > fCurrentFrame) { + if (*frame <= fCurrentFrame && wantFrame >= fCurrentFrame) { // The current frame is already closer to the wanted frame // than the next keyframe before it. *frame = fCurrentFrame; diff --git a/src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.h b/src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.h index 4c27720aec..aafe415ab7 100644 --- a/src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.h +++ b/src/apps/mediaplayer/supplier/MediaTrackVideoSupplier.h @@ -26,7 +26,7 @@ class MediaTrackVideoSupplier : public VideoTrackSupplier { virtual status_t ReadFrame(void* buffer, bigtime_t* performanceTime, - const media_format* format, + const media_raw_video_format& format, bool& wasCached); virtual status_t FindKeyFrameForFrame(int64* frame); virtual status_t SeekToTime(bigtime_t* performanceTime); diff --git a/src/apps/mediaplayer/supplier/ProxyVideoSupplier.cpp b/src/apps/mediaplayer/supplier/ProxyVideoSupplier.cpp index 69f3b991bf..c2e834b255 100644 --- a/src/apps/mediaplayer/supplier/ProxyVideoSupplier.cpp +++ b/src/apps/mediaplayer/supplier/ProxyVideoSupplier.cpp @@ -1,10 +1,14 @@ /* - * Copyright © 2008 Stephan Aßmus + * Copyright 2008-2010 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ + + #include "ProxyVideoSupplier.h" #include +#include +#include #include @@ -12,34 +16,66 @@ ProxyVideoSupplier::ProxyVideoSupplier() - : fSupplierLock("video supplier lock") - , fSupplier(NULL) + : + fSupplierLock("video supplier lock"), + fSupplier(NULL), + fCachedFrame(NULL), + fCachedFrameSize(0), + fCachedFrameValid(false), + fUseFrameCaching(true) { } ProxyVideoSupplier::~ProxyVideoSupplier() { + free(fCachedFrame); } status_t ProxyVideoSupplier::FillBuffer(int64 startFrame, void* buffer, - const media_format* format, bool& wasCached) + const media_raw_video_format& format, bool& wasCached) { BAutolock _(fSupplierLock); //printf("ProxyVideoSupplier::FillBuffer(%lld)\n", startFrame); if (fSupplier == NULL) return B_NO_INIT; - bigtime_t performanceTime = 0; - if (fSupplier->CurrentFrame() == startFrame + 1) { - printf("ProxyVideoSupplier::FillBuffer(%lld) - Could re-use previous " - "buffer!\n", startFrame); + if (fUseFrameCaching) { + size_t bufferSize = format.display.bytes_per_row + * format.display.line_count; + if (fCachedFrame == NULL || fCachedFrameSize != bufferSize) { + // realloc cached frame + fCachedFrameValid = false; + void* cachedFrame = realloc(fCachedFrame, bufferSize); + if (cachedFrame != NULL) { + fCachedFrame = cachedFrame, + fCachedFrameSize = bufferSize; + } else + fUseFrameCaching = false; + fCachedFrameValid = false; + } } + + if (fSupplier->CurrentFrame() == startFrame + 1) { + if (fCachedFrameValid) { + memcpy(buffer, fCachedFrame, fCachedFrameSize); + wasCached = true; + return B_OK; + } +// TODO: The problem here is hidden in PlaybackManager::_PushState() +// not computing the correct current_frame for the new PlayingState. + printf("ProxyVideoSupplier::FillBuffer(%lld) - TODO: Avoid " + "asking for the same frame twice (%lld)!\n", startFrame, + fSupplier->CurrentFrame()); + } + + status_t ret = B_OK; + bigtime_t performanceTime = 0; if (fSupplier->CurrentFrame() != startFrame) { int64 frame = startFrame; - status_t ret = fSupplier->SeekToFrame(&frame); + ret = fSupplier->SeekToFrame(&frame); if (ret != B_OK) return ret; // Read frames until we reach the frame before the one we want to read. @@ -57,10 +93,14 @@ ProxyVideoSupplier::FillBuffer(int64 startFrame, void* buffer, } } - // TODO: cache into intermediate buffer to handle the - // currentFrame = startFrame + 1 case! + ret = fSupplier->ReadFrame(buffer, &performanceTime, format, wasCached); - return fSupplier->ReadFrame(buffer, &performanceTime, format, wasCached); + if (fUseFrameCaching && ret == B_OK) { + memcpy(fCachedFrame, buffer, fCachedFrameSize); + fCachedFrameValid = true; + } + + return ret; } diff --git a/src/apps/mediaplayer/supplier/ProxyVideoSupplier.h b/src/apps/mediaplayer/supplier/ProxyVideoSupplier.h index 2bf41f1352..67427c2e65 100644 --- a/src/apps/mediaplayer/supplier/ProxyVideoSupplier.h +++ b/src/apps/mediaplayer/supplier/ProxyVideoSupplier.h @@ -1,5 +1,5 @@ /* - * Copyright © 2008 Stephan Aßmus + * Copyright 2008 Stephan Aßmus * All rights reserved. Distributed under the terms of the MIT licensce. */ #ifndef PROXY_VIDEO_SUPPLIER_H @@ -19,7 +19,7 @@ public: virtual ~ProxyVideoSupplier(); virtual status_t FillBuffer(int64 startFrame, void* buffer, - const media_format* format, + const media_raw_video_format& format, bool& wasCached); virtual void DeleteCaches(); @@ -30,6 +30,11 @@ private: BLocker fSupplierLock; VideoTrackSupplier* fSupplier; + + void* fCachedFrame; + size_t fCachedFrameSize; + bool fCachedFrameValid; + bool fUseFrameCaching; }; #endif // PROXY_VIDEO_SUPPLIER_H diff --git a/src/apps/mediaplayer/supplier/VideoTrackSupplier.h b/src/apps/mediaplayer/supplier/VideoTrackSupplier.h index cc9e5c5eec..dfb430fc3d 100644 --- a/src/apps/mediaplayer/supplier/VideoTrackSupplier.h +++ b/src/apps/mediaplayer/supplier/VideoTrackSupplier.h @@ -23,7 +23,7 @@ class VideoTrackSupplier { virtual status_t GetCodecInfo(media_codec_info* info) const = 0; virtual status_t ReadFrame(void* buffer, bigtime_t* performanceTime, - const media_format* format, + const media_raw_video_format& format, bool& wasCached) = 0; virtual status_t FindKeyFrameForFrame(int64* frame) = 0; virtual status_t SeekToTime(bigtime_t* performanceTime) = 0;