src/lavf_utils.c
author Mathieu Schroeter <mathieu.schroeter@mycable.ch>
Fri Aug 20 20:04:25 2010 +0200 (13 days ago)
changeset 1059 db49307366bb
parent 567f8d69d569094
permissions -rw-r--r--
updates in the documentation
     1 /*
     2  * GeeXboX Valhalla: tiny media scanner API.
     3  * Copyright (C) 2009 Mathieu Schroeter <mathieu.schroeter@gamesover.ch>
     4  *
     5  * This file is part of libvalhalla.
     6  *
     7  * libvalhalla is free software; you can redistribute it and/or
     8  * modify it under the terms of the GNU Lesser General Public
     9  * License as published by the Free Software Foundation; either
    10  * version 2.1 of the License, or (at your option) any later version.
    11  *
    12  * libvalhalla is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    15  * Lesser General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU Lesser General Public
    18  * License along with libvalhalla; if not, write to the Free Software
    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    20  */
    21 
    22 #include <stdio.h>
    23 #include <string.h>
    24 
    25 #include <libavformat/avformat.h>
    26 
    27 #include "valhalla.h"
    28 #include "valhalla_internals.h"
    29 #include "logs.h"
    30 #include "lavf_utils.h"
    31 
    32 static const struct fileext_s {
    33   const char *fmtname;
    34   const char *suffix;
    35 } g_fileext[] = {
    36   { "ape",                     "apl"  },
    37   { "ape",                     "mac"  },
    38   { "daud",                    "302"  },
    39   { "dv",                      "dif"  },
    40   { "flic",                    "fli"  },
    41   { "flic",                    "flc"  },
    42   { "h264",                    "264"  },
    43   { "h264",                    "h26l" },
    44   { "image2",                  "bmp"  },
    45   { "image2",                  "dpx"  },
    46   { "image2",                  "gif"  },
    47   { "image2",                  "im1"  },
    48   { "image2",                  "im8"  },
    49   { "image2",                  "im24" },
    50   { "image2",                  "jp2"  },
    51   { "image2",                  "jpeg" },
    52   { "image2",                  "jpg"  },
    53   { "image2",                  "pcx"  },
    54   { "image2",                  "pbm"  },
    55   { "image2",                  "pgm"  },
    56   { "image2",                  "png"  },
    57   { "image2",                  "pnm"  },
    58   { "image2",                  "ppm"  },
    59   { "image2",                  "ptx"  },
    60   { "image2",                  "ras"  },
    61   { "image2",                  "rs"   },
    62   { "image2",                  "sgi"  },
    63   { "image2",                  "sun"  },
    64   { "image2",                  "tga"  },
    65   { "image2",                  "tif"  },
    66   { "image2",                  "tiff" },
    67   { "ingenient",               "cgi"  },
    68   { "matroska",                "mkv"  },
    69   { "mjpeg",                   "mjpg" },
    70   { "mov,mp4,m4a,3gp,3g2,mj2", "3g2"  },
    71   { "mov,mp4,m4a,3gp,3g2,mj2", "3gp"  },
    72   { "mov,mp4,m4a,3gp,3g2,mj2", "m4a"  },
    73   { "mov,mp4,m4a,3gp,3g2,mj2", "mov"  },
    74   { "mov,mp4,m4a,3gp,3g2,mj2", "mp4"  },
    75   { "mov,mp4,m4a,3gp,3g2,mj2", "mj2"  },
    76   { "mpeg1video",              "m1v"  },
    77   { "mpeg1video",              "mpeg" },
    78   { "mpeg1video",              "mpg"  },
    79   { "mp3",                     "m2a"  },
    80   { "mp3",                     "mp2"  },
    81   { "nc",                      "v"    },
    82   { "oma",                     "aa3"  },
    83   { "rawvideo",                "cif"  },
    84   { "rawvideo",                "qcif" },
    85   { "rawvideo",                "rgb"  },
    86   { "rawvideo",                "yuv"  },
    87   { "siff",                    "son"  },
    88   { "siff",                    "vb"   },
    89   { "truehd",                  "thd"  },
    90   { "yuv4mpegpipe",            "y4m"  },
    91   { NULL,                      NULL   },
    92 };
    93 
    94 const char *
    95 vh_lavf_utils_fmtname_get (const char *suffix)
    96 {
    97   const struct fileext_s *it;
    98 
    99   if (!suffix)
   100     return NULL;
   101 
   102   for (it = g_fileext; it->fmtname; it++)
   103     if (!strcasecmp (suffix, it->suffix))
   104       return it->fmtname;
   105 
   106   return suffix;
   107 }
   108 
   109 static const char *
   110 suffix_fmt_guess (const char *file)
   111 {
   112   const char *it;
   113 
   114   if (!file)
   115     return NULL;
   116 
   117   it = strrchr (file, '.');
   118   if (it)
   119     it++;
   120 
   121   return vh_lavf_utils_fmtname_get (it);
   122 }
   123 
   124 #define PROBE_BUF_MIN 2048
   125 #define PROBE_BUF_MAX (1 << 20)
   126 
   127 /*
   128  * This function is fully inspired of (libavformat/utils.c v52.28.0
   129  * "av_open_input_file()") to probe data in order to test if *ftm argument
   130  * is the right fmt or not.
   131  *
   132  * The original function from avformat "av_probe_input_format2()" is really
   133  * slow because it probes the fmt of _all_ demuxers for each probe_data
   134  * buffer. Here, the test is only for _one_ fmt and returns the score
   135  * (if > score_max) provided by fmt->probe().
   136  *
   137  * WARNING: this function depends of some internal behaviours of libavformat
   138  *          and can be "broken" with future versions of FFmpeg.
   139  */
   140 static int
   141 lavf_utils_probe (AVInputFormat *fmt, const char *file)
   142 {
   143   FILE *fd;
   144   int rc = 0;
   145   int p_size;
   146   AVProbeData p_data;
   147 
   148   if (!fmt->read_probe)
   149     return 0;
   150 
   151   p_data.filename = file;
   152   p_data.buf = NULL;
   153   p_data.buf_size = 0;
   154 
   155   /* No file should be opened here. */
   156   if (fmt->flags & AVFMT_NOFILE)
   157   {
   158     rc = fmt->read_probe (&p_data);
   159     goto out;
   160   }
   161 
   162   fd = fopen (file, "rb");
   163   if (!fd)
   164     return 0;
   165 
   166   for (p_size = PROBE_BUF_MIN; p_size <= PROBE_BUF_MAX; p_size <<= 1)
   167   {
   168     int score;
   169     int score_max = p_size < PROBE_BUF_MAX ? AVPROBE_SCORE_MAX / 4 : 0;
   170 
   171     p_data.buf = realloc (p_data.buf, p_size + AVPROBE_PADDING_SIZE);
   172     if (!p_data.buf)
   173       break;
   174 
   175     p_data.buf_size = fread (p_data.buf, 1, p_size, fd);
   176     if (p_data.buf_size != p_size) /* EOF is reached? */
   177       break;
   178 
   179     memset (p_data.buf + p_data.buf_size, 0, AVPROBE_PADDING_SIZE);
   180 
   181     if (fseek (fd, 0, SEEK_SET))
   182       break;
   183 
   184     score = fmt->read_probe (&p_data);
   185     if (score > score_max)
   186     {
   187       rc = score;
   188       break;
   189     }
   190   }
   191 
   192   fclose (fd);
   193 
   194  out:
   195   if (p_data.buf)
   196     free (p_data.buf);
   197   return rc;
   198 }
   199 
   200 AVFormatContext *
   201 vh_lavf_utils_open_input_file (const char *file)
   202 {
   203   int res;
   204   const char *name;
   205   AVFormatContext   *ctx;
   206   AVFormatParameters ap;
   207   AVInputFormat     *fmt = NULL;
   208 
   209   ctx = avformat_alloc_context ();
   210   if (!ctx)
   211     return NULL;
   212 
   213   ctx->flags |= AVFMT_FLAG_IGNIDX;
   214 
   215   /*
   216    * Try a format in function of the suffix.
   217    * We gain a lot of speed if the fmt is already the right.
   218    */
   219   name = suffix_fmt_guess (file);
   220   if (name)
   221     fmt = av_find_input_format (name);
   222 
   223   if (fmt)
   224   {
   225     int score = lavf_utils_probe (fmt, file);
   226     vh_log (VALHALLA_MSG_VERBOSE,
   227             "Probe score (%i) [%s] : %s", score, name, file);
   228     if (!score) /* Bad score? */
   229       fmt = NULL;
   230   }
   231 
   232   memset (&ap, 0, sizeof (ap));
   233   ap.prealloced_context = 1;
   234 
   235   res = av_open_input_file (&ctx, file, fmt, 0, &ap);
   236   if (res)
   237   {
   238     vh_log (VALHALLA_MSG_WARNING,
   239             "FFmpeg can't open file (%i) : %s", res, file);
   240     return NULL;
   241   }
   242 
   243   return ctx;
   244 }