Форум: "Начинающим";
Текущий архив: 2012.05.20;
Скачать: [xml.tar.bz2];
ВнизПередача видео и звука с помощью Indy Найти похожие ветки
← →
3asys © (2011-12-04 01:13) [120]Спасибо, буду стараться :)
← →
3asys © (2011-12-10 15:43) [121]Добрый день )
> DVM ©
Реализовал получение окном формы пользовательского сообщения (procedure TfrmClient.WndProc(var Msg: TMessage)):
unit uclnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, ToolWin, StdCtrls, jpeg,
IdHTTP, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
uClientFunctions, uBuffer;
type
TfrmClient = class(TForm)
ToolBar1: TToolBar;
tbtnStart: TToolButton;
PaintBox1: TPaintBox;
Splitter1: TSplitter;
Image1: TImage;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure tbtnStartClick(Sender: TObject);
// procedure GetVideoMsg(var Msg: TMsg; var Handled: Boolean);
procedure WndProc(var Msg: TMessage); override;
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmClient: TfrmClient;
Host: string;
Port: integer;
Path: string;
UserName: string;
Password: string;
VideoThread : THTTPInputThread;
VideoStream : TMemoryStream;
implementation
{$R *.dfm}
procedure TfrmClient.FormCreate(Sender: TObject);
begin
Host := "127.0.0.1";
Port := 8081;
Path := "/";
UserName := "";
Password := "";
VideoStream:=TMemoryStream.Create;
end;
procedure TfrmClient.tbtnStartClick(Sender: TObject);
begin
VideoThread := THTTPInputThread.Create(Host, Port, Path, UserName, Password);
end;
procedure TfrmClient.WndProc(var Msg: TMessage);
begin
if Msg.Msg = FSendNewFrameMessage then
begin
// Здесь загрузка данных в поток, выгрузка оттуда их в Jpeg
// декодирование и отрисовка
end
else
inherited;
end;
procedure TfrmClient.FormDestroy(Sender: TObject);
begin
VideoThread.Terminate;
VideoThread.WaitFor;
FreeAndNil(VideoThread);
end;
end.
Для упрощения обработки, с сообщением передаю сам кадр:
SendMessage(frmClient.Handle, FSendNewFrameMessage, 0, Longint(FrameData^.FrameData));
Далее пробовал по разному, но не смог загрузить данные в поток и не понимаю, как преобразовать их в jpg/
Как загрузить принятые данные в поток (передается Longint) и преобразовать их в jpg ?
← →
DVM © (2011-12-10 21:29) [122]
> Как загрузить принятые данные в поток (передается Longint)
> и преобразовать их в jpg ?
Наверное лучше (на будущее) будет не LongInt там использовать, а LParam. Но пока суть не в этом. Ты неправильно написал немного. Ты передаешь с сообщением указатель на сам кадр, но не передаешь размер кадра. Такое в поток не загрузить. Нужно и размер передавать LParam(FrameData). Я подразумеваю, что FrameData у тебя это указатель на запись в которой есть поле FrameData - указатель на данные, и есть там еще одно поле - размер.
В WndProc ты получаешь код сообщения, LPARAM и WPARAM. Твой LPARAM это на самом деле указатель на структуру с данными. Просто приведи его обратно к типу структуры:
var
FrameData: PFrameData; // считаем, что PFrameData = ^TFrameData
...
FrameData := PFrameData(Msg.Lparam);
Вуаля. В твоем распоряжении указатель на структуру с данными. Тебе остается скопировать данные в TMemoryStream. Смотри методы TMemoryStream которые могу загрузить данные из буфера.
Потом можешь грузить данные обратно в JPEG. Не забудь предварительно только позицию в TMemoryStream выставить на начало его.
Все описанное выше десяток строк.
Вообще я бы не стал туда сюда гонять данные между буфером и стримом потом TJpegImage - можно сразу передать с сообщением буфер и прямо из него декодировать, например с помощью Intel Jpeg Library. Юудет быстрее. Но это потом. Сначала разберись по простому.
← →
3asys © (2011-12-11 18:39) [123]Пробую создавать сообщение:
SendMessage(frmClient.Handle, FSendNewFrameMessage, 0, LParam(FBuffer));
В WndProc принимаю таким образом:
FrameData := PFrameData(Msg.Lparam);
VideoStream.WriteBuffer(FrameData,FrameData^.FrameDataLen);
расчитывая в дальнейшем сделать что-то вроде:
jpg:=TJPEGImage.Create;
VideoStream.Position:=0;
jpg.LoadFromStream(VideoStream);
b:=TBitmap.Create;
b.Assign(jpg);
Image1.Picture.Assign(b);
При обработки строки
VideoStream.WriteBuffer(FrameData,FrameData^.FrameDataLen);
выдается ошибка "Access violation".
Что я делаю неправильно?
← →
DVM © (2011-12-11 19:19) [124]
> Что я делаю неправильно?
с какого перепуга ты приводишь FBuffer типа TBuffer к PFrameData ???
в [102] же все написано было. Не торопись, сделай сначала так как я написал, потом будешь пытаться улучшать.
Это раз.type
TFrameData = record
FrameData: PAnsiChar;
FrameDataLen: integer;
end;
PFrameData = ^TFrameData;
FrameData := PFrameData(Msg.Lparam);
VideoStream.WriteBuffer(FrameData^.FrameData,FrameData^.FrameDataLen);
Это два.
← →
3asys © (2011-12-11 21:53) [125]Создаю сообщение в соответствии с [102]:
SendMessage(frmClient.Handle, FSendNewFrameMessage, 0, Longint(FrameData));
Принимаю сообщение в модуле:
unit uclnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, ToolWin, StdCtrls, jpeg,
IdHTTP, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
uClientFunctions, uBuffer;
type
TfrmClient = class(TForm)
ToolBar1: TToolBar;
tbtnStart: TToolButton;
Splitter1: TSplitter;
Image: TImage;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure tbtnStartClick(Sender: TObject);
// procedure GetVideoMsg(var Msg: TMsg; var Handled: Boolean);
procedure WndProc(var Msg: TMessage); override;
private
{ Private declarations }
public
{ Public declarations }
end;
TFrameData = record
FrameData: PAnsiChar;
FrameDataLen: integer;
end;
PFrameData = ^TFrameData;
var
frmClient: TfrmClient;
Host: string;
Port: integer;
Path: string;
UserName: string;
Password: string;
VideoThread : THTTPInputThread;
VideoStream : TMemoryStream;
implementation
{$R *.dfm}
procedure TfrmClient.FormCreate(Sender: TObject);
begin
Host := "127.0.0.1";
Port := 8081;
Path := "/";
UserName := "";
Password := "";
VideoStream:=TMemoryStream.Create;
end;
procedure TfrmClient.tbtnStartClick(Sender: TObject);
begin
VideoThread := THTTPInputThread.Create(Host, Port, Path, UserName, Password);
end;
procedure TfrmClient.WndProc(var Msg: TMessage);
var
FrameData: PFrameData;
jpeg : TJPEGImage;
b : TBitmap;
begin
if Msg.Msg = FSendNewFrameMessage then
begin
FrameData := PFrameData(Msg.Lparam);
VideoStream.WriteBuffer(FrameData^.FrameData, FrameData^.FrameDataLen);
jpeg:=TJPEGImage.Create;
VideoStream.Position:=0;
jpeg.LoadFromStream(VideoStream);
b:=TBitmap.Create;
b.Assign(jpeg);
Image.Picture.Assign(b);
jpeg.Free;
b.Free;
end
else
inherited;
end;
procedure TfrmClient.FormDestroy(Sender: TObject);
begin
VideoThread.Terminate;
VideoThread.WaitFor;
FreeAndNil(VideoThread);
end;
end.
При выполнении строки
VideoStream.WriteBuffer(FrameData^.FrameData, FrameData^.FrameDataLen);
выдается сообщение "Access Violation". Иногда эту строку проходит благополучно, но тогда при выполнении строки
jpeg.LoadFromStream(VideoStream);
выдается сообщение "Exception class EJPEG with message "JPEG error #53" ".
Точного значения этой ошибки найти не удалось (но, насколько я понял - общий смысл в несоответствии данных формату jpeg).
На входе (от сервера) во время тестирования - видео с web-камеры.
Что тут теперь может быть?
← →
DVM © (2011-12-11 22:03) [126]
> 3asys © (11.12.11 21:53) [125]
А FSendNewFrameMessage у тебя чему равен?
← →
DVM © (2011-12-11 22:07) [127]И еще VideoStream очищай каждый раз перед записью в него
← →
3asys © (2011-12-11 22:21) [128]FSendNewFrameMessage регистрируется в
constructor THTTPInputThread.Create
FSendNewFrameMessage := RegisterWindowMessage("WM_NEW_FRAME");
При выполнении программы оно = 49778 всегда.
Перед
VideoStream.WriteBuffer(FrameData^.FrameData, FrameData^.FrameDataLen);
поставил:
VideoStream.Clear;
Результат не изменился, к сожалению. Опять Access violation и error #53
Что еще может быть?
← →
DVM © (2011-12-11 22:24) [129]
> 3asys © (11.12.11 22:21) [128]
> Что еще может быть?
VideoStream.WriteBuffer(FrameData^.FrameData^, FrameData^.FrameDataLen);
← →
3asys © (2011-12-11 22:30) [130]ЕСТЬ !!!
РАБОТАЕТ :)
СПАСИБО БОЛЬШОЕ !!!
← →
3asys © (2011-12-11 22:36) [131]Для интересующихся, вот полный код клиента (сервер в [78]):
unit uclnt;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, ToolWin, StdCtrls, jpeg,
IdHTTP, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
uClientFunctions, uBuffer;
type
TfrmClient = class(TForm)
ToolBar1: TToolBar;
tbtnStart: TToolButton;
Splitter1: TSplitter;
Image: TImage;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure tbtnStartClick(Sender: TObject);
// procedure GetVideoMsg(var Msg: TMsg; var Handled: Boolean);
procedure WndProc(var Msg: TMessage); override;
private
{ Private declarations }
public
{ Public declarations }
end;
TFrameData = record
FrameData: PAnsiChar;
FrameDataLen: integer;
end;
PFrameData = ^TFrameData;
var
frmClient: TfrmClient;
Host: string;
Port: integer;
Path: string;
UserName: string;
Password: string;
VideoThread : THTTPInputThread;
VideoStream : TMemoryStream;
implementation
{$R *.dfm}
procedure TfrmClient.FormCreate(Sender: TObject);
begin
Host := "127.0.0.1";
Port := 8081;
Path := "/";
UserName := "";
Password := "";
VideoStream:=TMemoryStream.Create;
end;
procedure TfrmClient.tbtnStartClick(Sender: TObject);
begin
VideoThread := THTTPInputThread.Create(Host, Port, Path, UserName, Password);
end;
procedure TfrmClient.WndProc(var Msg: TMessage);
var
FrameData: PFrameData;
jpeg : TJPEGImage;
b : TBitmap;
begin
if Msg.Msg = FSendNewFrameMessage then
begin
// Çäåñü çàãðóçêà äàííûõ â ïîòîê, âûãðóçêà îòòóäà èõ â Jpeg
// äåêîäèðîâàíèå è îòðèñîâêà
FrameData := PFrameData(Msg.Lparam);
VideoStream.Clear;
VideoStream.WriteBuffer(FrameData^.FrameData^, FrameData^.FrameDataLen);
jpeg:=TJPEGImage.Create;
VideoStream.Position:=0;
jpeg.LoadFromStream(VideoStream);
b:=TBitmap.Create;
b.Assign(jpeg);
Image.Picture.Assign(b);
jpeg.Free;
b.Free;
end
else
inherited;
end;
procedure TfrmClient.FormDestroy(Sender: TObject);
begin
VideoThread.Terminate;
VideoThread.WaitFor;
FreeAndNil(VideoThread);
end;
end.
← →
3asys © (2011-12-11 22:39) [132]
unit uClientFunctions;
interface
uses
Windows, Messages, Sysutils, Classes, SyncObjs, Winsock, EncdDecd,
uBuffer;
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;
var
FSendNewFrameMessage: Cardinal; // Äëÿ Win32API
implementation
uses uclnt;
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;
FSendNewFrameMessage := RegisterWindowMessage("WM_NEW_FRAME");
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;
//------------------------------------------------------------------------------
← →
3asys © (2011-12-11 22:41) [133]
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;
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;
//------------------------------------------------------------------------------
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(frmClient.Handle, FSendNewFrameMessage, 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;
end.
← →
DVM © (2011-12-11 22:45) [134]
> 3asys ©
вот тут чем то похожим человек занимается
http://delphimaster.net/view/8-1322690080/
← →
3asys © (2011-12-11 22:46) [135]код модуля uBuffer см. [86],[87],[88].
Все тестировалось на Delphi7.
← →
3asys © (2011-12-11 22:58) [136]> DVM ©
Да, спасибо, сегодня увидел.
Я смотрю Ваши рекомендации по улучшению/доработке.
Что бы Вы порекомендовали в первую очередь для уменьшения задержек (чуть подтормаживает, даже при нахождении сервера и клиента на одной и той же машине) и снижения трафика?
← →
DVM © (2011-12-11 23:08) [137]
> 3asys © (11.12.11 22:58) [136]
> Что бы Вы порекомендовали в первую очередь для уменьшения
> задержек
Отказаться от модуля jpeg в пользу Intel Jpeg Library 1.5. Она бесплатная в этой версии. В интернете есть заголовочные файлы для нее и есть модуль-переходник для кодирования-декодирования в-из TBitamp. Правда замечены за ней проблемы с многопоточностью, но это решаемо.
> и снижения трафика?
Переходить на MPEG4 ? Осваивать какой-то кодер-декодер придется. Метод передачи можно оставить тот же. Кодер-декодер FFMPEG можно взять.
Ну или FPS можно понижать.
Вообще данный метод позволяет выжать на средней машине 400 FPS (640x480) суммарно легко при использовании IJL.
← →
DVM © (2011-12-11 23:12) [138]
> 3asys © (11.12.11 22:58) [136]
>
Еще метод GetResponse совершенствовать надо. Сейчас он никак не учитывает Content-Length присылаемый ему с каждым кадром, а должен вообще то. Используя Content-Length мы можем не пытаться искать маркеры начала и конца кадра получив очередную порцию данных, что положительно скажется на производительности. Но это ты если хочешь сам уже пытайся.
← →
3asys © (2011-12-11 23:26) [139]Спасибо Вам БОЛЬШОЕ
← →
3asys © (2011-12-19 12:17) [140]Добрый день :)
> DVM ©
Насколько я понимаю, в связи тем, что в рамках системы видеоконференцсвязи, вещание (видео-аудио потока) ведется клиентами (на борту у каждого из которых находится и локальный сервер отдающий поток и локальный клиент принимающий потоки от других участников конференции) независимо друг от друга, то информировать участников об IP-адресах с которых вещают участники конференции должен глобальный (для этой конференции) сервер. При этом IP по которому можно подключиться к серверу есть только у глобального сервера, а у локальных серверов (на борту клиентов) таких IP нет.
Как организовать подключение участников конференции к локальным серверам друг друга?
← →
DVM © (2011-12-19 18:06) [141]
> 3asys © (19.12.11 12:17) [140]
Попробуй для начала разбить задачу на части.
1) Определи, в каких состояниях может находится клиент (ожидание, исходящий вызов, входящий вызов, присоединение к конференции, создание конференции и т.д.)
2) Определи, что клиенту надо знать самому в каждом состоянии и что надо сообщить другим.
Вот все эти данные и должны отправляться/приниматься на/с сервер/а
Сервер можно тоже HTTP раз уж начали его использовать.
← →
3asys © (2011-12-19 22:22) [142]> DVM ©
я имел в виду несколько другое:
для того, чтобы получить поток от сервера, клиент должен к нему подключиться, а для этого он должен быть настроен на IP сервера и определенный порт, но как клиент подключится к серверу имеющему динамический IP? Как он получит с него поток?
← →
DVM © (2011-12-19 22:34) [143]
> 3asys © (19.12.11 22:22) [142]
> а для этого он должен быть настроен на IP сервера и определенный
> порт, но как клиент подключится к серверу имеющему динамический
> IP? Как он получит с него поток?
>
>
У кого динамический IP у одного из участников видеоконференции или у центрального сервера?
← →
3asys © (2011-12-19 22:39) [144]> У кого динамический IP у одного из участников видеоконференции или у центрального сервера?
у участников конференции. Уцентрального сервера - статический IP
← →
DVM © (2011-12-19 22:43) [145]
> 3asys © (19.12.11 22:39) [144]
Я ж в 141 вроде бы все написал:
> Вот все эти данные и должны отправляться/приниматься на/с
> сервер/а
Клиент регистрируется на сервере и сообщает ему свой IP. Остальные участники конференции могут его там же получить.
← →
DVM © (2011-12-19 22:45) [146]А если участник конференции сидит за NAT то он еще должен сообщать серверу и порт, на который надо стучаться. А сам порт у него в настройках должен запоминаться.
← →
3asys © (2011-12-19 22:54) [147]:)
наверно я непавильно объяснил, что имею в виду:
допустим , я уже знаю и IP и порт сервера (одного из участников), с которого мне нужно получить поток. IP у этого сервера динамический и DNS не настроен. Как мой клиент сможет получить поток от этого сервера? - ведь достучаться к этому серверу, ввиду отсутствия DNS из интернета невозможно. Как же мой клиент получит от этого сервера поток? (может я чего-то не догоняю...)
← →
DVM © (2011-12-19 23:20) [148]
> 3asys © (19.12.11 22:54) [147]
> (может я чего-то не догоняю...)
не догоняешь, попробуй прочитать мой пост выше еще раз. :) Сервером я всегда называю центральный сервер с постоянным IP который всем известен.
← →
3asys © (2011-12-19 23:38) [149]прочитал Ваш пост несколько раз, правильно ли я понимаю, что
1.каждый клиент заходит на центральный сервер и сообщает ему свой IP и порт
2.центральный сервер передает IP и порт каждого клиента другим клиентам
3. каждый клиент обращается к серверам других клиентов (а у них IP динамический) по их полученным от центрального сервера IP и принимают от них видео-аудио поток
Если все это так, то единственное, что мне не понятно в этой схеме - как клиенты подключатся к динамическому IP серверов? Или зжесб еще что-то подразумевается?
← →
3asys © (2011-12-19 23:40) [150]:) простите опечатался - последнее предложение - "Или же здесь еще что-то подразумевается?"
← →
DVM © (2011-12-19 23:48) [151]
> Если все это так, то единственное, что мне не понятно в
> этой схеме - как клиенты подключатся к динамическому IP
> серверов?
Динамический IP - это такой же IP как и статический, он ничем не отличается от статического с той лишь разницей, что он периодически меняется. А меняется он как правило при очередном подключении компьютера пользователя к провайдеру. Зная этот IP точно так же можно подключиться к серверу, расположенному на этом IP.
А для того, чтобы все знали, какой у кого IP в данный момент времени нужен центральный сервер, который и будет поддерживать списки текущих IP для активных клиентов, а также кто какую конференцию начал и т.д.
← →
3asys © (2011-12-19 23:49) [152]т.е. после получения от центрального сервера IP других участников, клиент обращается к их серверам напрямую, так?
← →
3asys © (2011-12-19 23:50) [153]понял Вас.
← →
DVM © (2011-12-19 23:54) [154]
> 3asys © (19.12.11 23:49) [152]
> клиент обращается к их серверам напрямую, так?
ну да, как все и делают, скайп например.
← →
3asys © (2011-12-20 00:02) [155]Спасибо Большое
Буду пробовать
← →
Германн © (2011-12-20 02:47) [156]Похоже что Дима Муратов в свободное время наконец-то напишет работу для 3asys :)
← →
3asys © (2011-12-25 22:09) [157]Добрый день
> DVM ©
В соответствии с Вашими рекомендациями разделил потоки видео и аудио.
Возникли следующие вопросы:
1. Как выделить звук из http сообщения (есть ли, например, какие-то метки, как с Jpeg-ом (сейчас делаю это по аналогии))?
2. Как воспроизводить звук?
(сейчас воспроизвожу:
soundTest:=FBuffer.Extract(FContentLength);
PlaySound(soundTest, 0, SND_SYNC);
в function THTTPInputThread.GetResponse(): integer; )
← →
3asys © (2011-12-29 17:39) [158]Добрый день!
> DVM ©
выделение звука из http-сообщения вроде добился (ставлю свои метки), но никак не удается воспроизвести собственно звук.
Не могли бы Вы подсказать, каким образом это лучше сделать?
← →
DVM © (2012-01-05 11:32) [159]
> 3asys © (25.12.11 22:09) [157]
> 1. Как выделить звук из http сообщения (есть ли, например,
> какие-то метки, как с Jpeg-ом (сейчас делаю это по аналогии))?
>
в принципе там же есть уже разделитель boundary вот все что между ним и очередным HTTP подзаголовком собственно и есть твои данные. Это по замыслу так. Если ты будешь ставить какие то свои метки, то поток станет нестандартным и его не сможет никто воспроизвести кроме тебя.
> 2. Как воспроизводить звук?
Для начала попробуй воспроизвести полученное скажем с помощью VLC Media Player (он вроде бы понимает такой формат). Разумеется без твоих меток.
> (сейчас воспроизвожу:
>
> soundTest:=FBuffer.Extract(FContentLength);
> PlaySound(soundTest, 0, SND_SYNC);
И что воспроизводится? :)
Так не выйдет разумеется. Во первых ты должен где то сообщить подсистеме аудио как трактовать данные которые ты ей подсовываешь, т.е указать какая частота дискретизации у тебя, сколько каналов, сколько разрядов и т.д. После проинициализировать систему. Потом уже начинать подсовывать ей куски аудиоданных. Только тогда она сможет их воспроизводить.
Я по DirectShow и DSPack в частности не большой специалист, но могу посоветовать использовать обертку кроссплатформенную для аудио и видео - SDL. Работа с медиаподсистемами в ней сильно упрощена по сравнению с оригинальными API имеющимися в ОС, к тому же приведена к едином для различных ОС виду.
Вот например для аудио http://www.libsdl.org/intro.ru/usingsound.html
Сразу хочу сказать, что для использования ее в Delphi понадобится заголовочный файл для Делфи - он есть в интернет.
← →
3asys © (2012-01-05 11:57) [160]> DVM ©
Спасибо Большое
> Во первых ты должен где то сообщить подсистеме аудио как
> трактовать данные которые ты ей подсовываешь, т.е указать
> какая частота дискретизации у тебя, сколько каналов, сколько
> разрядов и т.д. После проинициализировать систему. Потом
> уже начинать подсовывать ей куски аудиоданных. Только тогда
> она сможет их воспроизводить.
В этом проблема, поскольку со звуком раньше никогда не работал, то как правильно предоставить данные и проинициализировать систему - не представляю, а в том что нашел по воспроизведению этого не увидел.
Может быть есть какой-то пример или подробное описание?
Страницы: 1 2 3 4 5 вся ветка
Форум: "Начинающим";
Текущий архив: 2012.05.20;
Скачать: [xml.tar.bz2];
Память: 0.9 MB
Время: 0.028 c