2

I want to upload a video file and get the first frame(or maybe specified frame) as thumbnail in my ASP.NET MVC project.

Controller:

[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
   // How to get the video file frames(or first frame) here
   // or Microsoft Azure Blob Storage provide the service to do this?
   // (I upload file to Microsoft Azure Blob)
}
Max
  • 4,439
  • 2
  • 18
  • 32
  • check this post: https://stackoverflow.com/questions/23232056/grabbing-a-thumbnail-from-a-video-when-uploading-azure-blob-storage – Thomas Mar 27 '18 at 08:05

2 Answers2

2

Per my understanding, you could use the wrapper VideoFileReader utilizing FFmpeg library to read video files. Here is the example from the official documentation:

// create instance of video reader
VideoFileReader reader = new VideoFileReader();
// open video file
reader.Open("test.avi");
// check some of its attributes
Console.WriteLine("width:  " + reader.Width);
Console.WriteLine("height: " + reader.Height);
Console.WriteLine("fps:    " + reader.FrameRate);
Console.WriteLine("codec:  " + reader.CodecName);
// read 100 video frames out of it
for(int i = 0; i < 100; i++)
{
    Bitmap videoFrame = reader.ReadVideoFrame();
    // process the frame somehow
    // ...

    // dispose the frame when it is no longer required
    videoFrame.Dispose();
}
reader.Close();

Note: You may need to copy FFmpeg binaries (DLLs) into your web application. For the AForge.Video.FFMPEG package, you could follow here or this similar issue.

Back to your scenario, you may need to temporarily store HttpPostedFileBase.InputStream into a temp file, then use this temp file to initialize the VideoFileReader instance.

For uploading file(s) to Azure Blob storage, you could leverage UploadFromFile or UploadFromStream,etc. Detailed tutorials, you could follow here.


UPDATE:

I checked AForge.Video.FFMPEG and found it could not work anymore. Per my test, you could install the Accord.Video.FFMPEG package which origins from the AForge.NET Framework and is part of the Accord.NET Framework to handle video. You just need to change the referenced namespace, and here is my test code on a console application:

using Accord.Video.FFMPEG;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleFfmpeg
{
    class Program
    {
        static void Main(string[] args)
        {
            // create instance of video reader
            VideoFileReader reader = new VideoFileReader();
            // open video file
            reader.Open(AppDomain.CurrentDomain.BaseDirectory+ @"Videos\FlickAnimation.avi");
            // check some of its attributes
            Console.WriteLine("width:  " + reader.Width);
            Console.WriteLine("height: " + reader.Height);
            Console.WriteLine("fps:    " + reader.FrameRate);
            Console.WriteLine("codec:  " + reader.CodecName);
            //read video frames
            for (int i = 0; i < reader.FrameCount; i++)
            {
                Bitmap videoFrame = reader.ReadVideoFrame();
                // process the frame somehow
                videoFrame.Save(AppDomain.CurrentDomain.BaseDirectory + $"Videos\\{i}.bmp");
                // dispose the frame when it is no longer required
                videoFrame.Dispose();
            }
            reader.Close();
            Console.ReadLine();
        }
    }
}

RESULT:

enter image description here

Bruce Chen
  • 18,207
  • 2
  • 21
  • 35
0

For Getting Snapshot, I have used FFmpeg tool.

It is a Console App for demo same logic can be used for Web as well.

public class Ffmpeg
{
    Process _ffmpeg;

    private void Exec(string input, string output, string duration)
    {
        _ffmpeg = new Process();

        _ffmpeg.StartInfo.Arguments = $"-ss {duration} -i {input} -vframes 1 {output}";

        // Path of Exe which will be in folder Q:\\ConsoleVideo\\ConsoleVideo\\utils\\ffmpeg.exe
        _ffmpeg.StartInfo.FileName = "Q:\\ConsoleVideo\\ConsoleVideo\\utils\\ffmpeg.exe";
        _ffmpeg.StartInfo.UseShellExecute = false;
        _ffmpeg.StartInfo.RedirectStandardOutput = true;
        _ffmpeg.StartInfo.RedirectStandardError = true;
        _ffmpeg.StartInfo.CreateNoWindow = true;          
        _ffmpeg.Start();
        _ffmpeg.WaitForExit();
        _ffmpeg.Close();
    }

    public void GetThumbnail(string video, string jpg, string duration)
    {
        Exec(video, jpg, duration);  //hh:mm:ss.fff
    }
}


class Program
{
    static void Main(string[] args)
    {
        Ffmpeg f = new Ffmpeg();
        // GetThumbnail ("Video Input Path" , "Image OutPut Path" , "Time Frame of Snapshot" ) [hh:mm:ss.fff]
        f.GetThumbnail("Q:\\ConsoleVideo\\ConsoleVideo\\videos\\Wildlife.wmv", "C:\\Users\\1438\\Downloads\\thumb.jpg", "00:00:25.000");
    }
}

Project Structure

Project Structure

FFmpeg exe which are stored in utils folder can be downloaded from here.

pavelsaman
  • 7,399
  • 1
  • 14
  • 32
Saineshwar Bageri - MVP
  • 3,851
  • 7
  • 41
  • 47
  • Could I get the frame to the MemoryStream, not save as file? I tried $"-ss {duration} -i {input} -vframes 1 -f {extension} pipe:" Reference: https://stackoverflow.com/questions/19634749/can-i-use-ffmpeg-to-output-jpegs-to-a-memory-stream-instead-of-a-file But the output stream colud not use. – Max Mar 27 '18 at 09:58
  • @gary it will get snap from a video according to time you have passed to it, does not return MemoryStream – Saineshwar Bageri - MVP Mar 27 '18 at 10:01
  • So..., if I want to upload the snap(thumbnail) to azure blob storage, I must to save to the web server first, then read the file to upload? – Max Mar 27 '18 at 10:12
  • @gary right you need to store on the server gets thumbnail then get the base64string format of the thumbnail and push where you want to store. – Saineshwar Bageri - MVP Mar 27 '18 at 10:31