* 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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user