You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET MVC项目中上传视频并提取帧/首帧作为缩略图的实现方案

视频上传并提取缩略图(ASP.NET MVC + Azure Blob)

嗨,我来帮你搞定这个需求!你有两个主要方向可以选:要么在本地服务器先提取视频帧,再把视频和缩略图一起传到Azure Blob;要么借助Azure的媒体服务自动处理,不用自己在服务器上折腾视频编码。下面给你详细讲两种方案:

方法一:本地提取视频帧后上传到Azure Blob

Azure Blob Storage本身不直接支持视频帧提取,所以得先在你的MVC项目里处理好缩略图,再上传。这里推荐用MediaToolkit(封装了FFmpeg,用起来很省心):

步骤1:安装依赖

先在NuGet包管理器里安装MediaToolkit:

Install-Package MediaToolkit

或者用.NET CLI:

dotnet add package MediaToolkit

步骤2:修改Controller代码

在你的Upload方法里,先保存上传的视频临时文件,然后提取第一帧,最后把视频和缩略图都传到Azure Blob:

using MediaToolkit;
using MediaToolkit.Model;
using Azure.Storage.Blobs;
using System.IO;

[HttpPost]
public async Task<ActionResult> Upload(HttpPostedFileBase file)
{
    if (file == null || file.ContentLength == 0)
    {
        return RedirectToAction("Index", "Home");
    }

    // 临时文件路径(记得用完要删除)
    var tempVideoPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + Path.GetExtension(file.FileName));
    var tempThumbPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".jpg");

    try
    {
        // 1. 保存上传的视频到临时文件
        file.SaveAs(tempVideoPath);

        // 2. 提取视频第一帧作为缩略图
        var inputFile = new MediaFile { Filename = tempVideoPath };
        var outputFile = new MediaFile { Filename = tempThumbPath };

        using (var engine = new Engine())
        {
            // 提取第一帧(如果要指定帧,可以调整Seek参数,比如TimeSpan.FromSeconds(5))
            engine.GetThumbnail(inputFile, outputFile, TimeSpan.FromSeconds(0));
        }

        // 3. 上传视频和缩略图到Azure Blob
        var connectionString = "你的Azure Blob连接字符串";
        var containerName = "视频存储容器名";

        var blobServiceClient = new BlobServiceClient(connectionString);
        var containerClient = blobServiceClient.GetBlobContainerClient(containerName);

        // 上传视频
        var videoBlobName = $"videos/{Guid.NewGuid()}{Path.GetExtension(file.FileName)}";
        using (var videoStream = new FileStream(tempVideoPath, FileMode.Open))
        {
            await containerClient.UploadBlobAsync(videoBlobName, videoStream);
        }

        // 上传缩略图
        var thumbBlobName = $"thumbnails/{Path.GetFileNameWithoutExtension(videoBlobName)}.jpg";
        using (var thumbStream = new FileStream(tempThumbPath, FileMode.Open))
        {
            await containerClient.UploadBlobAsync(thumbBlobName, thumbStream);
        }

        // 这里可以返回缩略图URL或者成功提示
        return Content($"上传成功!视频Blob:{videoBlobName},缩略图Blob:{thumbBlobName}");
    }
    catch (Exception ex)
    {
        // 处理异常,比如日志记录
        return Content($"上传失败:{ex.Message}");
    }
    finally
    {
        // 清理临时文件
        if (System.IO.File.Exists(tempVideoPath))
        {
            System.IO.File.Delete(tempVideoPath);
        }
        if (System.IO.File.Exists(tempThumbPath))
        {
            System.IO.File.Delete(tempThumbPath);
        }
    }
}

方法二:用Azure Media Services自动生成缩略图

如果不想在自己的服务器上处理视频编码(比如担心性能、FFmpeg环境配置),可以用Azure Media Services——它专门做媒体处理,能自动帮你生成缩略图、转码等。

核心流程:

  1. 把上传的视频直接传到Azure Blob(或者Media Services的资产容器)
  2. 在Media Services里创建一个转码作业,配置缩略图生成规则(比如第一帧、每隔N秒生成一帧)
  3. 作业完成后,Media Services会把生成的缩略图存到指定的Blob容器里

简化代码示例(需要先配置Media Services账户):

using Azure.ResourceManager.Media;
using Azure.ResourceManager.Media.Models;
using Azure.Storage.Blobs;

[HttpPost]
public async Task<ActionResult> Upload(HttpPostedFileBase file)
{
    if (file == null || file.ContentLength == 0)
    {
        return RedirectToAction("Index");
    }

    // 1. 先把视频传到Azure Blob的临时容器
    var tempContainerName = "temp-uploads";
    var blobServiceClient = new BlobServiceClient("你的Blob连接字符串");
    var tempContainerClient = blobServiceClient.GetBlobContainerClient(tempContainerName);
    await tempContainerClient.CreateIfNotExistsAsync();

    var tempBlobName = Guid.NewGuid() + Path.GetExtension(file.FileName);
    using (var stream = file.InputStream)
    {
        await tempContainerClient.UploadBlobAsync(tempBlobName, stream);
    }

    // 2. 配置Media Services客户端
    var mediaServicesClient = new MediaServicesClient("你的Azure订阅ID", new DefaultAzureCredential());
    mediaServicesClient.AccountName = "你的Media Services账户名";
    mediaServicesClient.ResourceGroupName = "资源组名";

    // 3. 创建媒体资产,关联刚才上传的Blob
    var asset = await mediaServicesClient.Assets.CreateOrUpdateAsync(
        "资源组名",
        "你的Media Services账户名",
        "视频资产名",
        new Asset { StorageAccountName = "你的存储账户名" });

    // 4. 把Blob里的视频导入资产(具体逻辑可参考Media Services SDK官方文档)
    // 省略导入细节,核心是将临时Blob的内容复制到Media Services资产容器

    // 5. 创建转码作业,配置缩略图生成
    var transformName = "GenerateThumbnailTransform";
    // 先检查Transform是否存在,不存在则创建
    var transform = await mediaServicesClient.Transforms.GetIfExistsAsync("资源组名", "账户名", transformName);
    if (!transform.HasValue)
    {
        var output = new TransformOutput(
            new StandardEncoderPreset(
                codecs: new CodecBase[]
                {
                    new JpgImage(
                        start: "PT0S", // 从第0秒开始(第一帧)
                        step: "PT1H", // 只生成一帧
                        range: "PT0S",
                        layers: new JpgLayer[] { new JpgLayer(quality: 80, width: "1920", height: "1080") }
                    )
                },
                formats: new Format[] { new JpgFormat(new JpgFormatFilenamePattern("thumbnail-{Index}.jpg")) }
            ));

        transform = await mediaServicesClient.Transforms.CreateOrUpdateAsync("资源组名", "账户名", transformName, new Transform { Outputs = { output } });
    }

    // 6. 提交作业
    var jobName = $"GenerateThumbnailJob-{Guid.NewGuid()}";
    var jobInput = new JobInputAsset(assetName: asset.Name);
    var jobOutput = new JobOutputAsset(assetName: $"thumbnail-output-{Guid.NewGuid()}");
    var job = await mediaServicesClient.Jobs.CreateAsync("资源组名", "账户名", transformName, jobName, new Job { Input = jobInput, Outputs = { jobOutput } });

    // 7. 等待作业完成(生产环境建议用WebHook或者定时轮询)
    // 省略等待逻辑,作业完成后可从输出资产中获取缩略图的Blob URL

    return Content("作业已提交,稍后可以获取缩略图!");
}

注意事项:

  • 方法一中,如果你直接用原生FFmpeg而非MediaToolkit,需要把FFmpeg可执行文件放到项目中,并在初始化Engine时指定路径(比如new Engine(@"C:\ffmpeg\bin"))
  • 方法二中,Media Services会产生额外成本,但省去了自己维护视频编码环境的麻烦
  • 不管哪种方法,都要确保服务器有读写临时文件的权限,Azure Blob容器的权限配置正确(比如允许上传操作)

内容的提问来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:18:40