2013-01-21 38 views
5

Đây là vấn đề gọn gàng và không phải là "cho tôi biết mã nào hoạt động", mà là câu hỏi "cách tôi xử lý tình huống này một cách hợp lý".Làm cách nào tôi có thể xử lý lỗi C# .NET TimeSpan Progressive Rounding trong khi quay Video Frame-by-Frame?

Tôi có, trong ngắn hạn, video + âm thanh đến từ một camera IP qua RTSP.

Video và âm thanh đang được giải mã và ghi từng khung hình thành một vùng chứa mp4 duy nhất, theo các chuỗi riêng biệt (được hiển thị bên dưới).

Sự cố là video và âm thanh dần dần mất đồng bộ theo thời gian, do thiếu độ chính xác với thời gian kết thúc TimeSpan và thời gian bắt đầu cho mỗi khung hình video.

Thời lượng phải là 1/framerate = 0,0333667000333667 cho mỗi khung video, nhưng nó sử dụng (ngay cả với phương thức FromTicks()), thời gian bắt đầu = 0.0 và thời gian kết thúc là 0.0333667 cho khung đầu tiên.

Tôi có thể điều chỉnh giá trị tốc độ khung hình của bộ giải mã video từ 29,97 (nó kéo từ cài đặt của máy ảnh được hiển thị tốc độ khung hình), dẫn đến video trước âm thanh hoặc chậm hơn âm thanh - điều này đơn giản là làm cho mỗi video mediaBuffer .StartTime và mediaBuffer.EndTime quá sớm hoặc quá muộn, so với âm thanh.

Theo thời gian, việc cắt ngắn thập phân nhỏ sẽ kết thúc làm cho video và âm thanh không đồng bộ - bản ghi càng dài thì càng đồng bộ hóa hai bản nhạc.

Tôi không thực sự hiểu tại sao điều này xảy ra, bởi vì, làm tròn lỗi không quan trọng về mặt logic.

Thậm chí nếu tôi chỉ có độ chính xác 1 giây, tôi chỉ viết một khung hình video mỗi giây và vị trí của nó trong dòng thời gian sẽ gần bằng + - 1 giây, và điều đó sẽ làm cho mọi tiến bộ khung hình giống nhau - - 1 giây đến vị trí cần thiết, không thêm sai lệch dần dần. Tôi tưởng tượng điều này sẽ giống như thế cho mỗi khung hình:

[< -------- -1 giây --------> thời gian khung chính xác mong đợi < ------- - + 1s -------->] ------------------------------------ ---------------- thời gian khung được ghi --------

Tôi có thiếu gì đó ở đây không?

Tôi không làm "thời gian bắt đầu khung hình mới = thời gian kết thúc khung hình cuối cùng, thời gian kết thúc khung mới = thời gian bắt đầu khung hình mới + 1/khung hình" - Tôi thực sự đang làm "thời gian bắt đầu khung hình mới = chỉ mục khung - 1/tốc độ khung hình, thời gian kết thúc khung hình mới = chỉ mục khung hình/tốc độ khung hình ".

Tức là, tôi tính toán thời gian bắt đầu và kết thúc khung dựa trên thời gian dự kiến ​​mà họ nên có (khung thời gian = vị trí khung hình/khung hình).

thời gian thời gian dự kiến ​​---------- thời gian dự kiến ​​---------- thời gian dự kiến ​​ khung thời gian khung khung thời gian

:

gì mã của tôi được làm điều này là

Tôi hiểu vấn đề toán học, tôi chỉ không hiểu tại sao cắt ngắn thập phân là chứng minh vấn đề như vậy, hoặc một cách hợp lý biết giải pháp tốt nhất là sửa chữa nó là gì.

Nếu tôi triển khai nội dung "mỗi x khung hình, hãy sử dụng" (1/framerate) + một số tiền "để bù cho tất cả thời gian bị thiếu, có thể có khung khớp với vị trí của chúng hoặc chỉ dẫn đến video lộn xộn?

public void AudioDecoderThreadProc() 
    { 
     TimeSpan current = TimeSpan.FromSeconds(0.0); 

     while (IsRunning) 
     { 
      RTPFrame nextFrame = jitter.FindCompleteFrame(); 

      if (nextFrame == null) 
      { 
       System.Threading.Thread.Sleep(20); 
       continue; 
      } 

      while (nextFrame.PacketCount > 0 && IsRunning) 
      { 
       RTPPacket p = nextFrame.GetNextPacket(); 

       if (sub.ti.MediaCapability.Codec == Codec.G711A || sub.ti.MediaCapability.Codec == Codec.G711U) 
       { 
        MediaBuffer<byte> mediaBuffer = new MediaBuffer<byte>(p.DataPointer, 0, (int)p.DataSize); 
        mediaBuffer.StartTime = current; 
        mediaBuffer.EndTime = current.Add(TimeSpan.FromSeconds((p.DataSize)/(double)audioDecoder.SampleRate)); 

        current = mediaBuffer.EndTime; 

        if (SaveToFile == true) 
        { 
         WriteMp4Data(mediaBuffer); 
        } 
       } 
      } 
     } 
    } 

    public void VideoDecoderThreadProc() 
    { 
     byte[] totalFrame = null; 

     TimeSpan current = TimeSpan.FromSeconds(0.0); 
     TimeSpan videoFrame = TimeSpan.FromTicks(3336670); 
     long frameIndex = 1; 

     while (IsRunning) 
     { 
      if (completedFrames.Count > 50) 
      { 
       System.Threading.Thread.Sleep(20); 
       continue; 
      } 

      RTPFrame nextFrame = jitter.FindCompleteFrame(); 

      if (nextFrame == null) 
      { 
       System.Threading.Thread.Sleep(20); 
       continue; 
      } 

      if (nextFrame.HasSequenceGaps == true) 
      { 
       continue; 
      } 

      totalFrame = new byte[nextFrame.TotalPayloadSize * 2]; 
      int offset = 0; 

      while (nextFrame.PacketCount > 0) 
      { 
       byte[] fragFrame = nextFrame.GetAssembledFrame(); 

       if (fragFrame != null) 
       { 
        fragFrame.CopyTo(totalFrame, offset); 
        offset += fragFrame.Length; 
       } 
      } 

      MediaBuffer<byte> mediaBuffer = new MediaBuffer<byte>(
       totalFrame, 
       0, 
       offset, 
       TimeSpan.FromTicks(Convert.ToInt64((frameIndex - 1)/mp4TrackInfo.Video.Framerate * 10000000)), 
       TimeSpan.FromTicks(Convert.ToInt64(frameIndex/mp4TrackInfo.Video.Framerate * 10000000))); 

      if (SaveToFile == true) 
      { 
       WriteMp4Data(mediaBuffer); 
      } 

      lock (completedFrames) 
      { 
       completedFrames.Add(mediaBuffer); 
      } 

      frameIndex++; 
     } 
    } 
+0

Độ phân giải của TimeSpan là 100 nano giây. Vì vậy, nếu nó sẽ được tắt liên tục sau đó bạn không thể được tắt sau một giờ bởi hơn 100 nsec * 29.97 * 3600 = 11 msec. Bạn không thể thấy điều đó. Bạn sẽ cần phải tiếp tục tìm kiếm. Không tin tưởng tốc độ khung hình máy ảnh thực tế. Và hãy cẩn thận với tốc độ bit thay đổi cho âm thanh, khá phổ biến. –

+0

Vâng, chắc chắn là tốc độ khung hình sai, nhưng làm thế nào điều đó có thể được giải quyết? Guesswork? Tôi có thể nhận được nó gần, chậm hơn, hoặc đến nay nhanh hơn nó nên được. Nhưng nếu tôi không có cách nào thực sự tính toán khi nào đúng thời điểm để viết khung đó là .. Làm thế nào để mọi người thậm chí có thể thực hiện đồng bộ hóa A/V một cách chính xác? – user1518816

Trả lời

1

Có một vài điều bạn nên tìm cho ra:

  1. không đúng cách thủ công khung timestamping. Thường là một ý tưởng tồi để tính toán thời lượng khung bằng tay thay vì để cho trình điều khiển/thẻ/bất cứ điều gì cho bạn khung thời gian. Tự dán khung hình gần như luôn dẫn đến sự trôi dạt do tốc độ bit thay đổi, thời gian máy tính nội bộ, v.v.

  2. Độ lệch chính xác. Tôi đã chạy vào tình trạng trôi khi khi xử lý dấu thời gian của khung hình theo đơn vị mili giây, nhưng dấu thời gian nguồn của tôi là đơn vị nano giây. Điều này đòi hỏi tôi phải bỏ một đôi dài.

    Ví dụ: tôi nhận được thời gian truyền thông từ directshow bằng đơn vị nano giây, tuy nhiên, tính toán nội bộ của tôi yêu cầu đơn vị mili giây. Điều này có nghĩa là tôi cần phải chuyển đổi giữa ns và ms. Đối với tôi, đó là nơi mất chính xác. Giải pháp của tôi cho điều này là bạn cần phải theo dõi bất kỳ tổn thất chính xác nào.

    Điều tôi đã thực hiện trong quá khứ là tôi có bộ đếm "timingFraction" đang chạy. Về cơ bản bất cứ lúc nào tôi phân chia, điều đó mang lại cho tôi dấu thời gian cơ bản cho một khung hình (do đó, khung Thời gian/NS_PS_MS). Tuy nhiên, tôi cũng thêm phần phân đoạn đã giảm của dấu thời gian được đúc sẵn vào bộ đếm thời gian phân đoạn thời gian (bằng C++ tôi đã sử dụng hàm modf). Bây giờ tôi thêm dấu thời gian được đúc (là một số nguyên vì nó được đúc thành dài) với phần thời gian còn lại nếu phần thời gian là một số nguyên. Về cơ bản nếu bạn tích lũy thêm một phần nghìn giây, hãy đảm bảo thêm nó vào khung. Bằng cách này bạn có thể bù đắp cho bất kỳ độ lệch chính xác nào.

  3. Hiệu ứng Accordion. Trong khi theo thời gian, mọi thứ có thể được thêm vào đúng thứ và bạn nghĩ rằng ngay cả ở thời điểm hạt thứ 1 cũng sẽ phù hợp, chúng sẽ không. Âm thanh cần khớp hoàn hảo hoặc mọi thứ nghe có vẻ kỳ lạ. Điều này thường được đặc trưng bởi bạn nghe đúng âm thanh đến từ một người vào đúng thời điểm, nhưng đôi môi không xếp hàng. Theo thời gian mọi thứ vẫn ổn, nhưng không có gì hoàn toàn phù hợp. Điều này là do bạn không hiển thị khung vào đúng thời điểm. Một số khung hình hơi dài, một số khung hình hơi quá ngắn, trên tất cả mọi thứ thêm vào đúng vị trí, nhưng không có gì là chiều dài phù hợp.

Bây giờ, tại sao bạn lại chạy vào này nếu chính xác của bạn đã ở mức 100 nano giây, có vẻ với tôi như nó có thể là mục 1. Tôi sẽ xác nhận rằng bạn có chắc bạn đang tính toán cuối timestamp đúng trước khi tiếp tục.

Tôi cũng đôi khi chạy thử nghiệm nơi tôi tổng hợp các khe giữa các khung và đảm bảo mọi thứ đang được thêm chính xác. Tổng thời gian giữa mỗi khung trong suốt thời lượng luồng của bạn phải bằng thời gian phát trực tuyến. I E. khung 1 dài 33 mili giây và khung 2 dài 34 ms và bạn ghi lại được 67 ms. Nếu bạn ghi âm cho 70ms bạn bị mất một cái gì đó ở đâu đó. Các bản nháp thường xuất hiện sau vài giờ và dễ phát hiện hơn bằng tai/mắt khi kết hợp âm thanh và video với nhau.

Ngoài ra, để chống lại nhận xét của Hans, thế giới kỹ thuật âm thanh có rất nhiều điều để nói về điều này. 10ms là rất nhiều để nghe độ trễ đặc biệt là khi kết hợp với phản hồi video. Bạn có thể không thấy độ trễ 10ms nhưng chắc chắn bạn có thể nghe thấy.Từ http://helpx.adobe.com/audition/kb/troubleshoot-recording-playback-monitoring-audition.html

Hướng dẫn chung áp dụng cho thời gian trễ

Ít hơn 10 ms - cho phép giám sát thời gian thực của bài hát đến bao gồm cả các hiệu ứng.

Lúc 10 giờ - có thể phát hiện độ trễ nhưng vẫn có thể phát âm tự nhiên và có thể sử dụng để theo dõi.

11-20 ms - giám sát bắt đầu trở thành không sử dụng được, bôi nhọ nguồn âm thanh thực tế,> và đầu ra được giám sát là rõ ràng.

20-30 ms - âm thanh bị trì hoãn bắt đầu phát ra âm thanh giống như độ trễ thực tế thay vì thành phần của> tín hiệu ban đầu.

Tôi đã từng nghiêng về đây, nhưng có rất nhiều thứ khi chơi.

1

Một điều nổi bật là tính toán tốc độ khung hình của bạn sai.

Nó phải là một khoảng thời gian 1/framerate = ,0333667000333667 cho mỗi khung hình video

Đó là khi bạn sử dụng 29.97 như một khung hình. 29.97 chỉ đơn thuần là một giá trị hiển thị. Tốc độ khung hình thực tế là 30/1.001 = 29.97002997002997 FPS. Do đó, một khung hình kéo dài 1/(30/1.001) = 0.0333666666666667 giây. Source, xem '60i'.

Các vấn đề liên quan