[FFmpeg-devel] Add RTSP range header
Andriy Gelman
andriy.gelman at gmail.com
Thu Nov 26 19:09:33 EET 2020
Hi,
On Sun, 22. Nov 11:21, Yakov Okshtein wrote:
> Hi all,
>
> While working to get historical video off a DVR, I found the lack of a
> customizable Range: header for RTSP video frustrating (as, apparently, have
> others on StackOverflow and the Trac wiki, #6659). One user mentionedhaving
> made a custom patch, but didn't post it; so, I decided to make one.
When fetching the stream, have you tried to use -ss for seeking?
Is the rate-control option only supported by the onvif cameras?
https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec.pdf
If you want to add both options, they should be separate patches. And
you'll need to add documentation in doc/protocols.texi
> diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
> index 0be405aba1..ca0b92251c 100644
> --- a/libavformat/rtsp.c
> +++ b/libavformat/rtsp.c
> @@ -101,6 +101,8 @@ const AVOption ff_rtsp_options[] = {
> #endif
> COMMON_OPTS(),
> { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
> + { "range", "override Range header", OFFSET(range), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
I don't think you meant LIBAVFORMAT_IDENT to be the default (same for rate_control).
This would break seeking for regular streams.
> + { "rate_control", "override Rate-Control header", OFFSET(rate_control), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
> #if FF_API_OLD_RTSP_OPTIONS
> { "user-agent", "override User-Agent header (deprecated, use user_agent)", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
> #endif
> diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
> index 251ed86d19..0778515045 100644
> --- a/libavformat/rtsp.h
> +++ b/libavformat/rtsp.h
> @@ -409,6 +409,16 @@ typedef struct RTSPState {
> */
> char *user_agent;
>
> + /**
> + * Range header override; string.
> + */
> + char *range;
> +
> + /**
> + * Rate-Control header; optional string.
> + */
> + char *rate_control;
> +
> char default_lang[4];
> int buffer_size;
> int pkt_size;
> diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c
> index 28b35d1993..0a0de21b82 100644
> --- a/libavformat/rtspdec.c
> +++ b/libavformat/rtspdec.c
> @@ -541,11 +541,18 @@ static int rtsp_read_play(AVFormatContext *s)
> if (rt->state == RTSP_STATE_PAUSED) {
> cmd[0] = 0;
> } else {
> - snprintf(cmd, sizeof(cmd),
> - "Range: npt=%"PRId64".%03"PRId64"-\r\n",
> - rt->seek_timestamp / AV_TIME_BASE,
> - rt->seek_timestamp / (AV_TIME_BASE / 1000) % 1000);
> + if (rt->range != NULL) {
> + snprintf(cmd, sizeof(cmd), "Range: %s\r\n", rt->range);
> + } else {
> + snprintf(cmd, sizeof(cmd),
> + "Range: npt=%"PRId64".%03"PRId64"-\r\n",
> + rt->seek_timestamp / AV_TIME_BASE,
> + rt->seek_timestamp / (AV_TIME_BASE / 1000) % 1000);
> + }
> }
> + if (rt->rate_control != NULL) {
> + snprintf(cmd, sizeof(cmd), "Rate-Control: %s\r\n", rt->rate_control);
> + }
Your rate-control header is just going to overwrite your range header.
> ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL);
> if (reply->status_code != RTSP_STATUS_OK) {
> return ff_rtsp_averror(reply->status_code, -1);
> diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c
> index d50544456d..1b7281cc67 100644
> --- a/libavformat/rtspenc.c
> +++ b/libavformat/rtspenc.c
> @@ -113,8 +113,13 @@ static int rtsp_write_record(AVFormatContext *s)
> RTSPMessageHeader reply1, *reply = &reply1;
> char cmd[1024];
>
> - snprintf(cmd, sizeof(cmd),
> - "Range: npt=0.000-\r\n");
> + if (rt->range != NULL) {
> + snprintf(cmd, sizeof(cmd),
> + "Range: %s\r\n", rt->range);
> + } else {
> + snprintf(cmd, sizeof(cmd),
> + "Range: npt=0.0000-\r\n");
> + }
> ff_rtsp_send_cmd(s, "RECORD", rt->control_uri, cmd, reply, NULL);
> if (reply->status_code != RTSP_STATUS_OK)
> return ff_rtsp_averror(reply->status_code, -1);
--
Andriy
More information about the ffmpeg-devel
mailing list