You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-15 14:13:16 +02:00
avformat/udp: replace packet_gap with bitrate option
We haven't had a stable release since the packet_gap addition, so probably it is worth reworking the option to something that makes more sense to the end user. Also add burst_bits option to specify maximum length of bit bursts. Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
@@ -1285,8 +1285,13 @@ Set the UDP maximum socket buffer size in bytes. This is used to set either
|
|||||||
the receive or send buffer size, depending on what the socket is used for.
|
the receive or send buffer size, depending on what the socket is used for.
|
||||||
Default is 64KB. See also @var{fifo_size}.
|
Default is 64KB. See also @var{fifo_size}.
|
||||||
|
|
||||||
@item packet_gap=@var{seconds}
|
@item bitrate=@var{bitrate}
|
||||||
Delay between packets
|
If set to nonzero, the output will have the specified constant bitrate if the
|
||||||
|
input has enough packets to sustain it.
|
||||||
|
|
||||||
|
@item burst_bits=@var{bits}
|
||||||
|
When using @var{bitrate} this specifies the maximum number of bits in
|
||||||
|
packet bursts.
|
||||||
|
|
||||||
@item localport=@var{port}
|
@item localport=@var{port}
|
||||||
Override the local UDP port to bind with.
|
Override the local UDP port to bind with.
|
||||||
|
@@ -93,7 +93,8 @@ typedef struct UDPContext {
|
|||||||
int circular_buffer_size;
|
int circular_buffer_size;
|
||||||
AVFifoBuffer *fifo;
|
AVFifoBuffer *fifo;
|
||||||
int circular_buffer_error;
|
int circular_buffer_error;
|
||||||
int64_t packet_gap; /* delay between transmitted packets */
|
int64_t bitrate; /* number of bits to send per second */
|
||||||
|
int64_t burst_bits;
|
||||||
int close_req;
|
int close_req;
|
||||||
#if HAVE_PTHREAD_CANCEL
|
#if HAVE_PTHREAD_CANCEL
|
||||||
pthread_t circular_buffer_thread;
|
pthread_t circular_buffer_thread;
|
||||||
@@ -115,7 +116,8 @@ typedef struct UDPContext {
|
|||||||
#define E AV_OPT_FLAG_ENCODING_PARAM
|
#define E AV_OPT_FLAG_ENCODING_PARAM
|
||||||
static const AVOption options[] = {
|
static const AVOption options[] = {
|
||||||
{ "buffer_size", "System data size (in bytes)", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
|
{ "buffer_size", "System data size (in bytes)", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
|
||||||
{ "packet_gap", "Delay between packets", OFFSET(packet_gap), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, .flags = E },
|
{ "bitrate", "Bits to send per second", OFFSET(bitrate), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, .flags = E },
|
||||||
|
{ "burst_bits", "Max length of bursts in bits (when using bitrate)", OFFSET(burst_bits), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, .flags = E },
|
||||||
{ "localport", "Local port", OFFSET(local_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, D|E },
|
{ "localport", "Local port", OFFSET(local_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, D|E },
|
||||||
{ "local_port", "Local port", OFFSET(local_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
|
{ "local_port", "Local port", OFFSET(local_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
|
||||||
{ "localaddr", "Local address", OFFSET(localaddr), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
|
{ "localaddr", "Local address", OFFSET(localaddr), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
|
||||||
@@ -552,7 +554,11 @@ static void *circular_buffer_task_tx( void *_URLContext)
|
|||||||
URLContext *h = _URLContext;
|
URLContext *h = _URLContext;
|
||||||
UDPContext *s = h->priv_data;
|
UDPContext *s = h->priv_data;
|
||||||
int old_cancelstate;
|
int old_cancelstate;
|
||||||
int64_t target_timestamp = 0;
|
int64_t target_timestamp = av_gettime_relative();
|
||||||
|
int64_t start_timestamp = av_gettime_relative();
|
||||||
|
int64_t sent_bits = 0;
|
||||||
|
int64_t burst_interval = s->bitrate ? (s->burst_bits * 1000000 / s->bitrate) : 0;
|
||||||
|
int64_t max_delay = s->bitrate ? ((int64_t)h->max_packet_size * 8 * 1000000 / s->bitrate + 1) : 0;
|
||||||
|
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate);
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate);
|
||||||
pthread_mutex_lock(&s->mutex);
|
pthread_mutex_lock(&s->mutex);
|
||||||
@@ -591,15 +597,24 @@ static void *circular_buffer_task_tx( void *_URLContext)
|
|||||||
pthread_mutex_unlock(&s->mutex);
|
pthread_mutex_unlock(&s->mutex);
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate);
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate);
|
||||||
|
|
||||||
if (s->packet_gap) {
|
if (s->bitrate) {
|
||||||
timestamp = av_gettime_relative();
|
timestamp = av_gettime_relative();
|
||||||
if (timestamp < target_timestamp) {
|
if (timestamp < target_timestamp) {
|
||||||
target_timestamp = FFMIN(target_timestamp, timestamp + s->packet_gap);
|
int64_t delay = target_timestamp - timestamp;
|
||||||
av_usleep(target_timestamp - timestamp);
|
if (delay > max_delay) {
|
||||||
|
delay = max_delay;
|
||||||
|
start_timestamp = timestamp + delay;
|
||||||
|
sent_bits = 0;
|
||||||
|
}
|
||||||
|
av_usleep(delay);
|
||||||
} else {
|
} else {
|
||||||
target_timestamp = timestamp;
|
if (timestamp - burst_interval > target_timestamp) {
|
||||||
|
start_timestamp = timestamp - burst_interval;
|
||||||
|
sent_bits = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
target_timestamp += s->packet_gap;
|
sent_bits += len * 8;
|
||||||
|
target_timestamp = start_timestamp + sent_bits * 1000000 / s->bitrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = s->tmp;
|
p = s->tmp;
|
||||||
@@ -744,16 +759,16 @@ static int udp_open(URLContext *h, const char *uri, int flags)
|
|||||||
"'circular_buffer_size' option was set but it is not supported "
|
"'circular_buffer_size' option was set but it is not supported "
|
||||||
"on this build (pthread support is required)\n");
|
"on this build (pthread support is required)\n");
|
||||||
}
|
}
|
||||||
if (av_find_info_tag(buf, sizeof(buf), "packet_gap", p)) {
|
if (av_find_info_tag(buf, sizeof(buf), "bitrate", p)) {
|
||||||
if (av_parse_time(&s->packet_gap, buf, 1)<0) {
|
s->bitrate = strtoll(buf, NULL, 10);
|
||||||
av_log(h, AV_LOG_ERROR, "Can't parse 'packet_gap'");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (!HAVE_PTHREAD_CANCEL)
|
if (!HAVE_PTHREAD_CANCEL)
|
||||||
av_log(h, AV_LOG_WARNING,
|
av_log(h, AV_LOG_WARNING,
|
||||||
"'packet_gap' option was set but it is not supported "
|
"'bitrate' option was set but it is not supported "
|
||||||
"on this build (pthread support is required)\n");
|
"on this build (pthread support is required)\n");
|
||||||
}
|
}
|
||||||
|
if (av_find_info_tag(buf, sizeof(buf), "burst_bits", p)) {
|
||||||
|
s->burst_bits = strtoll(buf, NULL, 10);
|
||||||
|
}
|
||||||
if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) {
|
if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) {
|
||||||
av_strlcpy(localaddr, buf, sizeof(localaddr));
|
av_strlcpy(localaddr, buf, sizeof(localaddr));
|
||||||
}
|
}
|
||||||
@@ -936,15 +951,15 @@ static int udp_open(URLContext *h, const char *uri, int flags)
|
|||||||
/*
|
/*
|
||||||
Create thread in case of:
|
Create thread in case of:
|
||||||
1. Input and circular_buffer_size is set
|
1. Input and circular_buffer_size is set
|
||||||
2. Output and packet_gap and circular_buffer_size is set
|
2. Output and bitrate and circular_buffer_size is set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (is_output && s->packet_gap && !s->circular_buffer_size) {
|
if (is_output && s->bitrate && !s->circular_buffer_size) {
|
||||||
/* Warn user in case of 'circular_buffer_size' is not set */
|
/* Warn user in case of 'circular_buffer_size' is not set */
|
||||||
av_log(h, AV_LOG_WARNING,"'packet_gap' option was set but 'circular_buffer_size' is not, but required\n");
|
av_log(h, AV_LOG_WARNING,"'bitrate' option was set but 'circular_buffer_size' is not, but required\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!is_output && s->circular_buffer_size) || (is_output && s->packet_gap && s->circular_buffer_size)) {
|
if ((!is_output && s->circular_buffer_size) || (is_output && s->bitrate && s->circular_buffer_size)) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* start the task going */
|
/* start the task going */
|
||||||
|
@@ -33,7 +33,7 @@
|
|||||||
// Also please add any ticket numbers that you belive might regress here
|
// Also please add any ticket numbers that you belive might regress here
|
||||||
#define LIBAVFORMAT_VERSION_MAJOR 57
|
#define LIBAVFORMAT_VERSION_MAJOR 57
|
||||||
#define LIBAVFORMAT_VERSION_MINOR 38
|
#define LIBAVFORMAT_VERSION_MINOR 38
|
||||||
#define LIBAVFORMAT_VERSION_MICRO 101
|
#define LIBAVFORMAT_VERSION_MICRO 102
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||||
LIBAVFORMAT_VERSION_MINOR, \
|
LIBAVFORMAT_VERSION_MINOR, \
|
||||||
|
Reference in New Issue
Block a user