如何将图像叠加在视频上

How to put an image overlay over video

我想在视频上叠加图像,但我不确定该怎么做。我正在尝试修改此存储库 Azure 媒体服务 v3 .NET Core 教程中的示例 ,基本上我这里改的是transform:

private static Transform EnsureTransformForOverlayExists(IAzureMediaServicesClient client, string resourceGroupName, string accountName, string transformNameNew)
{
    Console.WriteLine(transformNameNew);

    Transform transform = client.Transforms.Get(resourceGroupName, accountName, transformName);

    if (transform == null)
    {
        TransformOutput[] outputs = new TransformOutput[]
        {
                    new TransformOutput(
  new StandardEncoderPreset(
    codecs: new Codec[]
    {
      new AacAudio(
        channels: 2,
        samplingRate: 48000,
        bitrate: 128000,
        profile: AacAudioProfile.AacLc
      ),
      new H264Video(stretchMode: "AutoFit",
        keyFrameInterval: TimeSpan.FromSeconds(2),
        layers: new[]
        {
          new H264Layer(
            bitrate: 1500000,
            maxBitrate: 1500000,
            width: "640",
            height: "360"
          )
        }
      ),
      new PngImage(
          start: "25%",
          step: "25%",
          range: "80%",
          layers: new PngLayer[]{
              new PngLayer(
                  width: "50%",
                  height: "50%"
              )
          }
      ),
    },
    filters: new Filters
    {
        Overlays = new List<Overlay>
        {
            new VideoOverlay("input1")
        }
    },
    formats: new Format[]
    {
      new Mp4Format(
        filenamePattern: "{Basename}_letterbox{Extension}"
      ),
      new PngFormat(
        filenamePattern: "{Basename}_{Index}_{Label}_{Extension}"
      ),
    }
  ))
        };

        transform = client.Transforms.CreateOrUpdate(resourceGroupName, accountName, transformName, outputs);
    }

    return transform;
}

RunAsync方法提供多个输入,其中一个应该是覆盖:

private static async Task RunAsync(ConfigWrapper config)
{

    IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(config);
    // Set the polling interval for long running operations to 2 seconds.
    // The default value is 30 seconds for the .NET client SDK
    client.LongRunningOperationRetryTimeout = 2;

    try
    {

        // Ensure that you have customized encoding Transform.  This is really a one time setup operation.
        Transform overlayTransform = EnsureTransformForOverlayExists(client, config.ResourceGroup, config.AccountName, transformName);

        // Creating a unique suffix so that we don't have name collisions if you run the sample
        // multiple times without cleaning up.
        string uniqueness = Guid.NewGuid().ToString().Substring(0, 13);

        string jobName = "job-" + uniqueness;
        string inputAssetName = "input-" + uniqueness;
        string outputAssetName = "output-" + uniqueness;


        Asset asset = client.Assets.CreateOrUpdate(config.ResourceGroup, config.AccountName, inputAssetName, new Asset());

        var inputs = new JobInputs(new List<JobInput>());

        var input = new JobInputHttp(
                            baseUri: "https://nimbuscdn-nimbuspm.streaming.mediaservices.windows.net/2b533311-b215-4409-80af-529c3e853622/",
                            files: new List<String> {"Ignite-short.mp4"},
                            label:"input1"
                            );
        
        inputs.Inputs.Add((input));

        input = new JobInputHttp(
            baseUri: "SomeBaseUriHere",
            files: new List<string> {"AssetVideo_000001_None_.png"}, 
            label: "overlay");

        inputs.Inputs.Add((input));

        Asset outputAsset = CreateOutputAsset(client, config.ResourceGroup, config.AccountName, outputAssetName);

        Job job = SubmitJob(client, config.ResourceGroup, config.AccountName, transformName, jobName, inputs, outputAsset.Name);

        DateTime startedTime = DateTime.Now;

        job = WaitForJobToFinish(client, config.ResourceGroup, config.AccountName, transformName, jobName);

        TimeSpan elapsed = DateTime.Now - startedTime;

        if (job.State == JobState.Finished)
        {
            Console.WriteLine("Job finished.");
            if (!Directory.Exists(outputFolder))
                Directory.CreateDirectory(outputFolder);
            await MakeContainerPublic(client, config.ResourceGroup, config.AccountName, outputAsset.Name, config.BlobConnectionString);
            DownloadResults(client, config.ResourceGroup, config.AccountName, outputAsset.Name, outputFolder).Wait();
        }
        else if (job.State == JobState.Error)
        {
            Console.WriteLine($"ERROR: Job finished with error message: {job.Outputs[0].Error.Message}");
            Console.WriteLine($"ERROR:                   error details: {job.Outputs[0].Error.Details[0].Message}");
        }
    }
    catch(ApiErrorException ex)
    {
        string code = ex.Body.Error.Code;
        string message = ex.Body.Error.Message;

        Console.WriteLine("ERROR:API call failed with error code: {0} and message: {1}", code, message);

    }          
}

但是我有这个错误

Microsoft.Cloud.Media.Encoding.PresetException: Preset ERROR: There are 2 input assets. Preset has 2 Source but does NOT specify AssetID for each Source and I have no idea how to overcome this.

目前无法使用 v3 API 创建叠加层。该功能未完全实现。有关 v2 和 v3 API 之间的其他差距,请参阅 this link

详情请看this site.