--- Makefile.am.orig	2017-05-18 05:55:17.000000000 +0900
+++ Makefile.am	2017-05-26 13:51:55.519612115 +0900
@@ -53,7 +53,7 @@
 	@LIBEXIF_LIBS@ \
 	@LIBINTL@ \
 	@LIBICONV@ \
-	-lFLAC $(flacogglibs) $(vorbislibs) $(avahilibs)
+	-lFLAC $(flacogglibs) $(vorbislibs) $(avahilibs) @LIBFFMPEGTHUMBNAILER_LIBS@
 
 minidlnad_LDFLAGS = @STATIC_LDFLAGS@
 
--- albumart.c.orig	2017-05-18 05:55:17.000000000 +0900
+++ albumart.c	2017-05-26 14:03:52.661089877 +0900
@@ -32,6 +32,10 @@
 
 #include <jpeglib.h>
 
+#ifdef THUMBNAIL_CREATION
+#include <libffmpegthumbnailer/videothumbnailerc.h>
+#endif
+
 #include "upnpglobalvars.h"
 #include "albumart.h"
 #include "sql.h"
@@ -348,14 +352,68 @@
 	return NULL;
 }
 
+#ifdef THUMBNAIL_CREATION
+char *
+generate_thumbnail(const char * path)
+{
+       char *tfile = NULL;
+       video_thumbnailer *vt = NULL;
+       char cache_dir[MAXPATHLEN];
+
+       if( art_cache_exists(path, &tfile) )
+               return tfile;
+
+       if ( is_video(path) )
+       {
+
+               vt = video_thumbnailer_create();
+               if ( !vt )
+               {
+                       free(tfile);
+                       return 0;
+               }
+               vt->thumbnail_image_type = Jpeg;
+               vt->thumbnail_image_quality = runtime_vars.thumb_quality;
+               vt->thumbnail_size = runtime_vars.thumb_width;
+               vt->seek_percentage = 20;
+               vt->overlay_film_strip = (GETFLAG(THUMB_FILMSTRIP))?1:0;
+
+               DPRINTF(E_DEBUG, L_METADATA, "generating thumbnail: %s\n", path);
+
+               strncpyt(cache_dir, tfile, sizeof(cache_dir));
+               if ( !make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) &&
+                       !video_thumbnailer_generate_thumbnail_to_file(vt, path, tfile) )
+               {
+                       video_thumbnailer_destroy(vt);
+                       return tfile;
+               }
+
+               video_thumbnailer_destroy(vt);
+       }
+       free(tfile);
+
+       return 0;
+}
+#endif
+
 int64_t
 find_album_art(const char *path, uint8_t *image_data, int image_size)
 {
 	char *album_art = NULL;
 	int64_t ret = 0;
 
-	if( (image_size && (album_art = check_embedded_art(path, image_data, image_size))) ||
-	    (album_art = check_for_album_file(path)) )
+	if(image_size)
+               album_art = check_embedded_art(path, image_data, image_size);
+
+	if(!album_art)
+               album_art = check_for_album_file(path);
+
+#ifdef THUMBNAIL_CREATION
+	if(!album_art && GETFLAG(THUMB_MASK))
+               album_art = generate_thumbnail(path);
+#endif
+
+	if(album_art)
 	{
 		ret = sql_get_int_field(db, "SELECT ID from ALBUM_ART where PATH = '%q'", album_art);
 		if( !ret )
--- configure.ac.orig	2017-05-18 05:55:17.000000000 +0900
+++ configure.ac	2017-05-26 14:08:49.528778727 +0900
@@ -617,6 +617,21 @@
         ]
 )
 
+AC_ARG_ENABLE(thumbnail,
+       [  --enable-thumbnail      enable video thumbnail generation using libffmpegthumbnailer],[
+       if test "$enableval" = "yes"; then
+               AC_DEFINE([THUMBNAIL_CREATION],[1],[Define to 1 if you want to enable video thumbnail generation])
+               PKG_CHECK_MODULES([LIBFFMPEGTHUMBNAILER], libffmpegthumbnailer, ,
+                       AC_MSG_ERROR([Unable to find libffmpegthumbnailer]))
+               AC_SUBST([LIBFFMPEGTHUMBNAILER_CFLAGS])
+               AC_SUBST([LIBFFMPEGTHUMBNAILER_LIBS])
+       else
+               AC_MSG_RESULT([no])
+       fi
+       ],[
+               AC_MSG_RESULT([no])
+       ]
+)
 
 case "$target_os" in
 	darwin*)
--- minidlna.c.orig	2017-05-18 05:55:17.000000000 +0900
+++ minidlna.c	2017-05-26 14:48:58.925667651 +0900
@@ -539,6 +539,11 @@
 	runtime_vars.root_container = NULL;
 	runtime_vars.ifaces[0] = NULL;
 
+#ifdef THUMBNAIL_CREATION
+       runtime_vars.thumb_width = 160;
+       runtime_vars.thumb_quality = 8;
+#endif
+
 	/* read options file first since
 	 * command line arguments have final say */
 	if (readoptionsfile(optionsfile) < 0)
@@ -752,6 +757,30 @@
 			if (strcasecmp(ary_options[i].value, "beacon") == 0)
 				CLEARFLAG(TIVO_BONJOUR_MASK);
 			break;
+#ifdef THUMBNAIL_CREATION
+               case ENABLE_THUMB:
+                       if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) )
+                               SETFLAG(THUMB_MASK);
+                       break;
+               case THUMB_WIDTH:
+                       runtime_vars.thumb_width = atoi(ary_options[i].value);
+                       if (runtime_vars.thumb_width < 120)
+                               runtime_vars.thumb_width = 120;
+                       if (runtime_vars.thumb_width > 480)
+                               runtime_vars.thumb_width = 480;
+                       break;
+               case THUMB_QUALITY:
+                       runtime_vars.thumb_quality = atoi(ary_options[i].value);
+                       if (runtime_vars.thumb_quality < 5)
+                               runtime_vars.thumb_quality = 5;
+                       if (runtime_vars.thumb_quality > 30)
+                               runtime_vars.thumb_quality = 30;
+                       break;
+               case ENABLE_THUMB_FILMSTRIP:
+                       if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) )
+                               SETFLAG(THUMB_FILMSTRIP);
+                       break;
+#endif
 		default:
 			DPRINTF(E_ERROR, L_GENERAL, "Unknown option in file %s\n",
 				optionsfile);
--- minidlna.conf.orig	2017-05-18 05:55:17.000000000 +0900
+++ minidlna.conf	2017-05-26 14:52:57.185771270 +0900
@@ -88,3 +88,15 @@
 
 # set this to yes to allow symlinks that point outside user-defined media_dirs.
 #wide_links=no
+
+# Suport to Movie Thumbnail generation. To use this option, thumbnail generation must be enable at compile time.
+#enable_thumbnail=no
+
+# The width of the thumbnail image. Large images takes more time to generate.  To use this option, thumbnail generation must be enable at compile time.
+#thumbnail_width=160
+
+# Thumbnail Image quality. To use this option, thumbnail generation must be enable at compile time.
+#thumbnail_quality=8
+
+# Should the thumbnail have a film strip? To use this option, thumbnail generation must be enable at compile time.
+#enable_thumbnail_filmstrip=no
--- options.c.orig	2017-05-18 05:55:17.000000000 +0900
+++ options.c	2017-05-26 14:56:38.408012333 +0900
@@ -64,7 +64,15 @@
 	{ USER_ACCOUNT, "user" },
 	{ FORCE_SORT_CRITERIA, "force_sort_criteria" },
 	{ MAX_CONNECTIONS, "max_connections" },
+#ifndef THUMBNAIL_CREATION
 	{ MERGE_MEDIA_DIRS, "merge_media_dirs" },
+#else
+       { MERGE_MEDIA_DIRS, "merge_media_dirs" },
+       { ENABLE_THUMB, "enable_thumbnail" },
+       { THUMB_WIDTH, "thumbnail_width" },
+       { THUMB_QUALITY, "thumbnail_quality" },
+       { ENABLE_THUMB_FILMSTRIP, "enable_thumbnail_filmstrip" },
+#endif
 	{ WIDE_LINKS, "wide_links" },
 	{ TIVO_DISCOVERY, "tivo_discovery" },
 };
--- options.h.orig	2017-05-18 05:55:17.000000000 +0900
+++ options.h	2017-05-26 15:07:15.637791194 +0900
@@ -57,7 +57,15 @@
 	USER_ACCOUNT,			/* user account to run as */
 	FORCE_SORT_CRITERIA,		/* force sorting by a given sort criteria */
 	MAX_CONNECTIONS,		/* maximum number of simultaneous connections */
+#ifndef THUMBNAIL_CREATION
 	MERGE_MEDIA_DIRS,		/* don't add an extra directory level when there are multiple media dirs */
+#else
+	MERGE_MEDIA_DIRS,               /* don't add an extra directory level when there are multiple media dirs */
+	ENABLE_THUMB,                   /* enable thumbnail generation */
+	THUMB_WIDTH,                    /* thunbnail image with */
+	THUMB_QUALITY,                  /* thumnail image quality */
+	ENABLE_THUMB_FILMSTRIP,         /* film strip overlay */
+#endif
 	WIDE_LINKS,			/* allow following symlinks outside the defined media_dirs */
 	TIVO_DISCOVERY,			/* TiVo discovery protocol: bonjour or beacon. Defaults to bonjour if supported */
 };
--- upnpglobalvars.h.orig	2017-05-18 05:55:17.000000000 +0900
+++ upnpglobalvars.h	2017-05-26 15:12:44.457010482 +0900
@@ -196,6 +196,11 @@
 #define SCANNING_MASK         0x0100
 #define RESCAN_MASK           0x0200
 
+#ifdef THUMBNAIL_CREATION
+#define THUMB_MASK            0x0100
+#define THUMB_FILMSTRIP       0x0200
+#endif
+
 #define SETFLAG(mask)	runtime_flags |= mask
 #define GETFLAG(mask)	(runtime_flags & mask)
 #define CLEARFLAG(mask)	runtime_flags &= ~mask
--- utils.h.orig	2017-05-18 05:55:17.000000000 +0900
+++ utils.h	2017-05-26 15:18:47.939957870 +0900
@@ -101,4 +101,8 @@
 int make_dir(char * path, mode_t mode);
 unsigned int DJBHash(uint8_t *data, int len);
 
+#ifdef THUMBNAIL_CREATION
+int rename_artcache_dir(const char * oldpath, const char * newpath);
+#endif
+
 #endif
--- minidlnatypes.h.orig	2017-05-18 05:55:17.000000000 +0900
+++ minidlnatypes.h	2017-05-26 15:25:08.389784656 +0900
@@ -51,6 +51,10 @@
 	int max_connections;	/* max number of simultaneous conenctions */
 	const char *root_container;	/* root ObjectID (instead of "0") */
 	const char *ifaces[MAX_LAN_ADDR];	/* list of configured network interfaces */
+#ifdef THUMBNAIL_CREATION
+       int thumb_width;
+       int thumb_quality;
+#endif
 };
 
 struct string_s {
--- monitor.c.orig	2017-05-18 05:55:17.000000000 +0900
+++ monitor.c	2017-05-26 16:28:48.306100398 +0900
@@ -322,6 +322,16 @@
 		sql_exec(db, "DELETE from OBJECTS where DETAIL_ID = %lld", detailID);
 	}
 	snprintf(art_cache, sizeof(art_cache), "%s/art_cache%s", db_path, path);
+
+#ifdef THUMBNAIL_CREATION
+       /* Remove video thumbnails */
+       if ( is_video(path) )
+       {
+               char *vthumb = art_cache;
+               strcpy(strchr(vthumb, '\0')-4, ".jpg");
+       }
+#endif
+
 	remove(art_cache);
 
 	return 0;
@@ -616,6 +626,11 @@
 	sigdelset(&set, SIGCHLD);
 	pthread_sigmask(SIG_BLOCK, &set, NULL);
 
+#ifdef THUMBNAIL_CREATION
+       char renpath_buf[PATH_MAX];
+       int cookie = 0;
+#endif
+
 	pollfds[0].fd = inotify_init();
 	pollfds[0].events = POLLIN;
 
@@ -685,6 +700,18 @@
 				{
 					DPRINTF(E_DEBUG, L_INOTIFY,  "The directory %s was %s.\n",
 						path_buf, (event->mask & IN_MOVED_TO ? "moved here" : "created"));
+
+#ifdef THUMBNAIL_CREATION
+                                       /* We do not want to regenerate the thumbnails if e rename a directory.
+                                          We should keep at least four cookies/olddir since IN_MOVED_FROM/IN_MOVED_TO may
+                                          not arrive in sequence, but one should cover most cases */
+                                       if (event->cookie == cookie && event->mask & IN_MOVED_TO)
+                                       {
+                                               DPRINTF(E_DEBUG, L_INOTIFY, "Directory rename: %s -> %s \n", renpath_buf, path_buf);
+                                               rename_artcache_dir(renpath_buf, path_buf);
+                                       }
+#endif
+
 					monitor_insert_directory(pollfds[0].fd, esc_name, path_buf);
 				}
 				else if ( (event->mask & (IN_CLOSE_WRITE|IN_MOVED_TO|IN_CREATE)) &&
@@ -717,7 +744,22 @@
 						(event->mask & IN_ISDIR ? "directory" : "file"),
 						path_buf, (event->mask & IN_MOVED_FROM ? "moved away" : "deleted"));
 					if ( event->mask & IN_ISDIR )
+
+#ifdef THUMBNAIL_CREATION
+                                        {
+                                               if ( event->mask & IN_MOVED_FROM )
+                                               {
+                                                       strncpy(renpath_buf, path_buf, sizeof(renpath_buf));
+                                                       cookie = event->cookie;
+                                               }
+#endif
+
 						monitor_remove_directory(pollfds[0].fd, path_buf);
+
+#ifdef THUMBNAIL_CREATION
+                                        }
+#endif
+
 					else
 						monitor_remove_file(path_buf);
 				}
--- utils.c.orig	2017-08-25 02:28:25.000000000 +0900
+++ utils.c	2017-09-15 04:00:57.174194577 +0900
@@ -531,3 +531,17 @@
 
 	return ALL_MEDIA;
 }
+
+#ifdef THUMBNAIL_CREATION
+int
+rename_artcache_dir(const char * oldpath, const char * newpath)
+{
+       char old_artcache[PATH_MAX];
+       char new_artcache[PATH_MAX];
+
+       snprintf(old_artcache, sizeof(old_artcache), "%s/art_cache%s", db_path, oldpath);
+       snprintf(new_artcache, sizeof(old_artcache), "%s/art_cache%s", db_path, newpath);
+
+       return rename(old_artcache, new_artcache);
+}
+#endif
