/// <summary> /// Submits a request to Media Services to apply the specified Transform to a given input video. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="transformName">The name of the transform.</param> /// <param name="jobName">The (unique) name of the job.</param> /// <param name="inputAssetName"></param> /// <param name="outputAssetName">The (unique) name of the output asset that will store the result of the encoding job. </param> // <SubmitJob> private static async Task <Job> SubmitJobAsync(IAzureMediaServicesClient client, string resourceGroupName, string accountName, string transformName, string jobName, string inputAssetName, JobOutput jobOutput) { JobInput jobInput = new JobInputAsset(assetName: inputAssetName); JobOutput[] jobOutputs = { jobOutput }; // In this example, we are assuming that the job name is unique. // // If you already have a job with the desired name, use the Jobs.Get method // to get the existing job. In Media Services v3, Get methods on entities returns ErrorResponseException // if the entity doesn't exist (a case-insensitive check on the name). Job job; try { job = await client.Jobs.CreateAsync( resourceGroupName, accountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, }); } catch (Exception exception) { if (exception.GetBaseException() is ErrorResponseException apiException) { Console.Error.WriteLine( $"ERROR: API call failed with error code '{apiException.Body.Error.Code}' and message '{apiException.Body.Error.Message}'."); } throw; } return(job); }
static void Main(string[] args) { ConfigWrapper config = new ConfigWrapper(); try{ IAzureMediaServicesClient client = CreateMediaServicesClient(config); Transform videoAnalyzerTransform = EnsureTransformExists(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, new VideoAnalyzerPreset("en-US")); // 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 outputAssetName = "output-" + uniqueness; string inputAssetName = "input-" + uniqueness; CreateInputAsset(client, config.ResourceGroup, config.AccountName, inputAssetName, InputMP4FileName); JobInput jobInput = new JobInputAsset(assetName: inputAssetName); Asset outputAsset = client.Assets.CreateOrUpdate(config.ResourceGroup, config.AccountName, outputAssetName, new Asset()); Job job = SubmitJob(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName, jobInput, outputAssetName); job = WaitForJobToFinish(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); if (!Directory.Exists(OutputFolder)) { Directory.CreateDirectory(OutputFolder); } DownloadResults(client, config.ResourceGroup, config.AccountName, outputAssetName, OutputFolder); } } catch (ApiErrorException ex) { Console.WriteLine("{0}", ex.Message); Console.WriteLine("Code: {0}", ex.Body.Error.Code); Console.WriteLine("Message: {0}", ex.Body.Error.Message); } }
/// <summary> /// Indexer のタスクを非同期で実行する。 /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <RunAsync> private static async Task RunAsync(ConfigWrapper config, Stream myBlob) { IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(config); // AMS の Task の完了をポーリングする間隔を設定 // デフォルト値は 30 秒 client.LongRunningOperationRetryTimeout = 2; // 複数回実行してもエラーにならないようにユニークな suffix を生成 // ここは実際にはユーザーの入力など、コントローラブルな変数にしても良い string uniqueness = Guid.NewGuid().ToString("N"); string jobName = $"job-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; string inputAssetName = $"input-{uniqueness}"; // Ensure that you have the desired Transform. This is really a one time setup operation. // // In this Transform, we specify to use the VideoAnalyzerPreset preset. // This preset enables you to extract multiple audio and video insights from a video. // In the example, the language ("en-US") is passed to its constructor. // You can also specify what insights you want to extract by passing InsightsToExtract to the constructor. Transform videoAnalyzerTransform = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, new VideoAnalyzerPreset("ja-JP")); // Create a new input Asset and upload the specified local video file into it. await CreateInputAssetAsync(client, config.ResourceGroup, config.AccountName, inputAssetName, InputMP4FileName, myBlob); // Use the name of the created input asset to create the job input. JobInput jobInput = new JobInputAsset(assetName: inputAssetName); // Output from the encoding Job must be written to an Asset, so let's create one Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName, jobInput, outputAsset.Name); // In this demo code, we will poll for Job status // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); } Console.WriteLine("Indexing Done."); }
private static async Task <Job> SubmitJobAsync(IAzureMediaServicesClient client, string resourceGroupName, string accountName, string transformName, string jobName, string inputAssetName, string outputAssetName) { JobInput jobInput = new JobInputAsset(assetName: inputAssetName); JobOutput[] jobOutputs = { new JobOutputAsset(outputAssetName), }; Job job = await client.Jobs.CreateAsync(resourceGroupName, accountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, }); return(job); }
/// <inheritdoc/> /// <param name="endTime">Mark Out of the encode. If null or empty, will end at, well the end.</param> public async Task CreateJobAsync(string transformName, string inputAssetName, string ouputAssetName, string jobName, TimeBasedEncodeDTO timeBasedEncodeInfo, IDictionary <string, string> correlationData, JObject operationContext) { await ConnectAsync().ConfigureAwait(false); CheckArgumentNotNullOrEmpty(transformName, nameof(transformName)); CheckArgumentNotNullOrEmpty(inputAssetName, nameof(inputAssetName)); CheckArgumentNotNullOrEmpty(ouputAssetName, nameof(ouputAssetName)); CheckArgumentNotNullOrEmpty(jobName, nameof(jobName)); // let's build the input and output objects var jobInput = new JobInputAsset(inputAssetName); var jobOutputs = new[] { new JobOutputAsset(ouputAssetName) }; // process mark in and mark out if provided, null otherwise. if (!(timeBasedEncodeInfo is null)) { if (timeBasedEncodeInfo.StartSeconds < 0) { throw new GridwichTimeParameterException(nameof(timeBasedEncodeInfo.StartSeconds), timeBasedEncodeInfo.StartSeconds, "Must be above zero."); } jobInput.Start = new AbsoluteClipTime(TimeSpan.FromSeconds(timeBasedEncodeInfo.StartSeconds)); if (timeBasedEncodeInfo.EndSeconds < 0) { throw new GridwichTimeParameterException(nameof(timeBasedEncodeInfo.EndSeconds), timeBasedEncodeInfo.EndSeconds, "Must be above zero."); } jobInput.End = new AbsoluteClipTime(TimeSpan.FromSeconds(timeBasedEncodeInfo.EndSeconds)); } // Submit the job: _ = await this.MediaServicesV3SdkWrapper.JobCreateAsync( transformName : transformName, jobName : jobName, parameters : new Job { Input = jobInput, Outputs = jobOutputs, CorrelationData = correlationData, }).ConfigureAwait(false); }
private async void listBoxInput_SelectedIndexChanged(object sender, EventArgs e) { dataGridInput.Rows.Clear(); if (MyJob.Input.GetType() == typeof(JobInputAsset)) { JobInputAsset inputA = MyJob.Input as JobInputAsset; dataGridInput.Rows.Add("Input type", "asset"); dataGridInput.Rows.Add("Asset name", inputA.AssetName); dataGridInput.Rows.Add("Asset type", (await AssetInfo.GetAssetTypeAsync(inputA.AssetName, _amsClient))?.Type); if (inputA.Start != null && inputA.Start.GetType() == typeof(AbsoluteClipTime)) { AbsoluteClipTime startA = inputA.Start as AbsoluteClipTime; dataGridInput.Rows.Add("Absolute Clip Time Start", startA.Time.ToString()); } if (inputA.End != null && inputA.End.GetType() == typeof(AbsoluteClipTime)) { AbsoluteClipTime endA = inputA.End as AbsoluteClipTime; dataGridInput.Rows.Add("Absolute Clip Time End", endA.Time.ToString()); } dataGridInput.Rows.Add("Label", inputA.Label); dataGridInput.Rows.Add("Files", string.Join(Constants.endline, inputA.Files)); } else if (MyJob.Input.GetType() == typeof(JobInputHttp)) { JobInputHttp inputH = MyJob.Input as JobInputHttp; dataGridInput.Rows.Add("Input type", "http"); dataGridInput.Rows.Add("Base Url", inputH.BaseUri); if (inputH.Start != null && inputH.Start.GetType() == typeof(AbsoluteClipTime)) { AbsoluteClipTime startA = inputH.Start as AbsoluteClipTime; dataGridInput.Rows.Add("Absolute Clip Time Start", startA.Time.ToString()); } if (inputH.End != null && inputH.End.GetType() == typeof(AbsoluteClipTime)) { AbsoluteClipTime endA = inputH.End as AbsoluteClipTime; dataGridInput.Rows.Add("Absolute Clip Time End", endA.Time.ToString()); } dataGridInput.Rows.Add("Label", inputH.Label); dataGridInput.Rows.Add("Files", string.Join(Constants.endline, inputH.Files)); } }
private JobInput GetJobInput(MediaJob mediaJob) { JobInput jobInput; if (!string.IsNullOrEmpty(mediaJob.InputFileUrl)) { jobInput = new JobInputHttp() { Files = new string[] { mediaJob.InputFileUrl } }; } else { jobInput = new JobInputAsset() { AssetName = mediaJob.InputAssetName }; } return(jobInput); }
// </CreateMediaServicesClient> private static void Cleanup(IAzureMediaServicesClient client, string resourceGroupName, string accountName, string transformName, string jobName, string outputAssetName, JobInput input, string streamingLocatorName, string contentKeyPolicyName) { client.Jobs.Delete(resourceGroupName, accountName, transformName, jobName); client.Assets.Delete(resourceGroupName, accountName, outputAssetName); JobInputAsset jobInputAsset = input as JobInputAsset; if (jobInputAsset != null) { client.Assets.Delete(resourceGroupName, accountName, jobInputAsset.AssetName); } // Delete the Streaming Locator client.StreamingLocators.Delete(resourceGroupName, accountName, streamingLocatorName); // Stop and delete the StreamingEndpoint - use this if you are creating a custom (non default) endpoint //client.StreamingEndpoints.Stop(resourceGroupName, accountName, endpointName); //client.StreamingEndpoints.Delete(resourceGroupName, accountName, endpointName); client.ContentKeyPolicies.Delete(resourceGroupName, accountName, contentKeyPolicyName); }
private void DisplayAssetInfo(bool input) { string assetName = null; if (input) { if (MyJob.Input.GetType() == typeof(JobInputAsset)) { JobInputAsset inputAsset = MyJob.Input as JobInputAsset; assetName = inputAsset.AssetName; } } else // output { int index = listBoxOutputs.SelectedIndices[0]; if (MyJob.Outputs[index].GetType() == typeof(JobOutputAsset)) { JobOutputAsset outputAsset = MyJob.Outputs[index] as JobOutputAsset; assetName = outputAsset.AssetName; } } if (assetName != null) { _amsClient.RefreshTokenIfNeeded(); Asset asset = Task.Run(() => _amsClient.AMSclient.Assets.GetAsync(_amsClient.credentialsEntry.ResourceGroup, _amsClient.credentialsEntry.AccountName, assetName)) .GetAwaiter().GetResult(); using (AssetInformation form = new AssetInformation(_mainform, _amsClient) { myAssetV3 = asset, myStreamingEndpoints = MyStreamingEndpoints // we want to keep the same sorting }) { DialogResult dialogResult = form.ShowDialog(this); } } }
public async Task <Job> SubmitJobAsync(IAzureMediaServicesClient client, string resourceGroupName, string accountName, string transformName, string jobName, string inputAssetName, string resultName) { // Use the name of the created input asset to create the job input. JobInput jobInput = new JobInputAsset(assetName: inputAssetName); JobOutput[] jobOutputs = { new JobOutputAsset(resultName), }; Job job = await client.Jobs.GetAsync(resourceGroupName, accountName, transformName, jobName); if (job != null) { await client.Jobs.DeleteAsync(resourceGroupName, accountName, transformName, jobName); // buat sinkronisasi await Task.Delay(3000); } job = await client.Jobs.CreateAsync( resourceGroupName, accountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, }); return(job); }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <RunAsync> private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client; try { client = await Authentication.CreateMediaServicesClientAsync(config, UseInteractiveAuth); } catch (Exception e) { Console.Error.WriteLine("TIP: Make sure that you have filled out the appsettings.json file before running this sample."); Console.Error.WriteLine($"{e.Message}"); return; } // 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; // 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("N"); string jobName = $"job-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; string inputAssetName = $"input-{uniqueness}"; // Ensure that you have the desired Transform. This is really a one time setup operation. // // In this Transform, we specify to use the VideoAnalyzerPreset preset. // This preset enables you to extract multiple audio and video insights from a video. // In the example, the language ("en-US") is passed to its constructor. // You can also specify what insights you want to extract by passing InsightsToExtract to the constructor, and which audio mode (standard or basic). _ = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, new VideoAnalyzerPreset("en-US")); // Create a new input Asset and upload the specified local video file into it. await CreateInputAssetAsync(client, config.ResourceGroup, config.AccountName, inputAssetName, InputMP4FileName); // Use the name of the created input asset to create the job input. JobInput jobInput = new JobInputAsset(assetName: inputAssetName); // Output from the encoding Job must be written to an Asset, so let's create one Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); _ = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName, jobInput, outputAsset.Name); // In this demo code, we will poll for Job status // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. Job job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); if (!Directory.Exists(OutputFolderName)) { Directory.CreateDirectory(OutputFolderName); } await DownloadOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, OutputFolderName); } Console.WriteLine("Done."); Console.WriteLine("When finished press enter to cleanup."); Console.Out.Flush(); Console.ReadLine(); Console.WriteLine("Cleaning up..."); await CleanUpAsync(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, job.Name, new List <string> { outputAsset.Name }, null); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { MediaServicesHelpers.LogInformation(log, "C# HTTP trigger function processed a request."); string requestBody = new StreamReader(req.Body).ReadToEnd(); dynamic data = JsonConvert.DeserializeObject(requestBody); // Validate input objects if (data.inputAssetName == null) { return(new BadRequestObjectResult("Please pass inputAssetName in the input object")); } if (data.transformName == null) { return(new BadRequestObjectResult("Please pass transformName in the input object")); } if (data.outputAssetNamePrefix == null) { return(new BadRequestObjectResult("Please pass outputAssetNamePrefix in the input object")); } string inputAssetName = data.inputAssetName; string transformName = data.transformName; string outputAssetNamePrefix = data.outputAssetNamePrefix; string assetStorageAccount = null; if (data.assetStorageAccount != null) { assetStorageAccount = data.assetStorageAccount; } // Azure region management var azureRegions = new List <string>(); if ((string)data.azureRegion != null) { azureRegions = ((string)data.azureRegion).Split(',').ToList(); } else { azureRegions.Add((string)null); } Asset inputAsset = null; string guid = Guid.NewGuid().ToString(); string jobName = "amsv3function-job-" + guid; string encoderOutputAssetName = null; string audioAnalyzerOutputAssetName = null; string videoAnalyzerOutputAssetName = null; JArray outputs = new JArray(); foreach (var region in azureRegions) { ConfigWrapper config = new ConfigWrapper(new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddEnvironmentVariables() .Build(), region ); MediaServicesHelpers.LogInformation(log, "config loaded.", region); MediaServicesHelpers.LogInformation(log, "connecting to AMS account : " + config.AccountName, region); var client = await MediaServicesHelpers.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 { inputAsset = client.Assets.Get(config.ResourceGroup, config.AccountName, inputAssetName); if (inputAsset == null) { return(new BadRequestObjectResult("Asset for input not found")); } Transform transform = client.Transforms.Get(config.ResourceGroup, config.AccountName, transformName); if (transform == null) { return(new BadRequestObjectResult("Transform not found")); } var jobOutputList = new List <JobOutput>(); for (int i = 0; i < transform.Outputs.Count; i++) { Guid assetGuid = Guid.NewGuid(); string outputAssetName = outputAssetNamePrefix + "-" + assetGuid.ToString(); Asset assetParams = new Asset(null, outputAssetName, null, assetGuid, DateTime.Now, DateTime.Now, null, outputAssetName, null, assetStorageAccount, AssetStorageEncryptionFormat.None); Asset outputAsset = client.Assets.CreateOrUpdate(config.ResourceGroup, config.AccountName, outputAssetName, assetParams); jobOutputList.Add(new JobOutputAsset(outputAssetName)); Preset preset = transform.Outputs[i].Preset; if (encoderOutputAssetName == null && (preset is BuiltInStandardEncoderPreset || preset is StandardEncoderPreset)) { encoderOutputAssetName = outputAssetName; } if (audioAnalyzerOutputAssetName == null && preset is AudioAnalyzerPreset) { audioAnalyzerOutputAssetName = outputAssetName; } if (videoAnalyzerOutputAssetName == null && preset is VideoAnalyzerPreset) { videoAnalyzerOutputAssetName = outputAssetName; } // set up jobOutputs JObject outObject = new JObject(); outObject["Preset"] = preset.ToString().Split('.').Last <string>(); outObject["OutputAssetName"] = outputAssetName; if (preset is BuiltInStandardEncoderPreset || preset is StandardEncoderPreset) { outObject["Category"] = "Encoder"; } else if (preset is AudioAnalyzerPreset || preset is VideoAnalyzerPreset) { outObject["Category"] = "Analyzer"; } else { outObject["Category"] = "Unknown"; } outputs.Add(outObject); } // Use the name of the created input asset to create the job input. JobInput jobInput = new JobInputAsset(assetName: inputAssetName); JobOutput[] jobOutputs = jobOutputList.ToArray(); Job job = client.Jobs.Create( config.ResourceGroup, config.AccountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, } ); } catch (ApiErrorException e) { log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}"); return(new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message)); } catch (Exception e) { log.LogError($"ERROR: Exception with message: {e.Message}"); return(new BadRequestObjectResult("Error: " + e.Message)); } } JObject result = new JObject(); result["jobName"] = jobName; result["jobOutputs"] = outputs; result["encoderOutputAssetName"] = encoderOutputAssetName; result["videoAnalyzerOutputAssetName"] = videoAnalyzerOutputAssetName; result["audioAnalyzerOutputAssetName"] = audioAnalyzerOutputAssetName; return((ActionResult) new OkObjectResult(result)); }
public async Task <TextModerationResult> ModerateVideo(string videoPath) { string resourceGroup = this.textModeratorConfig.ResourceGroup; string accountName = this.textModeratorConfig.AccountName; IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(); // 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; TextModerationResult result = null; try { string uniqueness = Guid.NewGuid().ToString(); string jobName = JobNamePrefix + uniqueness; string streamingOutputAssetName = textModeratorConfig + uniqueness; string analyticsOutputAssetName = textModeratorConfig + uniqueness; JobInput jobInput = null; List <Asset> outputAssetList = new List <Asset>(); Transform videoAnalyzerTransform = EnsureTransformExists(client, resourceGroup, accountName, VisualModerationTransformName); if (videoPath.StartsWith("http://") || videoPath.StartsWith("https://")) { Uri inputVideoUri = new Uri(videoPath); string baseUri = inputVideoUri.Scheme + "://" + inputVideoUri.Host; for (int i = 0; i < inputVideoUri.Segments.Length - 1; i++) { baseUri = baseUri + inputVideoUri.Segments[i]; } jobInput = new JobInputHttp( baseUri: baseUri, files: new List <String> { inputVideoUri.Segments[inputVideoUri.Segments.Length - 1] }, label: JobInputLabel ); } else { string inputAssetName = InputAssetNamePrefix + uniqueness; CreateInputAssetWithUploading(client, resourceGroup, accountName, inputAssetName, videoPath).Wait(); jobInput = new JobInputAsset(assetName: inputAssetName, label: JobInputLabel); } List <JobOutput> jobOutputList = new List <JobOutput>(); Asset analyticsOutputAsset = CreateOutputAsset(client, resourceGroup, accountName, analyticsOutputAssetName); outputAssetList.Add(analyticsOutputAsset); jobOutputList.Add(new JobOutputAsset(assetName: analyticsOutputAsset.Name, label: JobAnalyticsOutputLabel)); if (this.textModeratorConfig.EnableStreamingVideo) { Asset streamingOutputAsset = CreateOutputAsset(client, resourceGroup, accountName, streamingOutputAssetName); outputAssetList.Add(streamingOutputAsset); jobOutputList.Add(new JobOutputAsset(assetName: streamingOutputAsset.Name, label: JobVideoOutputLabel)); } JobOutput[] jobOutputs = jobOutputList.ToArray(); Job job = SubmitJob(client, resourceGroup, accountName, videoAnalyzerTransform.Name, jobName, jobInput, jobOutputs); job = WaitForJobToFinish(client, resourceGroup, accountName, videoAnalyzerTransform.Name, jobName); if (job.State == JobState.Finished) { Console.WriteLine("\nAMSv3 Job finished."); List <StreamingLocator> locators = PublishAssets(client, resourceGroup, accountName, jobOutputList); result = CreateVisualModeratorResult(client, resourceGroup, accountName, videoPath, locators); using (var webClient = new WebClient()) { webClient.Encoding = Encoding.UTF8; result.VisualModerationJson = webClient.DownloadString(result.StreamingUrlDetails.ContentModerationJsonUrl); result.OcrJson = webClient.DownloadString(result.StreamingUrlDetails.OcrJsonUrl); } } 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); } return(result); }
public async Task <IEnumerable <string> > EncodeVideoForStreaming(string inputMp4FileName, string uniqueMediaName, string downloadResultAssetsOutputPath = null) { var client = await CreateMediaServicesClientAsync(_configuration); // 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; // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. var jobName = $"job-{uniqueMediaName}"; var locatorName = $"locator-{uniqueMediaName}"; var outputAssetName = $"{uniqueMediaName}"; var inputAssetName = $"input-{uniqueMediaName}"; var existingStreamingUrls = await GetExistingStreamingUrls(locatorName, _configuration.ResourceGroup, _configuration.AccountName, client); if (existingStreamingUrls?.Any() == true) { return(existingStreamingUrls); } // Ensure that you have the desired encoding Transform. This is really a one time setup operation. _ = await GetOrCreateTransformAsync(client, _configuration.ResourceGroup, _configuration.AccountName, AdaptiveStreamingTransformName); // Create a new input Asset and upload the specified local video file into it. _ = await CreateInputAssetAsync(client, _configuration.ResourceGroup, _configuration.AccountName, inputAssetName, inputMp4FileName); // Use the name of the created input asset to create the job input. _ = new JobInputAsset(inputAssetName); // Output from the encoding Job must be written to an Asset, so let's create one var outputAsset = await CreateOutputAssetAsync(client, _configuration.ResourceGroup, _configuration.AccountName, outputAssetName); _ = await SubmitJobAsync(client, _configuration.ResourceGroup, _configuration.AccountName, AdaptiveStreamingTransformName, jobName, inputAssetName, outputAsset.Name); // In this demo code, we will poll for Job status // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. var job = await WaitForJobToFinishAsync(client, _configuration.ResourceGroup, _configuration.AccountName, AdaptiveStreamingTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("Job finished. Cleaning up resources."); await CleanUpAsync(client, _configuration.ResourceGroup, _configuration.AccountName, AdaptiveStreamingTransformName, jobName, new List <string> { inputAssetName }); if (!string.IsNullOrWhiteSpace(downloadResultAssetsOutputPath)) { if (!Directory.Exists(downloadResultAssetsOutputPath)) { Directory.CreateDirectory(downloadResultAssetsOutputPath); } await DownloadOutputAssetAsync(client, _configuration.ResourceGroup, _configuration.AccountName, outputAsset.Name, downloadResultAssetsOutputPath); } var locator = await CreateStreamingLocatorAsync(client, _configuration.ResourceGroup, _configuration.AccountName, outputAsset.Name, locatorName); // Note that the URLs returned by this method include a /manifest path followed by a (format=) // parameter that controls the type of manifest that is returned. // The /manifest(format=m3u8-aapl) will provide Apple HLS v4 manifest using MPEG TS segments. // The /manifest(format=mpd-time-csf) will provide MPEG DASH manifest. // And using just /manifest alone will return Microsoft Smooth Streaming format. // There are additional formats available that are not returned in this call, please check the documentation // on the dynamic packager for additional formats - see https://docs.microsoft.com/azure/media-services/latest/dynamic-packaging-overview var urls = await GetStreamingUrlsAsync(client, _configuration.ResourceGroup, _configuration.AccountName, locator.Name); return(urls); } throw new Exception($"Failed to upload video {inputAssetName}"); }
public async Task <VisualModerationResult> ModerateVideo(string videoPath) { string resourceGroup = this.visualModeratorConfig.ResourceGroup; string accountName = this.visualModeratorConfig.AccountName; IAzureMediaServicesClient client = await CreateMediaServicesClientAsync(); VisualModerationResult result = null; try { string uniqueness = Guid.NewGuid().ToString(); string jobName = "job-" + uniqueness; string inputAssetName = "asset-input-" + uniqueness; string outputAssetName1 = "asset-output-video-" + uniqueness; string outputAssetName2 = "asset-output-analysis-" + uniqueness; string streamingLocatorName1 = "streaminglocator-video-" + uniqueness; string streamingLocatorName2 = "streaminglocator-analysis-" + uniqueness; Transform videoAnalyzerTransform = EnsureTransformExists(client, resourceGroup, accountName, VisualModerationTransformName); CreateInputAsset(client, resourceGroup, accountName, inputAssetName, videoPath).Wait(); Asset outputAsset1 = CreateOutputAsset(client, resourceGroup, accountName, outputAssetName1); Asset outputAsset2 = CreateOutputAsset(client, resourceGroup, accountName, outputAssetName2); JobInput jobInput = new JobInputAsset(assetName: inputAssetName); JobOutput[] jobOutputs = { new JobOutputAsset(outputAsset1.Name), new JobOutputAsset(outputAsset2.Name), }; Job job = SubmitJob(client, resourceGroup, accountName, VisualModerationTransformName, jobName, jobInput, jobOutputs); job = WaitForJobToFinish(client, resourceGroup, accountName, VisualModerationTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("\nAMSv3 Job finished."); PublishStreamingAsset(client, resourceGroup, accountName, outputAsset1.Name, streamingLocatorName1); PublishDownloadAsset(client, resourceGroup, accountName, outputAsset2.Name, streamingLocatorName2); result = CreateVisualModeratorResult(client, resourceGroup, accountName, streamingLocatorName1, streamingLocatorName2); result.VideoName = outputAssetName1; result.VideoFilePath = videoPath; result.AccessToken = null; result.VisualModeratedJson = await GetVisualModerationJsonFile(client, resourceGroup, accountName, outputAsset2.Name); } 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); } return(result); }
static void Main(string[] args) { ConfigWrapper config = new ConfigWrapper(); try{ IAzureMediaServicesClient client = CreateMediaServicesClient(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; // 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 outputAssetName = "output-" + uniqueness; string inputAssetName = "input-" + uniqueness; // Ensure that you have the desired encoding Transform. This is really a one time setup operation. Transform videoAnalyzerTransform = EnsureTransformExists(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, new VideoAnalyzerPreset("en-US")); // Create a new input Asset and upload the specified local video file into it. CreateInputAsset(client, config.ResourceGroup, config.AccountName, inputAssetName, InputMP4FileName); // Use the name of the created input asset to create the job input. JobInput jobInput = new JobInputAsset(assetName: inputAssetName); // Output from the encoding Job must be written to an Asset, so let's create one Asset outputAsset = CreateOutputAsset(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = SubmitJob(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName, jobInput, outputAssetName); // In this demo code, we will poll for Job status // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. job = WaitForJobToFinish(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); if (!Directory.Exists(OutputFolder)) { Directory.CreateDirectory(OutputFolder); } DownloadResults(client, config.ResourceGroup, config.AccountName, outputAssetName, OutputFolder); } Console.WriteLine("Done."); Console.WriteLine("Press Enter to Continue"); Console.ReadLine(); } catch (ApiErrorException ex) { Console.WriteLine("{0}", ex.Message); Console.WriteLine("ERROR:API call failed with error code: {0} and message: {1}", ex.Body.Error.Code, ex.Body.Error.Message); } }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { log.Info($"AMS v3 Function - submit_job was triggered!"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); // Validate input objects if (data.inputAssetName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass inputAssetName in the input object" })); } if (data.transformName == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass transformName in the input object" })); } if (data.outputAssetNamePrefix == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass outputAssetNamePrefix in the input object" })); } string inputAssetName = data.inputAssetName; string transformName = data.transformName; string outputAssetNamePrefix = data.outputAssetNamePrefix; string assetStorageAccount = null; if (data.assetStorageAccount != null) { assetStorageAccount = data.assetStorageAccount; } MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper(); Asset inputAsset = null; string guid = Guid.NewGuid().ToString(); string jobName = "amsv3function-job-" + guid; string encoderOutputAssetName = null; string videoAnalyzerOutputAssetName = null; string outputContainer = null; try { var containerName = inputAssetName; containerName = containerName.Replace("asset", "saida"); IAzureMediaServicesClient client = CreateMediaServicesClient(amsconfig); inputAsset = client.Assets.Get(amsconfig.ResourceGroup, amsconfig.AccountName, inputAssetName); if (inputAsset == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Asset for input not found" })); } Transform transform = client.Transforms.Get(amsconfig.ResourceGroup, amsconfig.AccountName, transformName); if (transform == null) { return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Transform not found" })); } var jobOutputList = new List <JobOutput>(); for (int i = 0; i < transform.Outputs.Count; i++) { Guid assetGuid = Guid.NewGuid(); string outputAssetName = outputAssetNamePrefix + "-" + assetGuid.ToString(); Preset p = transform.Outputs[i].Preset; if (p is BuiltInStandardEncoderPreset || p is StandardEncoderPreset) { encoderOutputAssetName = outputAssetName; } else if (p is VideoAnalyzerPreset) { videoAnalyzerOutputAssetName = outputAssetName; } Asset assetParams = new Asset(null, outputAssetName, null, assetGuid, DateTime.Now, DateTime.Now, null, outputAssetName, containerName, assetStorageAccount, AssetStorageEncryptionFormat.None); Asset outputAsset = client.Assets.CreateOrUpdate(amsconfig.ResourceGroup, amsconfig.AccountName, outputAssetName, assetParams); jobOutputList.Add(new JobOutputAsset(outputAssetName)); if (outputContainer != null) { outputContainer += containerName + ","; } outputContainer += containerName; } // Use the name of the created input asset to create the job input. JobInput jobInput = new JobInputAsset(assetName: inputAssetName); JobOutput[] jobOutputs = jobOutputList.ToArray(); Job job = client.Jobs.Create( amsconfig.ResourceGroup, amsconfig.AccountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, } ); } catch (ApiErrorException e) { log.Error("error", e); log.Info($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "AMS API call error: " + e.Message })); } catch (Exception ex) { log.Error("error", ex); } return(req.CreateResponse(HttpStatusCode.OK, new { jobName = jobName, encoderOutputAssetName = encoderOutputAssetName, videoAnalyzerOutputAssetName = videoAnalyzerOutputAssetName, outputGuid = outputContainer })); }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <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 transforms for the VideoAnalyzer. This is really a one time setup operation. Transform videoAnalyzerTransform = EnsureTransformExists(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, new VideoAnalyzerPreset()); // 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; CreateInputAsset(client, config.ResourceGroup, config.AccountName, inputAssetName, inputMP4FileName).Wait(); JobInput input = new JobInputAsset(assetName: inputAssetName); Asset outputAsset = CreateOutputAsset(client, config.ResourceGroup, config.AccountName, outputAssetName); // Note that you can now pass custom correlation data Dictionary into the job to use via EventGrid or other Job polling listeners. // this is handy for passing tenant ID, or custom workflow data as part of your job. var correlationData = new Dictionary <string, string>(); correlationData.Add("customData1", "some custom data to pass through the job"); correlationData.Add("custom ID", "some GUID here"); Job job = SubmitJob(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName, input, outputAsset.Name, correlationData); DateTime startedTime = DateTime.Now; job = WaitForJobToFinish(client, config.ResourceGroup, config.AccountName, VideoAnalyzerTransformName, jobName); TimeSpan elapsed = DateTime.Now - startedTime; if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); if (!Directory.Exists(outputFolder)) { Directory.CreateDirectory(outputFolder); } 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); } }
public static async Task <HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext executionContext) { var log = executionContext.GetLogger("SubmitSubclipJob"); log.LogInformation("C# HTTP trigger function processed a request."); string triggerStart = DateTime.UtcNow.ToString("yyMMddHHmmss"); // Get request body data. string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var data = (RequestBodyModel)JsonConvert.DeserializeObject(requestBody, typeof(RequestBodyModel)); // Return bad request if input asset name is not passed in if (data.LiveEventName == null || data.LiveOutputName == null) { return(HttpRequest.ResponseBadRequest(req, "Please pass liveEventName and liveOutputName in the request body")); } data.IntervalSec ??= 60; ConfigWrapper config = ConfigUtils.GetConfig(); IAzureMediaServicesClient client; try { client = await Authentication.CreateMediaServicesClientAsync(config); } catch (Exception e) { if (e.Source.Contains("ActiveDirectory")) { log.LogError("TIP: Make sure that you have filled out the appsettings.json file before running this sample."); } log.LogError($"{e.Message}"); return(HttpRequest.ResponseBadRequest(req, e.Message)); } // 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 transform = await TransformUtils.GetOrCreateSubclipTransform(client, log, config.ResourceGroup, config.AccountName, SubclipTransformName); } catch (ErrorResponseException ex) { return(HttpRequest.ResponseBadRequest(req, LogUtils.LogError(log, ex, "Error when getting or creating the transform."))); } var liveOutput = await client.LiveOutputs.GetAsync(config.ResourceGroup, config.AccountName, data.LiveEventName, data.LiveOutputName); // let's analyze the client manifest and adjust times for the subclip job var doc = await LiveManifest.TryToGetClientManifestContentAsABlobAsync(client, config.ResourceGroup, config.AccountName, liveOutput.AssetName); var assetmanifestdata = LiveManifest.GetManifestTimingData(doc); if (assetmanifestdata.Error) { return(HttpRequest.ResponseBadRequest(req, "Data cannot be read from live output / asset manifest.")); } log.LogInformation("Timestamps : " + string.Join(",", assetmanifestdata.TimestampList.Select(n => n.ToString()).ToArray())); var livetime = TimeSpan.FromSeconds(assetmanifestdata.TimestampEndLastChunk / (double)assetmanifestdata.TimeScale); log.LogInformation($"Livetime : {livetime}"); var starttime = LiveManifest.ReturnTimeSpanOnGOP(assetmanifestdata, livetime.Subtract(TimeSpan.FromSeconds((int)data.IntervalSec))); log.LogInformation($"Value starttime : {starttime}"); if (data.LastSubclipEndTime != null) { var lastEndTime = (TimeSpan)data.LastSubclipEndTime; log.LogInformation($"Value lastEndTime : {lastEndTime}"); var delta = (livetime - lastEndTime - TimeSpan.FromSeconds((int)data.IntervalSec)).Duration(); log.LogInformation($"Delta: {delta}"); if (delta < (TimeSpan.FromSeconds(3 * (int)data.IntervalSec))) // less than 3 times the normal duration (3*60s) { starttime = lastEndTime; log.LogInformation($"Value new starttime : {starttime}"); } } var duration = livetime - starttime; log.LogInformation($"Value duration: {duration}"); if (duration == new TimeSpan(0)) // Duration is zero, this may happen sometimes ! { return(HttpRequest.ResponseBadRequest(req, "Stopping. Duration of subclip is zero.")); } Asset outputAsset; try { // Output from the Job must be written to an Asset, so let's create one outputAsset = await AssetUtils.CreateAssetAsync(client, log, config.ResourceGroup, config.AccountName, liveOutput.Name + "-subclip-" + triggerStart, data.OutputAssetStorageAccount); } catch (ErrorResponseException ex) { return(HttpRequest.ResponseBadRequest(req, LogUtils.LogError(log, ex, "Error when creating the output asset."))); } JobInput jobInput = new JobInputAsset( assetName: liveOutput.AssetName, start: new AbsoluteClipTime(starttime.Subtract(TimeSpan.FromMilliseconds(100))), end: new AbsoluteClipTime(livetime.Add(TimeSpan.FromMilliseconds(100))) ); Job job; try { job = await JobUtils.SubmitJobAsync( client, log, config.ResourceGroup, config.AccountName, SubclipTransformName, $"Subclip-{liveOutput.Name}-{triggerStart}", jobInput, outputAsset.Name ); } catch (ErrorResponseException ex) { return(HttpRequest.ResponseBadRequest(req, LogUtils.LogError(log, ex, "Error when submitting the job."))); } AnswerBodyModel dataOk = new() { SubclipAssetName = outputAsset.Name, SubclipJobName = job.Name, SubclipTransformName = SubclipTransformName, SubclipEndTime = starttime + duration }; return(HttpRequest.ResponseOk(req, dataOk, HttpStatusCode.Accepted)); } }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <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; // 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("N"); string jobName = $"job-{uniqueness}"; string locatorName = $"locator-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; string inputAssetName = $"input-{uniqueness}"; // Ensure that you have the desired encoding Transform. This is really a one time setup operation. _ = await GetOrCreateTransformAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName); // Create a new input Asset and upload the specified local video file into it. _ = await CreateInputAssetAsync(client, config.ResourceGroup, config.AccountName, inputAssetName, InputMP4FileName); // Use the name of the created input asset to create the job input. _ = new JobInputAsset(assetName: inputAssetName); // Output from the encoding Job must be written to an Asset, so let's create one Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); _ = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName, inputAssetName, outputAsset.Name); // In this demo code, we will poll for Job status // Polling is not a recommended best practice for production applications because of the latency it introduces. // Overuse of this API may trigger throttling. Developers should instead use Event Grid. Job job = await WaitForJobToFinishAsync(client, config.ResourceGroup, config.AccountName, AdaptiveStreamingTransformName, jobName); if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); if (!Directory.Exists(OutputFolderName)) { Directory.CreateDirectory(OutputFolderName); } await DownloadOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, OutputFolderName); StreamingLocator locator = await CreateStreamingLocatorAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, locatorName); // Note that the URLs returned by this method include a /manifest path followed by a (format=) // parameter that controls the type of manifest that is returned. // The /manifest(format=m3u8-aapl) will provide Apple HLS v4 manifest using MPEG TS segments. // The /manifest(format=mpd-time-csf) will provide MPEG DASH manifest. // And using just /manifest alone will return Microsoft Smooth Streaming format. // There are additional formats available that are not returned in this call, please check the documentation // on the dynamic packager for additional formats - see https://docs.microsoft.com/azure/media-services/latest/dynamic-packaging-overview IList <string> urls = await GetStreamingUrlsAsync(client, config.ResourceGroup, config.AccountName, locator.Name); foreach (var url in urls) { Console.WriteLine(url); } } Console.WriteLine("Done. Copy and paste the Streaming URL ending in '/manifest' into the Azure Media Player at 'http://aka.ms/azuremediaplayer'."); Console.WriteLine("See the documentation on Dynamic Packaging for additional format support, including CMAF."); Console.WriteLine("https://docs.microsoft.com/azure/media-services/latest/dynamic-packaging-overview"); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation($"AMS v3 Function - SubmitMediaJob was triggered!"); string requestBody = new StreamReader(req.Body).ReadToEnd(); dynamic data = JsonConvert.DeserializeObject(requestBody); // Validate input objects if (data.inputAssetName == null) { return(new BadRequestObjectResult("Please pass inputAssetName in the input object")); } if (data.transformName == null) { return(new BadRequestObjectResult("Please pass transformName in the input object")); } if (data.outputAssetNamePrefix == null) { return(new BadRequestObjectResult("Please pass outputAssetNamePrefix in the input object")); } string inputAssetName = data.inputAssetName; string transformName = data.transformName; string outputAssetNamePrefix = data.outputAssetNamePrefix; string outputAssetDescription = null; if (data.outputAssetDescription != null) { outputAssetDescription = data.outputAssetDescription; } string assetStorageAccount = null; if (data.assetStorageAccount != null) { assetStorageAccount = data.assetStorageAccount; } MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper(); Asset inputAsset = null; string guid = Guid.NewGuid().ToString(); string jobName = "amsv3function-job-" + guid; string encoderOutputAssetName = null; string audioAnalyzerOutputAssetName = null; string videoAnalyzerOutputAssetName = null; JArray outputs = new JArray(); try { IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig); inputAsset = client.Assets.Get(amsconfig.ResourceGroup, amsconfig.AccountName, inputAssetName); if (inputAsset == null) { return(new BadRequestObjectResult("Asset for input not found")); } Transform transform = client.Transforms.Get(amsconfig.ResourceGroup, amsconfig.AccountName, transformName); if (transform == null) { return(new BadRequestObjectResult("Transform not found")); } var jobOutputList = new List <JobOutput>(); for (int i = 0; i < transform.Outputs.Count; i++) { Guid assetGuid = Guid.NewGuid(); string outputAssetName = outputAssetNamePrefix + "-" + assetGuid.ToString(); if (outputAssetDescription == null) { outputAssetDescription = outputAssetName; } Asset assetParams = new Asset(null, outputAssetName, null, assetGuid, DateTime.Now, DateTime.Now, null, outputAssetDescription, null, assetStorageAccount, AssetStorageEncryptionFormat.None); Asset outputAsset = client.Assets.CreateOrUpdate(amsconfig.ResourceGroup, amsconfig.AccountName, outputAssetName, assetParams); jobOutputList.Add(new JobOutputAsset(outputAssetName)); Preset preset = transform.Outputs[i].Preset; if (encoderOutputAssetName == null && (preset is BuiltInStandardEncoderPreset || preset is StandardEncoderPreset)) { encoderOutputAssetName = outputAssetName; } if (audioAnalyzerOutputAssetName == null && preset is AudioAnalyzerPreset) { audioAnalyzerOutputAssetName = outputAssetName; } if (videoAnalyzerOutputAssetName == null && preset is VideoAnalyzerPreset) { videoAnalyzerOutputAssetName = outputAssetName; } // set up jobOutputs JObject outObject = new JObject(); outObject["Preset"] = preset.ToString().Split('.').Last <string>(); outObject["OutputAssetName"] = outputAssetName; if (preset is BuiltInStandardEncoderPreset || preset is StandardEncoderPreset) { outObject["Category"] = "Encoder"; } else if (preset is AudioAnalyzerPreset || preset is VideoAnalyzerPreset) { outObject["Category"] = "Analyzer"; } else { outObject["Category"] = "Unknown"; } outputs.Add(outObject); } // Use the name of the created input asset to create the job input. JobInput jobInput = new JobInputAsset(assetName: inputAssetName); JobOutput[] jobOutputs = jobOutputList.ToArray(); Job job = client.Jobs.Create( amsconfig.ResourceGroup, amsconfig.AccountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, } ); } catch (ApiErrorException e) { log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}"); return(new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message)); } catch (Exception e) { log.LogError($"ERROR: Exception with message: {e.Message}"); return(new BadRequestObjectResult("Error: " + e.Message)); } JObject result = new JObject(); result["jobName"] = jobName; result["jobOutputs"] = outputs; result["encoderOutputAssetName"] = encoderOutputAssetName; result["videoAnalyzerOutputAssetName"] = videoAnalyzerOutputAssetName; result["audioAnalyzerOutputAssetName"] = audioAnalyzerOutputAssetName; return((ActionResult) new OkObjectResult(result)); }
public static async Task <HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext executionContext) { var log = executionContext.GetLogger("SubmitEncodingJob"); log.LogInformation("C# HTTP trigger function processed a request."); // Get request body data. string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var data = (RequestBodyModel)JsonConvert.DeserializeObject(requestBody, typeof(RequestBodyModel)); // Return bad request if input asset name is not passed in if (data.InputAssetName == null && data.InputUrl == null) { return(HttpRequest.ResponseBadRequest(req, "Please pass inputAssetName or inputUrl in the request body")); } // Return bad request if input asset name is not passed in if (data.TransformName == null) { return(HttpRequest.ResponseBadRequest(req, "Please pass transformName in the request body")); } ConfigWrapper config = ConfigUtils.GetConfig(); IAzureMediaServicesClient client; try { client = await Authentication.CreateMediaServicesClientAsync(config); log.LogInformation("AMS Client created."); } catch (Exception e) { if (e.Source.Contains("ActiveDirectory")) { log.LogError("TIP: Make sure that you have filled out the appsettings.json file before running this sample."); } log.LogError($"{e.Message}"); return(HttpRequest.ResponseBadRequest(req, e.Message)); } // 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; // 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 outputAssetName = $"output-{uniqueness}"; Transform transform; try { // Ensure that you have the encoding Transform. This is really a one time setup operation. transform = await TransformUtils.CreateEncodingTransform(client, log, config.ResourceGroup, config.AccountName, data.TransformName, data.BuiltInPreset); log.LogInformation("Transform retrieved."); } catch (ErrorResponseException ex) { return(HttpRequest.ResponseBadRequest(req, LogUtils.LogError(log, ex, "Error when creating the transform."))); } Asset outputAsset; try { // Output from the job must be written to an Asset, so let's create one outputAsset = await AssetUtils.CreateAssetAsync(client, log, config.ResourceGroup, config.AccountName, outputAssetName, data.OutputAssetStorageAccount); log.LogInformation($"Output asset '{outputAssetName}' created."); } catch (ErrorResponseException ex) { return(HttpRequest.ResponseBadRequest(req, LogUtils.LogError(log, ex, "Error when creating the output asset."))); } // Job input prepration : asset or url JobInput jobInput; if (data.InputUrl != null) { jobInput = new JobInputHttp(files: new[] { data.InputUrl }); log.LogInformation("Input is a Url."); } else { jobInput = new JobInputAsset(assetName: data.InputAssetName); log.LogInformation($"Input is asset '{data.InputAssetName}'."); } Job job; try { // Job submission to Azure Media Services job = await JobUtils.SubmitJobAsync( client, log, config.ResourceGroup, config.AccountName, data.TransformName, jobName, jobInput, outputAssetName ); log.LogInformation($"Job '{jobName}' submitted."); } catch (ErrorResponseException ex) { return(HttpRequest.ResponseBadRequest(req, LogUtils.LogError(log, ex, "Error when submitting the job."))); } AnswerBodyModel dataOk = new() { OutputAssetName = outputAsset.Name, JobName = job.Name }; return(HttpRequest.ResponseOk(req, dataOk, HttpStatusCode.Accepted)); } }
public async Task <Job> StartEncode(Models.Resource resource) { var client = await GetClient(); var credential = _mediaCredential.Value; var contentAddress = new ContentAddress(resource.ContentAddress); var sourceName = $"raw-{contentAddress.ContainerName}"; var resultName = $"result-{contentAddress.ContainerName}"; var jobName = $"job-{contentAddress.ContainerName}"; //await client.Assets.DeleteAsync(credential.ResourceGroup, credential.AccountName, resultName); Asset resultAsset = await client.Assets.GetAsync(credential.ResourceGroup, credential.AccountName, resultName); if (resultAsset != null) { await client.Assets.DeleteAsync(credential.ResourceGroup, credential.AccountName, resultName); await Task.Delay(TimeSpan.FromSeconds(60)); } //do //{ // await Task.Delay(TimeSpan.FromSeconds(60)); // resultAsset = client.Assets.Get(credential.ResourceGroup, credential.AccountName, resultName); //} //while (resultAsset != null); resultAsset = await client.Assets.CreateOrUpdateAsync(credential.ResourceGroup, credential.AccountName, resultName, new Asset(name : resultName, container : resultName)); await client.Transforms.CreateOrUpdateAsync( credential.ResourceGroup, credential.AccountName, TRANSFORM_NAME, new List <TransformOutput> { new TransformOutput(MediaTransform.Preset) }); JobInput jobInput = new JobInputAsset(sourceName); JobOutput[] jobOutputs = { new JobOutputAsset(resultName), }; Job job = await client.Jobs.GetAsync(credential.ResourceGroup, credential.AccountName, TRANSFORM_NAME, jobName); if (job != null) { await client.Jobs.DeleteAsync(credential.ResourceGroup, credential.AccountName, TRANSFORM_NAME, jobName); } do // poll job status { await Task.Delay(TimeSpan.FromSeconds(3)); job = await client.Jobs.GetAsync(credential.ResourceGroup, credential.AccountName, TRANSFORM_NAME, jobName); }while (job != null); try { var tt = await client.Jobs.CreateWithHttpMessagesAsync(credential.ResourceGroup, credential.AccountName, TRANSFORM_NAME, jobName, parameters : new Job(input: jobInput, outputs: jobOutputs)); } catch (ApiErrorException aee) { throw new Exception(aee.Message); } catch (Exception e) { throw e; } return(job); }