public static async Task Run(
            [QueueTrigger("%PublishJobsQueueName%", Connection = "MediaStorageAccount")] string assetId,
            [Queue("%UpdateCMSQueueName%", Connection = "MediaStorageAccount")] ICollector <UpdateReferenceMessage> updateCMSQueue,
            TraceWriter log)
        {
            log.Info($"C# Queue trigger function processed: {assetId}");


            var context = MediaContextHelper.CreateContext();
            var asset   = context.Assets.Where(a => a.Id == assetId).FirstOrDefault();

            if (asset == null)
            {
                return;
            }

            var locator = await context.Locators.CreateAsync(
                LocatorType.OnDemandOrigin,
                asset,
                AccessPermissions.Read,
                TimeSpan.FromDays(365 * 10));

            updateCMSQueue.Add(new UpdateReferenceMessage
            {
                AssetId = asset.Id,
                Status  = AssetWorkflowStatus.Published
            });
        }
Example #2
0
        public static async Task Run(
            [QueueTrigger("%ContentProtectionJobsQueueName%", Connection = "MediaStorageAccount")]
            string assetId,
            [Queue("%PublishJobsQueueName%", Connection = "MediaStorageAccount")]
            ICollector <string> outputPublishQueue,
            TraceWriter log)
        {
            log.Info($"C# Queue trigger function processed: {assetId}");

            var context = MediaContextHelper.CreateContext();
            var asset   = context.Assets.Where(a => a.Id == assetId).FirstOrDefault();

            if (asset == null)
            {
                return;
            }

            // PlayReady + Widevine
            await AddPlayReadyWidevineEncryption(context, asset);

            // FairPlay
            await AddFairPlayEncryption(context, asset);

            outputPublishQueue.Add(asset.Id);
        }
        public static async Task Run(
            [BlobTrigger("%BlobIngestContainer%/{name}", Connection = "MediaStorageAccount")]
            CloudBlockBlob blob,
            TraceWriter log)
        {
            log.Info($"C# Blob trigger function Processed blob Name: {blob.Name}");

            // We're avoiding incomplete blob processing. Eventually the engine
            // will pick it up from the container, when it's completed.
            if (blob.CopyState.Status != CopyStatus.Success)
            {
                return;
            }

            var mediaStorageAccountCredentials = blob.ServiceClient.Credentials;
            var context = MediaContextHelper.CreateContext();

            var asset = await context.Assets.CreateFromBlobAsync(blob,
                                                                 mediaStorageAccountCredentials,
                                                                 AssetCreationOptions.None,
                                                                 CancellationToken.None);

            // Add the Alternate ID original stored on the Blob Name as partial path
            asset.AlternateId = blob.Name.Split('-').First();
            await asset.UpdateAsync();

            var mediaEncoderStandardTaskPreset =
                Environment.GetEnvironmentVariable("MediaEncoderStandardTaskPreset");

            var job = context.Jobs.CreateWithSingleTask(
                MediaProcessorNames.MediaEncoderStandard,
                mediaEncoderStandardTaskPreset,
                asset,
                $"{asset.Name} MES encoded",
                AssetCreationOptions.None);

            var notificationName = Environment.GetEnvironmentVariable("QueueNotificationEndpointName");
            var queueName        = Environment.GetEnvironmentVariable("EncodeJobsQueueName");

            var endpoint = await GetOrCreateQueueNotificationEndpoint(context, notificationName, queueName);

            job.JobNotificationSubscriptions.AddNew(NotificationJobState.All, endpoint);
            await job.SubmitAsync();

            // Clean up the original Blob from the Storage Account.
            await blob.DeleteIfExistsAsync();
        }
        public static async Task Run(
            [QueueTrigger("%EncodeJobsQueueName%", Connection = "MediaStorageAccount")]
            dynamic queueItem,
            [Queue("%ContentProtectionJobsQueueName%", Connection = "MediaStorageAccount")]
            ICollector <string> outputContentProtectionQueue,
            TraceWriter log)
        {
            log.Info($"C# Queue trigger function processed: {queueItem}");

            if (queueItem.Properties.NewState != JobState.Finished.ToString())
            {
                return;
            }

            var context = MediaContextHelper.CreateContext();
            var jobId   = (string)queueItem.Properties.JobId;

            var job = context.Jobs.Where(j => j.Id == jobId).FirstOrDefault();

            if (job == null)
            {
                return;
            }

            // Copy the Alternate ID from the Mezzanine Asset to the Output Asset
            var mezzanineAsset = job.InputMediaAssets.FirstOrDefault();
            var outputAsset    = job.OutputMediaAssets.FirstOrDefault();

            outputAsset.AlternateId = mezzanineAsset.AlternateId;
            await outputAsset.UpdateAsync();

            // Cleanup mezzanine asset
            await mezzanineAsset.DeleteAsync();

            // Add Content Protection
            outputContentProtectionQueue.Add(outputAsset.Id);
        }
Example #5
0
        public static async Task Run(
            [QueueTrigger("%UpdateCMSQueueName%", Connection = "MediaStorageAccount")]
            UpdateReferenceMessage message,
            TraceWriter log)
        {
            log.Info($"C# Queue trigger function processed: {message.AssetId}");

            var context = MediaContextHelper.CreateContext();
            var asset   = context.Assets.Where(a => a.Id == message.AssetId).FirstOrDefault();

            // We're filtering out the Published options, however this would be a great
            // place to update with error status and implement and error control flow.
            // e.g. Needs re-encoding and such.
            if (asset == null || message.Status != AssetWorkflowStatus.Published)
            {
                return;
            }

            // At this point you have the asset to do call the CMS and update it, all the required
            // information for the CMS, will be read from the Asset Metadata as follows.
            var metadata = await asset.GetMetadataAsync(CancellationToken.None);

            // Sometimes by the time we reach this point the locator ain't ready. Hence we're
            // we're throwing an exception when metadata isn't ready, to reprocess on a
            // future iteration.
            if (metadata == null || metadata.Count() == 0)
            {
                throw new Exception($"Asset {asset.Id} metadata is not ready yet.");
            }

            var aggregatedMetadata = new
            {
                AssetId          = asset.Id,
                AssetAlternateId = asset.AlternateId,
                BaseStreamingUri = asset.GetSmoothStreamingUri(),

                Duration           = metadata.Max(m => m.Duration),
                AudioTracksCount   = metadata.Max(m => m.AudioTracks.Count()),
                VideoBitratesCount = metadata.Count(),
                Bitrate            = metadata.SelectMany(m => m.VideoTracks).Max(vt => vt.Bitrate),
                Height             = metadata.SelectMany(m => m.VideoTracks).Max(vt => vt.Height),
                Width       = metadata.SelectMany(m => m.VideoTracks).Max(vt => vt.Width),
                AspectRatio = metadata.SelectMany(m => m.VideoTracks).Select(vt => $"{vt.DisplayAspectRatioNumerator}:{vt.DisplayAspectRatioDenominator}").FirstOrDefault()
            };

            log.Info($"AssetId: {aggregatedMetadata.AssetId}");
            log.Info($"AssetAlternateId: {aggregatedMetadata.AssetAlternateId}");
            log.Info($"Base Streaming URL: {asset.GetSmoothStreamingUri()}");
            log.Info($"Duration: {aggregatedMetadata.Duration}");
            log.Info($"Number of Audio Tracks: {aggregatedMetadata.AudioTracksCount}");
            log.Info($"Number of Video Bitrates: {aggregatedMetadata.VideoBitratesCount}");
            log.Info($"Bitrate: {aggregatedMetadata.Bitrate}");
            log.Info($"Height: {aggregatedMetadata.Height}");
            log.Info($"Width: {aggregatedMetadata.Width}");
            log.Info($"AspectRatio: {aggregatedMetadata.AspectRatio}");

            using (var client = new HttpClient())
            {
                await client.PostAsJsonAsync(
                    Environment.GetEnvironmentVariable("CMSCallbackUrl"), aggregatedMetadata);
            }
        }