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

如何在Azure上用C#结合FFmpeg实现WebJob视频压缩处理?

Implementing MP4 Compression & Trimming in Azure WebJob with FFmpeg.stable.GZCR

Got it, let's break down how to build your VideoCompressor WebJob to handle automatic MP4 compression and trimming using the FFmpeg.stable.GZCR NuGet package—no manual FFmpeg updates needed, just clean, integrated code.

1. Install the FFmpeg.stable.GZCR NuGet Package

First, add the package to your Azure WebJob project (this embeds FFmpeg binaries directly, so you don't have to manage external downloads or updates):

  • In Visual Studio, right-click your project > Manage NuGet Packages
  • Search for FFmpeg.stable.GZCR and install the latest stable version
  • Alternatively, run this in the Package Manager Console:
    Install-Package FFmpeg.stable.GZCR
    

2. Set Up the Queue Trigger Function

Create a queue-triggered function that listens for new video notifications. We'll assume your queue messages contain the SAS URL of the source MP4 blob (adjust if you're using local file paths). Here's the basic structure:

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.IO;
using Azure.Storage.Blobs;

public class VideoCompressor
{
    private readonly BlobServiceClient _blobServiceClient;

    // Inject BlobServiceClient (configure via appsettings.json for Azure Blob Storage)
    public VideoCompressor(BlobServiceClient blobServiceClient)
    {
        _blobServiceClient = blobServiceClient;
    }

    [FunctionName("VideoCompressor")]
    public void Run(
        [QueueTrigger("video-compression-queue")] string videoBlobSasUrl,
        ILogger log)
    {
        log.LogInformation($"Starting compression for video: {videoBlobSasUrl}");

        // Create temp directory to store source/compressed files
        var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
        Directory.CreateDirectory(tempDir);
        var sourcePath = Path.Combine(tempDir, "source.mp4");
        var outputPath = Path.Combine(tempDir, "compressed.mp4");

        try
        {
            // Download source blob to local temp file
            var sourceBlob = new BlobClient(new Uri(videoBlobSasUrl));
            sourceBlob.DownloadTo(sourcePath);

            // Run FFmpeg compression and trimming logic
            RunFfmpegProcessing(sourcePath, outputPath, log);

            // Upload compressed video back to storage (adjust destination as needed)
            var destBlobSasUrl = /* Your destination blob SAS URL or construct via BlobClient */;
            var destBlob = new BlobClient(new Uri(destBlobSasUrl));
            destBlob.Upload(outputPath, overwrite: true);

            log.LogInformation($"Successfully processed video: {outputPath}");
        }
        catch (Exception ex)
        {
            log.LogError(ex, $"Failed to process video: {videoBlobSasUrl}");
            throw; // Re-throw to trigger queue retry (configure via host.json)
        }
        finally
        {
            // Clean up temp files to avoid disk bloat
            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, recursive: true);
            }
        }
    }
}

3. Core FFmpeg Command Implementation

The RunFfmpegProcessing method executes the FFmpeg command that handles both scaling and trimming. Here's how to build it:

private void RunFfmpegProcessing(string sourcePath, string outputPath, ILogger log)
{
    // Get path to the embedded FFmpeg executable from the NuGet package
    var ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tools", "ffmpeg.exe");

    // Build FFmpeg arguments to meet your requirements:
    // - Scale to max 200px (preserve aspect ratio, no upscaling)
    // - Trim to first 2 minutes (120 seconds)
    // - Use efficient H.264/AAC encoding for MP4
    var arguments = $"-i \"{sourcePath}\" " +
                    $"-vf \"scale=min(200\\,iw):min(200\\,ih):force_original_aspect_ratio=decrease\" " +
                    $"-t 120 " +
                    $"-c:v libx264 -crf 23 -preset medium " +
                    $"-c:a aac -b:a 128k " +
                    $"-y \"{outputPath}\"";

    log.LogInformation($"Executing FFmpeg command: {ffmpegPath} {arguments}");

    // Configure and run the FFmpeg process
    var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = ffmpegPath,
            Arguments = arguments,
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            CreateNoWindow = true
        },
        EnableRaisingEvents = true
    };

    // Capture FFmpeg output for debugging
    process.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) log.LogInformation(e.Data); };
    process.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) log.LogWarning(e.Data); };

    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    process.WaitForExit();

    if (process.ExitCode != 0)
    {
        throw new InvalidOperationException($"FFmpeg failed with exit code {process.ExitCode}");
    }
}

Key FFmpeg Arguments Explained:

  • -vf "scale=min(200\,iw):min(200\,ih):force_original_aspect_ratio=decrease": Scales the video so the largest dimension (width/height) is at most 200px, preserving original aspect ratio. It won't upscale small videos.
  • -t 120: Trims the video to the first 120 seconds (2 minutes). To trim from a specific start time, use -ss [start-time] -t 120 (e.g., -ss 60 -t 120 for 2 minutes starting at 1 minute).
  • -c:v libx264 -crf 23: Uses H.264 codec with a Constant Rate Factor of 23— a balanced setting for quality vs file size (lower CRF = better quality, larger file).
  • -c:a aac -b:a 128k: Encodes audio with AAC at 128kbps, standard for MP4 compatibility.
  • -y: Overwrites the output file if it exists, ideal for temporary files.

4. Important Configuration & Best Practices

  • Queue Retry Policy: Configure retry logic in host.json to handle transient failures:
    {
        "version": "2.0",
        "extensions": {
            "queues": {
                "maxDequeueCount": 5,
                "visibilityTimeout": "00:05:00"
            }
        }
    }
    
  • Temp Storage: Always clean up temp files in the finally block to avoid filling Azure WebJob disk space.
  • Logging: Use the built-in ILogger to track success/failure—this integrates with Azure Monitor for easy debugging.
  • Blob Permissions: Ensure your WebJob's managed identity or connection string has read access to source blobs and write access to destination blobs.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:36:23