![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Передача видео и звука с помощью Indy [D7]
3asys © (2011-11-26 15:48:00)
Страницы: < 1 2 3 4 5 6 7 8 9 10 >
На клиенте получаю видео и звук с web-камеры (с встроенным микрофоном) с помощью DirectShow.
Нужно передать их серверу для рассылки другим клиентам.
Видео и звук с Web-камеры получаю стандартным способом, описанным в примерах к DSPack, - примерно так:
var
multiplexer: IBaseFilter;
Writer: IFileSinkFilter;
PinList: TPinList;
i: integer;
begin
with MainForm do
begin
CaptureGraph.Active := true;
if AudioSourceFilter.FilterGraph <> nil then
begin
PinList := TPinList.Create(AudioSourceFilter as IBaseFilter);
i := 0;
while i < PinList.Count do
if PinList.PinInfo[i].dir = PINDIR_OUTPUT then
begin
if AudioFormats.ItemIndex <> -1 then
with (PinList.Items[i] as IAMStreamConfig) do
SetFormat(AudioMediaTypes.Items[AudioFormats.ItemIndex].AMMediaType^);
PinList.Delete(i);
end else inc(i);
if InputLines.ItemIndex <> -1 then
with (PinList.Items[InputLines.ItemIndex] as IAMAudioInputMixer) do
put_Enable(true);
PinList.Free;
end;
if VideoSourceFilter.FilterGraph <> nil then
begin
PinList := TPinList.Create(VideoSourceFilter as IBaseFilter);
if VideoFormats.ItemIndex <> -1 then
with (PinList.First as IAMStreamConfig) do
SetFormat(VideoMediaTypes.Items[VideoFormats.ItemIndex].AMMediaType^);
PinList.Free;
end;
with CaptureGraph as IcaptureGraphBuilder2 do
begin
// set the output filename
SetOutputFileName(MEDIASUBTYPE_Avi, PWideChar(CapFile), multiplexer, Writer);
if VideoSourceFilter.BaseFilter.DataLength > 0 then
RenderStream(@PIN_CATEGORY_PREVIEW, nil, VideoSourceFilter as IBaseFilter,
nil , form1.VideoWindow as IBaseFilter);
if VideoSourceFilter.FilterGraph <> nil then
RenderStream(@PIN_CATEGORY_CAPTURE, nil, VideoSourceFilter as IBaseFilter,
nil, multiplexer as IBaseFilter);
if AudioSourceFilter.FilterGraph <> nil then
begin
RenderStream(nil, nil, AudioSourceFilter as IBaseFilter,
nil, multiplexer as IBaseFilter);
end;
end;
CaptureGraph.Play;
В RenderStream получаем потоки, но как их передать через IdTCPClient, IdTCPServer я сообразить не могу.
Как это сделать?
Германн (2011-11-29 00:28:00) [141]
> Это не я, это Delphi XE2. Пространства имен такие теперь
> там.
Хм. Спасибо за ответ.
DVM (2011-11-29 00:19:00) [142]
> Dennis I. Komarov © (28.11.11 23:58) [44]
> Вот 50 - (http)серверов каждый из которых будет слать 50-
> и клиентам видео, и не сжатый поток, а полные кадры...
Да дался вам этот HTTP и 50 клиентов. Ну кто заставляет слать полные JPEG кадры? Можно сжимать в MPEG4 или H264 и слать P, I кадры, указывая, где какой в HTTP подзаголовках. Принцип тот же - multipart/x-mixed-replace. HTTP не такой медленный как многие думают, он же бинарный по сути, так что скорость сопоставима с просто TCP.
UDP же требует кучи кода, предназначенного для контроля ошибок и собственно в RTP и RTCP это и делается.
50 клиентов вполне реально, только не надо гнать все через один сервер. Пусть гоняют между собой видео.
> Германн © (29.11.11 00:02) [45]
> Зачем вы, Дмитрий, добавили эти префиксы?
Это не я, это Delphi XE2. Пространства имен такие теперь там.
Германн (2011-11-29 00:02:00) [143]
> winapi.windows не находит что-то
> DVM © (28.11.11 23:10) [38]
А в самом деле. Зачем вы, Дмитрий, добавили эти префиксы?
Dennis I. Komarov (2011-11-28 23:58:00) [144]
> У тебя задача пока хотя бы передать данные между 2-мя пользователями.
> А там дальше будешь думать.
А потом он все с нуля переделвать будет... :)
> мне необходимо реализовать конференцию в минимальные сроки
> и чтобы она работала с приемлемым качеством человек на 50.
> Как я понял, самый быстрый способ - http - поэтому HTTP
Вот 50 - (http)серверов каждый из которых будет слать 50-и клиентам видео, и не сжатый поток, а полные кадры...
З.Ы. Я конечно не делал видеоконференции, но в такую реализацию мне чего-то не верится... :)
3asys (2011-11-28 23:33:00) [145]разобрался :)
СПАСИБО ВАМ ОГРОМНОЕ ЗА ВРЕМЯ И УСИЛИЯ
3asys (2011-11-28 23:27:00) [146]winapi.windows не находит что-то. что подключить?
DVM (2011-11-28 23:23:00) [147]Клиента завтра будем делать.
Ну и все объяснения тоже завтра.
DVM (2011-11-28 23:19:00) [148]Особые моменты в коде.
AResponseInfo.ContentLength := 1000000;
Indy всегда пытается всунуть в заголовок ответа сервера ContentLength, идеально было бы вообще без него, но от него не избавиться, поэтому ставим заведомо большое число, оно мало на что влияет, но 0 ставить нельзя.
Sleep(100);
Костыль. Ограничивает частоту кадров на клиенте. Частоту кадров стоит вычислять более умно. Хотя можно просто ограничить скажем величиной 25. Но все равно надо рассчитать тогда паузу между кадрами, чтоб получалось 25 кадров в секунду.
DVM (2011-11-28 23:15:00) [149]Итак, что тут к чему. Во-первых, это лишь пример, иллюстрирующий принцип. Не надо отсюда слепо копировать.
На форму кинуть таймер и TIdHTTPServer. Таймер нужен лишь для генерации картинок (типа кадры), интервал у таймера стоит 100.
TidHTTPServer слушает порт 8081.
Запускаем все это дело, берем Firefox (и только его, другие браузеры не понимают этот формат) и обращаемся в нем по адресу http://127.0.0.1:8081
Видим в окне браузера сменяющие друг друга картинки, фактически видео.
DVM (2011-11-28 23:10:00) [150]
unit uMain;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.SyncObjs, Vcl.Imaging.jpeg,
Vcl.ExtCtrls,
IdBaseComponent, IdComponent, IdTCPServer, IdCustomHTTPServer, IdGlobal,
IdHTTPServer, IdCustomTCPServer, IdContext, IdSchedulerOfThread, IdGlobalProtocols;
type
TSafeBuffer = class(TMemoryStream)
strict private
FLock: TCriticalSection;
public
constructor Create;
destructor Destroy; override;
procedure Lock;
procedure Unlock;
end;
TfrmMin = class(TForm)
tmrUpdateFrame: TTimer;
idhtpsrvrMain: TIdHTTPServer;
procedure tmrUpdateFrameTimer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure idhtpsrvrMainCommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
private
{ Private declarations }
public
Buffer: TSafeBuffer;
end;
var
frmMin: TfrmMin;
implementation
{$R *.dfm}
constructor TSafeBuffer.Create;
begin
FLock := TCriticalSection.Create;
inherited Create;
end;
destructor TSafeBuffer.Destroy;
begin
inherited Destroy;
FLock.Free;
end;
procedure TSafeBuffer.Lock;
begin
FLock.Enter;
end;
procedure TSafeBuffer.Unlock;
begin
FLock.Leave;
end;
procedure TfrmMin.FormCreate(Sender: TObject);
begin
Buffer := TSafeBuffer.Create;
end;
procedure TfrmMin.FormDestroy(Sender: TObject);
begin
Buffer.Free;
end;
procedure TfrmMin.idhtpsrvrMainCommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
const
Boundary = '--myboundary';
CRLF = #13#10;
var
Stream: TMemoryStream;
SubHeader: AnsiString;
begin
Stream := TMemoryStream.Create;
try
AResponseInfo.FreeContentStream := false;
AResponseInfo.Server := 'StreamServer';
AResponseInfo.CacheControl := 'no-cache';
AResponseInfo.Pragma := 'no-cache';
AResponseInfo.Expires := Now;
AResponseInfo.CharSet :='';
AResponseInfo.Connection := 'close';
AResponseInfo.ContentType := 'multipart/x-mixed-replace; boundary=' + Boundary;
AResponseInfo.ContentLength := 1000000;
AResponseInfo.WriteHeader;
while ((not (AContext.Yarn as TIdYarnOfThread).Thread.Terminated) and (AContext.Connection.Connected)) do
begin
Buffer.Lock;
try
AResponseInfo.ContentLength := Buffer.Size;
SubHeader := AnsiString(Boundary + CRLF +
'Content-Type: image/jpeg' + CRLF +
'Content-Length: ' + IntToStr(AResponseInfo.ContentLength) + CRLF + CRLF);
Stream.Size := 0;
Stream.Write(SubHeader[1], length(SubHeader));
Stream.Write(Buffer.Memory^, Buffer.Size);
finally
Buffer.Unlock;
end;
Stream.Position := 0;
AResponseInfo.ContentStream := Stream;
AResponseInfo.WriteContent;
Sleep(100);
end;
finally
Stream.Free;
end;
end;
procedure TfrmMin.tmrUpdateFrameTimer(Sender: TObject);
var
Bmp: TBitmap;
JPG: TJPEGImage;
begin
Bmp := TBitmap.Create;
try
Bmp.Width := 320;
Bmp.Height := 240;
Bmp.PixelFormat :=pf24bit;
Bmp.Canvas.TextOut(50, 50, FormatDateTime('hh:nn:ss.zzz', Now));
JPG := TJPEGImage.Create;
try
JPG.Assign(Bmp);
Buffer.Lock;
try
Buffer.Size := 0;
JPG.SaveToStream(Buffer);
Buffer.Position :=0;
finally
Buffer.Unlock;
end;
finally
JPG.Free;
end;
finally
Bmp.Free;
end;
end;
end.
DVM (2011-11-28 22:30:00) [151]
> 3asys © (28.11.11 22:25) [36]
Ну HTTP так HTTP. Щас набросаю тебе пример.
3asys (2011-11-28 22:25:00) [152]мне необходимо реализовать конференцию в минимальные сроки и чтобы она работала с приемлемым качеством человек на 50. Как я понял, самый быстрый способ - http - поэтому HTTP
DVM (2011-11-28 22:18:00) [153]Короче у тебя 3 пути:
1) Использовать самописный протокол для коммутации и передачи медиаданных.
2) Использовать HTTP и для передачи и для коммутации.
3) Использовать SIP для коммутации и RTP для передачи (вот этот вариант самый правильный, и вобщем то повсеместно используется в IP телефонии)
4) Использовать что-то типа http://ru.wikipedia.org/wiki/XMPP
Что выбираешь?
3asys (2011-11-28 22:10:00) [154]согласен
DVM (2011-11-28 22:09:00) [155]
> я полагал, что должно быть N клиентов, каждый из которых
> передает свои видео и звук серверу, а сервер транслирует
> их всем остальным. Это не так?
Это может быть и так, а можно и по другому. Если все будет проходить через сервер, то нагрузка на него будет большая при большом числе клиентов, если видео не будет идти через сервер, то нагрузка на него будет минимальная, но будет меньше контроля. Вообще все это - это вопрос коммутации, это отдельный разговор. Вот SIP или RTSP и есть протоколы, которые предназначены для коммутации. У тебя задача пока хотя бы передать данные между 2-мя пользователями. А там дальше будешь думать.
3asys (2011-11-28 21:24:00) [156]это видеоконференция и в ней каждый клиент передает другим видео и звук со своей web-камеры/микрофона.
я полагал, что должно быть N клиентов, каждый из которых передает свои видео и звук серверу, а сервер транслирует их всем остальным. Это не так?
DVM (2011-11-28 19:53:00) [157]Если нужна двусторонняя передача видео, то для http каждый клиент должен быть одновременно сервером и клиентом для сервера другого клиента так как в http данные всегда передаются в основном канале в отличие от RTSP или SIP в котором RTP данные могут передаваться как поверх основного канала так и в независимых и в обоих направлениях.
3asys (2011-11-28 19:25:00) [158]:) про IdHTTPServer понятно (написал не посмотрев сообшения)
3asys (2011-11-28 19:22:00) [159]В качестве http сервера IdHTTPServer подойдет?
Если буфер обмена создается на клиенте, как данные от клиента попадут на сервер? или каждый клиент одновременно и сервер?
DVM (2011-11-28 19:18:00) [160]Как показывает практика не накладно. Мы же не будем для каждого кадра делать запрос, запрос будет сделан 1 раз.Остальное позже напишу - с телефона неудобно.