From 818577b203870d5b3625514a99c35726f42cbde3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Mon, 6 Sep 2010 19:27:25 +0000 Subject: [PATCH] * Make PlaybackManager::CurrentFrame() return int64, like what it's internally using. Adapt NotifyCurrentFrameChanged() implementors. * Controller::SetTo() does not need to set the current frame, since either Init() or FormatChanged() will have taken care of it now. * Reset the seeking request info in Controller::SetTo(). * Changed the parameter passed to VideoSupplier::FillBuffer() from media_format to media_raw_video_format, so the VideoProducer doesn't have to generate a media_format for each frame... * ProxyVideoSupplier caches the last produced frame, which avoids a situation that the VideoProducer asks to generate the same frame twice sometimes. * In PlaybackManager::_PushState(), make sure we really schedule the next current_frame if asked. This avoids one situation in which the VideoSupplier was asked to generate the same frame again and fixes playback after pausing (was showing black video until the next keyframe before. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38553 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/mediaplayer/Controller.cpp | 6 +- src/apps/mediaplayer/Controller.h | 2 +- .../media_node_framework/PlaybackManager.cpp | 28 +++++--- .../media_node_framework/PlaybackManager.h | 4 +- .../video/VideoProducer.cpp | 6 +- .../video/VideoSupplier.h | 4 +- .../supplier/MediaTrackVideoSupplier.cpp | 18 +++--- .../supplier/MediaTrackVideoSupplier.h | 2 +- .../supplier/ProxyVideoSupplier.cpp | 64 +++++++++++++++---- .../mediaplayer/supplier/ProxyVideoSupplier.h | 9 ++- .../mediaplayer/supplier/VideoTrackSupplier.h | 2 +- 11 files changed, 100 insertions(+), 45 deletions(-) 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;