generic: implemente a generic parser plugin
authorLeandro Dorileo <leandro.maciel.dorileo@intel.com>
Thu, 19 Dec 2013 16:55:38 +0000 (14:55 -0200)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Fri, 27 Dec 2013 13:23:14 +0000 (11:23 -0200)
A generic parser plugin based on libavcoded, initially supporting
mpeg1, mpeg2 and mp3.

configure.ac
src/plugins/Makefile.am
src/plugins/generic/generic.c [new file with mode: 0644]

index 9483a59..635f141 100644 (file)
@@ -95,6 +95,12 @@ define([CHECK_MODULE_FLAC],
         AC_LMS_CHECK_PKG(FLAC, flac, [], [FLAC=false])
 ])
 
+AM_CONDITIONAL(HAVE_GENERIC, false)
+define([CHECK_MODULE_GENERIC],
+[
+        AC_LMS_CHECK_PKG(GENERIC, [libavcodec libavformat], [], [GENERIC=false])
+])
+
 # plugins declarations
 AC_LMS_OPTIONAL_MODULE([dummy], true)
 AC_LMS_OPTIONAL_MODULE([jpeg], true)
@@ -110,6 +116,7 @@ AC_LMS_OPTIONAL_MODULE([mp4], true, [CHECK_MODULE_MP4])
 AC_LMS_OPTIONAL_MODULE([id3], true)
 AC_LMS_OPTIONAL_MODULE([flac], true, [CHECK_MODULE_FLAC])
 AC_LMS_OPTIONAL_MODULE([wave], true)
+AC_LMS_OPTIONAL_MODULE([generic], true, [CHECK_MODULE_GENERIC])
 
 
 AC_ARG_ENABLE([daemon],
index d7c94ab..956ec8f 100644 (file)
@@ -113,4 +113,10 @@ wave_wave_la_SOURCES = wave/wave.c
 wave_wave_la_LIBADD = $(PLUGINS_LIBADD) $(FLAC_LIBS)
 endif
 
+if USE_MODULE_GENERIC
+pkg_LTLIBRARIES += generic/generic.la
+generic_generic_la_SOURCES = generic/generic.c
+generic_generic_la_LIBADD = $(PLUGINS_LIBADD) $(GENERIC_LIBS)
+endif
+
 CLEAN_FILES = $(BUILT_SOURCES)
diff --git a/src/plugins/generic/generic.c b/src/plugins/generic/generic.c
new file mode 100644 (file)
index 0000000..99221d5
--- /dev/null
@@ -0,0 +1,1098 @@
+/**
+ * Copyright (C) 2013 by Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * @author Leandro Dorileo <leandro.maciel.dorileo@intel.com>
+ */
+
+#include <libavformat/avformat.h>
+#include <libavutil/dict.h>
+#include "libavutil/opt.h"
+
+#include <lightmediascanner_db.h>
+#include <lightmediascanner_plugin.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static const char _name[] = "generic";
+
+static const struct lms_string_size _exts[] = {
+    LMS_STATIC_STRING_SIZE(".mpeg"),
+    LMS_STATIC_STRING_SIZE(".mpg"),
+    LMS_STATIC_STRING_SIZE(".mpeg2"),
+    LMS_STATIC_STRING_SIZE(".mp2"),
+    LMS_STATIC_STRING_SIZE(".mp3"),
+    LMS_STATIC_STRING_SIZE(".m3u"),
+};
+
+static const char *_cats[] = {
+    "multimedia",
+    "audio",
+    "video",
+    NULL
+};
+
+static const char *_authors[] = {
+    "Leandro Dorileo",
+    NULL
+};
+
+struct plugin {
+    struct lms_plugin plugin;
+    lms_db_audio_t *audio_db;
+    lms_db_video_t *video_db;
+};
+
+struct mpeg_info {
+    struct lms_string_size title;
+    struct lms_string_size artist;
+    struct lms_string_size album;
+    struct lms_string_size genre;
+};
+
+#define DECL_STR(cname, str)                                            \
+  static const struct lms_string_size cname = LMS_STATIC_STRING_SIZE(str) \
+
+#define DLNA_VIDEO_RES(_width, _height)                                 \
+    &(struct dlna_video_res) {.width = _width, .height = _height}       \
+
+#define DLNA_VIDEO_RES_RANGE(_wmin, _wmax, _hmin, _hmax)                \
+    &(struct dlna_video_res_range) {.width_min = _wmin,                 \
+            .width_max = _wmax, .height_min = _hmin,                    \
+            .height_max = _hmax}                                        \
+
+#define DLNA_BITRATE(_min, _max)                            \
+    &(struct dlna_bitrate) {.min = _min, .max = _max}       \
+
+#define DLNA_LEVEL(_val...)                            \
+  &(struct dlna_level) {.levels = {_val, NULL}}                \
+
+#define DLNA_PROFILE(_val...)                              \
+  &(struct dlna_profile) {.profiles = {_val, NULL}}        \
+
+#define DLNA_AUDIO_RATE(_val...)                               \
+  &(struct dlna_audio_rate) {.rates = {_val, INT32_MAX}}       \
+
+#define DLNA_VIDEO_PIXEL_ASPECT(_val...)                               \
+  &(struct dlna_video_pixel_aspect) {                                  \
+    .pixel_aspect_ratio = {_val, NULL}}                                        \
+
+#define DLNA_VIDEO_FRAMERATE(_val...)                                  \
+  &(struct dlna_video_framerate) {.framerate = {_val, INT32_MAX}}      \
+
+#define DLNA_VIDEO_PACKETSIZE(_packet_size)                            \
+  &(struct dlna_video_packet_size) {.packet_size = _packet_size}       \
+
+#define MAX_AUDIO_MPEG_VERSIONS 2
+#define MAX_AUDIO_RATES 9
+#define MAX_AUDIO_LEVELS 5
+#define MAX_VIDEO_RULE_LEVEL 12
+#define MAX_VIDEO_RULE_PROFILE 3
+#define MAX_VIDEO_RULE_FRAMERATE 7
+#define MAX_VIDEO_PIXEL_ASPECT 3
+
+struct dlna_bitrate {
+     const unsigned int min;
+     const unsigned int max;
+};
+
+struct dlna_video_res {
+     const unsigned int width;
+     const unsigned int height;
+};
+
+struct dlna_video_res_range {
+    const unsigned int width_min;
+    const unsigned int width_max;
+    const unsigned int height_min;
+    const unsigned int height_max;
+};
+
+struct dlna_level {
+     const char *levels[MAX_VIDEO_RULE_LEVEL];
+};
+
+struct dlna_profile {
+     const char *profiles[MAX_VIDEO_RULE_PROFILE];
+};
+
+struct dlna_video_framerate {
+     const double framerate[MAX_VIDEO_RULE_FRAMERATE];
+};
+
+struct dlna_video_pixel_aspect {
+     const char *pixel_aspect_ratio[MAX_VIDEO_PIXEL_ASPECT];
+};
+
+struct dlna_video_rule {
+     const struct dlna_video_res *res;
+     const struct dlna_video_res_range *res_range;
+     const struct dlna_bitrate *bitrate;
+     const struct dlna_profile *profiles;
+     const struct dlna_level *levels;
+     const struct dlna_video_framerate *framerate;
+     const struct dlna_video_pixel_aspect *pixel_aspect;
+};
+
+struct dlna_audio_rate {
+     const unsigned int rates[MAX_AUDIO_RATES];
+};
+
+struct dlna_audio_rule {
+     const struct lms_string_size *codec;
+     const struct lms_string_size *container;
+     const struct dlna_audio_rate *rates;
+     const struct dlna_level *levels;
+     const struct dlna_bitrate *channels;
+     const struct dlna_bitrate *bitrate;
+};
+
+struct dlna_video_packet_size {
+     const int64_t packet_size;
+};
+
+struct dlna_video_profile {
+     const struct lms_string_size *dlna_profile;
+     const struct lms_string_size *dlna_mime;
+     const struct dlna_video_rule *video_rules;
+     const struct dlna_audio_rule *audio_rule;
+     const struct lms_string_size *container;
+     const struct dlna_video_packet_size *packet_size;
+};
+
+struct dlna_audio_profile {
+     const struct lms_string_size *dlna_profile;
+     const struct lms_string_size *dlna_mime;
+     const struct dlna_audio_rule *audio_rule;
+};
+
+DECL_STR(_dlna_profile_mpeg_ts_sd_eu_iso, "MPEG_TS_SD_EU_ISO");
+DECL_STR(_dlna_profile_mpeg_ts_sd_eu, "MPEG_TS_SD_EU");
+DECL_STR(_dlna_profile_mpeg_ts_hd_na_iso, "MPEG_TS_HD_NA_ISO");
+DECL_STR(_dlna_profile_mpeg_ts_hd_na, "MPEG_TS_HD_NA");
+DECL_STR(_dlna_profile_mpeg_ts_sd_na_iso, "MPEG_TS_SD_NA_ISO");
+DECL_STR(_dlna_profile_mpeg_ts_sd_na, "MPEG_TS_SD_NA");
+DECL_STR(_dlna_profile_mpeg_ps_pal, "MPEG_PS_PAL");
+DECL_STR(_dlna_profile_mpeg_ps_ntsc, "MPEG_PS_NTSC");
+DECL_STR(_dlna_profile_mpeg1, "MPEG1");
+DECL_STR(_dlna_profile_mp3, "MP3");
+DECL_STR(_dlna_profile_mp3x, "MP3X");
+
+DECL_STR(_dlna_mime_audio, "audio/mpeg");
+DECL_STR(_dlna_mime_video, "video/mpeg");
+DECL_STR(_dlna_mim_video_tts, "video/vnd.dlna.mpeg-tts");
+
+DECL_STR(_container_mpegts, "mpegts");
+DECL_STR(_container_mpeg, "mpeg");
+DECL_STR(_container_mp3, "mp3");
+
+static const struct dlna_video_rule _dlna_video_rule_mpeg_ps_pal[] = {
+    {
+        .res = DLNA_VIDEO_RES(720, 576),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main"),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("64:45", "16:15"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(704, 576),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main"),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("64:45", "16:15"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(544, 576),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main"),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("32:17", "24:17"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(480, 576),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main"),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("32:15", "8:5"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 576),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main"),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("32:11", "24:11"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 288),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main"),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("16:11", "12:11"),
+    },
+    { NULL },
+};
+
+static const struct dlna_video_rule _dlna_video_rule_mpeg1[] = {
+    {
+        .res = DLNA_VIDEO_RES(352, 288),
+        .bitrate = DLNA_BITRATE(1150000, 1152000),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 240),
+        .bitrate = DLNA_BITRATE(1150000, 1152000),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 240),
+        .bitrate = DLNA_BITRATE(1150000, 1152000),
+        .framerate = DLNA_VIDEO_FRAMERATE(24000/1001),
+    },
+    {
+        .bitrate = DLNA_BITRATE(1150000, 1152000),
+    },
+    { NULL },
+};
+
+static const struct dlna_video_rule _dlna_video_rule_mpeg_ps_ntsc[] = {
+    {
+        .res = DLNA_VIDEO_RES(720, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("32:27", "8:9"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(704, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .framerate = DLNA_VIDEO_FRAMERATE(24000/1001, 24/1, 30000/1001, 30/1,
+                    60000/1001, 60/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("40:33", "10:11"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(480, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("16:9", "4:3"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(544, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("80:51", "20:17"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("80:33", "20:11"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 240),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .bitrate = DLNA_BITRATE(1, 9800000),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("16:11", "12:11"),
+    },
+    { NULL },
+};
+
+static const struct dlna_video_rule _dlna_video_rule_mpeg_ts_sd_na[] = {
+    {
+        .res = DLNA_VIDEO_RES(720, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("32:27", "8:9"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(704, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(24000/1001, 24/1, 30000/1001, 30/1,
+                                          60000/1001, 60/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("40:33", "10:11"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(640, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(24000/1001, 24/1, 30000/1001, 30/1,
+                                          60000/1001, 60/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("1:1", "4:3"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(480, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("16:9", "4:3"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(544, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("80:51", "20:17"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 480),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("80:33", "20:11"),
+    },
+    { NULL },
+};
+
+static const struct dlna_video_rule _dlna_video_rule_mpeg_ts_hd_na[] = {
+    {
+        .res = DLNA_VIDEO_RES(1920, 1080),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001, 30/1, 24000/1001, 24/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("1:1", "9:16"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(1280, 720),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001, 30/1, 24000/1001, 24/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("1:1", "9:16"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(1080, 1440),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001, 30/1, 24000/1001, 24/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("4:3"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(1080, 1280),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(30000/1001, 30/1, 24000/1001, 24/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("3:2"),
+    },
+    { NULL },
+};
+
+static const struct dlna_video_rule _dlna_video_rule_mpeg_ts_sd_eu[] = {
+    {
+        .res = DLNA_VIDEO_RES(720, 576),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("64:45", "16:15"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(544, 576),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("32:17", "24:17"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(480, 576),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("32:15", "8:15"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 576),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("32:11", "24:11"),
+    },
+    {
+        .res = DLNA_VIDEO_RES(352, 288),
+        .profiles = DLNA_PROFILE("simple", "main"),
+        .levels = DLNA_LEVEL("low", "main", "high-1440", "high"),
+        .bitrate = DLNA_BITRATE(1, 18881700),
+        .framerate = DLNA_VIDEO_FRAMERATE(25/1),
+        .pixel_aspect = DLNA_VIDEO_PIXEL_ASPECT("16:11", "12:11"),
+    },
+    { NULL },
+};
+
+static const struct dlna_audio_rule _dlna_audio_rule_mpeg_ps = {
+    .rates = DLNA_AUDIO_RATE(48000),
+};
+
+static const struct dlna_audio_rule _dlna_audio_rule_mpeg1 = {
+    .bitrate = DLNA_BITRATE(224000, 224000),
+    .channels = DLNA_BITRATE(2, 2),
+    .rates = DLNA_AUDIO_RATE(44100),
+};
+
+static const struct dlna_audio_rule _dlna_audio_rule_mpeg_ts_sd_hd_na = {
+    .bitrate = DLNA_BITRATE(1, 448000),
+    .channels = DLNA_BITRATE(1, 6),
+    .rates = DLNA_AUDIO_RATE(48000),
+};
+
+static const struct dlna_audio_rule _dlna_audio_rule_mpeg_ts_sd_eu = {
+     .bitrate = DLNA_BITRATE(1, 448000),
+     .channels = DLNA_BITRATE(1, 6),
+     .rates = DLNA_AUDIO_RATE(32000, 44100, 48000),
+};
+
+static const  struct dlna_video_profile _dlna_video_profile_rules[] = {
+    {
+        .dlna_profile = &_dlna_profile_mpeg_ps_pal,
+        .dlna_mime = &_dlna_mime_video,
+        .video_rules = _dlna_video_rule_mpeg_ps_pal,
+        .audio_rule = &_dlna_audio_rule_mpeg_ps,
+        .container = &_container_mpeg,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mpeg1,
+        .dlna_mime = &_dlna_mime_video,
+        .video_rules = _dlna_video_rule_mpeg1,
+        .audio_rule = &_dlna_audio_rule_mpeg1,
+        .container = &_container_mpeg,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mpeg_ps_ntsc,
+        .dlna_mime = &_dlna_mime_video,
+        .video_rules = _dlna_video_rule_mpeg_ps_ntsc,
+        .audio_rule = &_dlna_audio_rule_mpeg_ps,
+        .container = &_container_mpeg,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mpeg_ts_sd_na,
+        .dlna_mime = &_dlna_mim_video_tts,
+        .video_rules = _dlna_video_rule_mpeg_ts_sd_na,
+        .audio_rule = &_dlna_audio_rule_mpeg_ts_sd_hd_na,
+        .packet_size = DLNA_VIDEO_PACKETSIZE(192),
+        .container = &_container_mpegts,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mpeg_ts_sd_na_iso,
+        .dlna_mime = &_dlna_mime_video,
+        .video_rules = _dlna_video_rule_mpeg_ts_sd_na,
+        .audio_rule = &_dlna_audio_rule_mpeg_ts_sd_hd_na,
+        .packet_size = DLNA_VIDEO_PACKETSIZE(188),
+        .container = &_container_mpegts,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mpeg_ts_hd_na,
+        .dlna_mime = &_dlna_mim_video_tts,
+        .video_rules = _dlna_video_rule_mpeg_ts_hd_na,
+        .audio_rule = &_dlna_audio_rule_mpeg_ts_sd_hd_na,
+        .packet_size = DLNA_VIDEO_PACKETSIZE(192),
+        .container = &_container_mpegts,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mpeg_ts_hd_na_iso,
+        .dlna_mime = &_dlna_mime_video,
+        .video_rules = _dlna_video_rule_mpeg_ts_hd_na,
+        .audio_rule = &_dlna_audio_rule_mpeg_ts_sd_hd_na,
+        .packet_size = DLNA_VIDEO_PACKETSIZE(188),
+        .container = &_container_mpegts,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mpeg_ts_sd_eu,
+        .dlna_mime = &_dlna_mim_video_tts,
+        .video_rules = _dlna_video_rule_mpeg_ts_sd_eu,
+        .audio_rule = &_dlna_audio_rule_mpeg_ts_sd_eu,
+        .packet_size = DLNA_VIDEO_PACKETSIZE(192),
+        .container = &_container_mpegts,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mpeg_ts_sd_eu_iso,
+        .dlna_mime = &_dlna_mime_video,
+        .video_rules = _dlna_video_rule_mpeg_ts_sd_eu,
+        .audio_rule = &_dlna_audio_rule_mpeg_ts_sd_eu,
+        .packet_size = DLNA_VIDEO_PACKETSIZE(188),
+        .container = &_container_mpegts,
+    },
+};
+
+static const struct dlna_audio_rule _dlna_audio_rule_mp3 = {
+     .container = &_container_mp3,
+     .rates = DLNA_AUDIO_RATE(32000, 44100, 48000),
+     .bitrate = DLNA_BITRATE(320000, 320000),
+     .channels = DLNA_BITRATE(1, 2),
+};
+
+static const struct dlna_audio_rule _dlna_audio_rule_mp3x = {
+     .container = &_container_mp3,
+     .rates = DLNA_AUDIO_RATE(16000, 22050, 24000, 32000, 44100, 48000),
+     .bitrate = DLNA_BITRATE(8000, 320000),
+     .channels = DLNA_BITRATE(1, 2),
+};
+
+static const  struct dlna_audio_profile _dlna_audio_profile_rules[] = {
+    {
+        .dlna_profile = &_dlna_profile_mp3,
+        .dlna_mime = &_dlna_mime_audio,
+        .audio_rule = &_dlna_audio_rule_mp3,
+    },
+    {
+        .dlna_profile = &_dlna_profile_mp3x,
+        .dlna_mime = &_dlna_mime_audio,
+        .audio_rule = &_dlna_audio_rule_mp3x,
+    },
+    {NULL},
+};
+
+static bool
+_uint_vector_has_value(const unsigned int *list, unsigned int wanted)
+{
+    int i;
+    unsigned int curr;
+
+    for (i = 0, curr = list[i]; curr != INT32_MAX; i++, curr = list[i])
+      if (curr == wanted) return true;
+
+    return false;
+}
+
+static bool
+_double_vector_has_value(const double *list, const double wanted)
+{
+    int i;
+    double curr;
+
+    for (i = 0, curr = list[i]; (int)curr != INT32_MAX; i++, curr = list[i]) {
+      if (!(curr < wanted && curr > wanted)) return true;
+    }
+
+    return false;
+}
+
+static bool
+_string_vector_has_value(const char **list, const char *wanted)
+{
+    int i;
+    const char *curr;
+
+    for (i = 0, curr = list[i]; curr != NULL; i++, curr = list[i]) {
+        if (!strcmp(curr, wanted)) return true;
+    }
+
+    return false;
+}
+
+static const struct dlna_video_profile *
+_get_video_dlna_profile(const struct lms_stream_audio_info *audio,
+                        const struct lms_stream *audio_stream,
+                        const struct lms_stream_video_info *video,
+                        const struct lms_stream *video_stream,
+                        int64_t packet_size,
+                        struct lms_string_size *container)
+{
+    int i, length;
+    const struct dlna_video_profile *curr;
+    char *level, *profile, *profile_level;
+
+    profile_level = strstr(video_stream->codec.str, "-p");
+    level = strstr(profile_level, "-l");
+
+    profile = calloc(1, sizeof(char) * (sizeof(level) - 2));
+    strncpy(profile, profile_level, sizeof(level) - 2);
+
+    length = sizeof(_dlna_video_profile_rules) / sizeof(struct dlna_video_profile);
+
+    for (i = 0, curr = &_dlna_video_profile_rules[i]; i < length; i++,
+             curr = &_dlna_video_profile_rules[i]) {
+        const struct dlna_video_rule *video_rule;
+        const struct dlna_audio_rule *audio_rule;
+        const struct dlna_video_rule *r;
+
+        audio_rule = curr->audio_rule;
+        r = curr->video_rules;
+
+        if (curr->container &&
+            strcmp(curr->container->str, container->str))
+            continue;
+
+        if (curr->packet_size &&
+            curr->packet_size->packet_size != packet_size)
+            continue;
+
+        if (audio) {
+
+            if (audio_rule->bitrate &&
+                (audio->bitrate < audio_rule->bitrate->min ||
+                 audio->bitrate > audio_rule->bitrate->max)) {
+                continue;
+            }
+
+            if (audio_rule->rates &&
+                !_uint_vector_has_value(audio_rule->rates->rates,
+                                        audio->sampling_rate))
+                continue;
+
+            if (audio_rule->channels &&
+                (audio->channels < audio_rule->channels->min ||
+                 audio->channels > audio_rule->channels->max))
+                continue;
+        }
+
+        if (audio_stream && audio_rule->codec &&
+            strcmp(audio_stream->codec.str, audio_rule->codec->str))
+            continue;
+
+        while (true) {
+            video_rule = r++;
+
+            if (!video_rule->res && !video_rule->bitrate && !video_rule->levels)
+                break;
+
+            if (video_rule->res && (video->width != video_rule->res->width &&
+                                    video->height != video_rule->res->height))
+                continue;
+
+            if (video_rule->res_range &&
+                !(video->width >= video_rule->res_range->width_min &&
+                  video->width <= video_rule->res_range->width_max &&
+                  video->height >= video_rule->res_range->height_min &&
+                  video->height <= video_rule->res_range->height_max))
+                continue;
+
+            if (video_rule->framerate &&
+                !_double_vector_has_value(video_rule->framerate->framerate,
+                                          video->framerate))
+                continue;
+
+            if (video_rule->pixel_aspect && !_string_vector_has_value
+                ((const char **)video_rule->pixel_aspect->pixel_aspect_ratio,
+                 video->aspect_ratio.str))
+                continue;
+
+            if (video_rule->bitrate &&
+                !(video->bitrate >= video_rule->bitrate->min &&
+                  video->bitrate <= video_rule->bitrate->max))
+                continue;
+
+            if (video_rule->levels &&
+                !_string_vector_has_value
+                ((const char **)video_rule->levels->levels, level + 2))
+                continue;
+
+            if (video_rule->profiles &&
+                !_string_vector_has_value
+                ((const char **)video_rule->profiles->profiles, profile + 2))
+                continue;
+
+            free(profile);
+            return curr;
+        }
+    }
+
+    free(profile);
+    return NULL;
+}
+
+static void
+_fill_video_dlna_profile(struct lms_video_info *info,
+                         int64_t packet_size,
+                         struct lms_string_size *container)
+{
+    const struct dlna_video_profile *profile;
+    const struct lms_stream *s, *audio_stream, *video_stream;
+    const struct lms_stream_audio_info *audio;
+    const struct lms_stream_video_info *video;
+
+    audio_stream = video_stream = NULL;
+    audio = NULL;
+    video = NULL;
+
+    for (s = info->streams; s; s = s->next) {
+        if (s->type == LMS_STREAM_TYPE_VIDEO) {
+            video = &s->video;
+            video_stream = s;
+            if (audio) break;
+        } else if (s->type == LMS_STREAM_TYPE_AUDIO) {
+            audio = &s->audio;
+            audio_stream = s;
+            if (video) break;
+        }
+    }
+
+    profile = _get_video_dlna_profile(audio, audio_stream, video,
+                                      video_stream, packet_size, container);
+    if (!profile) return;
+
+    info->dlna_profile = *profile->dlna_profile;
+    info->dlna_mime = *profile->dlna_mime;
+}
+
+static void
+_fill_audio_dlna_profile(struct lms_audio_info *info)
+{
+    int i = 0;
+
+    while (true) {
+      const struct dlna_audio_profile *curr = _dlna_audio_profile_rules + i;
+      const struct dlna_audio_rule *rule;
+
+      if (curr->dlna_profile == NULL && curr->dlna_mime == NULL &&
+          curr->audio_rule == NULL)
+        break;
+
+      i++;
+      rule = curr->audio_rule;
+
+      if (rule->bitrate && info->bitrate &&
+         (info->bitrate < rule->bitrate->min ||
+          info->bitrate > rule->bitrate->max))
+        continue;
+
+      if (rule->rates &&
+          !_uint_vector_has_value(rule->rates->rates,
+                                  info->sampling_rate))
+          continue;
+
+      if (rule->channels &&
+         (info->channels < rule->channels->min ||
+          info->channels > rule->channels->max))
+        continue;
+
+      if (rule->codec && strcmp(rule->codec->str, info->codec.str))
+        continue;
+
+      if (rule->container && strcmp(rule->container->str, info->container.str))
+        continue;
+
+      info->dlna_mime = *curr->dlna_mime;
+      info->dlna_profile = *curr->dlna_profile;
+      break;
+    }
+}
+
+static void *
+_match(struct plugin *p, const char *path, int len, int base)
+{
+    long i;
+
+    i = lms_which_extension(path, len, _exts, LMS_ARRAY_SIZE(_exts));
+    if (i < 0)
+      return NULL;
+    else
+      return (void*)(i + 1);
+}
+
+static char *
+_get_dict_value(AVDictionary *dict, const char *key)
+{
+    AVDictionaryEntry *tag = NULL;
+    tag = av_dict_get(dict, key, tag, AV_DICT_IGNORE_SUFFIX);
+    if (!tag) return NULL;
+    return tag->value;
+}
+
+static int
+_parse(struct plugin *plugin, struct lms_context *ctxt, const struct lms_file_info *finfo, void *match)
+{
+    int ret;
+    int64_t packet_size = 0;
+    unsigned int i;
+    AVFormatContext *fmt_ctx = NULL;
+    struct mpeg_info info = { };
+    char *metadata;
+    struct lms_audio_info audio_info = { };
+    struct lms_video_info video_info = { };
+    struct lms_string_size container = { };
+    bool video = false;
+
+    if ((ret = avformat_open_input(&fmt_ctx, finfo->path, NULL, NULL)))
+        return ret;
+
+    if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
+    goto fail;
+
+    metadata = _get_dict_value(fmt_ctx->metadata, "title");
+    if (metadata)
+        lms_string_size_strndup(&info.title, metadata, -1);
+
+    metadata = _get_dict_value(fmt_ctx->metadata, "artist");
+    if (metadata)
+        lms_string_size_strndup(&info.artist, metadata, -1);
+
+    metadata = _get_dict_value(fmt_ctx->metadata, "album");
+    if (metadata)
+        lms_string_size_strndup(&info.album, metadata, -1);
+
+    metadata = _get_dict_value(fmt_ctx->metadata, "genre");
+    if (metadata)
+        lms_string_size_strndup(&info.genre, metadata, -1);
+
+    av_opt_get_int(fmt_ctx, "ts_packetsize", AV_OPT_SEARCH_CHILDREN,
+                   &packet_size);
+
+    for (i = 0; i < fmt_ctx->nb_streams; i++) {
+        AVStream *stream = fmt_ctx->streams[i];
+        AVCodec *codec;
+
+        if (stream->codec->codec_id == AV_CODEC_ID_PROBE) {
+            printf("Failed to probe codec for input stream %d\n", stream->index);
+        } else if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
+            printf("Unsupported codec with id %d for input stream %d\n",
+                   stream->codec->codec_id, stream->index);
+        } else {
+            if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+                audio_info.bitrate = stream->codec->bit_rate;
+                audio_info.channels = av_get_channel_layout_nb_channels
+                  (stream->codec->channel_layout);
+                audio_info.sampling_rate = stream->codec->sample_rate;
+            } else if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+                const char *codec_name, *str_profile, *str_level;
+                char buf[256], aspect_ratio[256];
+                const char *language;
+                struct lms_stream *s;
+
+                s = calloc(1, sizeof(*s));
+                s->stream_id = (unsigned int)stream->id;
+
+                language = _get_dict_value(fmt_ctx->metadata, "language");
+                if (metadata)
+                  lms_string_size_strndup(&s->lang, language, -1);
+
+                s->type = LMS_STREAM_TYPE_VIDEO;
+                video = true;
+
+                codec_name = avcodec_get_name(stream->codec->codec_id);
+                if (codec_name) {
+                    str_profile = NULL;
+                    str_level = NULL;
+
+                    switch (stream->codec->profile) {
+                    case 6:
+                        str_profile = "simple";
+                        break;
+                    case 4:
+                        str_profile = "main";
+                        break;
+                    }
+
+                    switch (stream->codec->level) {
+                    case 5:
+                    case 8:
+                        str_level = "main";
+                        break;
+                    case 2:
+                    case 4:
+                        str_level = "high";
+                        break;
+                    case 6:
+                        str_level = "high";
+                        break;
+                    }
+
+                    snprintf(buf, sizeof(buf), "%s-p%s-l%s",
+                             codec_name, str_profile, str_level);
+
+                    lms_string_size_strndup(&s->codec, buf, -1);
+                }
+
+                s->video.bitrate = stream->codec->bit_rate;
+                if (!s->video.bitrate)
+                    s->video.bitrate = stream->codec->rc_max_rate;
+
+                s->video.width = stream->codec->width;
+                s->video.height = stream->codec->height;
+
+
+                if (stream->r_frame_rate.den)
+                    s->video.framerate = stream->r_frame_rate.num /
+                        stream->r_frame_rate.den;
+
+                snprintf(aspect_ratio, sizeof(aspect_ratio), "%d:%d",
+                         stream->codec->sample_aspect_ratio.num,
+                         stream->codec->sample_aspect_ratio.den);
+
+                lms_string_size_strndup(&s->video.aspect_ratio,
+                                        aspect_ratio, -1);
+
+                s->next = video_info.streams;
+                video_info.streams = s;
+            }
+        }
+    }
+
+    lms_string_size_strip_and_free(&info.title);
+    lms_string_size_strip_and_free(&info.artist);
+    lms_string_size_strip_and_free(&info.album);
+    lms_string_size_strip_and_free(&info.genre);
+
+    if (!info.title.str)
+        lms_name_from_path(&info.title, finfo->path, finfo->path_len,
+                           finfo->base, _exts[((long) match) - 1].len,
+                           NULL);
+
+    if (info.title.str)
+        lms_charset_conv(ctxt->cs_conv, &info.title.str, &info.title.len);
+    if (info.artist.str)
+        lms_charset_conv(ctxt->cs_conv, &info.artist.str, &info.artist.len);
+    if (info.album.str)
+      lms_charset_conv(ctxt->cs_conv, &info.album.str, &info.album.len);
+    if (info.genre.str)
+        lms_charset_conv(ctxt->cs_conv, &info.genre.str, &info.genre.len);
+
+
+    lms_string_size_strndup(&container, fmt_ctx->iformat->name, -1);
+
+    if (video) {
+        video_info.id = finfo->id;
+        video_info.title = info.title;
+        video_info.artist = info.artist;
+        video_info.container = container;
+
+        _fill_video_dlna_profile(&video_info, packet_size, &container);
+        ret = lms_db_video_add(plugin->video_db, &video_info);
+    } else {
+        audio_info.id = finfo->id;
+        audio_info.title = info.title;
+        audio_info.artist = info.artist;
+        audio_info.album = info.album;
+        audio_info.genre = info.genre;
+        audio_info.container = container;
+
+        _fill_audio_dlna_profile(&audio_info);
+        ret = lms_db_audio_add(plugin->audio_db, &audio_info);
+    }
+
+    free(info.title.str);
+    free(info.artist.str);
+    free(info.album.str);
+    free(info.genre.str);
+    free(container.str);
+
+    while (video_info.streams) {
+        struct lms_stream *s = video_info.streams;
+        video_info.streams = s->next;
+        free(s->codec.str);
+        if (s->type == LMS_STREAM_TYPE_VIDEO) {
+            free(s->video.aspect_ratio.str);
+        }
+        free(s->lang.str);
+        free(s);
+    }
+
+ fail:
+    avformat_close_input(&fmt_ctx);
+    return ret;
+}
+
+static int
+_close(struct plugin *plugin)
+{
+    free(plugin);
+    return 0;
+}
+
+static int
+_setup(struct plugin *plugin,  struct lms_context *ctxt)
+{
+    av_register_all();
+    plugin->audio_db = lms_db_audio_new(ctxt->db);
+    if (!plugin->audio_db)
+        return -1;
+    plugin->video_db = lms_db_video_new(ctxt->db);
+    if (!plugin->video_db)
+        return -1;
+
+    return 0;
+}
+
+static int
+_start(struct plugin *plugin, struct lms_context *ctxt)
+{
+    int r;
+    r = lms_db_audio_start(plugin->audio_db);
+    r |= lms_db_video_start(plugin->video_db);
+    return r;
+}
+
+static int
+_finish(struct plugin *plugin, struct lms_context *ctxt)
+{
+    if (plugin->audio_db)
+        lms_db_audio_free(plugin->audio_db);
+    if (plugin->video_db)
+        lms_db_video_free(plugin->video_db);
+
+    return 0;
+}
+
+API struct lms_plugin *
+lms_plugin_open(void)
+{
+    struct plugin *plugin;
+
+    plugin = (struct plugin *)malloc(sizeof(*plugin));
+    plugin->plugin.name = _name;
+    plugin->plugin.match = (lms_plugin_match_fn_t)_match;
+    plugin->plugin.parse = (lms_plugin_parse_fn_t)_parse;
+    plugin->plugin.close = (lms_plugin_close_fn_t)_close;
+    plugin->plugin.setup = (lms_plugin_setup_fn_t)_setup;
+    plugin->plugin.start = (lms_plugin_start_fn_t)_start;
+    plugin->plugin.finish = (lms_plugin_finish_fn_t)_finish;
+    plugin->plugin.order = INT32_MAX;
+
+    return (struct lms_plugin *)plugin;
+}
+
+API const struct lms_plugin_info *
+lms_plugin_info(void)
+{
+    static struct lms_plugin_info info = {
+        _name,
+        _cats,
+        "libavcodec",
+        PACKAGE_VERSION,
+        _authors,
+        "http://github.com/profusion/lightmediascanner"
+    };
+
+    return &info;
+}