Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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;

// &#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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.9 MB
Время: 0.028 c
15-1326289295
JohnKorsh
2012-01-11 17:41
2012.05.20
Конфигурация Dlue Tooth.


15-1320098450
Бездомный
2011-11-01 01:00
2012.05.20
Драйвер виртуальной звуковой карты


2-1326652931
TChecListBox
2012-01-15 22:42
2012.05.20
Удалить строку из ChecListBox


4-1257109119
Maksim V.
2009-11-01 23:58
2012.05.20
Запретить DrawFocusRect. при отрисовке строк Listbox


2-1326739475
Anthony
2012-01-16 22:44
2012.05.20
Коррекция ширины колонки в TStringGrid - не работает...





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский