Форум: "Начинающим";
Текущий архив: 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