// </SubmitJob> /// <summary> /// Polls Media Services for the status of the Job. /// </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 name of the job you submitted.</param> /// <returns></returns> // <WaitForJobToFinish> private static async Task <Job> WaitForJobToFinishAsync( IAzureMediaServicesClient client, AzureMediaServiceConfig amsConfig, string jobName) { const int SleepIntervalMs = 20 * 1000; Job job; do { job = await client.Jobs.GetAsync(amsConfig.ResourceGroup, amsConfig.AccountName, AdaptiveStreamingTransformName, jobName); Console.WriteLine($"Job is '{job.State}'."); for (int i = 0; i < job.Outputs.Count; i++) { JobOutput output = job.Outputs[i]; Console.Write($"\tJobOutput[{i}] is '{output.State}'."); if (output.State == JobState.Processing) { Console.Write($" Progress (%): '{output.Progress}'."); } Console.WriteLine(); } if (job.State != JobState.Finished && job.State != JobState.Error && job.State != JobState.Canceled) { await Task.Delay(SleepIntervalMs); } }while (job.State != JobState.Finished && job.State != JobState.Error && job.State != JobState.Canceled); return(job); }
public static async Task Main(string[] args) { AzureMediaServiceConfig config = new AzureMediaServiceConfig(new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddEnvironmentVariables() .Build()); try { await RunAsync(config); } catch (Exception exception) { if (exception.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($"{exception.Message}"); 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}'."); } } Console.WriteLine("Press Enter to continue."); Console.ReadLine(); }
// </EnsureTransformExists> /// <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">The name of the input asset.</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, AzureMediaServiceConfig amsConfig, string jobName, string inputAssetName, string outputAssetName) { // Use the name of the created input asset to create the job input. JobInput jobInput = new JobInputAsset(assetName: inputAssetName); 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( amsConfig.ResourceGroup, amsConfig.AccountName, AdaptiveStreamingTransformName, jobName, new Job { Input = jobInput, Outputs = jobOutputs, }); return(job); }
// </RunAsync> /// <summary> /// Create the ServiceClientCredentials object based on the credentials /// supplied in local configuration file. /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <GetCredentialsAsync> private static async Task <ServiceClientCredentials> GetCredentialsAsync(AzureMediaServiceConfig config) { // Use ApplicationTokenProvider.LoginSilentWithCertificateAsync or UserTokenProvider.LoginSilentAsync to get a token using service principal with certificate //// ClientAssertionCertificate //// ApplicationTokenProvider.LoginSilentWithCertificateAsync // Use ApplicationTokenProvider.LoginSilentAsync to get a token using a service principal with symetric key ClientCredential clientCredential = new ClientCredential(config.AadClientId, config.AadSecret); return(await ApplicationTokenProvider.LoginSilentAsync(config.AadTenantId, clientCredential, ActiveDirectoryServiceSettings.Azure)); }
public async static Task <Uri> GetUrl(IAzureMediaServicesClient client, AzureMediaServiceConfig config, string assetName = "") { // Use Media Services API to get back a response that contains // SAS URL for the Asset container into which to upload blobs. // That is where you would specify read-write permissions // and the exparation time for the SAS URL. var response = await client.Assets.ListContainerSasAsync( config.ResourceGroup, config.AccountName, assetName == string.Empty? "moon" : assetName, permissions : AssetContainerPermission.ReadWrite, expiryTime : DateTime.UtcNow.AddHours(4).ToUniversalTime()); return(new Uri(response.AssetContainerSasUrls.First())); }
// </CreateOutputAsset> /// <summary> /// If the specified transform exists, get that transform. /// If the it does not exist, creates a new transform with the specified output. /// In this case, the output is set to encode a video using one of the built-in encoding presets. /// </summary> /// <param name="azureMediaServiceClient">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> /// <returns></returns> // <EnsureTransformExists> private static async Task <Transform> GetOrCreateTransformAsync( IAzureMediaServicesClient azureMediaServiceClient, AzureMediaServiceConfig azureMediaServiceConfig) { // Does a Transform already exist with the desired name? Assume that an existing Transform with the desired name // also uses the same recipe or Preset for processing content. Transform transform = await azureMediaServiceClient.Transforms. GetAsync(azureMediaServiceConfig.ResourceGroup, azureMediaServiceConfig.AccountName, AdaptiveStreamingTransformName); if (transform == null) { throw new ArgumentException("could not find the specific transformer ", AdaptiveStreamingTransformName); } return(transform); }
// </CreateInputAsset> /// <summary> /// Creates an ouput asset. The output from the encoding Job must be written to an Asset. /// </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="outputAssetName">The output asset name.</param> /// <returns></returns> // <CreateOutputAsset> private static async Task <Asset> CreateOutputAssetAsync( IAzureMediaServicesClient client, AzureMediaServiceConfig amsConfig, string outputAssetName) { // Check if an Asset already exists Asset inputAsset = await client.Assets.GetAsync(amsConfig.ResourceGroup, amsConfig.AccountName, outputAssetName); Asset outputAsset = new Asset(); if (inputAsset != null) { throw new ArgumentException("the output asset name already exists", outputAssetName); } return(await client.Assets.CreateOrUpdateAsync(amsConfig.ResourceGroup, amsConfig.AccountName, outputAssetName, outputAsset)); }
// </CreateMediaServicesClient> /// <summary> /// Creates a new input Asset and uploads the specified local video file into it. /// </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="assetName">The asset name.</param> /// <param name="fileToUpload">The file you want to upload into the asset.</param> /// <returns></returns> // <CreateInputAsset> private static async Task <Asset> CreateInputAssetAsync( IAzureMediaServicesClient client, AzureMediaServiceConfig amsConfig, string assetName, string fileToUpload) { // In this example, we are assuming that the asset name is unique. // // If you already have an asset with the desired name, use the Assets.Get method // to get the existing asset. In Media Services v3, the Get method on entities returns null // if the entity doesn't exist (a case-insensitive check on the name). // Call Media Services API to create an Asset. // This method creates a container in storage for the Asset. // The files (blobs) associated with the asset will be stored in this container. Asset asset = await client.Assets.CreateOrUpdateAsync(amsConfig.ResourceGroup, amsConfig.AccountName, assetName, new Asset()); // Use Media Services API to get back a response that contains // SAS URL for the Asset container into which to upload blobs. // That is where you would specify read-write permissions // and the exparation time for the SAS URL. var response = await client.Assets.ListContainerSasAsync( amsConfig.ResourceGroup, amsConfig.AccountName, assetName, permissions : AssetContainerPermission.ReadWrite, expiryTime : DateTime.UtcNow.AddHours(4).ToUniversalTime()); var sasUri = new Uri(response.AssetContainerSasUrls.First()); // Use Storage API to get a reference to the Asset container // that was created by calling Asset's CreateOrUpdate method. BlobContainerClient container = new BlobContainerClient(sasUri); BlobClient blob = container.GetBlobClient(Path.GetFileName(fileToUpload)); // Use Strorage API to upload the file into the container in storage. if (File.Exists(InputMP4FilePath)) { var file = File.ReadAllBytes(InputMP4FileName); var stream = new MemoryStream(file); await blob.UploadAsync(stream); } return(asset); }
// </WaitForJobToFinish> /// <summary> /// Creates a StreamingLocator for the specified asset and with the specified streaming policy name. /// Once the StreamingLocator is created the output asset is available to clients for playback. /// </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="assetName">The name of the output asset.</param> /// <param name="locatorName">The StreamingLocator name (unique in this case).</param> /// <returns></returns> // <CreateStreamingLocator> private static async Task <StreamingLocator> CreateStreamingLocatorAsync( IAzureMediaServicesClient client, AzureMediaServiceConfig amsConfig, string assetName, string locatorName) { StreamingLocator locator = await client.StreamingLocators.CreateAsync( amsConfig.ResourceGroup, amsConfig.AccountName, locatorName, new StreamingLocator { AssetName = assetName, StreamingPolicyName = PredefinedStreamingPolicy.ClearStreamingOnly }); return(locator); }
/// <summary> /// Run the sample async. /// </summary> /// <param name="amsConfig">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <RunAsync> private static async Task RunAsync(AzureMediaServiceConfig amsConfig) { Console.WriteLine("starting creating assents."); IAzureMediaServicesClient azureMediaServiceClient = await CreateMediaServicesClientAsync(amsConfig); // Set the polling interval for long running operations to 2 seconds. // The default value is 30 seconds for the .NET client SDK azureMediaServiceClient.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 uniqueAssetName = "ignition"; string jobName = $"{uniqueAssetName}-job"; string locatorName = $"{uniqueAssetName}-locator"; string outputAssetName = $"{uniqueAssetName}-output"; string inputAssetName = $"{uniqueAssetName}-input"; // Ensure that you have the desired encoding Transform. This is really a one time setup operation. var transform = await GetOrCreateTransformAsync(azureMediaServiceClient, amsConfig); // Create a new input Asset and upload the specified local video file into it. var inputAsset = await CreateInputAssetAsync(azureMediaServiceClient, amsConfig, uniqueAssetName, 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 var outputAsset = await CreateOutputAssetAsync(azureMediaServiceClient, amsConfig, outputAssetName); _ = await SubmitJobAsync(azureMediaServiceClient, amsConfig, jobName, inputAssetName, 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 job = await WaitForJobToFinishAsync(azureMediaServiceClient, amsConfig, 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(azureMediaServiceClient, amsConfig, outputAssetName, 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(azureMediaServiceClient, amsConfig.ResourceGroup, amsConfig.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"); } }
// </GetCredentialsAsync> /// <summary> /// Creates the AzureMediaServicesClient object based on the credentials /// supplied in local configuration file. /// </summary> /// <param name="config">The parm is of type ConfigWrapper. This class reads values from local configuration file.</param> /// <returns></returns> // <CreateMediaServicesClient> private static async Task <IAzureMediaServicesClient> CreateMediaServicesClientAsync(AzureMediaServiceConfig config) { var credentials = await GetCredentialsAsync(config); return(new AzureMediaServicesClient(config.ArmEndpoint, credentials) { SubscriptionId = config.SubscriptionId, }); }