LINUX.ORG.RU

Как передать tcp-поток от китайского DVR в VLC?

 ,


0

2

Всем привет

Думаю, проблема с китайскими DVR, не имеющими возможностей вещать rtp, знакома многим. Проблема состоит в том, что получить видео с такого DVR можно либо через родную утилиту (которая под вайном крашится), либо из веб-интерфейса (с ActiveX).

Первую часть проблемы я решил, расковыряв протокол. Там всё относительно несложно - достаточно отправить один пакет (всегда одинаковый, только поле с номером камеры меняется) и в ответ польётся поток. Вторая часть проблемы хитрее - я хочу увидеть 20-30 таких потоков в мозайке, сделанной VLC

Для этого был написан мини-скрипт на питоне, который ждёт соединения извне (vlc умеет читать tcp://) и начинает вычитывать поток от DVR, зеркалируя его в новый сокет. И это даже работает и работает стабильно

Не работает только одно - мозайка (и вообще сколь бы то ни было долгое воспроизведение потока). vlc с мозайкой дохнет буквально через 4-7 секунд после начала вещания - говорит, дошёл до EOF

Я попробовал пойти другим путём и стал писать поток на диск и одновременно вычитывать его vlc. Но и тут та же проблема - vlc очень быстро доходит до конца файла и перестаёт показывать что-либо

Я, честно говоря, уже лишился идей. DVR шлёт голый h264-es, то есть с рандомного места плеер начать это показывать не может. Была предложена идея заворачивать это в контейнер и мультикастить, но блин, ковыряться с оборачиванием видео в контейнер мне совсем не хочется

Короче, на текущий момент я могу получить поток и записать его в файл, а потом проиграть этот файл. Но так не годится - плеер каждый раз будет играть запись сначала, что не есть хорошо

Многоуважаемый All, а есть ли у тебя какие-нибудь разумные идеи?

Спасибо!


Ответ на: комментарий от Radjah

Запускаю так:

cvlc --color --vlm-conf mosaic2.vlm --mosaic-width=1440 --mosaic-height=1160 --mosaic-keep-picture --mosaic-rows=2 --mosaic-cols=4 --mosaic-position=1 --mosaic-order=1,2,3,4,5,6,7,8  --ttl 12 -vvv

В mosaic2.vlm такое:

new cam1 broadcast
setup cam1 input "tcp://192.168.10.2:9001"
setup cam1 option demux=h264
setup cam1 option rate=0.2
setup cam1 option tcp-caching=0
setup cam1 output "#duplicate{dst=mosaic-bridge{id=1,height=288,width=352},select=video}"
setup cam1 enabled
...
ещё 7 камер
...
new background broadcast enabled
setup background input /home/khankin/projects/dvr/background.png
setup background output #transcode{sfilter=mosaic,vcodec=DIV3,vb=800,scale=auto,acodec=none}:display

control background play
control cam1 play
control cam2 play
control cam3 play
control cam4 play
control cam5 play
control cam6 play
control cam7 play
control cam8 play

В итоге в логе вот это:

...
[0x11ed798] [Media: background] main input debug: EOF reached
[0x7f4750004178] main subpicture warning: original picture size is undefined
[0x7f4750c62e48] [Media: background] main decoder debug: removing module "rawvideo"
[0x7f4750c62e48] [Media: background] main decoder debug: killing decoder fourcc `RGBA', 0 PES in FIFO
[0x7f4750000bd8] main stream output debug: removing a sout input (sout_input:0x7f47100008c0)
...
[0x11ed798] [Media: background] main input debug: Program doesn't contain anymore ES
[0x7f4750000bd8] main stream output debug: destroying useless sout
[0x7f4750001c58] main stream out debug: destroying chain... (name=transcode)
[0x7f4750001c58] main stream out debug: removing module "stream_out_transcode"
...

Причём сам vlc не закрывается - только вывод пропадает

hc ()

Если запускаю один поток, без мозайки

cvlc tcp://192.168.10.2:9021 --tcp-caching=0 --demux=h264 --rate=0.2 -vvv

, то работает дольше, но в итоге валится с той же проблемой:

[h264 @ 0x7f9f98c1f7c0] sps_id (32) out of range
[h264 @ 0x7f9f98c21d20] non-existing PPS 6 referenced
[h264 @ 0x7f9f98c21d20] decode_slice_header error
[h264 @ 0x7f9f98c21d20] no frame!
[0x7f9f98c10e08] avcodec decoder warning: cannot decode one frame (685 bytes)
[0x17af788] pulse audio output debug: changing sink 0: alsa_output.pci-0000_00_1b.0.analog-stereo (Built-in Audio Analog Stereo)
...
[0x7f9f9c000a68] main input debug: EOF reached
[0x7f9f9c000a68] main input debug: waiting decoder fifos to empty
...

Но опять же, отваливается только воспроизведение, поток продолжает вычитываться. Ну или уж не знаю, что там vlc делает, однако вызод не происходит сам собой

hc ()

Для этого был написан мини-скрипт на питоне, который ждёт соединения извне (vlc умеет читать tcp://) и начинает вычитывать поток от DVR, зеркалируя его в новый сокет. И это даже работает и работает стабильно

Не работает только одно - мозайка (и вообще сколь бы то ни было долгое воспроизведение потока). vlc с мозайкой дохнет буквально через 4-7 секунд после начала вещания - говорит, дошёл до EOF

EOF в данном случае означает разрыв TCP-соединия. Там не должно быть EOF. Я бы разобрался почему он происходит.

urquan ()
Ответ на: комментарий от urquan

Взял для простоты одну камеру, запускаю как в Как передать tcp-поток от китайского DVR в VLC? (комментарий). Параллельно запустил tcpdump. Выяснилась такая вещь: в какой-то момент моя питон-прокладка отправляет FIN, без видимых на то причин. В логе vlc появляется такое в этот момент:

[h264 @ 0x7fd3bcc1fee0] A non-intra slice in an IDR NAL unit.
[h264 @ 0x7fd3bcc1fee0] decode_slice_header error
[h264 @ 0x7fd3bcc1fee0] no frame!
[0x7fd3bcc0c618] avcodec decoder warning: cannot decode one frame (645 bytes)
[0x7fd3c80009b8] main input debug: EOF reached
[0x7fd3c80009b8] main input debug: waiting decoder fifos to empty
...

На стороне питоно-прокладки, однако же, выбросившийся экспшен утверждает, что виновата другая сторона:

[Errno 104] Connection reset by peer

После того, как vlc очистит свой буфер, он тоже присылает FIN и радостно закрывает сокет

Судя по записи трафика, получилось захватить около 350 секунд. Сейчас попробую ещё раз, посмотрю, нет ли в этих 350 секундах магии

hc ()
Ответ на: комментарий от hc

Кажется, дошла до меня природа этого FINа. В питон-прокладке написано так:

try:
    while True:
        frame = s.recv(1460)
        conn.sendall(frame)
except socket.error, e:
    print e
    s.close()
    conn.close()
, где s - сокет до DVR, conn - сокет, который вернул accept(). Вот и получается, что в случае неполадок с соединением до DVR я принудительно рву оба соединения. Сейчас мы это поправим

hc ()
Ответ на: комментарий от hc

Починил, теперь трансляция одиночного потока не прерывается. Оказывается, DVR может порвать соединение ни с того ни с сего.

Однако мозаика так работать и не хочет. В логах из подозрительного только это:

...
[0x929398] [Media: cam3] main input error: ES_OUT_SET_(GROUP_)PCR  is called too late (pts_delay increased to 1374 ms)
[0x929398] [Media: cam3] main input error: ES_OUT_RESET_PCR called
...
[0x923818] [Media: cam2] main input error: ES_OUT_SET_(GROUP_)PCR  is called too late (pts_delay increased to 1367 ms)
[0x923818] [Media: cam2] main input error: ES_OUT_RESET_PCR called
...

И так для всех камер. Питон-прокладка не сообщает о разрыве связи, коннекты живые, vlc продолжает получать видео и транскодить его. Но на экран выводится ничего

hc ()

А если запустить каждый поток в соём процессе? На тайловом ВМ. Если что-то поломается, то закроется только одно окошко. Удобно и практично.

anonymous ()

А ещё, почему вы решили, что у вас там голый tcp? Что за пакет вы отправляете, можно поинтересоваться?

anonymous ()
Ответ на: комментарий от anonymous

Если запустить каждый потом в своём окне, то оно не ломается уже часа 1,5 как (после того, как я пофиксил код прокладки)

hc ()
Ответ на: комментарий от anonymous

Пакет для камеры №1:

0000000 0000 0100 0000 0300 0002 0000 0000 0000
0000010 0000 6800 0000 0100 0000 1000 0000 0100
0000020 0000 0100 0000 0000 6441 696d 006e 0011
0000030 3630 0106 0000 0000 9340 0011 0000 011b
0000040 0222 7c91 0004 0000 0700 011b 0000 011b
0000050 c030 011b 9318 0011 0000 0000 955c 0011
0000060 e920 7c90 0228 7c91 0000 0000 0000 0000
0000070 0000 0000 0000 0000 0000 0000 0000 0000
*
00001f4

Это голый payload. В ответ на этот пакет dvr присылает какие-то 8 байт и потом начинает передавать видео. По адресу 0x1e (кажется) лежит номер камеры в бинарном виде - каждой камере отведён отдельный разряд в 16 битах, итого 16 камер

Для сравнения пакет для камеры №3:

0000000 0000 0100 0000 0300 0002 0000 0000 0000
0000010 0000 6800 0000 0100 0000 1000 0000 0400
0000020 0000 0100 0000 0000 6441 696d 006e 0011
0000030 3630 0106 0000 0000 9340 0011 0000 011b
0000040 0222 7c91 0004 0000 0700 011b 0000 011b
0000050 c030 011b 9318 0011 0000 0000 955c 0011
0000060 e920 7c90 0228 7c91 0000 0000 0000 0000
0000070 0000 0000 0000 0000 0000 0000 0000 0000
*
00001f4

hc ()
Ответ на: комментарий от hc

Начиная с 0х28 лежит логин. Остальные символы остались для меня загадкой

hc ()
Ответ на: комментарий от hc

Действительно, лажа какая-то. Удобнее, кстати, выровнять по 4 байта/32 бита. 0x1100 — похоже на конец части в блоке, а 0x00000000 — конец блока.

0000 0001   ....
0000 0003   ....
0200 0000   ....
0000 0000   ....

0000 0068   ...h
0000 0001   ....
0000 0010   ....
0000 0004   ....
0000 0001   ....
0000 0000   ....

4164 6d69   Admi
6e00 1100.  n...
3036 0601   06..
0000 0000   ....

4093 1100.  @...
0000 1b01   ....
2202 917c   "..|
0400 0000   ....
0007 1b01   ....
0000 1b01   ....
30c0 1b01   0...
1893 1100.  ....
0000 0000   ....

5c95 1100.  \...
20e9 907c    ..|
2802 917c   (..|
0000 0000   ....

0000 0000   ....
0000 0000   ....
0000 0000   ....
0000 0000   ....
0000 0000   ....
anonymous ()

Для этого был написан мини-скрипт на питоне, который ждёт соединения извне (vlc умеет читать tcp://) и начинает вычитывать поток от DVR, зеркалируя его в новый сокет. И это даже работает и работает стабильно

А где ссылка на гит?

BruteForce ★★★ ()
Ответ на: комментарий от BruteForce

Ну, во-первых, оно ещё не в том виде, чтобы делиться. Во-вторых, у меня нет аккаунта неа гитхабе. В-третьих, я скромный админ, ваш гит пугает меня

hc ()

Для мозаики из живых потоков vlc не пригоден. Любые отклонения от нормы на одном потоке или 100% загрузка CPU ломают его. У этой программы нет отказоустойчивости при обработке сразу нескольких входных живых потоков.

ffmpeg лучше справляется с этой задачей, но также отсутствует отказоустойчивость. Ошибка на одном канале влияет на всю мозаику.

Идею запускать отдельный проигрыватель на каждый поток уже советовали. Но возиться потом с кучей окон муторно. Я б их собрал в одно с помощью встраивания xembed, например, «mplayer -wid $id ...».

fopen ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.