Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2012.05.20;
Скачать: [xml.tar.bz2];

Вниз

Передача видео и звука с помощью Indy   Найти похожие ветки 

 
3asys ©   (2011-11-26 15:48) [0]

На клиенте получаю видео и звук с 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-26 17:07) [1]

Для начала надо изучить имеющиеся у используемого компонента методы.


 
3asys ©   (2011-11-26 23:29) [2]

> Плохиш ©
я научился передавать в потоке через связку TIdTCPClient - TIdTCPServer отдельные картинки из TImage (по таймеру), но мне не ясно, как загрузить видео и звук в поток из TFilterGraph (DSPack).
Или нужно желать как-то по другому?


 
3asys ©   (2011-11-27 12:51) [3]

Делать картинки с TVideoWindow не хотелось бы. Хочется передавать видео и звук в поток. А как это сделать в DSPack - никак не пойму. Может кто-нибудь это уже делал?


 
3asys ©   (2011-11-27 22:55) [4]

МОЖЕТ КОМУ-НИБУДЬ ПРИГОДИТСЯ:
Нашел, как можно транслировать получаемое с помощью DSPack видео в потоке между TIdTCPClient и TIdTCPServer:
На Клиенте, при запущенном процессе получения видео с web-камеры (как получить видео с web-камеры - есть в примерах для Delphi, прилагаемых к библиотеке DSPack), выполняем в таймере (TTimer):

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 bm:=TBitmap.Create; //Это у меня происходит в Form1.OnCreate
 stream:=TMemoryStream.Create;
 SampleGrabber.GetBitmap(bm);
 bm.SaveToStream(stream);
 stream.Position:=0;
 IdTCPClient1.WriteStream(stream, true, true,0);
end;

На Сервере в событии Execute компонента TIdTCPServer пишем:

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
stream : TStream;
begin
try
 stream:=TMemoryStream.Create;
 AThread.Connection.ReadStream(stream,-1,False);
 stream.Position:=0;
 Image1.Picture.Bitmap.LoadFromStream(stream);
finally
 stream.Free;
end;

end;

Запускаем Сервер, затем запускаем Клиента и видим в TImage размещенном на Сервере видео с TVideoWindow находящегося на Клиенте.


 
Сергей М. ©   (2011-11-28 12:53) [5]

А теперь разнеси своих клиента и сервера по разным углам Тырнета и полюбуйся тормозами транслируемого тобой видео.

Со звуком картина будет еще печальней.


 
Dennis I. Komarov ©   (2011-11-28 13:35) [6]


> Со звуком картина будет еще печальней.

О каком звуке может идти речь, если передается простой Bitmap по таймеру?
Да и на клиенте "Out of memory" обеспечено...


 
3asys ©   (2011-11-28 14:10) [7]

> Сергей М.
> Dennis I. Komarov

Как было бы правильно передавать видео и звук (для избежания тормозов, которые есть конечно)?


 
Сергей М. ©   (2011-11-28 14:10) [8]


> Dennis I. Komarov ©   (28.11.11 13:35) [6]


> передается простой Bitmap по таймеру


Ну это у ТС пока в планах, ибо

> Нужно передать их серверу для рассылки другим клиентам


Я о том что ТС изначально движется неверной дорогой, стремясь передать медиаданные вот таким незамысловатым макаром)


 
Сергей М. ©   (2011-11-28 14:14) [9]


> 3asys ©   (28.11.11 14:10) [7]


Кодировать передаваемые данные в соответствии с протоколами передачи медиа в режиме реального времени - RTP, RTSP и иже с ними.
Но они подразумевают UDP на трансп.уровне.


 
3asys ©   (2011-11-28 14:28) [10]

> Сергей М.
Не могли бы вы привести пример такой реализации (или ее элементов) или ссылки на описание таких решений, если возможно, для delphi


 
Dennis I. Komarov ©   (2011-11-28 14:57) [11]

http://www.google.ru/#hl=ru&cp=23&gs_id=6&xhr=t&q=%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB+%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%87%D0%B8+%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE&pf=p&sclient=psy-ab&newwindow=1&site=&source=hp&pbx=1&oq=%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB+%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%87%D0%B8+%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE&aq=0&aqi=g1g-v2&aql=&gs_sm=&gs_upl=&bav=on.2,or.r_gc.r_pw.r_cp.,cf.osb&fp=6b74bf870ecf0e8a&bi w=1280&bih=915


 
3asys ©   (2011-11-28 15:35) [12]

> Dennis I. Komarov
Спасибо большое.
В виду того, что задача срочная, к сожалению, нет возможности сильно углубляться в изучение протокола, а способа ПРАКТИЧЕСКОЙ реализации я в интернете не нашел.
Хотел бы либо увидеть исходники полной или частичной реализации,
либо обсудить условия реализации соответствующего функционала (см. e-mail).


 
Anatoly Podgoretsky ©   (2011-11-28 15:57) [13]

> 3asys  (28.11.2011 15:35:12)  [12]

Ты что в Интернете есть куча реализаций, от бесплатных до очень дорогих


 
Dennis I. Komarov ©   (2011-11-28 16:06) [14]

[Form + ] WebBrowser + Flash = уже почти клиент


 
DVM ©   (2011-11-28 16:10) [15]


> 3asys ©

Проще всего передавать видео и аудио по HTTP. Не самый быстрый и производительный способ, но самый простой.

Вот посмотри как это делают IP камеры, передавая MJPEG и аудио:
http://www.axis.com/files/manuals/VAPIX_3_HTTP_API_3_00.pdf


 
DVM ©   (2011-11-28 16:13) [16]


> Anatoly Podgoretsky ©


> Ты что в Интернете есть куча реализаций, от бесплатных до
> очень дорогих

Все на C++


> 3asys ©

Из бесплатных достойных не очень много, точнее мне известна лишь одна реализация RTSP/RTP сервера и клиента - библиотека live555. И разумеется она на C++. Из нее вероятно можно попробовать сделать dll и использовать в Delphi (может кто-то уже и сделал dll) но трудоемко. И начинать надо с изучения RFC соответствующих. С HTTP проще на порядок все.


 
Anatoly Podgoretsky ©   (2011-11-28 16:34) [17]

> DVM  (28.11.2011 16:13:16)  [16]

> Все на C++

Неправда есть в виде готовых программ. Кроме того чем С++ плох. Ты его не
любишь/Не занешь - твое горе


 
DVM ©   (2011-11-28 16:46) [18]


> Anatoly Podgoretsky ©   (28.11.11 16:34) [17]


> Неправда есть в виде готовых программ.

Ему же надо в свою программу встраивать. То, что есть готовые программы никто не отрицает. Их немало. VLC например.


> Кроме того чем С++ плох. Ты его не
> любишь/Не занешь - твое горе

Я здесь причем? Автор программу на Delphi пишет.


 
3asys ©   (2011-11-28 16:52) [19]

> All
Спасибо :)
Что реализовать можно - знаю, имел к практической реализации таких систем (не публичных) некоторое отношение. Но сейчас нужно сделать свою и "вчера".
Стал делать на Delphi просто потому, что работал на нем (не с мультимедиа) и какое-то кол-во граблей представляю.
Пробовал ActionScript, но в проекте есть компоненты, реализовать которые на нем мне показалось сложнее, чем на Delphi (для меня) - эти комопненты реализовал.
С предложенными здесь рекомендациями 100% согласен, но проблема на самом деле простая - отсутствие времени (нет пары месяцев чтобы во всем спокойно разобраться), поэтому и пытаюсь найти готовые фрагменты, дописывая только швы.
Если бы кто-то имеющий опыт практической реализации систем видеоконференцсвязи согласился бы поучаствовать в реализации, надеюсь смогли бы договориться.


 
Gu   (2011-11-28 17:14) [20]

http://lakeofsoft.com/vc/
интересные компоненты, там похоже то что вам надо. в сети есть enterprise 2010 (последняя 2011) версия с исходниками.


 
3asys ©   (2011-11-28 17:30) [21]

> Gu
Спасибо, очень интересно - попробую для работы со звуком


 
DVM ©   (2011-11-28 18:22) [22]


> 3asys ©

Еще раз советую HTTP юзать, передача звукового потока и кадров реализуется элементарно, буквально 100 строк, прием тоже столько же примерно. Если решишь делать, задавай тут вопросы объясню как. По RTSP/RTP в принципе тоже мог бы объяснить, но эта тема очееень обширная.


 
3asys ©   (2011-11-28 18:36) [23]

> DVM
Спасибо, с удовольствием. Поскольку времени практически нет - то чем быстрее реализация тем лучше.
Что нужно для реализации через http?


 
Dennis I. Komarov ©   (2011-11-28 18:56) [24]

http-сервер, который будет получать поток с камеры и раздавать клиентам


 
DVM ©   (2011-11-28 19:02) [25]

Первое что тебе понадобится - это сделать потокобезопасный кадровый буфер. Для начала сойдет буфер на один кадр. Потокобезопасность можно организовать через защиту буфера критической секцией. С одной стороны этот буфер будет обновляться источником кадров (твоей камерой ), с другой стороны оттуда вебсервер из клиентского потока будет забирать очередной кадр для передачи клиенту. Такая схема позволяет клиенту автоматически подстраиваться под ширину канала.


 
DVM ©   (2011-11-28 19:12) [26]

Второё , что понадобится - это сервер TIDHttpServer, он у нас будет передавать клиенту бесконечный поток данных с особым типом контента multipart/x-mixed-relace. Этот тип контента позволяет передавать практически сколько угодно параллельных потоков чего угодно. То есть можно передавать видео звук субтитры и прочее вместе. Но можно сделать отдельные потоки для звука и видео, что. Проще при приеме.


 
Dennis I. Komarov ©   (2011-11-28 19:13) [27]


> DVM ©   (28.11.11 19:02) [25]

А не накладно будет покадрово передавать, тем более с камеры?


 
DVM ©   (2011-11-28 19:18) [28]

Как показывает практика не накладно. Мы же не будем для каждого кадра делать запрос, запрос будет сделан 1 раз.Остальное позже напишу - с телефона неудобно.


 
3asys ©   (2011-11-28 19:22) [29]

В качестве http сервера IdHTTPServer подойдет?
Если буфер обмена создается на клиенте, как данные от клиента попадут на сервер? или каждый клиент одновременно и сервер?


 
3asys ©   (2011-11-28 19:25) [30]

:) про  IdHTTPServer  понятно (написал не посмотрев сообшения)


 
DVM ©   (2011-11-28 19:53) [31]

Если нужна двусторонняя передача видео, то для http каждый клиент должен быть одновременно сервером и клиентом для сервера другого клиента так как в http данные всегда передаются в основном канале в отличие от RTSP или SIP в котором RTP данные могут передаваться как поверх основного канала так и в независимых и в обоих направлениях.


 
3asys ©   (2011-11-28 21:24) [32]

это видеоконференция и в ней каждый клиент передает другим видео и звук со своей web-камеры/микрофона.
я полагал, что должно быть N клиентов, каждый из которых передает свои видео и звук серверу, а сервер транслирует их всем остальным.  Это не так?


 
DVM ©   (2011-11-28 22:09) [33]


> я полагал, что должно быть N клиентов, каждый из которых
> передает свои видео и звук серверу, а сервер транслирует
> их всем остальным.  Это не так?

Это может быть и так, а можно и по другому. Если все будет проходить через сервер, то нагрузка на него будет большая при большом числе клиентов, если видео не будет идти через сервер, то нагрузка на него будет минимальная, но будет меньше контроля. Вообще все это - это вопрос коммутации, это отдельный разговор. Вот SIP или RTSP и есть протоколы, которые предназначены для коммутации. У тебя задача пока хотя бы передать данные между 2-мя пользователями. А там дальше будешь думать.


 
3asys ©   (2011-11-28 22:10) [34]

согласен


 
DVM ©   (2011-11-28 22:18) [35]

Короче у тебя 3 пути:

1) Использовать самописный протокол для коммутации и передачи медиаданных.
2) Использовать HTTP и для передачи и для коммутации.
3) Использовать SIP для коммутации и RTP для передачи (вот этот вариант самый правильный, и вобщем то повсеместно используется в IP телефонии)
4) Использовать что-то типа http://ru.wikipedia.org/wiki/XMPP

Что выбираешь?


 
3asys ©   (2011-11-28 22:25) [36]

мне необходимо реализовать конференцию в минимальные сроки и чтобы она работала с приемлемым качеством человек на 50. Как я понял, самый быстрый способ - http - поэтому HTTP


 
DVM ©   (2011-11-28 22:30) [37]


> 3asys ©   (28.11.11 22:25) [36]

Ну HTTP так HTTP. Щас набросаю тебе пример.


 
DVM ©   (2011-11-28 23:10) [38]


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 23:15) [39]

Итак, что тут к чему. Во-первых, это лишь пример, иллюстрирующий принцип. Не надо отсюда слепо копировать.
На форму кинуть таймер и TIdHTTPServer. Таймер нужен лишь для генерации картинок (типа кадры), интервал у таймера стоит 100.
TidHTTPServer слушает порт 8081.

Запускаем все это дело, берем Firefox (и только его, другие браузеры не понимают этот формат) и обращаемся в нем по адресу http://127.0.0.1:8081
Видим в окне браузера сменяющие друг друга картинки, фактически видео.


 
DVM ©   (2011-11-28 23:19) [40]

Особые моменты в коде.

AResponseInfo.ContentLength := 1000000;
Indy всегда пытается всунуть в заголовок ответа сервера ContentLength, идеально было бы вообще без него, но от него не избавиться, поэтому ставим заведомо большое число, оно мало на что влияет, но 0 ставить нельзя.

Sleep(100);
Костыль. Ограничивает частоту кадров на клиенте. Частоту кадров стоит вычислять более умно. Хотя можно просто ограничить скажем величиной 25. Но все равно надо рассчитать тогда паузу между кадрами, чтоб получалось 25 кадров в секунду.



Страницы: 1 2 3 4 5 вся ветка

Форум: "Начинающим";
Текущий архив: 2012.05.20;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.59 MB
Время: 0.005 c
15-1326441149
Riply
2012-01-13 11:52
2012.05.20
Распознавание изображений


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


2-1326795550
illiya
2012-01-17 14:19
2012.05.20
Method identifier expected


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


15-1326347387
Demo
2012-01-12 09:49
2012.05.20
Выбор ноутбука для Delphi





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