42

I want to display thumbnails for videos listed on my site, I want to fetch a single frame from a video (from a particular time) and display them as thumbnails.

I have try this http://ramcrishna.blogspot.com/2008/09/playing-videos-like-youtube-and.html but is not working.

Is that possible using .NET C#?

BogadoDiego
  • 329
  • 3
  • 7
meer
  • 932
  • 1
  • 10
  • 11
  • For anyone who is facing this issue now. Above answers didn't work for me so this is my solution: [I answered in detail regarding this issue.](https://stackoverflow.com/a/63652125/13897029) – Mohammad Subhan Aug 29 '20 at 21:57

5 Answers5

66

FFMpeg is a right tool that can be used to extract video frame at some position. You can invoke ffmpeg.exe as mentioned above or just use existing .NET wrapper (like Video converter for .NET (it's free) to get thumbnail with just one line of code:

var ffMpeg = new NReco.VideoConverter.FFMpegConverter();
ffMpeg.GetVideoThumbnail(pathToVideoFile, thumbJpegStream,5);
Vitaliy Fedorchenko
  • 8,447
  • 3
  • 37
  • 34
  • 1
    how can i use that? I have added "Install-Package NReco.Application.Web" via nuget but can't use that lines of code.. – gsiradze Oct 07 '14 at 14:52
  • 3
    You've installed wrong package. The right one is "Install-Package NReco.VideoConverter" (NReco.Application.Web is about NReco framework for ASP.NET applications). – Vitaliy Fedorchenko Oct 07 '14 at 16:02
  • 1
    for future reference: the performance is very good, 1954 thumbs from a 3.5 gb video file took around 5 minutes on a decent machine. – dvdmn Sep 10 '15 at 19:02
  • I know its very late but it can help someone , yes it can work first of all you need to convert like this ffMpeg.ConvertMedia(pathToVideoFile, "video.mp4", Format.mp4); and then you can simply use it – sohaib javed Aug 29 '16 at 08:26
  • 2
    can it be used to get thumbnail with particular dimensions? As I am getting image but its is in default dimensions i.e. 426x240 and I need 720x360 – sohaib javed Aug 29 '16 at 14:24
  • Api Reference doesn't give any option to reduce frame size. – Akshay Hazari May 08 '17 at 11:24
  • 2
    @AkshayHazari you can use ConvertMedia method for conversion to 1-frame mjpeg output (this is how GetVideoThumbnail actually do). Nevertheless, it is good idea to add extra options to GetVideoThumbnail, thank you for noticing about that. – Vitaliy Fedorchenko May 08 '17 at 13:09
  • Hi Vitaliy, I have been trying to use the method GetVideoThumbnail from my API to work on a Azure resource (i.e. the video file is present in a Azure Blob container and made public), however the same crashes with an error "NReco.VideoConverter.FFMpegException: Error opening filters! (exit code: 1)". Please note the same approach works for converting the Media into an Audio using ConvertMedia. – Sachin Patel Apr 05 '18 at 06:17
  • @SachinPatel "Error opening filters!" usually means that you have incorrect options set for this concrete input; try to test your options with ffmpeg.exe in your dev env (for this Azure Blob URL) – Vitaliy Fedorchenko Apr 05 '18 at 12:07
  • Hi Vitaliy, It seems logical but the mystery is that ConvertMedia function works perfectly for the same resource (azure path is exactly same) – Sachin Patel Apr 09 '18 at 02:13
  • Is this commercial product? – Sameera R. Apr 12 '19 at 04:32
  • 1
    @SameeraR. NReco.VideoConverter (only for .NET Framework) can be used for free in single-deployment/non-SaaS apps. LT-version that is compatible with .NET Core requires a license key. – Vitaliy Fedorchenko Apr 12 '19 at 10:18
  • Is any way to return Image file from video link/file using NReco.VideoConverter? bcoz I don't want to save to local folder. I need to to save this thumbnail into azure storage – kabijoy Aug 09 '19 at 07:22
  • @kabijoy you can use GetVideoThumbnail method that writes output to Stream – Vitaliy Fedorchenko Aug 09 '19 at 07:41
  • Thanks @VitaliyFedorchenko .. Shall i have the sample code? – kabijoy Aug 09 '19 at 07:42
  • Plaese update it var ffMpeg = new NReco.VideoConverter.FFMpegConverter(); ffMpeg.GetVideoThumbnail("VideoURL", "What I give here", 5); – kabijoy Aug 09 '19 at 07:45
  • It doesn't work. – Mr. TA Mar 18 '21 at 11:41
19

You can programmatically execute FFmpeg to generate a thumbnail image file. Then open the image file to use it however you wish.

Here is some sample code:

public static Bitmap GetThumbnail(string video, string thumbnail)
{
    var cmd = "ffmpeg  -itsoffset -1  -i " + '"' + video + '"' + " -vcodec mjpeg -vframes 1 -an -f rawvideo -s 320x240 " + '"' + thumbnail + '"';

    var startInfo = new ProcessStartInfo
    {
        WindowStyle = ProcessWindowStyle.Hidden,
        FileName = "cmd.exe",
        Arguments = "/C " + cmd
    };

    var process = new Process
    {
        StartInfo = startInfo
    };

    process.Start();
    process.WaitForExit(5000);

    return LoadImage(thumbnail);
}

static Bitmap LoadImage(string path)
{
    var ms = new MemoryStream(File.ReadAllBytes(path));
    return (Bitmap)Image.FromStream(ms);
}
markyd13
  • 709
  • 6
  • 15
  • 2
    Why `WaitForExit(5000)` ? – Parimal Raj Mar 29 '13 at 13:23
  • @PaRiMaLRaJ Did you try this code? What do you have to passed on the parameter 'thumbnail' ? I Even created a file with extension .bmp. And passed (C:\Users\Public\Videos\Sample Videos\test1.bmp) to the thumbnail but it gives me an error on the last line of the code = "parameter is not valid" . Can you help me please. Thanks in Advance – CodeEngine Feb 12 '15 at 20:58
  • Will this program run for an application deployed on a server / Remote Virtual Machine. I'm planning to generate the Thumbnail for a video that the user uploads on my website. The bitmap should be generated on the fly. Since this will be running on server, will this method work? This works perfectly on my local machine though. – Aditya Sep 24 '16 at 07:07
  • If you take the `video` or `thumbnail` parameters from an untrusted source (e.g. over the network, or from a form if you're doing this from ASP), an attacker may be able to leverage this code to get code execution on your system. You should, at minimum, run both of those parameters through `Path.GetFullPath()`, and then compare each canonical path to a known-safe base path. If you want to reject UNC paths (e.g. `\\evilserver\foo`) then you should use `Uri.IsUnc` too. – Polynomial Jul 15 '18 at 23:33
  • For those who wonder why WaitForExit(5000), maybe this [Q/A](https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why) helps. Basically it helps to prevent from deadlock. – Weihui Guo Aug 31 '18 at 14:54
15

For people don't want to use FFMpeg as its trouble in Commercial software. I have an old solution here:

ShellFile shellFile = ShellFile.FromFilePath(VideoFileName);
Bitmap bm = shellFile.Thumbnail.Bitmap;

Then you will get a Bitmap object that can be used in drawing. If you want a file, just do:

bm.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);

if you want a BitmapImage that you can use it in Xaml binding. just transfer the Bitmap to BitmapImage. Here is an example:

public static BitmapImage ConvertBitmapToBitmapImage(Bitmap bitmap)
        {
            MemoryStream ms = new MemoryStream();
            bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            ms.Seek(0, SeekOrigin.Begin);
            image.StreamSource = ms;
            image.EndInit();

            return image;
        }
Ken
  • 1,234
  • 10
  • 16
  • 6
    This worked unlike the FFMpeg solution. You do need to install a Nuget package for this (WindowsAPICodePack-Shell). – Mr. TA Mar 18 '21 at 11:41
  • What namespace / package is BitmapImage from? – Chris Jul 07 '22 at 23:16
  • 1
    @Chris BitmapImage is from the [System.Windows.Media.Imaging](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.imaging.bitmapimage) namespace. Look at this [answer for more information](https://stackoverflow.com/a/7308792/7452153) – LiamJM Dec 29 '22 at 14:52
12

Xabe.FFmpeg - free (for non-commercial use), open source and cross-platform library. Provides fluent API to FFmpeg. Generating thumbnail from video in Xabe.F

    string output = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + FileExtensions.Png);
    IConversionResult result = await Conversion.Snapshot(Resources.Mp4WithAudio, output, TimeSpan.FromSeconds(0))
                                               .Start();

It requires FFmpeg executables like in other answer but you can download it by

    FFmpeg.GetLatestVersion();

Full documentation available here - Xabe.FFmpeg Documentation

Sellorio
  • 1,806
  • 1
  • 16
  • 32
viewbevy
  • 239
  • 3
  • 6
-2
 [HttpPost]
        [Route("UploadImages")]
        public HttpResponseMessage Post()
        {
            HttpResponseMessage response = new HttpResponseMessage();
            var httpRequest = HttpContext.Current.Request;
            if (httpRequest.Files.Count > 0)
            {
                var docfiles = new List<string>();
                foreach (string file in httpRequest.Files)
                {
                    var postedFile = httpRequest.Files[file];
                    var filePath1 = HttpContext.Current.Server.MapPath("~/ImgFolder/" + postedFile.FileName);

                    Stream strm = postedFile.InputStream;

                    CreateThumbnail(strm, postedFile.FileName);

                    Compressimage(strm, filePath1, postedFile.FileName);


                }
                response = Request.CreateResponse(HttpStatusCode.Created, docfiles);
            }
            else
            {
                response = Request.CreateResponse(HttpStatusCode.BadRequest);
            }
            return response;
        }
        public static void **CreateThumbnail**(Stream sourcePath, string filename)
        {
            Image image = Image.FromStream(sourcePath);
            Image thumb = image.GetThumbnailImage(120, 120, () => false, IntPtr.Zero);
             var filePath1 = HttpContext.Current.Server.MapPath("~/Thumbnail/" + filename);

             thumb.Save(filePath1 + filename);

        }

        public static void Compressimage(Stream sourcePath, string targetPath, String filename)  
        {  


            try  
            {  
                using (var image = Image.FromStream(sourcePath))  
                {  
                    float maxHeight = 900.0f;  
                    float maxWidth = 900.0f;  
                    int newWidth;  
                    int newHeight;  
                    string extension;  
                    Bitmap originalBMP = new Bitmap(sourcePath);  
                    int originalWidth = originalBMP.Width;  
                    int originalHeight = originalBMP.Height;  

                    if (originalWidth > maxWidth || originalHeight > maxHeight)  
                    {  

                        // To preserve the aspect ratio  
                        float ratioX = (float)maxWidth / (float)originalWidth;  
                        float ratioY = (float)maxHeight / (float)originalHeight;  
                        float ratio = Math.Min(ratioX, ratioY);  
                        newWidth = (int)(originalWidth * ratio);  
                        newHeight = (int)(originalHeight * ratio);  
                    }  
                    else  
                    {  
                        newWidth = (int)originalWidth;  
                        newHeight = (int)originalHeight;  

                    }  
                    Bitmap bitMAP1 = new Bitmap(originalBMP, newWidth, newHeight);  
                    Graphics imgGraph = Graphics.FromImage(bitMAP1);  
                    extension = Path.GetExtension(targetPath);  
                    if (extension == ".png" || extension == ".gif")  
                    {  
                        imgGraph.SmoothingMode = SmoothingMode.AntiAlias;  
                        imgGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;  
                        imgGraph.DrawImage(originalBMP, 0, 0, newWidth, newHeight);  


                        bitMAP1.Save(targetPath, image.RawFormat);  

                        bitMAP1.Dispose();  
                        imgGraph.Dispose();  
                        originalBMP.Dispose();  
                    }  
                    else if (extension == ".jpg")  
                    {  

                        imgGraph.SmoothingMode = SmoothingMode.AntiAlias;  
                        imgGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;  
                        imgGraph.DrawImage(originalBMP, 0, 0, newWidth, newHeight);  
                        ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);  
                        Encoder myEncoder = Encoder.Quality;  
                        EncoderParameters myEncoderParameters = new EncoderParameters(1);  
                        EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);  
                        myEncoderParameters.Param[0] = myEncoderParameter;  
                        bitMAP1.Save(targetPath, jpgEncoder, myEncoderParameters);  

                        bitMAP1.Dispose();  
                        imgGraph.Dispose();  
                        originalBMP.Dispose();  

                    }  


                }  

            }  
            catch (Exception)  
            {  
                throw;  

            }  
        }  


        public static ImageCodecInfo GetEncoder(ImageFormat format)  
        {  

            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();  

            foreach (ImageCodecInfo codec in codecs)  
            {  
                if (codec.FormatID == format.Guid)  
                {  
                    return codec;  
                }  
            }  
            return null;  
        }  
Debendra Dash
  • 5,334
  • 46
  • 38
  • 2
    This is for thumbnail of Image using webapi. – Debendra Dash Aug 10 '16 at 06:24
  • 1
    While this code snippet may solve the question, [including an explanation](//meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, as this reduces the readability of both the code and the explanations! – Blue Aug 17 '16 at 08:53
  • 2
    This is not an answer. The OP wants to get a thumbnail of a **video**. – mbomb007 Sep 20 '16 at 14:53