2015-07-19 132 views
0

我有一个motion-jpeg解码器,我为查看ip-camera流而编写。它工作的很好,我可以轻松实现超过30 fps与多个设备。我的问题是这些帧可能通过网络爆发。平滑可变帧率(视频)

我想实现的是一个公式,用于平均帧之间的时间以获得更稳定的回放。目前,我的帧被放入网络线程的ConcurrentQueue中,并且最近的帧被显示在UI线程中。下面是我的电流平滑的视频流编码,但我的计划是不工作...

PlaybackFrame)类持有的BitmapImage - > “图片
base.getFrame() )从ConcurrentQueue

private const int MAX_FRAME_DELAY = 500; 
    private const float RATE_FACTOR = 0.1f; 

    private long last_frame_time; 
    private long last_update_time; 
    private float rate; 

    //============================= 


    public override bool Get(out BitmapImage image) { 
      PlaybackFrame f = null; 
      if (base.getFrame(out f)) { 
       long now = Environment.TickCount; 
       if (last_frame_time > 0) { 
        // Get # of frames in buffer 
        int count = getCount(); 
        // 
        // Get duration since last update & last frame displayed 
        int update_duration = (int)(now - last_update_time); 
        int frame_duration = (int)(now - last_frame_time); 
        // 
        // estimated delay based on current frame-rate 
        float target_rate = 0; 
        if (count > 0) target_rate = update_duration/(float)count; 
        // 
        // offset actual delay/rate by current value 
        last_update_time = now; 
        rate = lerp(rate, target_rate, RATE_FACTOR); 
        // 
        // [backup] if duration exceeds 0.5 seconds, display next frame 
        if (frame_duration >= MAX_FRAME_DELAY) { 
         image = f.Image; 
         last_frame_time = now; 
         return true; 
        } 
        // 
        // if duration exceeds delay, display image 
        if (frame_duration > rate) { 
         image = f.Image; 
         last_frame_time = now; 
         return true; 
        } else { 
         // too soon, wait... 
         image = null; 
         return false; 
        } 
       } else { 
        // first image, display 
        last_frame_time = now; 
        image = f.Image; 
        return true; 
       } 
      } else { 
       // no image available 
       image = null; 
       return false; 
      } 
     } 

     private float lerp(float a, float b, float f) { 
      return a*(1f - f) + b*f; 
     } 
+0

为什么不使用缓冲区? – SimpleVar

+0

你能更具体吗? ConcurrentQueue充当缓冲区,保存传入图像的列表。我正在寻找一种方法来延迟这些图像的显示,基于传入的帧速率。 – Null511

+0

每当缓冲区少于X个下一帧时暂停视频。 – SimpleVar

回答

0

检索PlaybackFrame发现我的错误。我在base.getFrame()方法内计算我的时间测量,该方法仅在帧可用时执行。通过将测量移动到该块之外,它们会在每个渲染事件中更新,根据缓冲区内可用帧的数量创建平滑时间步。

  • 仍然需要清理,但伟大的工作......

    private const int MAX_FRAME_DELAY = 500; 
    private const float RATE_FACTOR = 0.01f; 
    
    private long last_frame_time; 
    private long last_update_time; 
    private float rate; 
    
    //============================= 
    
    public override bool Get(out BitmapImage image) { 
        PlaybackFrame f = null; 
        long now = Environment.TickCount; 
        if (last_frame_time > 0) { 
         int count = getCount(); 
         // 
         int update_duration = (int)(now - last_update_time); 
         int frame_duration = (int)(now - last_frame_time); 
         // 
         float target_rate = 0; 
         if (count > 0) target_rate = update_duration/(float)count; 
         // 
         last_update_time = now; 
         rate = lerp(rate, target_rate, RATE_FACTOR); 
         // 
         if (frame_duration >= MAX_FRAME_DELAY) { 
          if (getFrame(out f)) { 
           rate = MAX_FRAME_DELAY; 
           last_frame_time = now; 
           image = f.Image; 
           return true; 
          } else { 
           image = null; 
           return false; 
          } 
         } 
         // 
         if (frame_duration > rate) { 
          if (getFrame(out f)) { 
           last_frame_time = now; 
           image = f.Image; 
           return true; 
          } else { 
           image = null; 
           return false; 
          } 
         } else { 
          image = null; 
          return false; 
         } 
        } else { 
         if (getFrame(out f)) { 
          last_frame_time = now; 
          image = f.Image; 
          return true; 
         } else { 
          image = null; 
          return false; 
         } 
        } 
    } 
    
    private float lerp(float a, float b, float f) { 
        return a*(1f - f) + b*f; 
    }