Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2012.05.20;
Скачать: [xml.tar.bz2];

Вниз

Передача видео и звука с помощью Indy   Найти похожие ветки 

 
DVM ©   (2011-11-30 23:45) [80]

Ну таймер думаю отсюда надо убрать. Перенести получение очередного кадра в отдельный поток. И вообще все оформить в виде отдельного класса со своими методами, отделить от формы, веб сервер создавать в рантайм. Короче там есть что прикрутить.

Ты вот как то спрашивал про несколько клиентов. Открой пять вкладок в файерфоксе и во всех можешь наблюдать видео. Можешь открыть и 50.


 
3asys ©   (2011-11-30 23:45) [81]

> DVM ©  
Спасибо, без Вас бы это не получилось :)

Как можно сделать клиента?


 
3asys ©   (2011-11-30 23:49) [82]

Попробую :)
Я тогда имел в виду, что каждый участник конференции будет не только смотреть но и сам транслировать и вопрос был - если все будут по одному порту вещать, то не будут ли они мешать друг другу?


 
DVM ©   (2011-11-30 23:55) [83]


> 3asys ©   (30.11.11 23:45) [81]


> Как можно сделать клиента?

Из TIdTCPClient или TIDHTTPClient (хотя насчет последнего не уверен). Можно и чистые Windows Sockets использовать.

Для начала поищи тут на форуме класс TBuffer я когда то выкладывал для Германн - это будет твой приемный буфер.

Подумай, как сделать TCP клиента, который бы принимал данные с твоего сервера и клал в этот буфер.

Остальное завтра.


 
DVM ©   (2011-11-30 23:57) [84]


> если все будут по одному порту вещать, то не будут ли они
> мешать друг другу?

Сервера же на разных компьютерах, мешать друг другу они не будут. А у клиентов у всех порт разный, он системой автоматически выбирается.


 
3asys ©   (2011-11-30 23:58) [85]

Спасибо :)


 
DVM ©   (2011-12-01 00:05) [86]


unit uBuffer;

interface

const
 MinAllocation = 1024;

type

 TBuffer = class(TObject)
 private
   FStorage: PAnsiChar;                    // Указатель на начало буфера
   FAllocation: integer;                   // Размер памяти, выделенной под буфер
   FHead: PAnsiChar;                       // Указатель на начало данных в буфере
   FTail: PAnsiChar;                       // Указатель на конец данных в буфере
   FSize: integer;                         // Размер данных в буфере
   function GetBytes(Index: Integer): PAnsiChar;
   procedure SetSize(ASize: integer);
 public
   constructor Create; overload;
   constructor Create(ASize: integer); overload;
   constructor Create(AStorage: PAnsiChar; ASize: integer); overload;
   constructor Create(ABuffer: TBuffer); overload;

   destructor Destroy; override;

   function Append(ABuffer: TBuffer): integer; overload;
   function Append(AStorage: PAnsiChar; ASize: integer): integer; overload;

   function Assign(AStorage: PAnsiChar; ASize: integer): integer; overload;
   function Assign(ABuffer: TBuffer): integer; overload;

   function Consume(ACount: integer): integer;
   procedure Empty;
   procedure Compact;
   function IsEmpty: boolean;
   function Expand(ACount: integer): integer;
   function Extract(ACount: integer): PAnsiChar;
   function Shrink(ACount: integer): integer;
   procedure Tidy;
   property Head: PAnsiChar read FHead;
   property Size: integer read FSize write SetSize;
   property Storage: PAnsiChar read FStorage;
   property Tail: PAnsiChar read FTail;
   property Allocation: integer read FAllocation;
   property Bytes[Index: Integer]: PAnsiChar read GetBytes;
 end;



 
DVM ©   (2011-12-01 00:05) [87]


implementation

//------------------------------------------------------------------------------

constructor TBuffer.Create;
begin
 Create(0);
end;

//------------------------------------------------------------------------------

constructor TBuffer.Create(ASize: integer);
begin
 if ASize > 0 then
   FAllocation := ASize
 else
   FAllocation := MinAllocation;
 FSize := 0;
 GetMem(FStorage, FAllocation);
 FHead := FStorage;
 FTail := FHead;
end;

//------------------------------------------------------------------------------

constructor TBuffer.Create(AStorage: PAnsiChar; ASize: integer);
begin
 if (ASize > 0) and Assigned(AStorage) then
   begin
    FAllocation := ASize;
    FSize := ASize;
    GetMem(FStorage, FAllocation);
    FHead := FStorage;
    Move(AStorage^, FStorage^, ASize);
    FTail := FHead + FSize;
   end
 else
   Create;
end;

//------------------------------------------------------------------------------

constructor TBuffer.Create(ABuffer: TBuffer);
begin
 if (Assigned(ABuffer)) and (ABuffer.Size > 0) then
   begin
     FAllocation := ABuffer.Size;
     FSize := ABuffer.Size;
     GetMem(FStorage, FAllocation);
     FHead := FStorage;
     Move(ABuffer.Storage^, FStorage^, ABuffer.Size);
     FTail := FHead + FSize;
   end
 else
   Create;
end;

//------------------------------------------------------------------------------

procedure TBuffer.SetSize(ASize: integer);
begin
if FSize <> ASize then
   begin
     if FSize < ASize then
       Expand(ASize)
     else
       begin
         FSize := ASize;
         FTail := FHead + FSize;
       end;
   end;
end;

// Отсекает первые ACount символов ----------------------------------------------

function TBuffer.Consume(ACount: integer): integer;
begin
 if ACount > FSize then ACount := FSize;
 if ACount < 0 then ACount := 0;
 FHead := FHead + ACount;
 FSize := FSize - ACount;
 Result := ACount;
end;

// Отсекает последние ACount символов -------------------------------------------

function TBuffer.Shrink(ACount: integer): integer;
begin
 if ACount > FSize then ACount := FSize;
 if ACount < 0 then ACount := 0;
 FSize := FSize - ACount;
 if FTail > FHead + FSize then FTail := FHead + FSize;
 Result := ACount;
end;

// Расширение буфера -----------------------------------------------------------

function TBuffer.Expand(ACount: integer): integer;
var
 Spare, HeadSpace, TailSpace, Width, OldAllocation: integer;
 NewStorage: PAnsiChar;
begin
 result := FSize;
 if ACount <= 0 then exit;
 // Свободный (незанятый) объем буфера
 Spare := FAllocation - FSize;
 // Свободное место в начале буфера
 HeadSpace := FHead - FStorage;
 // Свободное место в конце буфера
 TailSpace := Spare - HeadSpace;
 // Размер (ширина) занятой части буфера
 Width := Tail - Head;
 // Если в буфере есть достаточно свободного места для добавления ACount байт
 if Spare >= ACount then
   begin
     // Если хвост меньше чем надо добавить
     if TailSpace < ACount then
       begin
         // Двигаем полезные данные в начало буфера
        Move(FHead^, FStorage^, FSize);
         // Начало данных совпадает с началом буфера
        FHead := FStorage;
         // Хвост данных на расстоянии width от головы
         FTail := FHead + Width;
       end;
   end
 else
   // Если в буфере недостаточно места для добавления count символов
   begin
     OldAllocation := FAllocation;
     // Общий объем буфера увеличиваем на count
     FAllocation := FAllocation + ACount;
     // Создаем временный буфер нужного размера
     GetMem(NewStorage, FAllocation);
     FillChar(NewStorage^, FAllocation, 0);
     if FStorage <> nil then
       begin
         // Копируем в него данные из старого буфера
         Move(FHead^, NewStorage^, FSize);
         // Старый буфер удаляем
         FreeMem(FStorage, OldAllocation);
       end;
     // Новый буфер заменяет старый
     FStorage := NewStorage;
     // Данные в начале буфера
     FHead := FStorage;
     // Хвоcт на расстоянии width от головы буфера
     FTail := FHead + Width;
   end;
 // Устанавливаем новый размер буфера
 FSize := FSize + ACount;
 // Возвращаем новый размер
 result := FSize;
end;



 
DVM ©   (2011-12-01 00:08) [88]


// Добавление данных в конец буфера --------------------------------------------

function TBuffer.Append(AStorage: PAnsiChar; ASize: integer): integer;
begin
 if Assigned(AStorage) and (ASize > 0) then
   begin
     Expand(ASize);
     Move(AStorage^, FTail^, ASize);
     FTail := FTail + ASize;
   end;
 result := FSize;
end;

// Добавление данных в конец буфера --------------------------------------------

function TBuffer.Append(ABuffer: TBuffer): integer;
begin
 result := Append(ABuffer.Storage, ABuffer.Size);
end;

// Извлечение первых ACount символов с их удалением из буфера ------------------

function TBuffer.Extract(ACount: integer): PAnsiChar;
var
 OldHead: PAnsiChar;
begin
 if ACount > FSize then ACount := FSize;
 if ACount < 0 then ACount := 0;
 OldHead := FHead;
 Inc(FHead, ACount);
 Dec(FSize, ACount);
 result := OldHead;
end;

//------------------------------------------------------------------------------

procedure TBuffer.Empty;
begin
 FSize := 0;
 FHead := FStorage;
 FTail := FHead;
end;

//------------------------------------------------------------------------------

function TBuffer.Assign(AStorage: PAnsiChar; ASize: integer): integer;
begin
 if Assigned(AStorage) and (ASize > 0) then
   begin
     FreeMem(FStorage, FAllocation);
     FSize := ASize;
     FAllocation := FSize;
     GetMem(FStorage, FAllocation);
     FHead := FStorage;
     Move(AStorage^, FStorage^, FSize);
     FTail := FHead + FSize;
   end;
 result := FSize;
end;

//------------------------------------------------------------------------------

function TBuffer.Assign(ABuffer: TBuffer): integer;
begin
 result := Assign(ABuffer.Storage, ABuffer.Size);
end;

//------------------------------------------------------------------------------

destructor TBuffer.Destroy;
begin
 FreeMem(FStorage, FAllocation);
 inherited Destroy;
end;

//------------------------------------------------------------------------------

function TBuffer.GetBytes(Index: Integer): PAnsiChar;
begin
 result := Head + Index;
end;

//------------------------------------------------------------------------------

procedure TBuffer.Tidy;
begin
 if FHead <> FStorage then
   begin
     if FSize = 0 then
       begin
         FHead := FStorage;
         FTail := FHead;
       end
     else
       begin
         Move(FHead^, FStorage, FSize);
         FHead := FStorage;
         FTail := FHead + FSize;
       end;
   end;
end;

//------------------------------------------------------------------------------

function TBuffer.IsEmpty: boolean;
begin
 result := FSize = 0;
end;

//------------------------------------------------------------------------------

procedure TBuffer.Compact;
var
 Temp: PAnsiChar;
begin
 if FSize > 0 then
   begin
     GetMem(Temp, FSize);
     Move(FHead^, Temp^, FSize);
     FreeMem(FStorage, FAllocation);
     FStorage := Temp;
     FAllocation := FSize;
   end
 else
   begin
     FreeMem(FStorage, FAllocation);
     FSize := 0;
     FAllocation := MinAllocation;
     GetMem(FStorage, FAllocation);
   end;
 FHead := FStorage;
 FTail := FHead + FSize;
 FAllocation := FSize;
end;

//------------------------------------------------------------------------------

end.



На кой ляд нам этот буфер нужен?
Он нужен чтобы данные добавлять в него с одной стороны, а с другой их забирать, причем с минимальными телодвижениями в памяти.

TMemoryStream к сожалению не подойдет.


 
3asys ©   (2011-12-01 00:36) [89]

Спасибо,  а на чем визуализировать изображение? на TImage?


 
brother ©   (2011-12-01 06:44) [90]

на canvas формы


 
DVM ©   (2011-12-01 10:29) [91]


> 3asys ©   (01.12.11 00:36) [89]


> а на чем визуализировать изображение? на TImage?

Я бы на твоем месте, наверное объединил код приема изображения с самописным компонентом, на Canvas которого и выводил бы изображение. Так как прием данных надо делать в отдельном потоке скорее всего, то обновление изображения (которое должно происходить в основном потоке) производил по мере поступления уведомлений от оп потока, что принят новый кадр. Эти уведомления лучше всего сделать на базе сообщений. Synchronize тоже можно, но тяжеловесен он больно.

На TImage лучше не выводить, этот компонент не предназначен для рисования и динамического содержимого, лучше TPaintBox. Или на канву формы (панели какой нить) даже.


 
3asys ©   (2011-12-01 12:02) [92]

понял.
А как должна осуществляться трансляция звука - мы транслировали в поток jpeg-и, а звук как?


 
DVM ©   (2011-12-01 12:13) [93]


> 3asys ©   (01.12.11 12:02) [92]


> а звук как?

Посмотрел документ от Axis ссылка на который дана выше? Это для начала.


 
3asys ©   (2011-12-01 12:18) [94]

хорошо


 
Anatoly Podgoretsky ©   (2011-12-01 12:58) [95]

> 3asys  (01.12.2011 12:02:32)  [92]

Звук - WAV, MP3


 
DVM ©   (2011-12-01 14:19) [96]


> Anatoly Podgoretsky ©   (01.12.11 12:58) [95]


> Звук - WAV

это контейнер, в его случае нет файлов, значит нет и Wav.


 
3asys ©   (2011-12-02 16:58) [97]

> DVM ©

Добрый день
вопрос по клиенту: пытаюсь организовать прием трафика от сервера. Как записать в Buffer данные? - запись вида IdTCPClient1.Socket.ReadStream(...) не подходит, т.к. TBuffer = class(TObject). Как быть?


 
DVM ©   (2011-12-02 18:54) [98]

В этот мой буфер надо принимать данные чистым сокетом без инди.набросаю тебе вечером сегодня код приема упрощенный. Для инди надо по другому


 
DVM ©   (2011-12-02 23:14) [99]


interface

uses
 Windows, Messages, Sysutils, Classes, SyncObjs, Winsock, EncdDecd;

const
 CR = #13;
 LF = #10;
 CRLF = #13#10;
 StartJpegMarker = #255#216;
 EndJpegMarker = #255#217;

type

 THTTPInputThread = class(TThread)
 private
   FHost: String;
   FPort: integer;
   FPath: String;
   FUsername: String;
   FPassword: String;
   FSock: integer;
   FAddr: TSockAddr;
   FTimeout: TTimeVal;
   FBuffer: TBuffer;
   FRequest: String;
   FContentLength: integer;
   function SocketConnect: integer;
   function Init: integer;
   function SendRequest(ASock: integer; ARequest: String): integer;
   function ReadData(ABuffer: TBuffer; BytesExpected: integer): integer;
   function GetResponse: integer;
   function SocketDisconnect: integer;
 protected
   procedure Execute; override;
 public
   constructor Create(AHost: string; APort: integer; APath: string; AUserName: string; APassword: string);
   destructor Destroy;  override;
 end;


.................................


 
DVM ©   (2011-12-02 23:15) [100]


function MemStr2(const S, N: PAnsiChar; const Limit: Cardinal): PAnsiChar;
var
 I: Cardinal;
 pB1, pB2: PAnsiChar;
begin
 result := nil;
 if (s = nil) or (n = nil) then exit;
 if limit < 2 then exit;
 pB1 := S; pB2 := N;
 for I := 0 to Limit - 2 do
   if (pB1^ = pB2^) and ((pB1 + 1)^ = (pB2 + 1)^) then
     begin
       result := pB1;
       exit;
     end
   else
     inc(pB1);
end;

//------------------------------------------------------------------------------

constructor THTTPInputThread.Create(AHost: string; APort: integer;
                                   APath: string; AUserName: string; APassword: string);
begin
 inherited Create(true);
 FHost := AHost;
 FPort := APort;
 FPath := APath;
 FUserName := AUserName;
 FPassword := APassword;
 FBuffer := TBuffer.Create(0);
 Resume;
end;

//------------------------------------------------------------------------------

destructor THTTPInputThread.Destroy;
begin
 FBuffer.Free;
 inherited Destroy;
end;

//------------------------------------------------------------------------------

function THTTPInputThread.SocketConnect: integer;
var
 NoBlock: integer;
 Wfd, EFd: TFDSet;
 TimeVal: TTimeVal;
begin

 Result := socket(AF_INET, SOCK_STREAM, 0);
 if Result = INVALID_SOCKET then
   begin
     Result := -1;
     exit;
   end;

 NoBlock := 1;
 if ioctlsocket(Result, FIONBIO, NoBlock) = SOCKET_ERROR then
   begin
     CloseSocket(Result);
     Result := -1;
     exit;
   end;
 
 if Connect(Result, FAddr, SizeOf(FAddr)) = SOCKET_ERROR then
   begin  
     if WSAGetLastError =  WSAEWOULDBLOCK then
       begin
         while not Terminated do
           begin
             FD_ZERO(wfd);
             FD_SET(result, wfd);

             FD_ZERO(efd);
             FD_SET(result, efd);

             TimeVal.tv_sec := 0;
             TimeVal.tv_usec := 100;

             case select(0, nil, @wfd, @efd, @TimeVal) of
               0: sleep(50);
               1: if FD_ISSET(Result, wfd) then
                    break
                  else
                    if FD_ISSET(Result, efd) then
                      begin  
                        NoBlock := 0;
                        ioctlsocket(Result, FIONBIO, NoBlock);
                        CloseSocket(Result);
                        Result := -1;
                        exit;
                      end;
               SOCKET_ERROR:
                 begin
                   NoBlock := 0;
                   ioctlsocket(Result, FIONBIO, NoBlock);
                   CloseSocket(Result);
                   Result := -1;
                   exit
                 end;
             end;
           end;
        end
      else
        begin
          NoBlock := 0;
          ioctlsocket(Result, FIONBIO, NoBlock);
          CloseSocket(Result);
          Result := -1;
        end;
   end;

 //Возврат в блокирующий режим
 NoBlock := 0;
 if ioctlsocket(Result, FIONBIO, NoBlock) = SOCKET_ERROR then
   begin
     CloseSocket(Result);
     Result := -1;
   end;
end;

//------------------------------------------------------------------------------

function THTTPInputThread.SocketDisconnect(): integer;
begin
 if FSock <> -1 then
   begin
     ShutDown(FSock, SD_BOTH);
     CloseSocket(FSock);
     FSock := -1;
   end;
 Result := 0;
end;

//------------------------------------------------------------------------------



 
DVM ©   (2011-12-02 23:16) [101]


function THTTPInputThread.Init: integer;
begin
 FBuffer.Empty;
 ZeroMemory(@FAddr, SizeOf(FAddr));
 FAddr.sin_family := PF_INET;
 FRequest := "GET " + FPath + " HTTP/1.1" + CRLF +
             "Host: " + FHost + ":" + inttostr(FPort) + CRLF +
             "User-Agent: Mozilla/5.0" + CRLF +
             "Accept: */*" + CRLF +
             "Keep-Alive: 300"  + CRLF +
             "Connection: keep-alive";
 FRequest := FRequest + CRLF + "Authorization: Basic " + EncodeString(FUserName + ":" + FPassword);
 FRequest := FRequest + CRLF + CRLF;
 FAddr.sin_addr.s_addr := InetAddr(AnsiString(FHost));
 FAddr.sin_port := htons(FPort);
 FTimeout.tv_sec := 20;
 FTimeout.tv_usec := 0;
 FSock := -1;
 Result := 0;
end;

//------------------------------------------------------------------------------

function THTTPInputThread.SendRequest(ASock: integer; ARequest: String): integer;
var
 ReturnCode: integer;
 Req: AnsiString;
begin
 Req := AnsiString(ARequest);
 ReturnCode := send(ASock, Req[1], Length(Req), 0);
 if ReturnCode = SOCKET_ERROR then
   begin
     Result := -1;
     SocketDisconnect();
   end
 else
   begin
     Result := 0;
   end;
end;

//------------------------------------------------------------------------------

function THTTPInputThread.ReadData(ABuffer: TBuffer; BytesExpected: integer): integer;
const
 MaxLen = 262144;
var
 TotalBytesToRead, Found, TotalBytesRead, BytesToRead, BytesRead: integer;
 Rfds: TFDSet;
 TempBuff: array [0..Pred(MaxLen)] of AnsiChar;
begin
 FD_ZERO(Rfds);
 FD_SET(FSock, Rfds);
 Found := select(FSock, @Rfds, nil, nil, @FTimeout);
 if Found = 0 then
   begin
     // Select timed out
     Result := -1;
     exit;
   end
 else
   if Found = SOCKET_ERROR then
     begin
       // Select error
       Result := -1;
       exit;
     end;
 TotalBytesToRead := 0;
 if BytesExpected <> 0 then
   begin
     TotalBytesToRead := BytesExpected;
   end
 else
   begin
     if ioctlsocket(FSock, FIONREAD, TotalBytesToRead) = SOCKET_ERROR then
       begin
         // Cannot ioctl()
         Result := -1;
         exit;
       end;
     if TotalBytesToRead = 0  then
       begin
         SocketDisconnect();
         Result := 0;
         exit;
       end;
   end;
 TotalBytesRead := 0;
 repeat
   if TotalBytesToRead > MaxLen then
     BytesToRead := MaxLen
   else
     BytesToRead := TotalBytesToRead;
   ZeroMemory(@TempBuff[0], MaxLen);
   BytesRead := recv(FSock, TempBuff, BytesToRead, 0);
   if BytesRead = SOCKET_ERROR then
     begin
       // Read error
       SocketDisconnect();
       Result := -1;
       exit;
     end
   else
     if BytesRead = 0 then
       begin
         SocketDisconnect();
         Result := 0;
         exit;
       end
     else
       begin
         // Если буфер стал слишком большой
         if ABuffer.Size >= 2097152 then
           begin
             SocketDisconnect();
             Result := -1;
             exit;
           end;
         ABuffer.Append(@TempBuff[0], BytesRead);
         TotalBytesRead := TotalBytesRead + BytesRead;
         TotalBytesToRead := TotalBytesToRead - BytesRead;
       end;
 until TotalBytesToRead <= 0;
 Result := TotalBytesRead;
end;

//------------------------------------------------------------------------------

function THTTPInputThread.GetResponse(): integer;
var
 StartPtr, EndPtr: PAnsiChar;
 BufferLen, Offset: integer;
 GotStartMarker: Boolean;
begin
 result := -1;
 Offset := 0;
 GotStartMarker := False;
 while (not Terminated) do
   begin
     if (not GotStartMarker) and (FBuffer.Size > 2) then
       begin
         StartPtr := MemStr2(FBuffer.Head, StartJpegMarker, FBuffer.Size);
         if StartPtr <> nil then
           begin
             FBuffer.Consume(StartPtr - FBuffer.Head);
             GotStartMarker := true;
           end
         else
           FBuffer.Empty;
       end;
     if GotStartMarker and (FBuffer.Size > 2) then
       begin
         EndPtr := MemStr2(FBuffer.Head + Offset, EndJpegMarker, FBuffer.Size - Offset);
         if EndPtr <> nil then
           begin
             Result := EndPtr - FBuffer.Head + 2;
             exit;
           end
         else
           Offset := FBuffer.Size - 2;
       end;
     BufferLen := ReadData(FBuffer, 0);
     if BufferLen < 0 then
       begin
         result := -1;
         exit;
       end;
   end;
end;

//------------------------------------------------------------------------------


 
DVM ©   (2011-12-02 23:19) [102]


type

TFrameData = record
   FrameData: PAnsiChar;
   FrameDataLen: integer;
 end;
 PFrameData = ^TFrameData;

procedure THTTPInputThread.Execute;
var
 FrameData: PFrameData;
 Wsa: TWSADATA;
begin  
 WSAStartUp($0101, Wsa);
 try  
   while not Terminated do
     try
       Init;
       FSock := SocketConnect();
       if FSock <> -1 then
         try
           if SendRequest(FSock, FRequest) <> 0 then exit;
           repeat
             FContentLength := GetResponse;
             if FContentLength > 0 then
               begin
                 FrameData := New(PFrameData);
                 try
                   FrameData^.FrameData := FBuffer.Extract(FContentLength);
                   FrameData^.FrameDataLen := FContentLength;
                   SendMessage(FWindowHandle, WM_NEWFRAME, 0, Longint(FrameData));
                 finally
                   Dispose(FrameData);
                 end;
               end;
           until Terminated or (FContentLength = -1);
         finally
           SocketDisconnect;
         end
       else sleep(500);
     except
       sleep(500);
     end;
 finally
    WSACleanUp;
 end;
end;



разбирайся, если что непонятно спрашивай.


 
3asys ©   (2011-12-03 00:06) [103]

Спасибо!


 
Германн ©   (2011-12-03 00:11) [104]


> DVM ©   (02.12.11 18:54) [98]
>
> В этот мой буфер надо принимать данные чистым сокетом без
> инди.

Что-то мне подсказывает, что использование ICS вместо инди решило бы проблему без такой кучи писанины :)
Но могу и ошибаться.


 
DVM ©   (2011-12-03 00:21) [105]


> Германн ©   (03.12.11 00:11) [104]


> Что-то мне подсказывает, что использование ICS вместо инди
> решило бы проблему без такой кучи писанины :)

Да можно и с инди и с ICS. Да не сильно короче бы вышло.


 
3asys ©   (2011-12-03 00:39) [106]

не декларированный идентификатор InetAddr в выражении
FAddr.sin_addr.s_addr := InetAddr(AnsiString(FHost));
в функции:
function THTTPInputThread.Init: integer;

и также недекларированный идентификатор FWindowHandle в выражении
SendMessage(FWindowHandle, WM_NEWFRAME, 0, Longint(FrameData));
в профедуре: procedure THTTPInputThread.Execute;


 
3asys ©   (2011-12-03 00:41) [107]

в остальном компилируется.
Что с этими идентификаторами делать?


 
DVM ©   (2011-12-03 00:45) [108]


> 3asys ©   (03.12.11 00:39) [106]


function InetAddr(const AHost: AnsiString): DWORD;
var
 PHost: PAnsiChar;
 HostEnt: PHostEnt;
begin
 if AHost = "" then
   result := DWORD($FFFFFFFF)
 else
   begin
     PHost := PAnsiChar(AHost);
     Result := inet_addr(PHost);
     if Result = DWORD($FFFFFFFF) then
       begin
         HostEnt := GetHostByName(PHost);
         if HostEnt <> nil then
           Result := DWORD(pointer(HostEnt^.h_addr^)^);
       end;
   end;
end;


Ну а SendMessage пока просто убери. Или заведи поле FWindowHandle у класса потока и передавай в его конструктор хэндл окна которому будут приходить сообщения из потока. В конструкторе присваивай FWindowHandle переданное в конструктор значение.

Будь внимателен, код старый, пока постил сюда подправил кое-где на предмет PChar - > PAnsiChar, но мог пропустить что-то.


 
DVM ©   (2011-12-03 00:46) [109]


> Что с этими идентификаторами делать?

с какими идентификаторами?


 
3asys ©   (2011-12-03 00:50) [110]

если InetAddr - это Inet_Addr, то все равно несовпадение типов в выражении String и PAnsiChar


 
3asys ©   (2011-12-03 00:51) [111]

понял - спасибо :)


 
Германн ©   (2011-12-03 01:19) [112]


> Да можно и с инди и с ICS.

Не. ICS рассчитана исторически на асинхронную работу. Ну это то (примерно) что вы привели в [99] - [102].


 
DVM ©   (2011-12-03 01:34) [113]


> Германн ©   (03.12.11 01:19) [112]


> Не.

C ICS можно было бы отказаться от потока. Но, это бы усложнило логику. Тут желательно чтобы все последовательно было,так оно нагляднее, особенно для примера. Indy потребовала бы поток, но можно было бы избавиться от рутины типа ReadData(). Но у Indy блокирующий коннект. Иногда это сильно мешает. А на сокетах все прозрачно и на виду. Для понимания процесса полезно имхо.


 
3asys ©   (2011-12-03 14:37) [114]

Добрый день :)
> DVM ©
Правильно ли я понял, что
1. При запуске клиента вызываем THTTPInputThread.Create
1.1. передаем ей
 адрес сервера,
 порт,
 имя пользователяи
 пароль пользователя
 ЧТО ТАКОЕ APath ?
2. При подключении к серверу вызываем THTTPInputThread.Execute
3. При выключении клиента вызываем THTTPInputThread.Destroy

Включил в проект модуль uBuffer (буфер) и модуль uClientFunctions (работа клиента)
Сейчас модуль клиента выглядит так:

unit uclnt;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, ExtCtrls, ComCtrls, ToolWin,

 IdHTTP, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,

 uBuffer, uClientFunctions;

type
 TfrmClient = class(TForm)
   ToolBar1: TToolBar;
   tbtnStart: TToolButton;
   Panel1: TPanel; // на нее буду выводить видео
   procedure FormCreate(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
   procedure tbtnStartClick(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 frmClient: TfrmClient;
 Host: string;
 Port: integer;
 Path: string;
 UserName: string;
 Password: string;

implementation

{$R *.dfm}

procedure TfrmClient.FormCreate(Sender: TObject);
begin
 Host := "127.0.0.1";
 Port := 8081;
 Path := "";
 UserName := "";
 Password := "";
 THTTPInputThread.Create(Host, Port, Path, UserName, Password);
end;

procedure TfrmClient.tbtnStartClick(Sender: TObject);
begin
 THTTPInputThread.Execute;
end;

procedure TfrmClient.FormDestroy(Sender: TObject);
begin
 THTTPInputThread.Destroy;
end;

end.

На вызов THTTPInputThread.Execute; сообщается "недекларированный идентификатор Execute",
На вызов THTTPInputThread.Destroy; сообщает "not enough actual parameters"
Что можно сделать?


 
Германн ©   (2011-12-03 14:50) [115]


> Что можно сделать?
>

Создать THTTPInputThread правильно.


 
DVM ©   (2011-12-03 15:05) [116]


> 3asys ©   (03.12.11 14:37) [114]


> Правильно ли я понял, что
> 1. При запуске клиента вызываем THTTPInputThread.Create
> 1.1. передаем ей
>  адрес сервера,
>  порт,
>  имя пользователяи
>  пароль пользователя

вобщем да, но лучше чуть по другому, смотри ниже.


> ЧТО ТАКОЕ APath ?

в том сервере, что я тебе писал выше это игнорируется, ну передай туда "/", это путь на сервере, ну например, он мог бы быть /mjpeg.cgi или /GetVideo.


> 2. При подключении к серверу вызываем THTTPInputThread.Execute

При подключении к серверу ты должен создать поток.
VideoThread := THTTPInputThread.Create(...)

Execute protected метод его ты не вызовешь из кода программы, да это и не надо, он сам вызовется. Читай справку про потоки.


> 3. При выключении клиента вызываем THTTPInputThread.Destroy

при отключении вызывай метод Free у экземпляра этого потока, предварительно остановив его (вообще это азы и это в справке есть).

VideoThread.Terminate;
VideoThread.WaitFor;
FreeAndNil(VideoThread)


> Сейчас модуль клиента выглядит так:

Касательно использования потока там написан бред. См. как надо выше.


 
DVM ©   (2011-12-03 15:12) [117]

Также, я хотел заметить, что приведенный выше метод function THTTPInputThread.GetResponse(): integer; сильно упрощен. Это даже не чтение ответа именно HTTP сервера, это чтение и попытка выделить JPEG из любого потока TCP в любом формате. По-хорошему, надо принимать и анализировать заголовки сервера, тип контента, длину контента в подзаголовках и на основании этого читать строго заданное количество данных, учитывать разделители. Все это положительным образом скажется на производительности. Но код усложниться в десяток раз. Поэтому пока так.


 
3asys ©   (2011-12-04 01:00) [118]

Спасибо, создал поток, как было указано,
смотрю отладчиком - с сервером соединяется, данные получает,
а как вывести их на канву (для простоты использую TPaintBox) не могу сообразить.
Правильно ли я понимаю, что экземпляр буффера создается созданным экземпляром THTTPInputThread, так сказать находится внутри потока и мне его создавать самому не нужно?
Если это так, то каким образом до него (Buffer) достучаться? А если это не так, то создав VideoBuffer := TBuffer.Create, как связать его с потоком и канвой?


 
DVM ©   (2011-12-04 01:09) [119]


> 3asys ©   (04.12.11 01:00) [118]

Достукиваться лучше не до самого буфера:

 FrameData^.FrameData := FBuffer.Extract(FContentLength);
                  FrameData^.FrameDataLen := FContentLength;^.FrameData := FBuffer.Extract(FContentLength);
FrameData^.FrameDataLen := FContentLength;

Вот здесь в первой строке из буфера извлекается очередной кадр и помещается в структуру FrameData. Указатель на эту структуру можно с сообщением Windows передать в основной поток программы окну твоей формы например. Можно в принципе с сообщением передавать и сам буфер, так как SendMessage все равно синхронизирует доступ к нему, но наверное лучше вот так со структурой.
Как получать окном формы пользовательские сообщения давай сам думай, это не сложно и примеров интернет масса.

Когда получишь сообщение, тебе лишь надо будет декодировать из JPEG данных кадр и отрисовать его. Т.е придется сначала загнать данные в поток, загрузить оттуда их в JPEG потом декодировать и отрисовать на BMP.


 
3asys ©   (2011-12-04 01:13) [120]

Спасибо, буду стараться :)



Страницы: 1 2 3 4 5 вся ветка

Форум: "Начинающим";
Текущий архив: 2012.05.20;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.77 MB
Время: 0.014 c
15-1326364010
Псарь
2012-01-12 14:26
2012.05.20
Ну и в чем тут подвох?


15-1326382496
brother
2012-01-12 19:34
2012.05.20
Хочу не понятного?


2-1322308094
3asys
2011-11-26 15:48
2012.05.20
Передача видео и звука с помощью Indy


15-1326278247
>|<
2012-01-11 14:37
2012.05.20
Печать наклейки на USB-принтере


2-1326697088
Nikitos
2012-01-16 10:58
2012.05.20
Перевод чисел из арабских в почтовый индекс





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский