Beispiel #1
0
        private static async Task StoreBreakdownJsonInCosmos(VideoBreakdown videoBreakdownJson, TraceWriter log)
        {
            //string CosmosCollectionName = ConfigurationManager.AppSettings["CosmosCollectionName"];
            //if (String.IsNullOrEmpty(CosmosCollectionName))
            //    throw new ApplicationException("CosmosCollectionName app setting not set");
            var cosmosHelper   = new CosmosHelper(log);
            var collectionName = "Breakdowns";
            var client         = cosmosHelper.GetCosmosClient(collectionName);
            var json           = JsonConvert.SerializeObject(videoBreakdownJson);

            cosmosHelper.LogMessage($"saving json: {json}");
            // save the json as a new document
            try
            {
                Document r =
                    await client.UpsertDocumentAsync(
                        UriFactory.CreateDocumentCollectionUri(CosmosHelper.CosmosDatabasename, collectionName),
                        videoBreakdownJson);
            }
            catch (Exception e)
            {
                cosmosHelper.LogMessage($"error inserting document in cosmos: {e.Message}");
                // ignore for now, but maybe should replace the document if it already exists..
                // seems to be caused by dev environment where queue items are being reprocesssed
            }
        }
Beispiel #2
0
        public static async Task RunAsync(
            [QueueTrigger("%EncodingCompleteQueue%", Connection = "AzureWebJobsStorage")] string myQueueItem, TraceWriter log)
        {
            var videoIndexerHelper = new VideoIndexerHelper(log);
            var cosmosHelper       = new CosmosHelper(log);
            var msg = JsonConvert.DeserializeObject <NotificationMessage>(myQueueItem);

            if (msg.EventType != NotificationEventType.TaskStateChange)
            {
                return; // ignore anything but job complete
            }
            var newJobStateStr = msg.Properties.FirstOrDefault(j => j.Key == Constants.NEWSTATE).Value;

            if (newJobStateStr == Enums.StateEnum.Finished.ToString())
            {
                var jobId  = msg.Properties["JobId"];
                var taskId = msg.Properties["TaskId"];

                _context = MediaServicesHelper.Context;

                var job = _context.Jobs.Where(j => j.Id == jobId).FirstOrDefault();
                if (job == null)
                {
                    videoIndexerHelper.LogMessage($"Job for JobId:{jobId} is null");
                    return;
                }
                var task = job.Tasks.Where(l => l.Id == taskId).FirstOrDefault();
                if (task == null)
                {
                    videoIndexerHelper.LogMessage($"Task for taskId:{taskId} is null");
                    return;
                }
                var outputAsset = task.OutputAssets[0];
                var inputAsset  = task.InputAssets[0];


                cosmosHelper.LogMessage("Read policy");
                var readPolicy =
                    _context.AccessPolicies.Create("readPolicy", TimeSpan.FromHours(4), AccessPermissions.Read);
                var outputLocator = _context.Locators.CreateLocator(LocatorType.Sas, outputAsset, readPolicy);
                cosmosHelper.LogMessage("Create cloud blob client");
                var destBlobStorage = BlobHelper.AmsStorageAccount.CreateCloudBlobClient();
                cosmosHelper.LogMessage("get asset container");
                // Get the asset container reference
                var outContainerName = new Uri(outputLocator.Path).Segments[1];
                var outContainer     = destBlobStorage.GetContainerReference(outContainerName);
                cosmosHelper.LogMessage("use largest single mp4 ");
                // use largest single mp4 output (highest bitrate) to send to Video Indexer
                var biggestblob = outContainer.ListBlobs().OfType <CloudBlockBlob>()
                                  .Where(b => b.Name.ToLower().EndsWith(".mp4"))
                                  .OrderBy(u => u.Properties.Length).Last();
                cosmosHelper.LogMessage("GetSasUrl");
                var sas = videoIndexerHelper.GetSasUrl(biggestblob);
                cosmosHelper.LogMessage(" submit to VI ");
                // Submit processing job to Video Indexer
                await videoIndexerHelper.SubmitToVideoIndexerAsync(biggestblob.Name, sas, inputAsset.AlternateId, log);
            }
        }
Beispiel #3
0
        public static async Task Run([QueueTrigger("%InputQueue%", Connection = "AzureWebJobsStorage")] VippyProcessingState manifest,
                                     [Blob("%AmsBlobInputContainer%/{BlobName}", FileAccess.ReadWrite)] CloudBlockBlob videoBlobTriggered,
                                     [Blob("%ExistingAmsBlobInputContainer%/{BlobName}", FileAccess.ReadWrite)] CloudBlockBlob videoBlobExisting,

                                     TraceWriter log)
        {
            //================================================================================
            // Function AMSInputQueueHandler
            // Purpose:
            // This is where the start of the pipeline work begins. It will submit an encoding
            // job to Azure Media Services.  When that job completes asyncronously, a notification
            // webhook will be called by AMS which causes the next stage of the pipeline to
            // continue.
            //================================================================================
            CloudBlockBlob videoBlob = null;

            if (manifest.Origin == Enums.OriginEnum.Existing)
            {
                videoBlob = videoBlobExisting;
            }
            else if (manifest.Origin == Enums.OriginEnum.Trigger)
            {
                videoBlob = videoBlobTriggered;
            }
            if (videoBlob == null)
            {
                log.Error("There is being an error, videoblog not initialized, not marked as existing or trigger or video is null");
                return;
            }
            var context               = MediaServicesHelper.Context;
            var cosmosHelper          = new CosmosHelper(log);
            var toDeleteContainerName = Environment.GetEnvironmentVariable("AmsBlobToDeleteContainer");

            // only set the starttime if it wasn't already set in blob watcher function (that way
            // it works if the job is iniaited by using this queue directly
            if (manifest.StartTime == null)
            {
                manifest.StartTime = DateTime.Now;
            }

            var videofileName = videoBlob.Name;

            // get a new asset from the blob, and use the file name if video title attribute wasn't passed.
            IAsset newAsset;

            try
            {
                newAsset = BlobHelper.CreateAssetFromBlob(videoBlob, videofileName, log)
                           .GetAwaiter().GetResult();
            }
            catch (Exception e)
            {
                throw new ApplicationException($"Error occured creating asset from Blob;/r/n{e.Message}");
            }

            // If an internal_id was passed in the metadata, use it within AMS (AlternateId) and Cosmos(Id - main document id) for correlation.
            // if not, generate a unique id.  If the same id is ever reprocessed, all stored metadata
            // will be overwritten.

            newAsset.AlternateId = manifest.AlternateId;
            newAsset.Update();

            manifest.AmsAssetId = newAsset.Id;

            log.Info($"Deleting  the file  {videoBlob.Name} from the container ");

            //move the video to the to delete folder
            await BlobHelper.Move(videoBlob.Container.Name, toDeleteContainerName, videofileName, log);

            //move the manifest to the to delete folder
            string manifestName = videofileName.Remove(videofileName.IndexOf('.')) + ".json";

            log.Info($"Deleting  the file  {manifestName} from the container ");
            await BlobHelper.Move(videoBlob.Container.Name, toDeleteContainerName, manifestName, log);

            // copy blob into new asset
            // create the encoding job
            var job = context.Jobs.Create("MES encode from input container - ABR streaming");

            // Get a media processor reference, and pass to it the name of the
            // processor to use for the specific task.
            var processor = MediaServicesHelper.GetLatestMediaProcessorByName("Media Encoder Standard");

            var task = job.Tasks.AddNew("encoding task",
                                        processor,
                                        "Content Adaptive Multiple Bitrate MP4",
                                        TaskOptions.None
                                        );

            task.Priority = 100;
            task.InputAssets.Add(newAsset);

            // setup webhook notification
            var keyBytes = new byte[32];

            // Check for existing Notification Endpoint with the name "FunctionWebHook"
            var existingEndpoint = context.NotificationEndPoints.Where(e => e.Name == "FunctionWebHook").FirstOrDefault();
            INotificationEndPoint endpoint;

            //if (existingEndpoint != null)
            //{
            //    endpoint = existingEndpoint;
            //}
            //else
            try
            {
                endpoint = context.NotificationEndPoints.Create("FunctionWebHook",
                                                                NotificationEndPointType.WebHook, WebHookEndpoint, keyBytes);
            }
            catch (Exception)
            {
                throw new ApplicationException(
                          $"The endpoing address specified - '{WebHookEndpoint}' is not valid.");
            }

            task.TaskNotificationSubscriptions.AddNew(NotificationJobState.FinalStatesOnly, endpoint, false);
            cosmosHelper.LogMessage($"Add an output asset to contain the results of the job");
            // Add an output asset to contain the results of the job.
            // This output is specified as AssetCreationOptions.None, which
            // means the output asset is not encrypted.
            task.OutputAssets.AddNew(videofileName, AssetCreationOptions.None);

            // Starts the job in AMS.  AMS will notify the webhook when it completes
            job.Submit();
            cosmosHelper.LogMessage($"Saving on cosmos DB");
            // update processing progress with id and metadata payload
            await cosmosHelper.StoreProcessingStateRecordInCosmosAsync(manifest);

            cosmosHelper.LogMessage($"AMS encoding job submitted for {videofileName}");
        }