![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Прием большого потока данных по UDP
MBo © (2008-01-31 07:26:00)Задача следующая - некий спецдевайс передает по сети по протоколу UDP данные (видеопоток), порядка 11 мегабайт в секунду, пакет 770 байт - строка. Прием занимает очень значительную часть процессорного времени (применяется WSA-функции + RecvFrom, также пробовал использовать Indy и ICS), причем, если программа занимается еще чем-то, то пакеты, приходящие в этот момент, теряются. Например, если после приема кадра отрисовывать его, то несколько первых строк следующего кадра не принимаются.
Можно ли предпринять какие-то меры к улучшению ситуации?
C сетями ранее не работал, так что могут помочь любые идеи.
Slym (2008-02-04 05:13:00) [1]если картинка боле менее статичная, то потеря небольшого колва, каждый раз разных, строк не должна вызывать видимых артефактов...
если конечно старый кадр не затирать "чернухой", а оставлять отображая новый "поверх" старого
ага (2008-02-03 11:46:00) [2]2 MBo ©
WSARecv c кучей буферов сразу под весь кадр не пробовал? Те буфер один, но разбит на несколько, по числу строк.
Синхронизацию сообщениями я бы выкинул. Как и многопоточность, скоре всего, использовал бы асинхронный режим. В любом случае, синхронизация здесь - лишние потери, имхо. Два буфера, один рисуется, второй принимается. Буферы переключает "приемник", а по WM_PAINT выводится "рисуемый", независимо от того, было ли обновление.
Как гипотеза - может вывод через DirectX побыстрее будет. Не знаю, не спец.
Slym (2008-02-01 04:51:00) [3]
procedure x;
type
TLineRec=packed record
Info:word;
Data:array[0..192*4-1] of char;
end;
var
Bitmap:TBitmap;
Line:TLineRec;
FromLen,LineNum,CadrNum,Wrd:integer;
WSResult:integer;
UD:TSocket;
Addr:TSockAddr;
begin
Bitmap:=TBitmap.Create;
try
Bitmap.PixelFormat:=pf32bit;
Bitmap.Width:=192;
Bitmap.Height:=192;
while not Terminated do begin
FromLen := SizeOf(TSockAddr);
WSResult := RecvFrom(UD, Line, SizeOf(Line), 0, Addr, FromLen);
if WSResult<>SizeOf(Line) then continue;
Wrd := Swap(Line.Info);
LineNum:= Wrd and $3FF;
if (LineNum>-1) and (LineNum<Bitmap.Height) then
Move(Line.Data,Bitmap.ScanLine[LineNum]^,SizeOf(Line.Data));
if LineNum = Bitmap.Height-1 then
begin
Inc(FrameCount);
FCanvas.Lock;
try
FCanvas.Draw(0,0,Bitmap);
finally
FCanvas.Unlock;
end;
end;
end;
finally
Bitmap.Free;
end;
end;
DVM (2008-02-01 00:01:00) [4]
> Собственно, интересно - так и должна машина нагружаться
> при приеме из сети потока такой интенсивности, или руки
> нужно выпрямлять?
Нет, не должна. Вся нагрузка возникает, если в принимаемом потоке надо. что то искать, выцеплять, декодировать. Отрисовка это тоже мелочи.
DVM (2008-01-31 23:58:00) [5]
> MBo ©
А что за девайс такой? IP камера? Просто знакомая мне тематика.
Anatoly Podgoretsky (2008-01-31 20:05:00) [6]> MBo (31.01.2008 18:31:24) [24]
Э, ну ты даешь, программа то у тебя, задача сложная, явно не для форума, да и сеть у тебя работает за пределами возможностей. 11 мб не любая сеть обеспечит, а еще твоя обработка.
Так что придется тебе самому грызть.
MBo (2008-01-31 18:31:00) [7]>а в другом месте.
Вот и хочется понять, что это за место ;)
Anatoly Podgoretsky (2008-01-31 16:28:00) [8]> MBo (31.01.2008 15:47:22) [22]
100 мегабит это ничто для процессора, проблема не в количестве, а в другом месте.
MBo (2008-01-31 15:47:00) [9]>А если отрисовка медленней заполнения ?
тогда бы я ставил в очередь и отрисовывал бы только часть кадров.
В данном случае хватает двух буферов.
14400 пакетов в секунду, 0.07 мс один пакет
Отрисовка сначала у меня происходила более сложно, и занимала 3-4 мс, это по времени порядка 60 пакетов, около 40 КБ данных.
Визуально - если критерий отрисовки - приход нулевой строки, то в районе 20-50 строк было много выпавших.
Сейчас отрисовка быстрее, и артефактов на моей машине (Athlon 3500) практически нет, но на машинах вдвое медленнее - все-таки появляются.
Собственно, интересно - так и должна машина нагружаться при приеме из сети потока такой интенсивности, или руки нужно выпрямлять?
(С цифрового видеограббера без проблем принимаю, достаточно сложным образом обрабатываю и отрисовываю втрое-вчетверо больший поток)
Anatoly Podgoretsky (2008-01-31 15:41:00) [10]> MBo (31.01.2008 14:32:19) [19]
Для испытания временно отключи отрисовку.
Сергей М. (2008-01-31 15:16:00) [11]
> один заполняется, предыдущий отрисовывается
А если отрисовка медленней заполнения ?
Подумай ...
MBo (2008-01-31 14:32:00) [12]>PostMessage… да ещё и SetDiBits
Отрисовку, временно забыв об опасностях обращения к основному окну из доп. потока, можно вести и прямо из потока, ничего принципиально это не меняет.
SetDiBitsToDevice - оказался в данном случае наименее затратный способ из испытанных (альтернатива, например - формирование битмапа, происходит дольше)
насчет DirectX - еще не прорабатывал, побоялся затрат времени на преобразование цветов.
ketmar (2008-01-31 14:11:00) [13]у-у-у. PostMessage… да ещё и SetDiBits… есть (ничем не обоснованое, правда) мнение, что:
эту фигню надо тихонько совать в буфер моска сразу по получении. раз.
наладить frame skiping, если не успевает отрисоваться, а в буферг гадит.
рисовать директиксом на оверлеях (тут, возможно, вылезут тормоза с преобразованием цветовых пространств, искать карты, оверлеи на которых потянут rgb).
да, это: присылает, как я понял, не твоя программа, так что вправить моск именно ей никак?
MBo (2008-01-31 13:52:00) [14]
инициализация в конструкторе потока
if WSAStartup($0202, WSAD) <> 0 then
Exception.Create('WSAStartup Error');
Ud := Socket(AF_INET, Sock_Dgram, 0);
if INVALID_SOCKET = Ud then
Exception.Create('Socket Create Error');
Addr.sin_family := PF_Inet;
Addr.sin_addr.S_addr := Inet_Addr('0.0.0.0');
Addr.sin_port := HtoNS(FPort);
FillChar(Addr.sin_zero, SizeOf(Addr.sin_zero), 0);
if Bind(UD, Addr, SizeOf(Addr)) = Socket_Error then
Exception.Create('Socket Bind Error');
поточная функция
Len := 770;
while not Terminated do begin
FromLen := SizeOf(TSockAddr);
WSResult := RecvFrom(UD, LineBuf, Len, 0, Addr, FromLen);
Wrd := Swap(PWord(@LineBuf[0])^);
LineNum := Wrd and $3FF;
CadrNum := (Wrd shr 12) and 1;
if LineNum = 0 then begin
Inc(FrameCount);
PostMessage(Form3.Handle, WM_USER, FrameCount and $F, CadrNum xor 1);
end;
Move(LineBuf[2], Buf[CadrNum, LineNum, 0], Wdt);
end;
Buf - 2 массива, один заполняется, предыдущий отрисовывается
в обработчике WM_USER отрисовка
SetDiBitsToDevice(Canvas.Handle, 0, 0, Wdt, Hgt, 0, 0, 0, Hgt,
@Buf[M.LParam], PBitmapInfo(@Info)^, DIB_RGB_COLORS);
ketmar (2008-01-31 11:23:00) [15]>[15] Сергей М. ©(31.01.08 10:54)
я подозреваю, что ничего там такого нет. тупо сетка успевает впритык.
однако ж глянуть не помешает в любом случае, да.
Сергей М. (2008-01-31 10:54:00) [16]
> MBo © (31.01.08 10:37) [14]
Ты бы код своего транспортного алгоритма показал ..
MBo (2008-01-31 10:37:00) [17]> лучше таки накапливай где-то на отдельном сервере и с него уже забирай. и на гигабитке, желательно
Увы, не получится - в реальности будут полевые условия, железка - кабель - ноутбук.
ketmar (2008-01-31 10:19:00) [18]>[12] MBo ©(31.01.08 10:11)
ну, ты учти, что поток не может быть особо приоритетней приложения. подними ещё приоритет самому приложению. другим потокам приоритет поспускай.
а лучше таки накапливай где-то на отдельном сервере и с него уже забирай. и на гигабитке, желательно.
MBo (2008-01-31 10:11:00) [19]да, прием ведется в отдельном потоке, повышение приоритета частично помогает, но полностью проблему не снимает.
ketmar (2008-01-31 09:58:00) [20]>[10] Сергей М. ©(31.01.08 09:53)
так нечестно, я это уже посоветовал! %-)