[haiku-commits] r38662 - in haiku/trunk/src/apps/mediaplayer: media_node_framework/video supplier

  • From: superstippi@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 15 Sep 2010 20:15:20 +0200 (CEST)

Author: stippi
Date: 2010-09-15 20:15:20 +0200 (Wed, 15 Sep 2010)
New Revision: 38662
Changeset: http://dev.haiku-os.org/changeset/38662

Modified:
   haiku/trunk/src/apps/mediaplayer/media_node_framework/video/VideoProducer.cpp
   haiku/trunk/src/apps/mediaplayer/media_node_framework/video/VideoProducer.h
   haiku/trunk/src/apps/mediaplayer/supplier/ProxyVideoSupplier.cpp
   haiku/trunk/src/apps/mediaplayer/supplier/ProxyVideoSupplier.h
Log:
 * Instead of using some bogus latency for the VideoProducer,
   compute the latency from the buffer count. It should be
   the duration of in-flight buffers (i.e. number of buffers
   minus the one currently showing).
 * Compute the wakeUp time based on the buffer latency used
   above.
 * Make the "wasCached" mechanism work again, i.e. don't send
   the buffer to the consumer if the contents did not change.
   This removes the need to cache frames in the ProxyVideoSupplier
   and thus one more memcpy() (5ms on my Q6600 for full-HD content).
 * Remove the weird forceSendingBuffer override and the setting
   of the header starttime to 0. Now seeking clips works also
   when the playback is paused.

All in all, playback is more efficient now, and the chances of
dropping frames are much less. Something is still fishy, though,
since VLC, even though seemingly using slightly more CPU, drops
frames more seldomly than MediaPlayer. Audio/Video sync seems to
be better, though, since the VideoProducer is using a more accurate
latency now.


Modified: 
haiku/trunk/src/apps/mediaplayer/media_node_framework/video/VideoProducer.cpp
===================================================================
--- 
haiku/trunk/src/apps/mediaplayer/media_node_framework/video/VideoProducer.cpp   
    2010-09-15 17:49:47 UTC (rev 38661)
+++ 
haiku/trunk/src/apps/mediaplayer/media_node_framework/video/VideoProducer.cpp   
    2010-09-15 18:15:20 UTC (rev 38662)
@@ -51,6 +51,10 @@
          fUsedBufferGroup(NULL),
          fThread(-1),
          fFrameSync(-1),
+         fFrame(0),
+         fFrameBase(0),
+         fPerformanceTimeBase(0),
+         fBufferLatency(0),
          fRunning(false),
          fConnected(false),
          fEnabled(false),
@@ -422,9 +426,6 @@
 }
 
 
-#define NODE_LATENCY 20000
-
-
 void
 VideoProducer::Connect(status_t error, const media_source& source,
        const media_destination& destination, const media_format& format,
@@ -454,29 +455,25 @@
 
        fOutput.destination = destination;
        strcpy(_name, fOutput.name);
+       fConnectedFormat = format.u.raw_video;
+       fBufferDuration = 20000;
 
-       if (fOutput.format.u.raw_video.field_rate != 0.0f) {
+       if (fConnectedFormat.field_rate != 0.0f) {
                fPerformanceTimeBase = fPerformanceTimeBase
                        + (bigtime_t)((fFrame - fFrameBase)
-                               * 1000000 / 
fOutput.format.u.raw_video.field_rate);
+                               * 1000000LL / fConnectedFormat.field_rate);
                fFrameBase = fFrame;
+               fBufferDuration = 1000000LL / fConnectedFormat.field_rate;
        }
 
-       fConnectedFormat = format.u.raw_video;
        if (fConnectedFormat.display.bytes_per_row == 0) {
                ERROR("Connect() - connected format still has BPR wildcard!\n");
                fConnectedFormat.display.bytes_per_row
                        = 4 * fConnectedFormat.display.line_width;
        }
 
-       // get the latency
-       bigtime_t latency = 0;
-       media_node_id tsID = 0;
-       FindLatencyFor(fOutput.destination, &latency, &tsID);
-       SetEventLatency(latency + NODE_LATENCY);
-
        // Create the buffer group
-       if (!fUsedBufferGroup) {
+       if (fUsedBufferGroup == NULL) {
                fBufferGroup = new 
BBufferGroup(fConnectedFormat.display.bytes_per_row
                        * fConnectedFormat.display.line_count, BUFFER_COUNT);
                status_t err = fBufferGroup->InitCheck();
@@ -489,6 +486,20 @@
                fUsedBufferGroup = fBufferGroup;
        }
 
+       // get the latency
+       fBufferLatency = (BUFFER_COUNT - 1) * fBufferDuration;
+
+       int32 bufferCount;
+       if (fUsedBufferGroup->CountBuffers(&bufferCount) == B_OK) {
+               // recompute the latency
+               fBufferLatency = (bufferCount - 1) * fBufferDuration;
+       }
+
+       bigtime_t latency = 0;
+       media_node_id tsID = 0;
+       FindLatencyFor(fOutput.destination, &latency, &tsID);
+       SetEventLatency(latency + fBufferLatency);
+
        fConnected = true;
        fEnabled = true;
 
@@ -665,8 +676,6 @@
 VideoProducer::_FrameGeneratorThread()
 {
        bool forceSendingBuffer = true;
-       bigtime_t lastFrameSentAt = 0;
-       int64 lastPlaylistFrame = 0;
        int32 droppedFrames = 0;
        const int32 kMaxDroppedFrames = 15;
        bool running = true;
@@ -680,7 +689,6 @@
                bigtime_t nextPerformanceTime = 0;
                bigtime_t waitUntil = 0;
                bigtime_t nextWaitUntil = 0;
-               bigtime_t maxRenderTime = 0;
                int32 playingDirection = 0;
                int32 playingMode = 0;
                int64 playlistFrame = 0;
@@ -691,14 +699,11 @@
                                // get the times for the current and the next 
frame
                                performanceTime = 
fManager->TimeForFrame(fFrame);
                                nextPerformanceTime = 
fManager->TimeForFrame(fFrame + 1);
-                               maxRenderTime = min_c(bigtime_t(40000),
-                                       max_c(fSupplier->ProcessingLatency(), 
maxRenderTime));
                                playingMode = fManager->PlayModeAtFrame(fFrame);
-
                                waitUntil = 
TimeSource()->RealTimeFor(fPerformanceTimeBase
-                                       + performanceTime, 0) - maxRenderTime;
+                                       + performanceTime, fBufferLatency);
                                nextWaitUntil = 
TimeSource()->RealTimeFor(fPerformanceTimeBase
-                                       + nextPerformanceTime, 0) - 
maxRenderTime;
+                                       + nextPerformanceTime, fBufferLatency);
                                // get playing direction and playlist frame for 
the current
                                // frame
                                bool newPlayingState;
@@ -707,10 +712,6 @@
                                TRACE("_FrameGeneratorThread: performance time: 
%Ld, "
                                        "playlist frame: %lld\n", 
performanceTime, playlistFrame);
                                forceSendingBuffer |= newPlayingState;
-                               if (lastPlaylistFrame != playlistFrame) {
-                                       forceSendingBuffer = true;
-                                       lastPlaylistFrame = playlistFrame;
-                               }
                                
fManager->SetCurrentVideoTime(nextPerformanceTime);
                                fManager->Unlock();
                                break;
@@ -748,7 +749,7 @@
                                if (ignoreEvent || !fRunning || !fEnabled) {
                                        TRACE("_FrameGeneratorThread: ignore 
event\n");
                                        // nothing to do
-                               } else if (nextWaitUntil < system_time()
+                               } else if (nextWaitUntil < system_time() - 
fBufferLatency
                                        && droppedFrames < kMaxDroppedFrames) {
                                        // Drop frame if it's at least a frame 
late.
                                        printf("VideoProducer: dropped frame 
(%Ld)\n", fFrame);
@@ -765,78 +766,72 @@
                                        TRACE("_FrameGeneratorThread: produce 
frame\n");
                                        BAutolock _(fLock);
                                        // Fetch a buffer from the buffer group
+                                       fUsedBufferGroup->WaitForBuffers();
                                        BBuffer* buffer = 
fUsedBufferGroup->RequestBuffer(
                                                
fConnectedFormat.display.bytes_per_row
                                                * 
fConnectedFormat.display.line_count, 0LL);
-                                       if (buffer != NULL) {
-                                               // Fill out the details about 
this buffer.
-                                               media_header* h = 
buffer->Header();
-                                               h->type = B_MEDIA_RAW_VIDEO;
-                                               h->time_source = 
TimeSource()->ID();
-                                               h->size_used = 
fConnectedFormat.display.bytes_per_row
-                                                       * 
fConnectedFormat.display.line_count;
-                                               // For a buffer originating 
from a device, you might
-                                               // want to calculate this based 
on the
-                                               // PerformanceTimeFor the time 
your buffer arrived at
-                                               // the hardware (plus any 
applicable adjustments).
-                                               h->start_time = 
fPerformanceTimeBase + performanceTime;
-// TODO: Fix the runmode stuff! Setting the consumer to B_OFFLINE does
-// not do the trick. I made the VideoConsumer check the performance
-// time of the buffer and if it is 0, it plays it regardless.
-if (playingMode < 0 || droppedFrames >= kMaxDroppedFrames) {
-h->start_time = 0;
-}
-                                               h->file_pos = 0;
-                                               h->orig_size = 0;
-                                               h->data_offset = 0;
-                                               h->u.raw_video.field_gamma = 
1.0;
-                                               h->u.raw_video.field_sequence = 
fFrame;
-                                               h->u.raw_video.field_number = 0;
-                                               h->u.raw_video.pulldown_number 
= 0;
-                                               
h->u.raw_video.first_active_line = 1;
-                                               h->u.raw_video.line_count
-                                                       = 
fConnectedFormat.display.line_count;
-                                               // Fill in a frame
-                                               TRACE("_FrameGeneratorThread: 
frame: %Ld, "
-                                                       "playlistFrame: %Ld\n", 
fFrame, playlistFrame);
-                                               bool forceOrWasCached = 
forceSendingBuffer;
-
-                                               err = 
fSupplier->FillBuffer(playlistFrame,
-                                                       buffer->Data(), 
fConnectedFormat,
-                                                       forceOrWasCached);
-                                               // clean the buffer if 
something went wrong
+                                       if (buffer == NULL) {
+                                               // Wait until a buffer becomes 
available again
+                                               TRACE("_FrameGeneratorThread: 
no buffer!\n");
+//                                             ERROR("_FrameGeneratorThread: 
no buffer!\n");
+                                               break;
+                                       }
+                                       // Fill out the details about this 
buffer.
+                                       media_header* h = buffer->Header();
+                                       h->type = B_MEDIA_RAW_VIDEO;
+                                       h->time_source = TimeSource()->ID();
+                                       h->size_used = 
fConnectedFormat.display.bytes_per_row
+                                               * 
fConnectedFormat.display.line_count;
+                                       // For a buffer originating from a 
device, you might
+                                       // want to calculate this based on the
+                                       // PerformanceTimeFor the time your 
buffer arrived at
+                                       // the hardware (plus any applicable 
adjustments).
+                                       h->start_time = fPerformanceTimeBase + 
performanceTime;
+                                       h->file_pos = 0;
+                                       h->orig_size = 0;
+                                       h->data_offset = 0;
+                                       h->u.raw_video.field_gamma = 1.0;
+                                       h->u.raw_video.field_sequence = fFrame;
+                                       h->u.raw_video.field_number = 0;
+                                       h->u.raw_video.pulldown_number = 0;
+                                       h->u.raw_video.first_active_line = 1;
+                                       h->u.raw_video.line_count
+                                               = 
fConnectedFormat.display.line_count;
+                                       // Fill in a frame
+                                       TRACE("_FrameGeneratorThread: frame: 
%Ld, "
+                                               "playlistFrame: %Ld\n", fFrame, 
playlistFrame);
+                                       bool wasCached = false;
+                                       err = 
fSupplier->FillBuffer(playlistFrame,
+                                               buffer->Data(), 
fConnectedFormat, wasCached);
+                                       // clean the buffer if something went 
wrong
+                                       if (err != B_OK) {
+                                               // TODO: should use "back 
value" according
+                                               // to color space!
+                                               memset(buffer->Data(), 0, 
h->size_used);
+                                               err = B_OK;
+                                       }
+                                       // Send the buffer on down to the 
consumer
+                                       if (wasCached || (err = 
SendBuffer(buffer, fOutput.source,
+                                                       fOutput.destination) != 
B_OK)) {
+                                               // If there is a problem 
sending the buffer,
+                                               // or if we don't send the 
buffer because its
+                                               // contents are the same as the 
last one,
+                                               // return it to its buffer 
group.
+                                               buffer->Recycle();
+                                               // we tell the supplier to 
delete
+                                               // its caches if there was a 
problem sending
+                                               // the buffer
                                                if (err != B_OK) {
-                                                       // TODO: should use 
"back value" according
-                                                       // to color space!
-                                                       memset(buffer->Data(), 
0, h->size_used);
-                                                       err = B_OK;
-                                               }
-                                               // Send the buffer on down to 
the consumer
-                                               if (SendBuffer(buffer, 
fOutput.source,
-                                                               
fOutput.destination) < B_OK) {
                                                        
ERROR("_FrameGeneratorThread: Error "
                                                                "sending 
buffer\n");
-                                                       // If there is a 
problem sending the buffer,
-                                                       // or if we don't send 
the buffer because its
-                                                       // contents are the 
same as the last one,
-                                                       // return it to its 
buffer group.
-                                                       buffer->Recycle();
-                                                       // we tell the supplier 
to delete
-                                                       // its caches if there 
was a problem sending
-                                                       // the buffer
                                                        
fSupplier->DeleteCaches();
                                                }
-                                               // Only if everything went fine 
we clear the flag
-                                               // that forces us to send a 
buffer even if not
-                                               // playing.
-                                               if (err == B_OK) {
-                                                       forceSendingBuffer = 
false;
-                                                       lastFrameSentAt = 
performanceTime;
-                                               }
-                                       } else {
-                                               TRACE("_FrameGeneratorThread: 
no buffer!\n");
-//                                             ERROR("_FrameGeneratorThread: 
no buffer!\n");
                                        }
+                                       // Only if everything went fine we 
clear the flag
+                                       // that forces us to send a buffer even 
if not
+                                       // playing.
+                                       if (err == B_OK)
+                                               forceSendingBuffer = false;
                                        // next frame
                                        fFrame++;
                                        droppedFrames = 0;

Modified: 
haiku/trunk/src/apps/mediaplayer/media_node_framework/video/VideoProducer.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/media_node_framework/video/VideoProducer.h 
2010-09-15 17:49:47 UTC (rev 38661)
+++ haiku/trunk/src/apps/mediaplayer/media_node_framework/video/VideoProducer.h 
2010-09-15 18:15:20 UTC (rev 38662)
@@ -132,6 +132,8 @@
                int64                           fFrame;
                int64                           fFrameBase;
                bigtime_t                       fPerformanceTimeBase;
+               bigtime_t                       fBufferDuration;
+               bigtime_t                       fBufferLatency;
                media_output            fOutput;
                media_raw_video_format  fConnectedFormat;
                bool                            fRunning;

Modified: haiku/trunk/src/apps/mediaplayer/supplier/ProxyVideoSupplier.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/supplier/ProxyVideoSupplier.cpp    
2010-09-15 17:49:47 UTC (rev 38661)
+++ haiku/trunk/src/apps/mediaplayer/supplier/ProxyVideoSupplier.cpp    
2010-09-15 18:15:20 UTC (rev 38662)
@@ -18,18 +18,13 @@
 ProxyVideoSupplier::ProxyVideoSupplier()
        :
        fSupplierLock("video supplier lock"),
-       fSupplier(NULL),
-       fCachedFrame(NULL),
-       fCachedFrameSize(0),
-       fCachedFrameValid(false),
-       fUseFrameCaching(true)
+       fSupplier(NULL)
 {
 }
 
 
 ProxyVideoSupplier::~ProxyVideoSupplier()
 {
-       free(fCachedFrame);
 }
 
 
@@ -44,35 +39,12 @@
        if (fSupplier == NULL)
                return B_NO_INIT;
 
-       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());
+               wasCached = true;
+               return B_OK;
        }
 
+       wasCached = false;
        status_t ret = B_OK;
        bigtime_t performanceTime = 0;
        if (fSupplier->CurrentFrame() != startFrame) {
@@ -97,11 +69,6 @@
 
        ret = fSupplier->ReadFrame(buffer, &performanceTime, format, wasCached);
 
-       if (fUseFrameCaching && ret == B_OK) {
-               memcpy(fCachedFrame, buffer, fCachedFrameSize);
-               fCachedFrameValid = true;
-       }
-
        fProcessingLatency = system_time() - now;
 
        return ret;

Modified: haiku/trunk/src/apps/mediaplayer/supplier/ProxyVideoSupplier.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/supplier/ProxyVideoSupplier.h      
2010-09-15 17:49:47 UTC (rev 38661)
+++ haiku/trunk/src/apps/mediaplayer/supplier/ProxyVideoSupplier.h      
2010-09-15 18:15:20 UTC (rev 38662)
@@ -30,11 +30,6 @@
                        BLocker                         fSupplierLock;
 
                        VideoTrackSupplier*     fSupplier;
-
-                       void*                           fCachedFrame;
-                       size_t                          fCachedFrameSize;
-                       bool                            fCachedFrameValid;
-                       bool                            fUseFrameCaching;
 };
 
 #endif // PROXY_VIDEO_SUPPLIER_H


Other related posts:

  • » [haiku-commits] r38662 - in haiku/trunk/src/apps/mediaplayer: media_node_framework/video supplier - superstippi