Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2012.05.20;
Скачать: CL | DM;

Вниз

Передача видео и звука с помощью 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;

// &#194;&#238;&#231;&#226;&#240;&#224;&#242; &#226; &#225;&#235;&#238;&#234;&#232;&#240;&#243;&#254;&#249;&#232;&#233; &#240;&#229;&#230;&#232;&#236;
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
        // &#197;&#241;&#235;&#232; &#225;&#243;&#244;&#229;&#240; &#241;&#242;&#224;&#235; &#241;&#235;&#232;&#248;&#234;&#238;&#236; &#225;&#238;&#235;&#252;&#248;&#238;&#233;
        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;
Скачать: CL | DM;

Наверх




Память: 0.89 MB
Время: 0.021 c
15-1326237348
MastaK
2012-01-11 03:15
2012.05.20
Инфляция в шахматах


15-1326702784
картман
2012-01-16 12:33
2012.05.20
массив случайных чисел заданной суммы


15-1326277214
OW
2012-01-11 14:20
2012.05.20
по Oracle и PL/SQL Developer. Как его научить автоформатировать?


15-1326499809
KilkennyCat
2012-01-14 04:10
2012.05.20
новый вид памяти


15-1326313802
Юрий
2012-01-12 00:30
2012.05.20
С днем рождения ! 12 января 2012 четверг