Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.147.46.174] |
|
Страницы: (3) [1] 2 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
всем привет!
надо сделать интерфейс общения с IP камерой, через RTSP уже нашёл описание данного стандарта (правда на английском, но это не проблема) на данный момент не получается правильно последовательно считать данные с камеры отправляю запрос: 'DESCRIBE rtsp://admin:admin@10.10.10.64:554/ RTSP/1.0' + #13#10 + 'CSeq: 2' + #13#10 + 'User-Agent: AppName' + #13#10 + 'Accept: application/sdp' + #13#10; назад получаю не полные данные, что именно я должен получить я знаю, но вот приходят они частично обрезанные получилось считать целиком при помощи IdTCPClient но второй запрос уже обрабатываться не хочет, т.е. отсылаю его, а мне в ответ ошибка 10054 подскажите как правильно отправить/получить данные P.S. разве в нет в дельфи аналогов функций SEND, RECV и обязательно надо использовать подключение заголовочного файла из "си" |
Сообщ.
#2
,
|
|
|
Все есть, и recv, и классовые обертки. Но если уровень познаний в сокетах невелик, то легче использовать Indy.
Обрезанные данные - скорее всего потому, что вычитываешь не полностью. |
Сообщ.
#3
,
|
|
|
да, уровень знаний равен НУЛЮ (((
понятно что не полностью читается, но в "индях" первый пакет данных читается полностью, а вот при отправке запроса на второй пакет, вылетает ошибка - почему инди не правильно работает, если там всё "оптимизировано и настроено"? |
Сообщ.
#4
,
|
|
|
Цитата Fr0sT @ Все есть, и recv, и классовые обертки. а где именно есть? и что за обёртка - win.sockets и TBaseSocket? |
Сообщ.
#5
,
|
|
|
Почему сервер рвет связь - это уж неизвестно. Возможно, ты ему что-то не то скармливаешь. Можешь попробовать отправлять запросы вручную через telnet - вот уж там точно влияние надстроек исключено. Ну а неполное вычитывание, не имея кода, точно никак не проверишь.
Цитата woojin @ а где именно есть? и что за обёртка - win.sockets и TBaseSocket? WinSock, TSocketClient |
Сообщ.
#6
,
|
|
|
procedure TForm1.Button3Click(Sender: TObject); var request: TRequest; cmd, h, c: string; szh, szc: integer; begin cmd := 'DESCRIBE rtsp://admin:admin@10.10.10.64:554/ RTSP/1.0' + #13#10 + 'CSeq: 2' + #13#10 + 'User-Agent: AppName' + #13#10 + 'Accept: application/sdp' + #13#10; TcpClient1.Open; TcpClient1.Active:=True; TcpClient1.Sendln(cmd); // TcpClient1.Receiveln; end; procedure TForm1.TcpClient1Receive(Sender: TObject; Buf: PAnsiChar; var DataLen: Integer); begin Memo1.Lines.Add('Receive(' + IntToStr(DataLen) + '): ' + Buf); end; вот таким кодом отправляю запрос, но в ответ ни чего не получаю без закомментированной строки если её раскоментировать, то в Memo сразу появляется текст RTSP/1.0 200 OK CSeq: 2 Content-Type: application/sdp Content-Base: rtsp://10.10.10.64:554/ Content-Length: 545 v=0 o=- 1480520940099739 1480520940099739 IN IP4 10.10.10.64 s=Media Presentation e=NONE b=AS:5050 t=0 0 a=control:rtsp://10.10.10.64:554/ m=video 0 RTP/AVP 96 c=IN IP4 0.0.0.0 b=AS:5000 a=recvonly a=x-dimensions:1280,720 a=control:rtsp://10.10.10.64:554/trackID=1 a=rtpmap:96 H264/90000 a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z0IAII2NQCgC3QgAADhAAAr8gCA=,aM44gA== a=Media_header: но он не полный! не хватает в конце (после двоеточия) MEDIAINFO=494D4B48010100000400010000000000000000000000000000000000000000000000000000000000; a=appversion:1.0 |
Сообщ.
#7
,
|
|
|
Что такое TcpClient? Он синхронный или асинхронный? Что за партизаны, каждый кусок инфы клещами тянуть приходится...
Не знаю, как там у RTSP, но у HTTP по стандарту запрос должен завершаться двумя \r\n |
Сообщ.
#8
,
|
|
|
Цитата Fr0sT @ Что такое TcpClient? у RAD STUDIO XE5 есть набор компонентов INTENET, это оттуда Цитата Fr0sT @ запрос должен завершаться двумя \r\n это \r\n\r\n? |
Сообщ.
#9
,
|
|
|
Цитата woojin @ это \r\n\r\n? Ага. |
Сообщ.
#10
,
|
|
|
сделал на другом компоненте
вроде как получилось, с одним "НО" ни как не могу понять, как подцепится к видео потоку var session: string; // глобальная переменная // получаю данные с камеры procedure TForm1.ButtonDescrClick(Sender: TObject); var s: string; begin s := 'DESCRIBE rtsp://admin:admin@10.10.10.64:554 RTSP/1.0'+#13#10+ 'CSeq: 2'+#13#10+ 'User-Agent: AppName'+#13#10+ 'Accept: application/sdp'+#13#10; if ClientSocket1.Socket.Connected then begin ClientSocket1.Socket.Close; ClientSocket1.Close; end; ClientSocket1.Port := 554; ClientSocket1.Address := '10.10.10.64'; ClientSocket1.ClientType := TClientType(ComboBox1.ItemIndex); // ctNonBlocking или ctBlocking - без разницы работает одинаково ClientSocket1.Open; end; ответ RTSP/1.0 200 OK CSeq: 2 Content-Type: application/sdp Content-Base: rtsp://admin:admin@10.10.10.64:554/ Content-Length: 575 v=0 o=- 1481815230001505 1481815230001505 IN IP4 10.10.10.64 s=Media Presentation e=NONE b=AS:5050 t=0 0 a=control:rtsp://admin:admin@10.10.10.64:554/ m=video 0 RTP/AVP 96 c=IN IP4 0.0.0.0 b=AS:5000 a=recvonly a=x-dimensions:1280,720 a=control:rtsp://admin:admin@10.10.10.64:554/trackID=1 a=rtpmap:96 H264/90000 a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z0IAII2NQCgC3QgAADhAAAr8gCA=,aM44gA== a=Media_header:MEDIAINFO=494D4B48010100000400010000000000000000000000000000000000000000000000000000000000; a=appversion:1.0 // делаю настройки procedure TForm1.ButtonSetupClick(Sender: TObject); var s: string; start, finish: integer; begin s := 'SETUP rtsp://admin:admin@10.10.10.64:554/trackID=1 RTSP/1.0'+#13#10+ 'CSeq: 3'+#13#10+ 'User-Agent: AppName'+#13#10+ 'Transport: RTP/AVP;unicast;client_port=10024-10025'+#13#10+#13#10; // порты взяты на обум но они свободны ClientSocket1.Socket.SendText(s); sleep(300); s := ClientSocket1.Socket.ReceiveText; start := pos('Session:', s)+Length('Session:'); // \ finish := pos(';', s, start); // > получаю номер сессии в глобальную переменную session session := trim(copy(s, start, finish-start)); // / Memo1.Lines.Add(s); end; ответ RTSP/1.0 200 OK CSeq: 3 Session: 1471661481;timeout=60 Transport: RTP/AVP;unicast;client_port=10024-10025;server_port=8280-8281;ssrc=509cf2f0;mode="play" Date: Thu, Dec 15 2016 15:20:30 GMT // отправляю запрос на проигрывание procedure TForm1.ButtonPlayClick(Sender: TObject); var s: string; begin s := 'PLAY rtsp://admin:admin@10.10.10.64:554/ RTSP/1.0'+#13#10+ 'CSeq: 4'+#13#10+ 'User-Agent: AppName'+#13#10+ 'Session: '+ session +#13#10+ 'Range: npt=0.000-'+#13#10+#13#10; ClientSocket1.Socket.SendText(s); sleep(300); s := ClientSocket1.Socket.ReceiveText; Memo1.Lines.Add(s); end; ответ RTSP/1.0 200 OK CSeq: 4 Session: 1471661481 RTP-Info: url=rtsp://admin:admin@10.10.10.64:554/trackID=1;seq=49912;rtptime=665131904 Date: Thu, Dec 15 2016 15:20:30 GMT и далее как то надо начать читать поток... но вот как не могу разобраться, т.е. как назначить своему клиенту именно те порты которые я указал выше (10024-10025) и что именно надо писать после внесения данных в лог (Memo1.Lines.Add(s) что бы началось чтение из указанных портов сервера? надо ли создавать новы(й/е) компонент(ы) TClientSocket с разными портами сервера (опять же вопрос как назначить свои собственные порты)? в логе програмки на С++ вот что отображается (часть с предыдущего ответа): Date: Thu, Dec 15 2016 15:20:30 GMT [URL:"rtsp://admin:admin@10.10.10.64:554/"]: Started playing session... Stream "rtsp://admin:admin@10.10.10.64:554/"; video/H264: Received 20 bytes. Presentation time: 1481797230.432135! Stream "rtsp://admin:admin@10.10.10.64:554/"; video/H264: Received 4 bytes. Presentation time: 1481797230.432135! Stream "rtsp://admin:admin@10.10.10.64:554/"; video/H264: Received 25377 bytes. Presentation time: 1481797230.432135! Stream "rtsp://admin:admin@10.10.10.64:554/"; video/H264: Received 3025 bytes. Presentation time: 1481797230.472135! Stream "rtsp://admin:admin@10.10.10.64:554/"; video/H264: Received 3041 bytes. Presentation time: 1481797230.512135! если кто то занимался подобными вещами посоветуйте плиз |
Сообщ.
#11
,
|
|
|
Если надо слушать порт на своей машине, чтобы сервер на него начал передавать поток, то это Bind на порт, Listen, Accept, получение принимающего сокета и затем чтение из него. Если же надо инициировать соединение самому, то это проще - просто еще один clientsocket.
А вообще советую почитать статью А. Григорьева про сокеты, чтобы иметь представление о предмете. Потому что "ctNonBlocking или ctBlocking - без разницы работает одинаково", "sleep(300);" - это тихий ужас. Кроме того, если ответ сервера не уместится в один пакет, то ReceiveText вернет только часть ответа. Надо собирать ответ в буфере, пока не встретится сигнатура завершения, и тогда уже его разбирать. |
Сообщ.
#12
,
|
|
|
Цитата Fr0sT @ "ctNonBlocking или ctBlocking - без разницы работает одинаково" по поводу этого, мне просто не понятно в каком случае применить блокировку Цитата Fr0sT @ ReceiveText вернет только часть ответа ползал я в System.Win.ScktComp эта функция (на сколько я понимаю, хотя могу и ошибаться) читает полностью весь пакет function TCustomWinSocket.ReceiveText: AnsiString; begin SetLength(Result, ReceiveBuf(Pointer(nil)^, -1)); // выставляет длину получаемых данных SetLength(Result, ReceiveBuf(Pointer(Result)^, Length(Result))); // и тут уже записывает их в Result end; а вот без этого Цитата Fr0sT @ "sleep(300);" вообще читать ни чего не хочет, кстати интересно что если поставить меньше 300 то тоже ни каких данных не приходит если использовать OnRead снова ни чего нет, я так понял что надо самому инициализировать чтение потока, по этому сначала отправка сообщения, потом задержка и чтение P.S. статейка эта Статья :: 2.2. Сокеты Windows : А Григорьев? правильно нашёл? и ещё Bind, Listen, Accept - их можно задать у ClientSocket или придётся всё самому описывать с использованием WinApi.WinSock? |
Сообщ.
#13
,
|
|
|
Цитата woojin @ по поводу этого, мне просто не понятно в каком случае применить блокировку Блокировка блокирует выполнение, если в данный момент не получается выполнить функцию прямо сейчас. Т.е. вокруг неблокирующего сокета должна быть обвязка, тем или иным способом повторяющая вызов либо проверяющая результат. В твоем случае легче блокирующий. Цитата woojin @ ползал я в System.Win.ScktComp эта функция (на сколько я понимаю, хотя могу и ошибаться) читает полностью весь пакет Да, пакет читает. Но что если ответ сервера в него не влезет? Функция прочитает только часть. Т.ч. в идеале надо склеивать в накопитель, искать там \r\n\r\n (конец заголовка), разбирать его, вычленять content-length и считывать тело ответа, если он есть. Цитата woojin @ вообще читать ни чего не хочет, кстати интересно что если поставить меньше 300 то тоже ни каких данных не приходит если использовать OnRead снова ни чего нет, я так понял что надо самому инициализировать чтение потока, по этому сначала отправка сообщения, потом задержка и чтение При блокирующем режиме должен читать без всяких слипов. Цитата woojin @ P.S. статейка эта Статья :: 2.2. Сокеты Windows : А Григорьев? правильно нашёл? Почти, только в WSA не стоит лезть, можно обойтись берклевскими функциями. Цитата woojin @ и ещё Bind, Listen, Accept - их можно задать у ClientSocket или придётся всё самому описывать с использованием WinApi.WinSock? Насколько я помню, нужен ServerSocket. Но я не знаю, как используется этот порт - клиент у себя открывает или сервер. |
Сообщ.
#14
,
|
|
|
Цитата Fr0sT @ При блокирующем режиме должен читать без всяких слипов. подцепляюсь с блокировкой (кнопка DESCR) - ни какого ответа пока не нажмёшь на кнопку SETUP - после приходит первый ответ (фигня какая то) Цитата Fr0sT @ Функция прочитает только часть там нет ограничений на количество прочитанного (о чём говорит параметр -1 SetLength(Result, ReceiveBuf(Pointer(nil)^, -1))) Цитата Fr0sT @ можно обойтись берклевскими функциями. примерчик можно? Цитата Fr0sT @ Насколько я помню, нужен ServerSocket. Но я не знаю, как используется этот порт - клиент у себя открывает или сервер. это получается сервер к серверу будет цепляться? есть пример? (если не сложно) P.S. могу дать С++ программу (она правда под FreeBSD) там (для меня) дикий сумбур, но хотелось бы сделать нечто подобное |
Сообщ.
#15
,
|
|
|
Цитата woojin @ подцепляюсь с блокировкой (кнопка DESCR) - ни какого ответа пока не нажмёшь на кнопку SETUP - после приходит первый ответ А какой может быть ответ, если в Descr ты ничего серверу не отсылаешь? Цитата woojin @ там нет ограничений на количество прочитанного (о чём говорит параметр -1 SetLength(Result, ReceiveBuf(Pointer(nil)^, -1))) там нет ограничений на количество прочитанного на момент вызова функции. 1. Пришел пакет с Response pt1 2. Socket.Read 3. Пришел пакет с Response pt2 4. ??? Цитата woojin @ примерчик можно? Это обычные функции/методы без WSA. recv, send, connect и т.д. См. первую часть статьи Григорьева. Цитата woojin @ это получается сервер к серверу будет цепляться? Повторяю: я не знаю, как устроен протокол. Смотри в спеки, как там эти порты будут использоваться. Если смущает название "сервер" - окей, пусть это будет "слушающий сокет на клиенте". Но компонент все равно называется ServerSocket. Цитата woojin @ могу дать С++ программу (она правда под FreeBSD) там (для меня) дикий сумбур, но хотелось бы сделать нечто подобное Давай |