You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-10-06 05:47:18 +02:00
avformat/utils: add helper function to set opts from query string
Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
@@ -649,4 +649,16 @@ int ff_bprint_get_frame_filename(struct AVBPrint *buf, const char *path, int64_t
|
||||
*/
|
||||
int ff_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp);
|
||||
|
||||
/**
|
||||
* Set a list of query string options on an object. Only the objects own
|
||||
* options will be set.
|
||||
*
|
||||
* @param obj the object to set options on
|
||||
* @param str the query string
|
||||
* @param allow_unknown ignore unknown query string options. This can be OK if
|
||||
* nested protocols are used.
|
||||
* @return <0 on error
|
||||
*/
|
||||
int ff_parse_opts_from_query_string(void *obj, const char *str, int allow_unkown);
|
||||
|
||||
#endif /* AVFORMAT_INTERNAL_H */
|
||||
|
@@ -24,11 +24,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/parseutils.h"
|
||||
#include "libavutil/time.h"
|
||||
#include "libavutil/time_internal.h"
|
||||
|
||||
@@ -41,6 +44,7 @@
|
||||
#include "network.h"
|
||||
#endif
|
||||
#include "os_support.h"
|
||||
#include "urldecode.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
@@ -618,3 +622,65 @@ int ff_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestam
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const AVOption* find_opt(void *obj, const char *name, size_t len)
|
||||
{
|
||||
char decoded_name[128];
|
||||
|
||||
if (ff_urldecode_len(decoded_name, sizeof(decoded_name), name, len, 1) < 0)
|
||||
return NULL;
|
||||
|
||||
return av_opt_find(obj, decoded_name, NULL, 0, 0);
|
||||
}
|
||||
|
||||
int ff_parse_opts_from_query_string(void *obj, const char *str, int allow_unknown)
|
||||
{
|
||||
const AVOption *opt;
|
||||
char optval[512];
|
||||
int ret;
|
||||
|
||||
if (*str == '?')
|
||||
str++;
|
||||
while (*str) {
|
||||
size_t len = strcspn(str, "=&");
|
||||
opt = find_opt(obj, str, len);
|
||||
if (!opt) {
|
||||
if (!allow_unknown) {
|
||||
av_log(obj, AV_LOG_ERROR, "Query string option '%.*s' does not exist\n", (int)len, str);
|
||||
return AVERROR_OPTION_NOT_FOUND;
|
||||
}
|
||||
av_log(obj, AV_LOG_VERBOSE, "Ignoring unknown query string option '%.*s'\n", (int)len, str);
|
||||
}
|
||||
str += len;
|
||||
if (!opt) {
|
||||
len = strcspn(str, "&");
|
||||
str += len;
|
||||
} else if (*str == '&' || *str == '\0') {
|
||||
/* Check for bool options without value, e.g. "?verify".
|
||||
* Unfortunately "listen" is a tri-state INT for some protocols so
|
||||
* we also have to allow that for backward compatibility. */
|
||||
if (opt->type != AV_OPT_TYPE_BOOL && strcmp(opt->name, "listen")) {
|
||||
av_log(obj, AV_LOG_ERROR, "Non-bool query string option '%s' has no value\n", opt->name);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
ret = av_opt_set_int(obj, opt->name, 1, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
av_assert2(*str == '=');
|
||||
str++;
|
||||
len = strcspn(str, "&");
|
||||
if (ff_urldecode_len(optval, sizeof(optval), str, len, 1) < 0) {
|
||||
av_log(obj, AV_LOG_ERROR, "Query string option '%s' value is too long\n", opt->name);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
ret = av_opt_set(obj, opt->name, optval, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
str += len;
|
||||
}
|
||||
if (*str)
|
||||
str++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user