Đâ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++;
}
}
Độ 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. –
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