* 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
This commit is contained in:
Stephan Aßmus
2010-09-06 19:27:25 +00:00
parent d859486b15
commit 818577b203
11 changed files with 100 additions and 45 deletions
+4 -2
View File
@@ -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
+1 -1
View File
@@ -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;
@@ -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);
@@ -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;
@@ -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
@@ -10,7 +10,7 @@
#include <SupportDefs.h>
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();
@@ -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;
@@ -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);
@@ -1,10 +1,14 @@
/*
* Copyright © 2008 Stephan Aßmus <[email protected]>
* Copyright 2008-2010 Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT licensce.
*/
#include "ProxyVideoSupplier.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Autolock.h>
@@ -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;
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2008 Stephan Aßmus <[email protected]>
* Copyright 2008 Stephan Aßmus <[email protected]>
* 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
@@ -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;