2015-05-13 3 views
1

Я получаю необработанные видеокадры из источника (который можно считать черным ящиком) со скоростью, которая может быть непоследовательной. Я пытаюсь записать видео-канал на диск. Я делаю это с AForge VideoRecorder и пишу в файл MP4.Предоставление видео в файл, который может иметь несогласованную частоту кадров

Однако непоследовательная скорость, с которой я получаю фреймы, приводит к тому, что видео появляется ускоренным. Похоже, что у меня есть только возможность создавать видеофайлы с фиксированной частотой кадров, хотя источник не имеет фиксированной частоты кадров.

Это не проблема при визуализации на экране, так как мы можем просто сделать как можно быстрее. Я не могу сделать это при записи в файл, так как воспроизведение файла будет воспроизводиться с фиксированной частотой кадров.

Какие у вас есть решения? Выходной сигнал не должен быть одного и того же видеоформата, если есть разумный способ его конвертировать позже (что не обязательно должно быть в режиме реального времени). Видеопотоки могут быть довольно длинными, поэтому я не могу просто сохранить все в памяти и позже закодировать.

Мой код в настоящее время выглядит по линии:

VideoFileWriter writer = new VideoFileWriter(); 
Stopwatch stopwatch = new Stopwatch(); 

public override void Start() { 
    writer.Open("output.mp4", videoWidth, videoHeight, frameRate, AForge.Video.FFMPEG.VideoCodec.MPEG4); 
    stopwatch.Start(); 
} 

public override void End() { 
    writer.Close(); 
} 

public override void Draw(Frame frame) { 
    double elapsedTimeInSeconds = stopwatch.ElapsedTicks/(double) Stopwatch.Frequency; 
    double timeBetweenFramesInSeconds = 1.0/FrameRate; 
    if (elapsedTimeInSeconds >= timeBetweenFramesInSeconds) { 
     stopwatch.Restart(); 
     writer.WriteVideoFrame(frame.ToBitmap()); 
    } 
} 

Где наш черный ящик называет Start, End и Draw методы. Текущая проверка, что у меня есть в Draw, мешает нам рисовать слишком быстро, но не делает ничего, чтобы обрабатывать случай рисования слишком медленно.

ответ

2

Оказалось, что WriteVideoFrame перегружен и один из вариантов функции WriteVideoFrame(Bitmap frame, TimeSpan timestamp). Как вы можете догадаться, метка времени используется для создания кадра в определенное время в видео.

Таким образом, отслеживая реальное время, мы можем установить каждый кадр, чтобы использовать время, которое должно быть в видео. Конечно, качество видео будет хуже, если вы не сможете сделать достаточно быстро, но это устраняет проблему.

Вот код, который я использовал для функции Draw:

// We can provide a frame offset so that each frame has a time that it's supposed to be 
// seen at. This ensures that the video looks correct if the render rate is lower than 
// the frame rate, since these times will be used (it'll be choppy, but at least it'll 
// be paced correctly -- necessary so that sound won't go out of sync). 
long currentTick = DateTime.Now.Ticks; 
StartTick = StartTick ?? currentTick; 
var frameOffset = new TimeSpan(currentTick - StartTick.Value); 

// Figure out if we need to render this frame to the file (ie, has enough time passed 
// that this frame will be in the file?). This prevents us from going over the 
// desired frame rate and improves performance (assuming that we can go over the frame 
// rate). 
double elapsedTimeInSeconds = stopwatch.ElapsedTicks/(double) Stopwatch.Frequency; 
double timeBetweenFramesInSeconds = 1.0/FrameRate; 
if (elapsedTimeInSeconds >= timeBetweenFramesInSeconds) 
{ 
    stopwatch.Restart(); 

    Writer.WriteVideoFrame(frame.ToBitmap(), frameOffset); 
} 

Где StartTick является long? членом объекта.

1

У меня также возникла эта проблема. В моем случае я подражаю Системе видеонаблюдения, используя Aforge. CCTV должен быть точным во время записи, поэтому я столкнулся с большой дилеммой. Вот работа, которую я использовал в этом.

Сначала объявите временной интервал, который станет базой записи. Вы должны установить это, когда начинаете запись. Значение этого времени - это время начала записи. Ради этого ответа давайте назовем это tmspStartRecording

Затем в новом событии кадра вашего устройства захвата:

var currentTime = DateTime.Now.TimeOfDay; 
// this will get the elapse time between 
// the current time from the time you start your recording 
TimeSpan elapse = currentTime - tmspStartRecording; 
writer.WriteVideoFrame((Bitmap)image.Clone(),elapse); 

Не забудьте установить значение исходного промежутка времени, хорошо?

+0

Возможно, стоит использовать '' System.Diagnostics.Stopwatch' (https://msdn.microsoft.com/library/system.diagnostics.stopwatch.aspx) вместо вычитания 'DateTime', если вы работаете с высокие частоты кадров - 'секундомер' [более точный] (http://blogs.msdn.com/b/ericlippert/archive/2010/04/08/precision-and-accuracy-of-datetime.aspx). –

+0

Это почти то же самое, что я использовал, за исключением того, что я (по какой-то причине в то время) получил промежуток времени от вычитания тиков из 'DateTime.Now' вместо того, чтобы просто вычитать напрямую (что приводит к' TimeSpan'. m довольно уверен, что вы не можете использовать 'TimeOfDay'. Это не удастся, если ваша запись пройдет полночь. Должен использовать только' DateTime.Now'. – Kat

+0

Я использую только 25 кадров в секунду, хотя моя веб-камера может справиться с этим. просто не могу обработать этот фрейм достаточно быстро. В моем случае я принудительно перезагружаю сохранение, когда он достиг полуночи, а затем инициализирует новый. Один из лучших способов увеличить процесс создания фальшивки - создать новый отдельный поток для писателя. – keysl

Смежные вопросы