• 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

Забыл уточнить, что во втором варианте программа вообще завешивается))))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

Войти

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

Войти
Авторизация  

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

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