2015-07-19 109 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; 
    }