Exporting thumbnail files from videos using c#

Saving thumbnails

Sometimes you need a video thumbnail for use outside of Fast video cataloger. You can easily just right click the thumbnail and select “save as”. This is fast and easy if its a single thumbnail you want to save but it will be very time consuming if you want to save all thubmnails for a video, or for several videos.

This is a good example of where the scripting support in Fast video cataloger can help, and it is really easy.

Exporting thumbnails from C# script

This example shows how to export out all thumbnails for the currently selected videos as files.

For each video we create a foder called thumbnails in the same folder as the video file. Then we get all the thumbnails for the selected video by calling GetThumbnailsForVideo(video_id, true );
we get all the thumbnails and only need to go through them all, generate a filename and call System.IO.File.WriteAllBytes(filename, image_data);
to write out the image to file.

using System;
using System.IO;
using System.Collections.Generic;
using VideoCataloger;
using VideoCataloger.RemoteCatalogService;

class ExportThumbnails
{
    static public void Run(IScripting scripting, string arguments)
    {
        scripting.GetConsole().Clear();

        var service = scripting.GetVideoCatalogService();
        ISelection selection = scripting.GetSelection();
        List selected = selection.GetSelectedVideos();
        foreach (long video_id in selected)
        {
            var video_file_entry = service.GetVideoFileEntry(video_id);
            string target_folder = video_file_entry.FilePath; 
            int path_end = target_folder.LastIndexOf('\\');
            target_folder = target_folder.Substring(0, path_end+1);
            target_folder += "Thumbnails\\";
            try
            {
                DirectoryInfo info = Directory.CreateDirectory(target_folder);
            }
            catch (Exception ex)
            {
                scripting.GetConsole().WriteLine( ex.Message );
            }

            long image_no = 1;
            Dictionary thumbnails = service.GetThumbnailsForVideo(video_id, true );
            foreach (KeyValuePair thumbnail_entry in thumbnails )
            {
                byte[] image_data = thumbnail_entry.Value.Image;

                string filename = target_folder + image_no.ToString() + ".jpg";
                scripting.GetConsole().WriteLine("Saving image to : " + filename);
                System.IO.File.WriteAllBytes(filename, image_data);
                image_no++;
            }
        }
    }
}

Import videos from All My Movies by BoildeSoft

All my movies

All My Movies by Boildesoft ( https://www.bolidesoft.com/allmymovies.html ) is a software that lets you manage your collection of bought movies. It downloads movie data from the imdb database and many other services (http://imdb.com). It also let you track and rate movies you have watched.

If you compare to Fast video cataloger the focus of All my movies is toward collecting movies while Fast video cataloger is geared toward organizing any type of video clips you have on your computer or in your organisation.

Importing videos from All my movies

This sample script shows how to use the scripting support in Fast video cataloger to import data from an All my movies database. The full script is included at the end, simply load the script into the script window in Fast video cataloger and run it.

Database format

All my movies uses an Access database with the extension set as .amm. If you rename the file extension to .mdb you can load it straight into Access and have a closer look at the data. To be able to read the Access database in a program you need to install the Access database engine. Download it from here. Since Fast video cataloger is a 64 bit program make sure you install the 64 bit version of the database engine.

Import videos script

The script to import videos is pretty straight forward. To make it easy to follow I have put it all in the entry function. If you want to expand on this script you should split it up into a number of functions and you should add error handling.

First we show a dialog to let the user pick the All my movies database file to read from:


Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "access"; // Default file name
dlg.DefaultExt = ".mdb"; // Default file extension
dlg.Filter = "mdb file (.mdb)|*.mdb|AllMyMovies file (.amm)|*.amm|All files (.*)|*.*"; // Filter files by extension
Nullable result = dlg.ShowDialog();

We then open the database file and runs a simple SQL query to get everything from the movies table in the database.


OleDbConnection connection = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + dlg.FileName + @";User Id=admin;Password =;");
connection.Open();
OleDbDataReader reader = null;
OleDbCommand command = new OleDbCommand("SELECT * from movies", connection);
reader = command.ExecuteReader();

Next we create some new extended properties for the catalog. Some of the properties in All my movies are not in the list of default video properties. But, since you can add your own properties in Fast video cataloger we will also do that for these properties.


var catalog = scripting.GetVideoCatalogService();
catalog.SetPropertyMeta("video_property", "year", "edit");
catalog.SetPropertyMeta("video_property", "studio", "edit");
catalog.SetPropertyMeta("video_property", "trailer", "edit");
catalog.SetPropertyMeta("video_property", "length", "edit");
catalog.SetPropertyMeta("video_property", "comments", "edit");

Then we read each line of the movie table in the database to create video entries.

while (reader.Read())
{
  string name = reader["Name"].ToString();
  string path = reader["LocalPath"].ToString();
  string description = reader["description"].ToString();
  string url = reader["url"].ToString();
  int video_id = catalog.AddVideo(path, name, 0, description, 0, 0, url, null, 0, null, null);

Once we have the video created we get the id of the newly created video and can use that to set the extended properties.

  string year = reader["year"].ToString();
  catalog.SetVideoFileExtendedProperty(video_id, "year", year);
  string studio = reader["studio"].ToString();
  catalog.SetVideoFileExtendedProperty(video_id, "studio", studio);
  string trailer = reader["trailer"].ToString();
  catalog.SetVideoFileExtendedProperty(video_id, "trailer", trailer);
  string length = reader["length"].ToString();
  catalog.SetVideoFileExtendedProperty(video_id, "length", length);
  string comments = reader["comments"].ToString();
  catalog.SetVideoFileExtendedProperty(video_id, "comments", comments);
}

Finally, we close the Access database and refresh Fast video cataloger to show the imported videos.


connection.Close();
scripting.GetGUI().Refresh("");

Conclusion

It is pretty easy to import data from All my movies into Fast video cataloger. You can use the same techniques to import data from other software, or, your custom solutions into Fast video cataloger. If you have imported a file to the video you can select “reindex” on the videos. Then the program will scan the video file for thumbnails and extended properties.

Below is the full script. You can also find the file in the sample script folder when you downlod Fast video cataloger.

using System.Collections.Generic;
using VideoCataloger;
using Microsoft.Win32;
using System;
using System.IO;

namespace VideoCataloger
{
    using RemoteCatalogService;
    using System.Data.OleDb;

    public class ImportMDB
    {
        static public void Run(IScripting scripting, string argument)
        {
            scripting.GetConsole().Clear();

            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.FileName = "access"; 
            dlg.DefaultExt = ".mdb"; 
            dlg.Filter = "mdb file (.mdb)|*.mdb|AllMyMovies file (.amm)|*.amm|All files (.*)|*.*"; 
            Nullable result = dlg.ShowDialog();
            if (result == true)
            {

                try
                {
                    // https://www.microsoft.com/en-us/download/details.aspx?id=13255
                    // to download the access database runtime of the provider is not installed
                    // note you need the 64 bit version

                    OleDbConnection connection = 
                    new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" 
                    + dlg.FileName + @";User Id=admin;Password =;");
                    connection.Open();
                    OleDbDataReader reader = null;
                    OleDbCommand command = new OleDbCommand("SELECT * from  movies", connection);
                    reader = command.ExecuteReader();

                    // Setup the extended video properties
                    var catalog = scripting.GetVideoCatalogService();
                    catalog.SetPropertyMeta("video_property", "year", "edit");
                    catalog.SetPropertyMeta("video_property", "studio", "edit");
                    catalog.SetPropertyMeta("video_property", "trailer", "edit");
                    catalog.SetPropertyMeta("video_property", "length", "edit");
                    catalog.SetPropertyMeta("video_property", "comments", "edit");

                    while (reader.Read())
                    {
                        string name = reader["Name"].ToString();
                        string path = reader["LocalPath"].ToString();
                        string description = reader["description"].ToString();
                        string url = reader["url"].ToString();

                        int video_id = 
                        catalog.AddVideo(path, name, 0, description, 0, 0, url, null, 0, null, null);

                        string year = reader["year"].ToString();
                        catalog.SetVideoFileExtendedProperty(video_id, "year", year);
                        string studio = reader["studio"].ToString();
                        catalog.SetVideoFileExtendedProperty(video_id, "studio", studio);
                        string trailer = reader["trailer"].ToString();
                        catalog.SetVideoFileExtendedProperty(video_id, "trailer", trailer);
                        string length = reader["length"].ToString();
                        catalog.SetVideoFileExtendedProperty(video_id, "length", length);
                        string comments = reader["comments"].ToString();
                        catalog.SetVideoFileExtendedProperty(video_id, "comments", comments);
                    }

                    connection.Close();
                    scripting.GetGUI().Refresh("");
                }
                catch (Exception ex)
                {
                    scripting.GetConsole().WriteLine( ex.Message );
                }
            }
        }
    }

}

c# for all the really advanced video searches

Extending the video search

The basic idea I show you here is how to write a script in C# that determines if a video matches your search criteria or not and put the matching videos in a custom Bin.

You will learn by a simple step by step example how to write a script that goes through all videos in you catalog and puts all short videos(the critera we have as an example) in a bin.

After you have this skill you can expand your skill and continue to experiment.

About the native video search

Fast video cataloger has a very powerful, fast and simple search engine. The text below show how easy you can extend it even more with advanced custom video search in C#.

Our simple user interface make searching in Fast video cataloger straight forward for everyone. However, we do not provide a SQL interface for search so there are searches you can simply not express given our user interface. With the scripting interface you can do basically anything.

AI For example… What if you want to search with facial recognition or object detection or the next big thing in AI and video?

You an do all this and more by leveraging the scripting capabilities in Fast video cataloger

step by step breakdown on the Video search script in c#

Run(…) in the code below, is the entry function where the execution of the script starts.

    static public void Run(IScripting scripting, string argument)
    {
        FilterToBin instance = new FilterToBin(scripting);
        instance.SetBinTarget("short videos");
        instance.Filter();
        scripting.GetGUI().Refresh("");
    }

I have encapsulated all functionality in a class called “FilterToBin” that has two functions.

SetBinTarget() let you set the name of the Bin that will be used for search results. Please note that this Bin will be cleared every time you run the search.

Filter() does the actual filtering of videos.

    private void Filter()
    {
        var catalog = m_Scripting.GetVideoCatalogService();

        VideoQuery query = new VideoQuery();
        VideoFileEntry[] videos = catalog.SearchVideos(query);

        long bin_id = CreateBin();

        foreach (VideoFileEntry entry in videos)
        {
            if (IsVideoPassingFilter(entry))
                catalog.AddVideoToBin(entry.ID, bin_id);
        }
    }

The Filter() function first does a search to get all videos. In this example we pass in en empty VideoQuery object. That will give us all videos in the catalog. You can of course leverage the search here and first do a high level search to get a subset of your videos and then apply a more advanced search on that subset.

We then call CreateBin() to ensure we have a bin to put our results in. If we look closer in the FilterToBin class the CreateBin member function has some logic to create a Bin if its not already created and clear it from videos if it already exists.

Finally we iterate over all videos and call the IsVideoPassingFilter() function on each video. Videos that pass the test are put in the result Bin.

    private bool IsVideoPassingFilter( VideoFileEntry entry )
    {
        if ( entry.LengthSeconds < 60)
            return true;
        return false;
    }

If you want to change the filter criteria this is the only function you need to edit. In this example we only check if the video length property is smaller than 60s.

To run this script you copy paste it or type it (or load it) into the script window and then click the Run button.

Go the Bin window and select the "short videos" to see the result (if the bin is not there go into the edit bin to refresh the window, this is needed on older versions of Fast video cataloger).

Edit button in bin window

Edit button in bin window

Full source code in C#

using VideoCataloger;
using VideoCataloger.RemoteCatalogService;

public class FilterToBin
{
    IScripting m_Scripting;
    string m_BinLabel;

    FilterToBin(IScripting scripting)
    {
        m_Scripting = scripting;
    }

    private void SetBinTarget(string bin_label)
    {
        m_BinLabel = bin_label;
    }

    private void Filter()
    {
        var catalog = m_Scripting.GetVideoCatalogService();

        VideoQuery query = new VideoQuery();
        VideoFileEntry[] videos = catalog.SearchVideos(query);

        long bin_id = CreateBin();

        foreach (VideoFileEntry entry in videos)
        {
            if (IsVideoPassingFilter(entry))
                catalog.AddVideoToBin(entry.ID, bin_id);
        }
    }

    private bool IsVideoPassingFilter( VideoFileEntry entry )
    {
        if ( entry.LengthSeconds < 60)
            return true;
        return false;
    }

    private long CreateBin()
    {
        var catalog = m_Scripting.GetVideoCatalogService();
        Bin[] all_bins = catalog.GetAllBins();
        foreach (Bin bin in all_bins)
        {
            if (bin.Label == m_BinLabel)
            {
                VideoFileEntry[] videos = catalog.GetVideosInBin(bin.BinID);
                foreach (VideoFileEntry entry in videos)
                {
                    catalog.RemoveVideoFromBin( bin.BinID, entry.ID );
                }

                return bin.BinID;
            }
        }

        Bin target_bin = catalog.CreateBin(m_BinLabel, -1, 0xffffff);
        return target_bin.BinID;
    }

    static public void Run(IScripting scripting, string argument)
    {
        FilterToBin instance = new FilterToBin(scripting);
        instance.SetBinTarget("short videos");
        instance.Filter();
        scripting.GetGUI().Refresh("");
    }
}