Я использую TPL Dataflow для загрузки видео (я использую библиотеку Emgu.CV для загрузки) с пути и через TPL Dataflow сначала рисую его в приложении Windows Form (после этого будет этап обмена данными между доской). У меня было еще одно сообщение, которое очень помогло мне с потоком данных TPL здесь: Асинхронная задача, буферизация видео
Но после настройки потока данных TPL первое изображение загружается только в графический интерфейс, а после этого (в то время как блок работает, потому что отпечатки отображаются в cmd) изображение не обновляется ... Я не могу понять, что не так? Это связано с планировщиком или с потоком данных TPL? Ниже приведен код:
public async void CreateVideoProcessingNetwork()
{
string video_path = @"C:\.......\video_640x360_360p.mp4";
/* displayVideo Block*/
var display_video = new ActionBlock<Bitmap>(async received_bitmap =>
{
Console.WriteLine("Inside display_video");
PicturePlot2.Refresh();
PicturePlot2.Image = received_bitmap;
Console.WriteLine("Image size = " + received_bitmap.Size);
Console.WriteLine("Image width = " + received_bitmap.Width);
await Task.Delay(30);
});
var loadVideo = new ActionBlock<string>(async path =>
{
capture = new VideoCapture(path);
Mat matrix = new Mat();
capture.Read(matrix);
var mem_stream = new MemoryStream();
Bitmap HWimage;
while (matrix.Rows != 0 && matrix.Width != 0)
{
Console.WriteLine("Inside LoadVideo");
matrix = new Mat();
capture.Read(matrix);
Bitmap bitmap = new Bitmap(matrix.Width, matrix.Rows);
bitmap = matrix.ToBitmap();
bitmap.Save(mem_stream, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] image_array = mem_stream.ToArray();
Console.WriteLine("image_array = " + image_array.Length);
using (var mem_stream_hw = new MemoryStream(image_array)) HWimage = new Bitmap(mem_stream_hw);
var accepted = await display_video.SendAsync(HWimage);
if (!accepted) break;
await Task.Delay(25);
}
});
PropagateCompletion(loadVideo, display_video);
loadVideo.Post(video_path);
loadVideo.Complete();
await display_video.Completion;
}
Я что-то не так понимаю? Я хотел бы сделать какой-то конвейер в отображении видео через TPL Dataflow.
ОБНОВИТЬ:
После того, как я изменил упомянутые видео, воспроизводится. Но есть еще одна проблема. Скорость создания данных производителем выше (на самом деле это зависит от времени Thread.Sleep в TransformManyBlock), и после нескольких секунд воспроизведения видео приложение вылетает со следующей ошибкой:
Unhandled Exception: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.
at System.Drawing.Graphics.MeasureString(String text, Font font, SizeF layoutArea, StringFormat stringFormat)
at System.Drawing.Graphics.MeasureString(String text, Font font, Int32 width)
at System.Windows.Forms.ThreadExceptionDialog..ctor(Exception t)
at System.Windows.Forms.Application.ThreadContext.OnThreadException(Exception t)
at System.Windows.Forms.Control.WndProcException(Exception e)
at System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(Exception e)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at ntComlabGUI.Program.Main()
Если, например, удалить Thread.Sleep, ошибка возникает практически сразу (в первые 1-2 секунды). Как можно управлять потоком? В сообщении Асинхронная задача, буферизация видео упоминается метод BoundedCapacity. но я попробовал, и ошибка все еще существует. Ниже приведен код:
public async void CreateVideoProcessingNetwork()
{
//string video_path = @"C:\Projects_Repo\ComlabDMA_Ethernet_video\ntComlabGUI_Ultrascale_ethernet\ntComlabGUI\video_640x360_360p.mp4";
string video_path = @"C:\Projects_Repo\ComlabDMA_Ethernet_video\ntComlabGUI_Ultrascale_ethernet\ntComlabGUI\video_640x360_360p.mp4";
/* Video Loading TPL Block */
var video_loader = new TransformManyBlock<string, Bitmap>(load_video,
new ExecutionDataflowBlockOptions { BoundedCapacity = 128 });
IEnumerable<Bitmap> load_video(string path)
{
capture = new VideoCapture(path);
Mat matrix = new Mat();
capture.Read(matrix);
var mem_stream = new MemoryStream();
while (matrix.Rows != 0 && matrix.Width != 0)
{
capture.Read(matrix);
Bitmap bitmap = new Bitmap(matrix.Width, matrix.Rows);
bitmap = matrix.ToBitmap();
yield return bitmap;
//Thread.Sleep(1);
}
yield break;
}
/* Video Loading TPL Block */
var display_video = new ActionBlock<Bitmap>(async received_image =>
{
PicturePlot2.Image = received_image;
await Task.Delay(33);
},
new ExecutionDataflowBlockOptions()
{
TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(),
BoundedCapacity = 128
});
var linkOptions = new DataflowLinkOptions { PropagateCompletion = true };
video_loader.LinkTo(display_video, linkOptions);
video_loader.Post(video_path);
video_loader.Complete();
await display_video.Completion;
}
Возможно, следующая ссылка является решением? : Как организовать управление потоком в потоках данных TPL?
Заранее благодарим за помощь, а также за быстрый ответ, очень признательны!
Task.Run
, а не как блоки в конвейере. Вместо использования явного кода в одном блоке для отправки в другой вы должны использоватьTransformBlock
илиTransformManyBlock
и направлять его вывод в следующий блок с помощьюLinkTo
. Нет необходимости в явномPropagateCompletion
- person Panagiotis Kanavos   schedule 15.07.2021ToBitmap()
напрямую? Или еще лучше отправитьMat
в следующий блок? - person Panagiotis Kanavos   schedule 15.07.2021