Search code examples
linuxffmpegrtspip-cameraopenrtsp

RTSP stream to ffmpeg problems


I'm writing a web application for managing and viewing streams from ONVIF ip-cameras.
It's written in nodejs. The idea is to run a child process in node and pipe output to node, then send the buffer to client and render it on canvas. I have a working solution for sending data to client and rendering it on canvas using websockets but it only works on one of my cameras.

I own 2 IP cameras and both of them have rtsp server.
One of them(let's name it camX) kind of works with this ffmpeg command (sometimes it just stops, maybe due to packet losses):

ffmpeg -rtsp_transport tcp -re -i <rtsp_link> -f mjpeg pipe:1

But the other one(camY) returns Nonmatching transport in server reply and exits.

I discovered that the camY transport is unicast but ffmpeg doesn't support this particular lower_transport as I read on ffmpeg forum.

So I started looking for a solution. My first idea was to use openRTSP which works fine with both streams. I looked at the documentation and came up with this command:
openRTSP -4 -c <rtsp_link> | ffmpeg -re -i pipe:0 -f mjpeg pipe:1
-4 parameter returns stream to pipe in mp4 format
And here's another problem I ran into, ffmpeg returns:

[mov,mp4,m4a,3gp,3g2,mj2 @ 0x559a4b6ba900] moov atom not found  
pipe:0: Invalid data found when processing input

Is there any way to make this work? I tried various solutions I found, but none of them worked.

EDIT

As @Gyan suggested I used -i parameter instead of -4 but it didn't solve my problem.

My command:

openRTSP -V -i -c -K <rtsp_link> | ffmpeg -loglevel debug -re -i pipe:0 -f mjpeg pipe:1
  
Created receiver for "video/H264" subsession (client ports 49072-49073)
Setup "video/H264" subsession (client ports 49072-49073)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
AVIFileSink::setWord(): SeekFile64 failed (err 29)
Outputting to the file: "stdout"
[avi @ 0x5612944268c0] Format avi probed with size=2048 and score=100
[avi @ 0x56129442f7a0] use odml:1
Started playing session
Receiving streamed data (signal with "kill -HUP 15028" or "kill -USR1 15028" to terminate)...
^C
[AVIOContext @ 0x56129442f640] Statistics: 16904 bytes read, 0 seeks
pipe:0: Invalid data found when processing input

As you can see openRTSP command return err 29 but in meantime it outputs some data to pipe.
When I terminate the command ffmpeg shows that it read some data but couldn't process it.

Here's the function that produces that error:

void AVIFileSink::setWord(unsigned filePosn, unsigned size) {
  do {
    if (SeekFile64(fOutFid, filePosn, SEEK_SET) < 0) break;
    addWord(size);
    if (SeekFile64(fOutFid, 0, SEEK_END) < 0) break; // go back to where we were

    return;
  } while (0);

  // One of the SeekFile64()s failed, probable because we're not a seekable file
  envir() << "AVIFileSink::setWord(): SeekFile64 failed (err "
          << envir().getErrno() << ")\n";
}

In my opinion it looks like it won't be able to seek file because it's a stream not a static file.
Any suggestion for a workaround?


Solution

  • There are multiple things here:

    1. Nonmatching transport in server reply - this is most likely not due to unicast (because unicast is the normal way - sending the stream to a single client). The error most likely comes from the fact, that you are actually forcing RTP over TCP with the -rtsp_transport tcp flag. You have several options here - check the cameras which are not working, check if they are set to only UDP and set them to TCP, or even better - do not force the transport and let ffmpeg negotiate with the camera. Maybe this solves the issue at once.
    2. Regarding OpenRTSP - The moov atom is usually written at the end of the file when all the needed data is known, and since you are piping it, it actually breaks the logic here. I would assume OpenRTSP actually never emits the moov since it never ends the stream and thus ffmpeg never gets it. I would advise to simply try and fix the RTSP transport as stated above.