Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unable to recover playing after doing fast forward of rtsp stream #7472

Closed
arekm opened this issue Feb 18, 2020 · 12 comments
Closed

unable to recover playing after doing fast forward of rtsp stream #7472

arekm opened this issue Feb 18, 2020 · 12 comments
Labels

Comments

@arekm
Copy link

arekm commented Feb 18, 2020

Important Information

Provide following Information:

  • mpv git master 36ca0e0
  • Ubuntu 19.10
  • Source of the mpv binary - own build
  • If known which version of mpv introduced the problem - no idea but 0.29.1 also shows this problem

Reproduction steps

Viewing RTSP stream from CCTV camera with buffering enabled.

Fast forward it few times, mpv sees some EOF and now it doesn't recover playing that stream. It is not even possible to rewind into buffered data.

Used config:

$ cat  ~/.config/mpv/mpv.conf
keep-open=always
keep-open-pause=no
cache-secs=1200
cache=yes
#cache-backbuffer=1024000
cache-pause=no
demuxer-max-bytes=1G
demuxer-max-back-bytes=1G
#hr-seek=no

Expected behavior

I would expect fast forward to reach end of available stream data but be able to play more when these come in (and don't close that stream... or reopen it to conitnue).

Actual behavior

mpv stops playing and it doesn't show stream anymore but also it is not possible to rewind back to already played and still buffered data.

Log file

First log is:

  • mpv started
  • right cursor arrow pressed few times
  • mpv "hangs"

log-few-forward-presses.txt

Second log is:

  • mpv started
  • right cursor arrow pressed few times
  • mpv "hangs"
  • press left arrow currsor to try to view buffered data
  • mpv still "hangs"

log-few-forward-presses-and-then-trying-to-rewind-few-times.txt

Sample files

It's live stream from CCTV camera but I think I should be able to make it visible from the internet if logs are not enough.

@arekm arekm added the os:linux label Feb 18, 2020
@ghost
Copy link

ghost commented Feb 18, 2020

Seeking within the cache really shouldn't affect I/O, apart from timing, which could have an effect in less favorable circumstances (but my guess is no).

Actually it seems the cache is not kept:

[ 3.431][v][lavf] discarding unseekable range due to stream 0

Then it tell libavformat to perform a low level seek, which probably doesn't make sense at all:

[ 3.466][v][lavf] execute seek (to 6.880000 flags 4)

libavformat tries to do... something (see rtsp logs, I think it's a Range request which the server dnies), and fails:

[ 3.519][v][lavf] Seek failed (Invalid argument)

It seems it eventually think the stream died.

Viewing RTSP stream from CCTV camera with buffering enabled.

I don't have a CCTV camera => no reproduction.

@ghost
Copy link

ghost commented Feb 18, 2020

Also if there's only 1 seekable range, I think this discarding shouldn't even happen, could be a bug.

@ghost
Copy link

ghost commented Feb 18, 2020

Oh right, looking at the log and the code again, it's because you seek past the end of the stream. Since mpv thinks the stream is seekable, because libavformat seemed to indicate so (there's no good reporting on whether seeking works by the ffmpeg API), it simply executed that seek, because what else would it do. Normally, if an unseekable "live stream" is played, it would prevent any seeks outside of the cached range.

The cached range is discarded because certain properties about the stream make it hard/impossible to resume demuxing when switching back. This is pretty rare and doesn't even really matter in this case.

@arekm
Copy link
Author

arekm commented Feb 19, 2020

mpv -v -v -v "rtsp://test:test@91.234.176.65:5540/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=onvif"

should provide working stream for reproduction.

@ghost
Copy link

ghost commented Feb 19, 2020

I could at most blacklist RTSP for seeking (aka another hack to compensate for libavformat's awful "generic" API).

Edit: unless you find someone who wants to fix these things in libavformat/FFmpeg (not me).

@arekm
Copy link
Author

arekm commented Feb 19, 2020

ffplay seem to treat this stream as unseekable. I wonder how it detects that (and if mpv can do something similar)

@ghost
Copy link

ghost commented Feb 19, 2020

ffplay also tries to seek, but doesn't reset playback if seeking is reported as failing. This doesn't work for mpv for various reasons; it always resets playback immediately. But on the other hand, ffplay could also get "stuck" and didn't continue playback properly.

@arekm
Copy link
Author

arekm commented Feb 19, 2020

Side note - with this ffmpeg hack I got desired mpv results (seeking in buffer only):

AVInputFormat ff_rtsp_demuxer = {
    .name           = "rtsp",
    .long_name      = NULL_IF_CONFIG_SMALL("RTSP input"),
    .priv_data_size = sizeof(RTSPState),
    .read_probe     = rtsp_probe,
    .read_header    = rtsp_read_header,
    .read_packet    = rtsp_read_packet,
    .read_close     = rtsp_read_close,
//    .read_seek      = rtsp_read_seek,
    .flags          = AVFMT_NOFILE,
    .read_play      = rtsp_read_play,
    .read_pause     = rtsp_read_pause,
    .priv_class     = &rtsp_demuxer_class,
};
```

@ghost
Copy link

ghost commented Feb 19, 2020

Well yeah, we could add that to the format hacks list in demux_lavf.c. There's already an option to "force" seeking anyway, in case anyone really wants to seek in RTSP.

I still think that FFmpeg could in theory probe for support in the server code, or use the fact that it's (by declaration in the SDP) a real time stream. (I don't know much about RTSP conventions, though.)

@arekm
Copy link
Author

arekm commented Feb 19, 2020

ffmpeg code parses range header like this:

        } else if (av_strstart(p, "range:", &p)) {
            int64_t start, end;

            // this is so that seeking on a streamed file can work.
            rtsp_parse_range_npt(p, &start, &end);
            s->start_time = start;
            /* AV_NOPTS_VALUE means live broadcast (and can't seek) */
            s->duration   = (end == AV_NOPTS_VALUE) ?
                            AV_NOPTS_VALUE : end - start;

can't (s->duration == AV_NOPTS_VALUE) condition be used for such detection?

From tcpflow trace of my cctv stream:

$ grep Range log
Range: npt=0.000-
Range: npt=0.000-
Range: npt=0.000000-
Range: npt=0.000000-

@ghost
Copy link

ghost commented Feb 19, 2020

For RTSP, maybe. For other things... I don't know, doesn't seem robust enough. There can actually be files that have no duration set (or have a wrong duration set) and are still seekable, like mkv files. (mkv files use a different demuxer, but it's just an example.)

@ghost
Copy link

ghost commented Feb 20, 2020

Implemented your suggestion. I've seen your patch only later, but the solution is pretty similar anyway.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant