• 0
Авторизация  
gonzales

MJPEG в потоке с ip-камеры

Вопросы

Доброго времени суток!

Столкнулся с задачей организовать прием 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 ответ на этот вопрос

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

Авторизация  

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу