mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-24 02:09:03 +03:00
avformat/demux: allow returning AVERROR(EAGAIN) from read_probe()
This fills a gap in the probe scoring API; where it's not possible for a demuxer to both express "I don't know yet" and "this file could definitely be mine" at the same time. This is needed for the example of JPEG Multi-Picture Format files, which are uniquely distinguished from regular JPEG files by the presence of a special marker that can live arbitrarily far into the file. This is a bit analogous to the situation with ID3v2 tags, which can also hide the true file format behind them. In this case, the probe logic already has a special hack to detect and force more data (cf. `nodat`) - but letting the demuxer itself decide this case is an IMHO more elegant solution. Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
@@ -88,6 +88,15 @@ typedef struct FFInputFormat {
|
||||
* Tell if a given file has a chance of being parsed as this format.
|
||||
* The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes
|
||||
* big so you do not have to check for that unless you need more.
|
||||
*
|
||||
* If the final score is not yet resolvable, the special return value
|
||||
* AVERROR(EAGAIN) can be used to signal to the caller that probing must
|
||||
* be tried again with more bytes.
|
||||
*
|
||||
* This is distinct from AVPROBE_SCORE_RETRY, which means "possibly mine,
|
||||
* but if another format is more confident, let it have the file", whereas
|
||||
* AVERROR(EAGAIN) means "possibly mine, don't let another format claim
|
||||
* it until I've seen enough data to make a decision".
|
||||
*/
|
||||
int (*read_probe)(const AVProbeData *);
|
||||
|
||||
|
||||
@@ -153,8 +153,9 @@ const AVInputFormat *av_find_input_format(const char *short_name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const AVInputFormat *av_probe_input_format3(const AVProbeData *pd,
|
||||
int is_opened, int *score_ret)
|
||||
static const AVInputFormat *
|
||||
probe_input_format_internal(const AVProbeData *pd, int is_opened,
|
||||
int *score_ret, int *undecided)
|
||||
{
|
||||
AVProbeData lpd = *pd;
|
||||
const AVInputFormat *fmt1 = NULL;
|
||||
@@ -196,7 +197,13 @@ const AVInputFormat *av_probe_input_format3(const AVProbeData *pd,
|
||||
score = 0;
|
||||
if (ffifmt(fmt1)->read_probe) {
|
||||
score = ffifmt(fmt1)->read_probe(&lpd);
|
||||
if (score)
|
||||
if (score == AVERROR(EAGAIN)) {
|
||||
av_log(NULL, AV_LOG_TRACE, "Probing %s score:undecided size:%d\n",
|
||||
fmt1->name, lpd.buf_size);
|
||||
if (undecided)
|
||||
*undecided = 1;
|
||||
score = 0;
|
||||
} else if (score)
|
||||
av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size);
|
||||
if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) {
|
||||
switch (nodat) {
|
||||
@@ -235,11 +242,18 @@ const AVInputFormat *av_probe_input_format3(const AVProbeData *pd,
|
||||
return fmt;
|
||||
}
|
||||
|
||||
const AVInputFormat *av_probe_input_format3(const AVProbeData *pd,
|
||||
int is_opened, int *score_ret)
|
||||
{
|
||||
return probe_input_format_internal(pd, is_opened, score_ret, NULL);
|
||||
}
|
||||
|
||||
const AVInputFormat *av_probe_input_format2(const AVProbeData *pd,
|
||||
int is_opened, int *score_max)
|
||||
{
|
||||
int score_ret;
|
||||
const AVInputFormat *fmt = av_probe_input_format3(pd, is_opened, &score_ret);
|
||||
const AVInputFormat *fmt;
|
||||
fmt = probe_input_format_internal(pd, is_opened, &score_ret, NULL);
|
||||
if (score_ret > *score_max) {
|
||||
*score_max = score_ret;
|
||||
return fmt;
|
||||
@@ -250,7 +264,7 @@ const AVInputFormat *av_probe_input_format2(const AVProbeData *pd,
|
||||
const AVInputFormat *av_probe_input_format(const AVProbeData *pd, int is_opened)
|
||||
{
|
||||
int score = 0;
|
||||
return av_probe_input_format2(pd, is_opened, &score);
|
||||
return probe_input_format_internal(pd, is_opened, &score, NULL);
|
||||
}
|
||||
|
||||
int av_probe_input_buffer2(AVIOContext *pb, const AVInputFormat **fmt,
|
||||
@@ -313,7 +327,18 @@ int av_probe_input_buffer2(AVIOContext *pb, const AVInputFormat **fmt,
|
||||
memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);
|
||||
|
||||
/* Guess file format. */
|
||||
*fmt = av_probe_input_format2(&pd, 1, &score);
|
||||
int score_new, undecided = 0;
|
||||
const AVInputFormat *fmt_new;
|
||||
fmt_new = probe_input_format_internal(&pd, 1, &score_new, &undecided);
|
||||
|
||||
/* Retry undecided formats as long as we have more data to feed */
|
||||
if (undecided && probe_size < max_probe_size && !eof) {
|
||||
continue;
|
||||
} else if (score_new > score) {
|
||||
score = score_new;
|
||||
*fmt = fmt_new;
|
||||
}
|
||||
|
||||
if (*fmt) {
|
||||
/* This can only be true in the last iteration. */
|
||||
if (score <= AVPROBE_SCORE_RETRY) {
|
||||
|
||||
Reference in New Issue
Block a user