На форме idHTTP, idIOHandler и IdConnectionIntercept
У IdConnectionIntercept есть метод OnReceive.
procedure TForm1.IdConnectionInterceptReceive(ASender: TIdConnectionIntercept; var ABuffer: TIdBytes);
begin
Form1.ParseJPEGData;
end;
procedure TForm1.ParseJPEGData;
var
i: Integer;
StartPos, EndPos: Integer;
StartPt: Pointer;
Data, DataNext: PByte;
Amount: Integer;
buffer: TBytes;
begin
// Check size
if (FReceivedData.Size < 2) then
Exit;
// Initialize
Amount := 0;
StartPos := -1;
StartPt := nil;
// Data pointers
Data := FReceivedData.Memory;
DataNext := Data;
Inc(DataNext);
try
// Parsing loop
for i := 0 to FReceivedData.Size - 2 do
begin
// Check if we have found the start code
if (StartPos = -1) and (Data^ = $FF) and (DataNext^ = $D8) then
begin
StartPos := i;
StartPt := Data;
end
// Check if we have found the JPEG end code
else if (StartPos >= 0) and (Data^ = $FF) and (DataNext^ = $D9) then
begin
// End position
EndPos := i;
// Copy data (Higher performance than passing whole stream to load,
// because FBitmap.LoadFromStream will create a memory stream and copy
// everything if Position <> 0
FReceivedData.Position := StartPos;
FParsedData.SetSize((EndPos + 2) - StartPos);
FParsedData.Position := 0;
FParsedData.CopyFrom(FReceivedData, (EndPos + 2) - StartPos);
// CopyMemory(FParsedData.Memory, StartPt, (EndPos + 2) - StartPos);
// Load bitmap on screen
Image1.Bitmap.LoadFromStream(FParsedData);
FParsedData.Clear;
Application.ProcessMessages;
// Amount of data to delete
Amount := EndPos + 2;
// Reset
StartPos := -1;
StartPt := nil;
end;
// Next pointer
Inc(Data);
Inc(DataNext);
end;
// Delete the amount of parsed data
// FReceivedData.Delete(Amount);
DeleteStream(FReceivedData, Amount);
FReceivedData.Position := FReceivedData.Size;
Application.ProcessMessages;
except
FReceivedData.Clear;
end;
end;
Так все работает, но сильно грузит основной поток, так что даже программу нельзя закрыть.
Подумал, что может вынести процедуру ParseJPEGData в поток. Но что-то не срабатывает.
Вот код, прокомментируйте пожалуйста
procedure TForm1.ParseJPEGDataThread;
begin
TTask.Run(
procedure
var
aStream, newStream: TMemoryStream;
i: Integer;
StartPos, EndPos: Integer;
StartPt: Pointer;
Data, DataNext: PByte;
Amount: Integer;
begin
aStream := TMemoryStream.Create;
newStream := TMemoryStream.Create;
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
aStream.CopyFrom(FReceivedData, FReceivedData.Size);
end);
try
if (aStream.Size < 2) then
Exit;
// Initialize
Amount := 0;
StartPos := -1;
StartPt := nil;
// Data pointers
Data := aStream.Memory;
DataNext := Data;
Inc(DataNext);
try
// Parsing loop
for i := 0 to aStream.Size - 2 do
begin
// Check if we have found the start code
if (StartPos = -1) and (Data^ = $FF) and (DataNext^ = $D8) then
begin
StartPos := i;
StartPt := Data;
end
// Check if we have found the JPEG end code
else if (StartPos >= 0) and (Data^ = $FF) and (DataNext^ = $D9) then
begin
// End position
EndPos := i;
// Copy data (Higher performance than passing whole stream to load,
// because FBitmap.LoadFromStream will create a memory stream and copy
// everything if Position <> 0
aStream.Position := StartPos;
newStream.SetSize((EndPos + 2) - StartPos);
newStream.Position := 0;
newStream.CopyFrom(aStream, (EndPos + 2) - StartPos);
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
Image1.Bitmap.LoadFromStream(newStream);
end);
// Load bitmap on screen
newStream.Clear;
Application.ProcessMessages;
// Amount of data to delete
Amount := EndPos + 2;
// Reset
StartPos := -1;
StartPt := nil;
end;
// Next pointer
Inc(Data);
Inc(DataNext);
end;
// Delete the amount of parsed data
// FReceivedData.Delete(Amount);
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
DeleteStream(FReceivedData, Amount);
FReceivedData.Position := FReceivedData.Size;
end);
except
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
FReceivedData.Clear;
end);
end;
finally
FreeAndNil(aStream);
FreeAndNil(newStream);
end;
end)
end;
Вопрос
gonzales
Доброго времени суток!
Столкнулся с задачей организовать прием MJPEG c ip-камеры.
Само по себе все работает.
На кнопке висит GET запрос в камеру
procedure TForm1.FormCreate(Sender: TObject); begin FReceivedData := TMemoryStream.Create; FParsedData := TMemoryStream.Create; end; procedure TForm1.DeleteStream(Stream: TMemoryStream; Amount: Integer); var bufStream: TMemoryStream; newSize: int64; begin bufStream := TMemoryStream.Create; // Check size if (Amount < 0) then Amount := 0 else if Amount > Stream.Size then Amount := Stream.Size; Stream.Position := Amount; newSize := Stream.Size - Amount; bufStream.SetSize(newSize); bufStream.Position := 0; bufStream.CopyFrom(Stream, newSize); Stream.Clear; Stream.SetSize(newSize); Stream.Position := 0; bufStream.Position := 0; Stream.CopyFrom(bufStream, newSize); bufStream.Free; bufStream := nil; end; procedure TForm1.Button6Click(Sender: TObject); begin IdHTTP1.Get('http://192.168.0.9/videostream.cgi?user=admin&pwd=888888', FReceivedData); end;
На форме idHTTP, idIOHandler и IdConnectionIntercept
У IdConnectionIntercept есть метод OnReceive.
procedure TForm1.IdConnectionInterceptReceive(ASender: TIdConnectionIntercept; var ABuffer: TIdBytes); begin Form1.ParseJPEGData; end;
procedure TForm1.ParseJPEGData; var i: Integer; StartPos, EndPos: Integer; StartPt: Pointer; Data, DataNext: PByte; Amount: Integer; buffer: TBytes; begin // Check size if (FReceivedData.Size < 2) then Exit; // Initialize Amount := 0; StartPos := -1; StartPt := nil; // Data pointers Data := FReceivedData.Memory; DataNext := Data; Inc(DataNext); try // Parsing loop for i := 0 to FReceivedData.Size - 2 do begin // Check if we have found the start code if (StartPos = -1) and (Data^ = $FF) and (DataNext^ = $D8) then begin StartPos := i; StartPt := Data; end // Check if we have found the JPEG end code else if (StartPos >= 0) and (Data^ = $FF) and (DataNext^ = $D9) then begin // End position EndPos := i; // Copy data (Higher performance than passing whole stream to load, // because FBitmap.LoadFromStream will create a memory stream and copy // everything if Position <> 0 FReceivedData.Position := StartPos; FParsedData.SetSize((EndPos + 2) - StartPos); FParsedData.Position := 0; FParsedData.CopyFrom(FReceivedData, (EndPos + 2) - StartPos); // CopyMemory(FParsedData.Memory, StartPt, (EndPos + 2) - StartPos); // Load bitmap on screen Image1.Bitmap.LoadFromStream(FParsedData); FParsedData.Clear; Application.ProcessMessages; // Amount of data to delete Amount := EndPos + 2; // Reset StartPos := -1; StartPt := nil; end; // Next pointer Inc(Data); Inc(DataNext); end; // Delete the amount of parsed data // FReceivedData.Delete(Amount); DeleteStream(FReceivedData, Amount); FReceivedData.Position := FReceivedData.Size; Application.ProcessMessages; except FReceivedData.Clear; end; end;
Так все работает, но сильно грузит основной поток, так что даже программу нельзя закрыть.
Подумал, что может вынести процедуру ParseJPEGData в поток. Но что-то не срабатывает.
Вот код, прокомментируйте пожалуйста
procedure TForm1.ParseJPEGDataThread; begin TTask.Run( procedure var aStream, newStream: TMemoryStream; i: Integer; StartPos, EndPos: Integer; StartPt: Pointer; Data, DataNext: PByte; Amount: Integer; begin aStream := TMemoryStream.Create; newStream := TMemoryStream.Create; TThread.Synchronize(TThread.CurrentThread, procedure begin aStream.CopyFrom(FReceivedData, FReceivedData.Size); end); try if (aStream.Size < 2) then Exit; // Initialize Amount := 0; StartPos := -1; StartPt := nil; // Data pointers Data := aStream.Memory; DataNext := Data; Inc(DataNext); try // Parsing loop for i := 0 to aStream.Size - 2 do begin // Check if we have found the start code if (StartPos = -1) and (Data^ = $FF) and (DataNext^ = $D8) then begin StartPos := i; StartPt := Data; end // Check if we have found the JPEG end code else if (StartPos >= 0) and (Data^ = $FF) and (DataNext^ = $D9) then begin // End position EndPos := i; // Copy data (Higher performance than passing whole stream to load, // because FBitmap.LoadFromStream will create a memory stream and copy // everything if Position <> 0 aStream.Position := StartPos; newStream.SetSize((EndPos + 2) - StartPos); newStream.Position := 0; newStream.CopyFrom(aStream, (EndPos + 2) - StartPos); TThread.Synchronize(TThread.CurrentThread, procedure begin Image1.Bitmap.LoadFromStream(newStream); end); // Load bitmap on screen newStream.Clear; Application.ProcessMessages; // Amount of data to delete Amount := EndPos + 2; // Reset StartPos := -1; StartPt := nil; end; // Next pointer Inc(Data); Inc(DataNext); end; // Delete the amount of parsed data // FReceivedData.Delete(Amount); TThread.Synchronize(TThread.CurrentThread, procedure begin DeleteStream(FReceivedData, Amount); FReceivedData.Position := FReceivedData.Size; end); except TThread.Synchronize(TThread.CurrentThread, procedure begin FReceivedData.Clear; end); end; finally FreeAndNil(aStream); FreeAndNil(newStream); end; end) end;
Ссылка на комментарий
1 ответ на этот вопрос
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.