[FFmpeg-devel] [PATCH 4/4] avformat/libopenmpt: Probe file format from file data if possible

Carl Eugen Hoyos ceffmpeg at gmail.com
Sat Jan 6 17:10:45 EET 2018


2018-01-06 11:07 GMT+01:00 Jörn Heusipp <osmanx at problemloesungsmaschine.de>:
> When building with libopenmpt 0.3, use the libopenmpt file header
> probing functions for probing. libopenmpt probing functions are
> allocation-free and designed to be as fast as possible.
>
> For libopenmpt 0.2, or when libopenmpt 0.3 file header probing cannot
> probe successfully due to too small probe buffer, test the filename
> against the file extensions supported by the libopenmpt library that
> is actually linked, instead of relying on a hard-coded file extension
> list. File extension testing is also allocation-free and designed to
> be fast in libopenmpt. Avoiding a hard-coded file extension list is
> useful because later libopenmpt versions will likely add support for
> more module file formats.
>
> libopenmpt file header probing is tested regularly against the FATE
> suite and other diverse file collections by libopenmpt upstream in
> order to avoid false positives.

You could also test tools/probetest

> FATE passes with './configure --enable-libopenmpt' as well as with
> './configure --enable-libopenmpt --enable-libmodplug'.
>
> As expected, I did not see any measurable performance difference
> caused by libopenmpt file header probing when compared to the previous
> pure file extension based format probing (using the following
> synthetic test program (which tries to do nothing but exercise file
> probing) on the complete FATE suite).
>
>     // find ../fate/ -type f | xargs --no-run-if-empty ./probetest
>     #include <stdio.h>
>     #include "libavformat/avformat.h"
>     #define BUFSIZE 2048
>     static char buf[BUFSIZE + AVPROBE_PADDING_SIZE];
>     int main(int argc, const char * * argv) {
>         av_log_set_level(AV_LOG_WARNING);
>         av_register_all();
>         for (int i = 1; i < argc; ++i) {
>             AVProbeData pd;
>             FILE * f;
>             size_t size;
>             memset(&pd, 0, sizeof(AVProbeData));
>             pd.filename = argv[i];
>             memset(buf, 0, sizeof(buf));
>             f = fopen(pd.filename, "rb");
>             size = fread(buf, 1, BUFSIZE, f);
>             fclose(f);
>             pd.buf_size = size;
>             av_probe_input_format(&pd, 1);
>         }
>         return 0;
>     }
>
> Signed-off-by: Jörn Heusipp <osmanx at problemloesungsmaschine.de>
> ---
>  libavformat/libopenmpt.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 59 insertions(+)
>
> diff --git a/libavformat/libopenmpt.c b/libavformat/libopenmpt.c
> index 5efbdc4..a663b2e 100644
> --- a/libavformat/libopenmpt.c
> +++ b/libavformat/libopenmpt.c
> @@ -218,6 +218,64 @@ static int read_seek_openmpt(AVFormatContext *s, int stream_idx, int64_t ts, int
>      return 0;
>  }
>
> +static int read_probe_openmpt(AVProbeData * p)
> +{
> +    const int score_data      = AVPROBE_SCORE_MIME + 1;   /* 76 */
> +    const int score_ext       = AVPROBE_SCORE_EXTENSION;  /* 50 */
> +    const int score_ext_retry = AVPROBE_SCORE_RETRY;      /* 25 */
> +    const int score_retry     = AVPROBE_SCORE_RETRY / 2;  /* 12 */
> +    const int score_fail      = 0;                        /*  0 */
> +
> +    const char *ext;
> +    int probe_result;
> +    int score = score_fail;
> +
> +    if (p->filename) {
> +        ext = strrchr(p->filename, '.');
> +        if (ext && strlen(ext + 1) > 0) {
> +            ext++;  /* skip '.' */
> +            if (openmpt_is_extension_supported(ext) == 1)
> +                score = FFMAX(score, score_ext);
> +        }
> +    }
> +
> +#if OPENMPT_API_VERSION_AT_LEAST(0,3,0)
> +    if (p->buf && p->buf_size > 0) {
> +        probe_result = openmpt_probe_file_header_without_filesize(
> +                           OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT,
> +                           p->buf, p->buf_size,
> +                           &openmpt_logfunc, NULL, NULL, NULL, NULL, NULL);
> +        if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE) {
> +            score = score_fail;

What's wrong with return 0;?

> +        } else if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS) {
> +            score = FFMAX(score, score_data);

What does OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS mean?
Why not return MAX?

> +        } else if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA) {

I believe this should return 0 but maybe you found that this is bad?

> +            if (score > score_fail) {
> +                /* known file extension */
> +                score = FFMAX(score, score_ext_retry);
> +            } else {
> +                /* unknown file extension */
> +                if (p->buf_size >= openmpt_probe_file_header_get_recommended_size()) {
> +                    /* We have already received the recommended amount of data
> +                     * and still cannot decide. Return a rather low score.
> +                     */
> +                    score = FFMAX(score, score_retry);
> +                } else {
> +                    /* The file extension is unknown and we have very few data
> +                     * bytes available. libopenmpt cannot decide anything here,
> +                     * and returning any score > 0 would result in successfull
> +                     * probing of random data.
> +                     */
> +                    score = score_fail;

This patch indicates that it may be a good idea to require libopenmpt 0.3,
when was it released, which distributions do not include it?

Carl Eugen


More information about the ffmpeg-devel mailing list