private async Task CreateStreamingJobAsync(long id, string url, CancellationToken token) { var videoAsset = await CreateOutputAssetAsync(id.ToString(), AssetType.Long, token); var jobInput = new JobInputHttp(files: new[] { url }); JobOutput[] jobOutputs = { new JobOutputAsset(videoAsset.Name, label: AssetType.Long.ToString()), }; var v = await _context; // 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 null // if the entity doesn't exist (a case-insensitive check on the name). try { await v.Jobs.CreateAsync( _config.ResourceGroup, _config.AccountName, StreamingTransformer, $"{id} video", new Job { Input = jobInput, Outputs = jobOutputs, }, token); } catch (ApiErrorException e) when(e.Response.StatusCode == HttpStatusCode.Conflict) { //There is already a job on this } }
private static async Task <Job> SubmitJobAsync(string inputBlobName, string outputAssetName, IAzureMediaServicesClient client, string jobName, ILogger log, Dictionary <string, string> metadata) { try { JobInputHttp jobInput = new JobInputHttp(files: new[] { inputBlobName }); JobOutput[] jobOutputs = { new JobOutputAsset(outputAssetName) }; var metaString = JsonConvert.SerializeObject(metadata); Dictionary <string, string> metaDic = new Dictionary <string, string>(); metaDic.Add("metaString", metaString); // 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 null // if the entity doesn't exist (a case-insensitive check on the name). Job job = await client.Jobs.CreateAsync( ResourceGroup, AccountName, TransformName, jobName, new Job { CorrelationData = metaDic, Input = jobInput, Outputs = jobOutputs, }); return(job); } catch (Exception ex) { log.LogError($"Error with creating Job: {ex.Message}"); throw; } }
/// <summary> /// Generates test data /// </summary> /// <param name="sequenceNumber">sequence number</param> /// <param name="uniqueness">unique part of the names</param> /// <returns>Generated JobRequestModel</returns> private static JobRequestModel GenerateJobRequestModel(int sequenceNumber, string uniqueness) { var jobId = $"jobId-{sequenceNumber}-{uniqueness}"; var jobName = $"jobName-{sequenceNumber}-{uniqueness}"; var outputAssetName = $"output-{sequenceNumber}-{uniqueness}"; // Add job input for this test var input = new JobInputHttp( baseUri: "<Enter URL>", files: new List <string> { "<Enter Filename>" }, label: "input1" ); var request = new JobRequestModel { Id = jobId, JobName = jobName, OutputAssetName = outputAssetName, TransformName = transformName, JobInputs = new JobInputs { Inputs = new List <JobInput> { input } } }; return(request); }
private async Task <Job> SubmitJobAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string transformName, string outputAssetName, string jobName, string url) { JobInputHttp jobInput = new JobInputHttp(files: new[] { url }); JobOutput[] jobOutputs = { new JobOutputAsset(outputAssetName), }; Job job = await client.Jobs.CreateAsync( resourceGroup, accountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, }); return(job); }
/// <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="outputAssetName">The (unique) name of the output asset that will store the result of the encoding job. </param> /// <param name="jobName">The (unique) name of the job.</param> /// <returns></returns> private static Job SubmitJob(IAzureMediaServicesClient client, string resourceGroup, string accountName, string transformName, string outputAssetName, string jobName) { // This example shows how to encode from any HTTPs source URL - a new feature of the v3 API. // Change the URL to any accessible HTTPs URL or SAS URL from Azure. JobInputHttp jobInput = new JobInputHttp(files: new[] { "https://nimbuscdn-nimbuspm.streaming.mediaservices.windows.net/2b533311-b215-4409-80af-529c3e853622/Ignite-short.mp4" }); JobOutput[] jobOutputs = { new JobOutputAsset(outputAssetName), }; Job job = client.Jobs.Create( resourceGroup, accountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, }); return(job); }
public async Task CreateStudyRoomSessionEncoding(string sessionId, string url, CancellationToken token) { var thumbnailAsset = await CreateOutputAssetAsync(sessionId, AssetType.StudyRoom, token); var jobInput = new JobInputHttp(files: new[] { url }); JobOutput[] jobOutputs = { new JobOutputAsset(thumbnailAsset.Name, label: AssetType.StudyRoom.ToString()) }; var v = await _context; try { await v.Jobs.CreateAsync( _config.ResourceGroup, _config.AccountName, FullHdTransformer, $"{sessionId} study room session", new Job { Input = jobInput, Outputs = jobOutputs, }, token); } catch (ApiErrorException e) when(e.Response.StatusCode == HttpStatusCode.Conflict) { //Do nothing } }
// </CreateOutputAsset> /// <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="outputAssetName">The (unique) name of the output asset that will store the result of the encoding job. </param> /// <param name="jobName">The (unique) name of the job.</param> /// <returns></returns> // <SubmitJob> private static async Task <Job> SubmitJobAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string transformName, string outputAssetName, string jobName) { // This example shows how to encode from any HTTPs source URL - a new feature of the v3 API. // Change the URL to any accessible HTTPs URL or SAS URL from Azure. JobInputHttp jobInput = new JobInputHttp(files: new[] { "https://nimbuscdn-nimbuspm.streaming.mediaservices.windows.net/2b533311-b215-4409-80af-529c3e853622/Ignite-short.mp4" }); JobOutput[] jobOutputs = { new JobOutputAsset(outputAssetName), }; // 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, the Get method on entities returns null // if the entity doesn't exist (a case-insensitive check on the name). Job job = await client.Jobs.CreateAsync( resourceGroup, accountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, }); return(job); }
/// <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="resourceGroup">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="outputAssetName">The (unique) name of the output asset that will store the result of the encoding job. </param> /// <param name="jobName">The (unique) name of the job.</param> /// <returns></returns> private static async Task <Job> SubmitJobAsync(IAzureMediaServicesClient client, string resourceGroup, string accountName, string transformName, string outputAssetName, string jobName) { // This example shows how to encode from any HTTPs source URL - a new feature of the v3 API. // Change the URL to any accessible HTTPs URL or SAS URL from Azure. JobInputHttp jobInput = new JobInputHttp(files: new[] { "https://nimbuscdn-nimbuspm.streaming.mediaservices.windows.net/2b533311-b215-4409-80af-529c3e853622/Ignite-short.mp4" }); JobOutput[] jobOutputs = { new JobOutputAsset(outputAssetName), }; // 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, the Get method on entities returns null // if the entity doesn't exist (a case-insensitive check on the name). Job job; try { Console.WriteLine("Creating a job..."); job = await client.Jobs.CreateAsync( resourceGroup, accountName, transformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, } ); } catch (Exception exception) { if (exception.GetBaseException() is ApiErrorException apiException) { Console.Error.WriteLine( $"ERROR: API call failed with error code '{apiException.Body.Error.Code}' and message '{apiException.Body.Error.Message}'."); } throw exception; } return(job); }
private static void VerifyJobInput(JobInput expectedInput, JobInput actualInput, bool jobInputsAcceptable = true) { Type expectedInputType = expectedInput.GetType(); Assert.Equal(expectedInputType, actualInput.GetType()); if (typeof(JobInputAsset) == expectedInputType) { JobInputAsset expected = (JobInputAsset)expectedInput; JobInputAsset actual = (JobInputAsset)actualInput; Assert.Equal(expected.AssetName, actual.AssetName); } else if (typeof(JobInputHttp) == expectedInputType) { JobInputHttp expected = (JobInputHttp)expectedInput; JobInputHttp actual = (JobInputHttp)actualInput; Assert.Equal(expected.BaseUri, actual.BaseUri); Assert.Equal(expected.Label, actual.Label); Assert.Equal(expected.Files.Count, actual.Files.Count); for (int i = 0; i < expected.Files.Count; i++) { Assert.Equal(expected.Files[i], actual.Files[i]); } } else if (typeof(JobInputs) == expectedInputType) { if (!jobInputsAcceptable) { throw new InvalidOperationException("Only top level JobInputs are supported."); } JobInputs expected = (JobInputs)expectedInput; JobInputs actual = (JobInputs)actualInput; Assert.Equal(expected.Inputs.Count, actual.Inputs.Count); for (int i = 0; i < expected.Inputs.Count; i++) { VerifyJobInput(expected.Inputs[i], actual.Inputs[i], false); } } else { throw new InvalidOperationException($"Unexpected input type {expectedInputType.Name}"); } }
private async Task <List <Uri> > GenerateVideoThumbnailAsync(string fileUrl, string thumbnailStoragePath, string resourceGroup, string accountName) { pAzureMediaServicesClient.LongRunningOperationRetryTimeout = 2; var streamUris = new List <Uri>(); try { // Ensure that you have customized encoding Transform. This is really a one time setup operation. Transform adaptiveEncodeTransform = await EnsureTransformExistsAsync(pAzureMediaServicesClient, resourceGroup, accountName, fileUrl); // Creating a unique suffix so that we don't have name collisions if you run the sample // multiple times without cleaning up. var uniqueness = Guid.NewGuid().ToString().Substring(0, 13); var jobName = "job-" + uniqueness; var inputAssetName = "input-" + uniqueness; var outputAssetName = "output-" + uniqueness; var input = new JobInputHttp(files: new[] { fileUrl }); Asset asetInput = new Asset(); JobOutput[] jobOutputs = { new JobOutputAsset(outputAssetName) }; await pAzureMediaServicesClient.Assets.CreateOrUpdateAsync(resourceGroup, accountName, outputAssetName, asetInput); Job job = await pAzureMediaServicesClient.Jobs.CreateAsync(resourceGroup, accountName, fileUrl, jobName, new Job { Input = input, Outputs = jobOutputs }); job = await pAzureMediaServicesClient.Jobs.GetAsync(resourceGroup, accountName, fileUrl, jobName); var feedItemGuid = pBlobHelper.GetFileGuidFromFilePath(fileUrl); if (job.State == JobState.Finished) { streamUris = await GetStreamingUrlsAsync(pAzureMediaServicesClient, resourceGroup, accountName, feedItemGuid.ToString()); } } catch (ApiErrorException ex) { string code = ex.Body.Error.Code; string message = ex.Body.Error.Message; } return(streamUris); }
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); }
public async Task <Job> CreateEncodeJobAsync(IZeroBlob original, string encodedFileName, int contentId, CancellationToken cancellationToken) { var extension = Path.GetExtension(original.GetName()); if (extension == null || !_settings.SupportedVideoTypes.Contains(extension.ToLower())) { throw new NotSupportedException("Video type not supported"); } string uniqueness = $"{contentId}-{Guid.NewGuid().ToString("N").Substring(0, 10)}"; string jobName = $"job-{uniqueness}"; string outputAssetName = $"output-{uniqueness}"; var output = new Asset(description: $"{contentId}-{encodedFileName}"); var outPutAsset = await _client.Assets.CreateOrUpdateAsync(_settings.ResourceGroup, _settings.AccountName, outputAssetName, output, cancellationToken); JobOutput[] jobOutputs = { new JobOutputAsset(outPutAsset.Name) }; var jobInput = new JobInputHttp { Files = new[] { original.GetReadSharedAccessUrl("*") } }; IDictionary <string, string> correlationData = null; // Add custom data sent with the job. Can then be used when processing it. var job = await _client.Jobs.CreateAsync( _settings.ResourceGroup, _settings.AccountName, _settings.MediaServicesTransform, jobName, new Job { Input = jobInput, Outputs = jobOutputs, CorrelationData = correlationData } , cancellationToken); return(job); }
public async Task CreatePreviewJobAsync(long id, string url, TimeSpan videoLength, CancellationToken token) { var clipEndTime = Math.Min(TimeSpan.FromSeconds(30).Ticks, videoLength.Ticks); var videoAsset = await CreateOutputAssetAsync(id.ToString(), AssetType.Short, token); var jobInput = new JobInputHttp(files: new[] { url }, end: new AbsoluteClipTime(new TimeSpan(clipEndTime))); JobOutput[] jobOutputs = { new JobOutputAsset(videoAsset.Name, label: AssetType.Short.ToString()), }; var v = await _context; // 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 null // if the entity doesn't exist (a case-insensitive check on the name). try { await v.Jobs.CreateAsync( _config.ResourceGroup, _config.AccountName, StreamingTransformer, $"{id} preview", new Job { Input = jobInput, Outputs = jobOutputs, }, token); } catch (ApiErrorException e) when(e.Response.StatusCode == HttpStatusCode.Conflict) { //There is already a job on this } }
static void Main(string[] args) { ConfigWrapper config = new ConfigWrapper(); IAzureMediaServicesClient client = CreateMediaServicesClient(config); try { // Ensure that you have customized encoding Transform. This is really a one time setup operation. Transform adaptiveEncodeTransform = EnsureTransformExists(client, config.Region, 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(resourceGroupName, accountName, inputAssetName, new Asset()); var input = new JobInputHttp( baseUri: "https://nimbuscdn-nimbuspm.streaming.mediaservices.windows.net/2b533311-b215-4409-80af-529c3e853622/", files: new List <String> { "Ignite-short.mp4" } ); CreateOutputAsset(client, outputAssetName); Job job = SubmitJob(client, transformName, jobName, input, outputAssetName); DateTime startedTime = DateTime.Now; job = WaitForJobToFinish(client, transformName, jobName); TimeSpan elapsed = DateTime.Now - startedTime; if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); if (!Directory.Exists(outputFolder)) { Directory.CreateDirectory(outputFolder); } DownloadResults(client, outputAssetName, 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); } }
/// <summary> /// Run the sample async. /// </summary> /// <param name="config">This param is of type ConfigWrapper, which reads values from local configuration file.</param> /// <returns>A task.</returns> private static async Task RunAsync(ConfigWrapper config) { IAzureMediaServicesClient client; try { client = await CreateMediaServicesClientAsync(config); } catch (Exception e) { if (e.Source.Contains("ActiveDirectory")) { Console.Error.WriteLine("TIP: Make sure that you have filled out the appsettings.json file before running this sample."); Console.Error.WriteLine(); } 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().Substring(0, 13); string jobName = "job-" + uniqueness; string locatorName = "locator-" + uniqueness; string outputAssetName = "output-" + uniqueness; bool stopEndpoint = false; try { // Ensure that you have customized encoding Transform. This is really a one time setup operation. Transform adaptiveEncodeTransform = await EnsureTransformExists(client, config.ResourceGroup, config.AccountName, TransformName, preset : new BuiltInStandardEncoderPreset(EncoderNamedPreset.AdaptiveStreaming)); 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" ); // Output from the encoding Job must be written to an Asset, so let's create one. Note that we // are using a unique asset name, there should not be a name collision. Asset outputAsset = await CreateOutputAssetAsync(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = await SubmitJobAsync(client, config.ResourceGroup, config.AccountName, TransformName, jobName, input, outputAsset.Name); DateTime startedTime = DateTime.Now; // 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. To see how to implement the event grid, see the sample // https://github.com/Azure-Samples/media-services-v3-dotnet/tree/master/ContentProtection/BasicAESClearKey. job = WaitForJobToFinish(client, config.ResourceGroup, config.AccountName, TransformName, jobName); TimeSpan elapsed = DateTime.Now - startedTime; Console.WriteLine($"Job elapsed time: {elapsed}"); if (job.State == JobState.Finished) { Console.WriteLine("Job finished."); // Now that the content has been encoded, publish it for Streaming by creating // a StreamingLocator. StreamingLocator locator = await CreateStreamingLocatorAsync(client, config.ResourceGroup, config.AccountName, outputAsset.Name, locatorName); StreamingEndpoint streamingEndpoint = await client.StreamingEndpoints.GetAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); if (streamingEndpoint != null) { if (streamingEndpoint.ResourceState != StreamingEndpointResourceState.Running) { await client.StreamingEndpoints.StartAsync(config.ResourceGroup, config.AccountName, DefaultStreamingEndpointName); // We started the endpoint, we should stop it in cleanup. stopEndpoint = true; } } IList <string> urls = await GetStreamingUrlsAsync(client, config.ResourceGroup, config.AccountName, locator.Name, streamingEndpoint); foreach (var url in urls) { Console.WriteLine(url); Console.WriteLine(); } Console.WriteLine("To stream, copy and paste the Streaming URL into the Azure Media Player at 'http://aka.ms/azuremediaplayer'."); Console.WriteLine("When finished, press ENTER to continue."); Console.WriteLine(); Console.Out.Flush(); Console.ReadLine(); // Download output asset for verification. Console.WriteLine("Downloading output asset..."); Console.WriteLine(); if (!Directory.Exists(OutputFolder)) { Directory.CreateDirectory(OutputFolder); } DownloadResults(client, config.ResourceGroup, config.AccountName, outputAsset.Name, OutputFolder).Wait(); Console.WriteLine("Please check the files in the output folder."); Console.WriteLine("When finished, press ENTER to cleanup."); Console.Out.Flush(); Console.ReadLine(); } 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 e) { Console.WriteLine("Hit ApiErrorException"); Console.WriteLine($"\tCode: {e.Body.Error.Code}"); Console.WriteLine($"\tMessage: {e.Body.Error.Message}"); Console.WriteLine(); Console.WriteLine("Exiting, cleanup may be necessary..."); Console.ReadLine(); } finally { await CleanUpAsync(client, config.ResourceGroup, config.AccountName, TransformName, jobName, outputAssetName, locatorName, stopEndpoint, DefaultStreamingEndpointName); Console.WriteLine("Done."); } }
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 static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation($"AMS v3 Function - CopyUrlToStorage was triggered!"); string requestBody = new StreamReader(req.Body).ReadToEnd(); dynamic data = JsonConvert.DeserializeObject(requestBody); // Set up ENV variables string accountName = System.Environment.GetEnvironmentVariable("AccountName"); string resourceGroup = System.Environment.GetEnvironmentVariable("ResourceGroup"); MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper(); // Transform & Job string transformName = "abrTransform"; string jobName = "job-" + Guid.NewGuid(); // Asset & Url string remoteUrl = Convert.ToString(data.remoteUrl); string assetName = Convert.ToString(data.assetName); try { IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig); // Encode from any HTTPs source URL - a new feature of the v3 API. JobInputHttp jobInput = new JobInputHttp(files: new List <string> { remoteUrl }); JobOutput[] jobOutputs = { new JobOutputAsset(assetName), }; // In this function, we are ensuring that the job name is unique. Job job = await client.Jobs.CreateAsync( resourceGroup, 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 + " caused by " + e.StackTrace)); } return((ActionResult) new OkObjectResult(new { assetName = assetName })); }
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); }
/// <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 { // Generate a new random token signing key to use RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(TokenSigningKey); //Create the content key policy that configures how the content key is delivered to end clients // via the Key Delivery component of Azure Media Services. ContentKeyPolicy policy = EnsureContentKeyPolicyExists(client, config.ResourceGroup, config.AccountName, ContentKeyPolicyName); // Ensure that you have customized encoding Transform. This is really a one time setup operation. Transform adaptiveEncodeTransform = EnsureTransformExists(client, config.ResourceGroup, config.AccountName, transformName, preset: new BuiltInStandardEncoderPreset(EncoderNamedPreset.AdaptiveStreaming)); // 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; string streamingLocatorName = "locator-" + uniqueness; Asset asset = client.Assets.CreateOrUpdate(config.ResourceGroup, config.AccountName, inputAssetName, new Asset()); 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" ); Asset outputAsset = CreateOutputAsset(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = SubmitJob(client, config.ResourceGroup, config.AccountName, transformName, jobName, input, 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."); // Now that the content has been encoded, publish it for Streaming by creating // a StreamingLocator. Note that we are using one of the PredefinedStreamingPolicies // which tell the Origin component of Azure Media Services how to publish the content // for streaming. In this case it applies AES Envelople encryption, which is also known // ClearKey encryption (because the key is delivered to the playback client via HTTPS and // not instead a DRM license). StreamingLocator locator = new StreamingLocator( assetName: outputAsset.Name, streamingPolicyName: PredefinedStreamingPolicy.ClearKey, defaultContentKeyPolicyName: ContentKeyPolicyName); client.StreamingLocators.Create(config.ResourceGroup, config.AccountName, streamingLocatorName, locator); // We are using the ContentKeyIdentifierClaim in the ContentKeyPolicy which means that the token presented // to the Key Delivery Component must have the identifier of the content key in it. Since we didn't specify // a content key when creating the StreamingLocator, the system created a random one for us. In order to // generate our test token we must get the ContentKeyId to put in the ContentKeyIdentifierClaim claim. var response = client.StreamingLocators.ListContentKeys(config.ResourceGroup, config.AccountName, streamingLocatorName); string keyIdentifier = response.ContentKeys.First().Id.ToString(); // We can either use the "default" StreamingEndpoint or we can create a new StreamingEndpoint. // Typically we would just ensure that the default endpoint was started but let's create one // here to illustrate how it is done. // Console.WriteLine($"Creating a streaming endpoint named {endpointName}"); // Console.WriteLine(); //StreamingEndpoint streamingEndpoint = new StreamingEndpoint(location: mediaService.Location); var streamingEndpoint = client.StreamingEndpoints.Get(config.ResourceGroup, config.AccountName, "default"); // Get the URls to stream the output var paths = client.StreamingLocators.ListPaths(config.ResourceGroup, config.AccountName, streamingLocatorName); Console.WriteLine("The urls to stream the output from a client:"); Console.WriteLine(); var token = GetToken(Issuer, Audience, keyIdentifier, TokenSigningKey); for (int i = 0; i < paths.StreamingPaths.Count; i++) { UriBuilder uriBuilder = new UriBuilder(); uriBuilder.Scheme = "https"; uriBuilder.Host = streamingEndpoint.HostName; if (paths.StreamingPaths[i].Paths.Count > 0) { //uriBuilder.Path = paths.StreamingPaths[i].Paths[0]; //Console.WriteLine($"\t{paths.StreamingPaths[i].StreamingProtocol}-{paths.StreamingPaths[i].EncryptionScheme}"); //Console.WriteLine($"\t\t{uriBuilder.ToString()}"); //Console.WriteLine(); // Look for just the DASH path and generate a URL for the Azure Media Player to playback the content with the AES token to decrypt. // Note that the JWT token is set to expire in 1 hour. if (paths.StreamingPaths[i].StreamingProtocol == StreamingPolicyStreamingProtocol.Dash) { uriBuilder.Path = paths.StreamingPaths[i].Paths[0]; var dashPath = uriBuilder.ToString(); Console.WriteLine("Open the following URL in your browser to play back the file in the Azure Media Player"); Console.WriteLine($"https://ampdemo.azureedge.net/?url={dashPath}&aes=true&aestoken=Bearer%3D{token}"); Console.WriteLine(); } } } } 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}"); } Console.WriteLine("Try Streaming the content using Azure Media Player - https://ampdemo.azureedge.net."); Console.WriteLine("Use the Advanced options to see or modify the AES Bearer token in the AMP demo page. When finished press enter to cleanup."); Console.Out.Flush(); Console.ReadLine(); Console.WriteLine("Cleaning up..."); Cleanup(client, config.ResourceGroup, config.AccountName, transformName, jobName, outputAsset.Name, input, streamingLocatorName, ContentKeyPolicyName); } 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 void JobComboTest() { using (MockContext context = this.StartMockContextAndInitializeClients(this.GetType())) { try { string transformName = TestUtilities.GenerateName("transform"); string transformDescription = "A test transform"; string jobName = TestUtilities.GenerateName("job"); string outputAssetName = TestUtilities.GenerateName("outputAsset"); CreateMediaServicesAccount(); // Create a transform as it is the parent of Jobs TransformOutput[] outputs = new TransformOutput[] { new TransformOutput(new BuiltInStandardEncoderPreset(EncoderNamedPreset.AdaptiveStreaming)) }; Transform transform = MediaClient.Transforms.CreateOrUpdate(ResourceGroup, AccountName, transformName, outputs, transformDescription); // List jobs, which should be empty var jobs = MediaClient.Jobs.List(ResourceGroup, AccountName, transformName); Assert.Empty(jobs); // Try to get the job, which should not exist Job job = MediaClient.Jobs.Get(ResourceGroup, AccountName, transformName, jobName); Assert.Null(job); // Create a job using an input from an HTTP url and an output to an Asset Asset outputAsset = MediaClient.Assets.CreateOrUpdate(ResourceGroup, AccountName, outputAssetName, new Asset()); JobInputHttp jobInputHttp = new JobInputHttp(files: new string[] { "https://amssamples.streaming.mediaservices.windows.net/2e91931e-0d29-482b-a42b-9aadc93eb825/AzurePromo.mp4" }); JobInputs jobInputs = new JobInputs(inputs: new JobInput[] { jobInputHttp }); JobOutputAsset jobOutput = new JobOutputAsset(outputAssetName); JobOutput[] jobOutputs = new JobOutput[] { jobOutput }; Job input = new Job(jobInputs, jobOutputs); Job createdJob = MediaClient.Jobs.Create(ResourceGroup, AccountName, transformName, jobName, input); ValidateJob(createdJob, jobName, null, jobInputs, jobOutputs); // List jobs and validate the created job shows up jobs = MediaClient.Jobs.List(ResourceGroup, AccountName, transformName); Assert.Single(jobs); ValidateJob(jobs.First(), jobName, null, jobInputs, jobOutputs); // Get the newly created job job = MediaClient.Jobs.Get(ResourceGroup, AccountName, transformName, jobName); Assert.NotNull(job); ValidateJob(job, jobName, null, jobInputs, jobOutputs); // If the job isn't already finished, cancel it if (job.State != JobState.Finished) { MediaClient.Jobs.CancelJob(ResourceGroup, AccountName, transformName, jobName); do { System.Threading.Thread.Sleep(15 * 1000); job = MediaClient.Jobs.Get(ResourceGroup, AccountName, transformName, jobName); }while (job.State != JobState.Finished && job.State != JobState.Canceled); } // Delete the job MediaClient.Jobs.Delete(ResourceGroup, AccountName, transformName, jobName); // List jobs, which should be empty again jobs = MediaClient.Jobs.List(ResourceGroup, AccountName, transformName); Assert.Empty(jobs); // Try to get the job, which should not exist job = MediaClient.Jobs.Get(ResourceGroup, AccountName, transformName, jobName); Assert.Null(job); // Delete the transform MediaClient.Transforms.Delete(ResourceGroup, AccountName, transformName); } finally { DeleteMediaServicesAccount(); } } }
/// <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 encoding Transform. This is really a one time setup operation. Transform adaptiveEncodeTransform = EnsureTransformExists(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; // The input to the Job is a HTTPS URL pointing to an MP4 file var input = new JobInputHttp( baseUri: "https://nimbuscdn-nimbuspm.streaming.mediaservices.windows.net/2b533311-b215-4409-80af-529c3e853622/", files: new List <String> { "Ignite-short.mp4" } ); // Out from the 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, transformName, jobName, input, outputAsset.Name); DateTime startedTime = DateTime.Now; // 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. 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); } 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); } }
/// <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 encoding Transform. This is really a one time setup operation. Transform adaptiveEncodeTransform = EnsureTransformExists(client, config.ResourceGroup, config.AccountName, transformName, preset: new BuiltInStandardEncoderPreset(EncoderNamedPreset.AdaptiveStreaming)); // 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 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" ); Asset outputAsset = CreateOutputAsset(client, config.ResourceGroup, config.AccountName, outputAssetName); Job job = SubmitJob(client, config.ResourceGroup, config.AccountName, transformName, jobName, input, 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); } 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); } }