#c# #opencv #video-streaming #video-capture #emgucv
#c# #opencv #потоковое видео #видеозахват #emgucv
Вопрос:
Я пытаюсь прочитать видео (.mp4) из файла и показать его в поле изображения в формах. Когда я подсчитываю общее время воспроизведения, это на самом деле больше, чем фактическая длина видео. Например, если видео на самом деле длится 10 секунд, оно воспроизводится в течение 12-13 секунд. Почему это? Частота кадров для моего видео составляет 31 кадр / с
Я попытался убедиться, что переменная fps уже имеет правильную частоту кадров.
private void Play_Video(string filePath)
{
VideoCapture cameraCapture = new VideoCapture(filePath);
var stopwatch = new Stopwatch();
stopwatch.Start();
while (true)
{
Mat m = new Mat();
cameraCapture.Read(m);
if (!m.IsEmpty)
{
imageBox1.Image = m;
double fps = cameraCapture.GetCaptureProperty(CapProp.Fps);
Thread.Sleep(1000 / Convert.ToInt32(fps));
}
else
{
break;
}
}
stopwatch.Stop();
double elapsed_time = stopwatch.ElapsedMilliseconds * 0.001;
// My elapsed_time here shows about 13 seconds, when the actual length of video is 10 seconds. Why?
}
НОВОЕ РЕДАКТИРОВАНИЕ:
Я обновил извлечение кадров в отдельной функции, чтобы не вызывать задержки во время рендеринга, но задержка все еще составляет несколько секунд. Например, 30 секунд видео воспроизводится в течение 32-33 секунд. Мой обновленный код:
private void Play_Video(List<Mat> frames, double fps, Emgu.CV.UI.ImageBox imageBox)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < frames.Count; i )
{
imageBox.Image = frames[i];
Thread.Sleep(1000 / Convert.ToInt32(fps));
}
stopwatch.Stop();
double elapsed_time = stopwatch.ElapsedMilliseconds * 0.001;
}
Комментарии:
1. Обычно медиаплееры буферизуют кадры, чтобы не снижать скорость воспроизведения. Вы получаете 1 кадр на каждой итерации.
2. Как я могу это сделать? Есть ли какой-нибудь пример?
3. Во втором примере вы считываете все видео и воспроизводите его на основе таймера. В зависимости от размера кадра это много данных. Возможно ли, что в этом примере вы сжигаете GC, повышающий память?
4. На самом деле видео не воспроизводится по таймеру. Таймер существует только для того, чтобы я мог измерить, сколько времени занял цикл for.
Ответ №1:
Это был единственный способ получить точные кадры в секунду, потому что при использовании thread.sleep для включения и выключения требуется 10-15 мс. У меня была такая же проблема с Task.Задержка. Кажется, это работает отлично, если у кого-нибудь есть лучшее решение, я бы хотел его увидеть.
private void PlayVideo()
{
double framecount = video.Get(Emgu.CV.CvEnum.CapProp.FrameCount);
double fps = video.Get(Emgu.CV.CvEnum.CapProp.Fps);
video.Set(Emgu.CV.CvEnum.CapProp.PosFrames, (double)(framecount * (double)(savePercent / 100)));
int ms = Convert.ToInt32(((double)1000 / fps));
while (disablePreviewTimer == false)
{
DateTime dt = DateTime.Now;
Emgu.CV.Mat img = video.QueryFrame();
if (img == null)
{
disablePreviewTimer = true;
break;
}
else
{
Emgu.CV.Util.VectorOfByte vb = new Emgu.CV.Util.VectorOfByte();
Emgu.CV.CvInvoke.Resize(img, img, PreviewSize);
Emgu.CV.CvInvoke.Imencode(".jpg", img, vb);
pictureBox5.Image = Image.FromStream(new MemoryStream(vb.ToArray()));
Application.DoEvents();
while ((DateTime.Now - dt).TotalMilliseconds < ms)
{
Application.DoEvents();
}
label6.Text = ((int)(DateTime.Now - dt).TotalMilliseconds).ToString();
}
}
}