Сохранить поток RTSP в файл AVI с Gstreamer
У меня есть видеосервер, который дает мне видео и аудио потоков через RTSP. Я вижу это с помощью инструмента gstreamer gst-launch
с командой:
gst-launch-1.0 uridecodebin uri=rtsp://path/to/source ! autovideosink
Теперь мне нужно сохранить этот видеопоток в файл для последующего воспроизведения в любом популярном видеоплеере (VLC, Windows Media Player и т. Д.).
Я пытался просто заменить autovideosink
с filesink location=file.avi
и добавить -e
вариант, как рекомендуется в этом ответе. Файл создан, но я думаю, что он не в правильном формате видео (VLC не может воспроизвести его).
Также я попробовал команду из недавно упомянутого ответа:
gst-launch-1.0 -e rtspsrc location=rtsp://path/to/source ! decodebin ! x264enc ! mp4mux ! filesink location=file.avi
Это дает мне ошибку:
ERROR: from element /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc0: Internal data flow error. Additional debug info: gstbasesrc.c(2865): gst_base_src_loop (): /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc0: streaming task paused, reason not-linked (-1)
Причина в том (как я думаю) x264enc ! mp4mux
предназначен для кодека H.264, но мое устройство работает только в режиме MPEG4 part2 (MP4V-ES, т.е. H.263). Поэтому мне нужно заменить некоторые элементы в конвейере, чтобы удовлетворить возможности моего устройства. Но, просматривая список плагинов gstreamer, я не могу найти подходящих для MP4V-ES (H.263).
А теперь мой вопрос: как изменить команду gst-launch для сохранения видео с моего немного старого устройства в файл для дальнейшего воспроизведения?
Полный журнал для команды с многословием:
gst-launch-1.0 -e -v rtspsrc location=rtsp://192.168.101.44/moxa-cgi/multicaststream_ch1_stream1 ! decodebin ! avenc_mpeg4 ! mp4mux ! filesink location=file.mp4
Setting pipeline to PAUSED ... Pipeline is live and does not need PREROLL ... Progress: (open) Opening Stream Progress: (connect) Connecting to rtsp://192.168.101.44/moxa-cgi/multicaststream_ch1_stream1 Progress: (open) Retrieving server options Progress: (open) Retrieving media info Progress: (request) SETUP stream 0 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager: latency = 2000 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager: ntp-sync = false /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager: use-pipeline-clock = false /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager: drop-on-latency = false /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager: buffer-mode = Slave receiver to sender clock /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc0: timeout = 5000000000 (gst-launch-1.0:9068): GStreamer-WARNING **: gstpad.c:4555:store_sticky_event:<udpsrc1:src> Sticky event misordering, got 'caps' before 'stream-start' /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc1.GstPad:src: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc1.GstPad:src: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc1: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSink:udpsink0: ttl = 128 Progress: (request) SETUP stream 1 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc2: timeout = 5000000000 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc3.GstPad:src: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc3: caps = application/x-rtcp (gst-launch-1.0:9068): GStreamer-WARNING **: gstpad.c:4555:store_sticky_event:<udpsrc3:src> Sticky event misordering, got 'caps' before 'stream-start' /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc3.GstPad:src: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:recv_rtcp_sink_1.GstProxyPad:proxypad5: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager/GstRtpSession:rtpsession1.GstPad:sync_src: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager/GstRtpSsrcDemux:rtpssrcdemux1.GstPad:rtcp_sink: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager/GstRtpSession:rtpsession1.GstPad:recv_rtcp_sink: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:recv_rtcp_sink_1: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSink:udpsink2: ttl = 128 Progress: (open) Opened Stream Setting pipeline to PLAYING ... New clock: GstSystemClock Progress: (request) Sending PLAY request Progress: (request) Sending PLAY request Progress: (request) Sent PLAY request /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc0: timeout = 0 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc2: timeout = 0 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager/GstRtpSession:rtpsession0.GstPad:send_rtcp_src: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:send_rtcp_src_0: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSink:udpsink1.GstPad:sink: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:send_rtcp_src_0.GstProxyPad:proxypad3: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager/GstRtpSession:rtpsession1.GstPad:send_rtcp_src: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:send_rtcp_src_1: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSink:udpsink3.GstPad:sink: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:send_rtcp_src_1.GstProxyPad:proxypad6: caps = application/x-rtcp /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:recv_rtp_src_1_109102090_0: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0.GstGhostPad:recv_rtp_src_1_109102090_0: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstDecodeBin:decodebin0.GstGhostPad:sink.GstProxyPad:proxypad0: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstTypeFindElement:typefind.GstPad:src: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstTypeFindElement:typefind.GstPad:sink: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstDecodeBin:decodebin0.GstGhostPad:sink: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0.GstGhostPad:recv_rtp_src_1_109102090_0.GstProxyPad:proxypad8: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:recv_rtp_src_1_109102090_0.GstProxyPad:proxypad7: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstRtpPcmuDepay:rtppcmudepay0.GstPad:src: caps = audio/x-mulaw, channels=(int)1, rate=(int)8000 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstMuLawDec:mulawdec0.GstPad:sink: caps = audio/x-mulaw, channels=(int)1, rate=(int)8000 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstRtpPcmuDepay:rtppcmudepay0.GstPad:sink: caps = application/x-rtp, media=(string)audio, payload=(int)0, clock-rate=(int)8000, encoding-name=(string)PCMU, encoding-params=(string)1, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)2318609, seqnum-base=(uint)26256, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstMuLawDec:mulawdec0.GstPad:src: caps = audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)8000, channels=(int)1 /GstPipeline:pipeline0/GstDecodeBin:decodebin0.GstDecodePad:src_0.GstProxyPad:proxypad9: caps = audio/x-raw, format=(string)S16LE, layout=(string)interleaved, rate=(int)8000, channels=(int)1 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:recv_rtp_src_0_2387976809_96: caps = application/x-rtp, media=(string)video, payload=(int)96, clock-rate=(int)90000, encoding-name=(string)MP4V-ES, profile-level-id=(string)3, config=(string)000001B003000001B50900000100000001200088400668582120A31F, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)26503772, seqnum-base=(uint)15792, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0.GstGhostPad:recv_rtp_src_0_2387976809_96: caps = application/x-rtp, media=(string)video, payload=(int)96, clock-rate=(int)90000, encoding-name=(string)MP4V-ES, profile-level-id=(string)3, config=(string)000001B003000001B50900000100000001200088400668582120A31F, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)26503772, seqnum-base=(uint)15792, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0.GstGhostPad:recv_rtp_src_0_2387976809_96.GstProxyPad:proxypad11: caps = application/x-rtp, media=(string)video, payload=(int)96, clock-rate=(int)90000, encoding-name=(string)MP4V-ES, profile-level-id=(string)3, config=(string)000001B003000001B50900000100000001200088400668582120A31F, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)26503772, seqnum-base=(uint)15792, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstRtpBin:manager.GstGhostPad:recv_rtp_src_0_2387976809_96.GstProxyPad:proxypad10: caps = application/x-rtp, media=(string)video, payload=(int)96, clock-rate=(int)90000, encoding-name=(string)MP4V-ES, profile-level-id=(string)3, config=(string)000001B003000001B50900000100000001200088400668582120A31F, a-tool=(string)"MOXA\ 4CH\ Streamming\ Server\ V1.0", a-type=(string)broadcast, x-qt-text-nam=(string)"4CH\ Streaming", x-qt-text-inf=(string)/dev/at2042, clock-base=(uint)26503772, seqnum-base=(uint)15792, npt-start=(guint64)0, play-speed=(double)1, play-scale=(double)1 ERROR: from element /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc0: Internal data flow error. Additional debug info: gstbasesrc.c(2865): gst_base_src_loop (): /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0/GstUDPSrc:udpsrc0: streaming task paused, reason not-linked (-1) EOS on shutdown enabled -- waiting for EOS after Error Waiting for EOS...
Ctrl + C нажата здесь.
handling interrupt. Interrupt: Stopping pipeline ... Interrupt while waiting for EOS - stopping pipeline... Execution ended after 0:00:12.942466327 Setting pipeline to PAUSED ... Setting pipeline to READY ... Setting pipeline to NULL ... Freeing pipeline ...
Также вы можете посмотреть на diff для "хорошо" (сохранить в файл работает) с "плохо" (ошибка произошла) по этой ссылке.
2 ответа
Кажется, что ваша камера производит потоки MPEG4 Type 2, которые вы пытаетесь обернуть в контейнер mp4. Поэтому попытка x264_enc не будет работать, поскольку тип потока несовместим. Во-вторых, вы не можете использовать мультиплексор MP4 с типом файла AVI, как с другой попыткой, хотя вы можете попробовать Avimux для этого. Разбивая поток, который хорошо работает при согласовании ограничений, мы можем построить его следующим образом:
gst-launch-1.0 -v -e rtspsrc location=rtsp://path/to/source ! rtpmp4vdepay ! mpeg4videoparse ! mp4mux ! filesink location=test.mp4
rtpmp4vdepay
, mpeg4videoparse
и mp4mux
как правило, завернутые в decodebin
сам элемент, но просто чтобы сделать нашу жизнь проще и увидеть, что идет не так, всегда хорошо выложить элементы. Это дает вам контроль над конвейером, который вы строите, а не оставляете его на согласование ограничений, чтобы выяснить, что я бы не рекомендовал для IP-камер.
Я также рекомендовал бы опробовать конвейер (хотя избегайте декодирования для IP-камер):
gst-launch-1.0 -e rtspsrc location=rtsp://path/to/source ! decodebin ! avenc_mpeg4 ! mp4mux ! filesink location=file.mp4
Сказав, что эта ссылка размещена в исходном вопросе, показаны различные форматы переговоров при попытке воспроизвести поток. Например, тот, который "работает", пытается добавить элементы в порядке, указанном в рабочей линии выше, а нерабочий пытается договориться о другом формате, добавив элемент rtppcmudepay. Я думаю, что до камеры, которая заставляет декодер думать, что доступно более одного типа потока, и декодер стремится разрешить эти ограничения, добавив дополнительные элементы, которые не требуются.
С помощью avenc_mpeg4
вместо x264enc
работает для меня. Последняя команда:
gst-launch-1.0 -e rtspsrc location=rtsp://path/to/source ! decodebin ! avenc_mpeg4 ! mp4mux ! filesink location=file.avi
Оно работает. Но только 1 раз ~10. Другие 9 раз я получил ту же ошибку, что и в вопросе:
потоковое задание приостановлено, причина не связана (-1)
Я не знаю, какова реальная причина этого. Но я думаю, что это особенность устройства.
Тем не менее, команда, как:
gst-play-1.0 rtsp://path/to/source
работает стабильно, т.е. без ошибок.