コード例 #1
0
        // mode : "shots", "scenes", "purge", "load"
        //  [HttpPost]
        public async Task Importviscenes(string mode, string videoId, string viAcctID, string viSubKey, string viLocation, string translationLang)
        {
            if (mode == "load")
            {
                return;
            }

            Functions.SendProgress("Cleaning...", 0, 1);

            // Pass a list of blob URIs in ViewBag
            CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
            CloudBlobClient     client  = account.CreateCloudBlobClient();

            CloudBlobContainer containerVideoId = client.GetContainerReference(videoId);
            // Let's purge the data

            // let's purge all existing blobs
            List <IListBlobItem> blobsList = new List <IListBlobItem>();

            try
            {
                blobsList = containerVideoId.ListBlobs().ToList();
                List <Task> myTasks = new List <Task>();
                foreach (IListBlobItem item in containerVideoId.ListBlobs(useFlatBlobListing: true))
                {
                    var blob = item as CloudBlockBlob;

                    if (blob != null)
                    {
                        myTasks.Add(blob.DeleteAsync());
                    }
                }
                await Task.WhenAll(myTasks.ToArray()).ConfigureAwait(false);
            }
            catch (Exception exc)
            {
                ViewBag.ErrorMsg = exc.ToString();
                Functions.SendProgress("Error in ListBlobs:" + exc.Message, 0, 1);
            }

            // user wants only purge
            if (mode == "purge")
            {
                return;
            }

            Functions.SendProgress("Initialization...", 0, 1);

            await containerVideoId.CreateIfNotExistsAsync(BlobContainerPublicAccessType.Container, null, null).ConfigureAwait(false);

            // Translator credentials
            string translatorSubscriptionKey = ConfigurationManager.AppSettings["TranslatorSubscriptionKey"];
            string translatorEndpoint        = ConfigurationManager.AppSettings["TranslatorEndpoint"];

            // Computer vision init
            ComputerVisionClient vision = new ComputerVisionClient(
                new ApiKeyServiceClientCredentials(ConfigurationManager.AppSettings["VisionSubscriptionKey"]),
                new System.Net.Http.DelegatingHandler[] { }
                );

            vision.Endpoint = ConfigurationManager.AppSettings["VisionEndpoint"];

            VisualFeatureTypes[] features = new VisualFeatureTypes[] { VisualFeatureTypes.Description };

            // test code get all thumbnails
            string       jsonData = "";
            VideoIndexer myVI     = new VideoIndexer(viAcctID, viLocation, viSubKey);

            try
            {
                //videoToken = await myVI.GetVideoAccessTokenAsync(videoId).ConfigureAwait(false);
                jsonData = await myVI.GetInsightsAsync(videoId).ConfigureAwait(false);
            }
            catch (Exception exc)
            {
                ViewBag.ErrorMsg = exc.ToString();
                Functions.SendProgress("Error in GetInsightsAsync:" + exc.Message, 0, 1);

                return;
            }

            // SAVING INSIGHTS AS A BLOB
            CloudBlockBlob insightsBlob = containerVideoId.GetBlockBlobReference(dirInsights + "/" + fileInsights);
            JObject        jObj         = JObject.Parse(jsonData);
            await insightsBlob.UploadTextAsync(jObj.ToString(Formatting.Indented)).ConfigureAwait(false);

            List <BlobInfo> blobs = new List <BlobInfo>();

            Dictionary <TimeSpan, string> shotsTimingAndThumbnailsId = new Dictionary <TimeSpan, string>();
            Dictionary <TimeSpan, string> scenesTimingAndThumbnailId = new Dictionary <TimeSpan, string>();
            dynamic viInsights = JsonConvert.DeserializeObject <dynamic>(jsonData);
            var     video      = viInsights.videos[0];
            var     shots      = video.insights.shots;
            var     scenes     = video.insights.scenes;

            // list of shots
            foreach (var shot in shots)
            {
                foreach (var keyFrame in shot.keyFrames)
                {
                    foreach (var instance in keyFrame.instances)
                    {
                        string thumbnailId        = (string)instance.thumbnailId;
                        string thumbnailStartTime = (string)instance.adjustedStart;
                        shotsTimingAndThumbnailsId.Add(TimeSpan.Parse(thumbnailStartTime, CultureInfo.InvariantCulture), thumbnailId);
                    }
                }
            }
            var listTimings = shotsTimingAndThumbnailsId.Select(d => d.Key).ToList().OrderBy(d => d);

            //list of scenes (a scene contains several shots, but in the JSON, thumbnails are not defined in scenes)
            if (scenes != null) // sometimes, there is no scene !
            {
                foreach (var scene in scenes)
                {
                    TimeSpan start       = TimeSpan.Parse((string)scene.instances[0].adjustedStart, CultureInfo.InvariantCulture);
                    var      closestTime = listTimings.OrderBy(t => Math.Abs((t - start).Ticks))
                                           .First();
                    scenesTimingAndThumbnailId.Add(closestTime, shotsTimingAndThumbnailsId[closestTime]);
                }
            }

            // it's the list of thumbnails we want to process (scenes or all shots)
            Dictionary <TimeSpan, string> thumbnailsToProcessTimeAndId = new Dictionary <TimeSpan, string>();

            if (mode == "scenes")   // scenes only
            {
                if (scenes == null) // no scenes, let's quit
                {
                    Functions.SendProgress($"No scenes !", 10, 10);
                    return;
                }
                thumbnailsToProcessTimeAndId = scenesTimingAndThumbnailId;
            }
            else // all shots
            {
                thumbnailsToProcessTimeAndId = shotsTimingAndThumbnailsId;;
            }

            int index = 0;

            foreach (var thumbnailEntry in thumbnailsToProcessTimeAndId)
            {
                Functions.SendProgress($"Processing {thumbnailsToProcessTimeAndId.Count} thumbnails...", index, thumbnailsToProcessTimeAndId.Count);
                index++;
                //if (index == 100) break;

                string thumbnailId        = thumbnailEntry.Value;
                var    thumbnailStartTime = thumbnailEntry.Key;

                // Get the video thumbnail data and upload to photos folder
                var thumbnailHighResStream = await myVI.GetVideoThumbnailAsync(videoId, thumbnailId).ConfigureAwait(false);

                CloudBlockBlob thumbnailHighResBlob = containerVideoId.GetBlockBlobReference(dirHighRes + "/" + thumbnailId + ".jpg");
                await thumbnailHighResBlob.UploadFromStreamAsync(thumbnailHighResStream).ConfigureAwait(false);

                // let's create the low res version
                using (var thumbnailLowResStream = new MemoryStream())
                {
                    thumbnailHighResStream.Seek(0L, SeekOrigin.Begin);
                    var settings = new ResizeSettings {
                        MaxWidth = 192
                    };
                    ImageBuilder.Current.Build(thumbnailHighResStream, thumbnailLowResStream, settings);
                    thumbnailLowResStream.Seek(0L, SeekOrigin.Begin);
                    CloudBlockBlob thumbnailLowRes = containerVideoId.GetBlockBlobReference(dirLowRes + "/" + thumbnailId + ".jpg");
                    await thumbnailLowRes.UploadFromStreamAsync(thumbnailLowResStream).ConfigureAwait(false);
                }

                // Submit the image to Azure's Computer Vision API
                var result = await vision.AnalyzeImageAsync(thumbnailHighResBlob.Uri.ToString(), features).ConfigureAwait(false);

                // cleaning metadata on blobs
                thumbnailHighResBlob.Metadata.Clear();
                thumbnailHighResBlob.Metadata.Add("Index", index.ToString(CultureInfo.InvariantCulture));

                // Record the image description and tags in blob metadata
                if (result.Description.Captions.Count > 0)
                {
                    thumbnailHighResBlob.Metadata.Add("Description", result.Description.Captions[0].Text);
                    thumbnailHighResBlob.Metadata.Add("Confidence", (result.Description.Captions[0].Confidence * 100).ToString("F1", CultureInfo.InvariantCulture));

                    if (!string.IsNullOrEmpty(translationLang))
                    {
                        try
                        {
                            string descriptionTranslated = await Translator.TranslateTextRequest(translatorSubscriptionKey, translatorEndpoint, result.Description.Captions[0].Text, translationLang).ConfigureAwait(false);

                            thumbnailHighResBlob.Metadata.Add("DescriptionTranslated", Convert.ToBase64String(Encoding.UTF8.GetBytes(descriptionTranslated)));
                        }
                        catch (Exception exc)
                        {
                            ViewBag.ErrorMsg = exc.ToString();
                            Functions.SendProgress("Error in TranslateTextRequest:" + exc.Message, 0, 1);
                        }
                    }

                    //var guidThumbnail = Path.GetFileNameWithoutExtension(thumbnailHighResBlob.Name).Substring(18);
                }
                thumbnailHighResBlob.Metadata.Add("AdjustedStart", thumbnailStartTime.ToString());

                for (int i = 0; i < result.Description.Tags.Count; i++)
                {
                    string key = String.Format(CultureInfo.InvariantCulture, "Tag{0}", i);
                    thumbnailHighResBlob.Metadata.Add(key, result.Description.Tags[i]);
                }

                await thumbnailHighResBlob.SetMetadataAsync().ConfigureAwait(false);
            }

            // 100%
            Functions.SendProgress($"Processing {thumbnailsToProcessTimeAndId.Count} thumbnails...", 10, 10);
            //return RedirectToAction("Index");
        }
コード例 #2
0
        /// <summary>
        /// Retrieve all thumbnails from a video in VI and upload them to blob storage.
        /// Currently cycles through the thumbnails for every instance, in every keyframe, in every shot.
        /// </summary>
        /// <param name="videoid">The VI ID of the video to be parsed for thumbnails.</param>
        /// <returns>Awaitable task.</returns>
        private static async Task SaveThumbnailsFromVideoShots(string videoid)
        {
            string msg;

            try
            {
                // Tracking the start time for performance analytics
                DateTime startTimestamp = DateTime.Now;
                msg = $"[{startTimestamp.ToShortTimeString()}] Retrieving Video Indexer insights for video id: {videoid}... ";
                Console.Write(msg);

                int thumbcount = 0;

                // Retrieve all the insights from a given video to parse them for thumbnails
                var insights = await client.GetInsightsAsync(videoid).ConfigureAwait(false);

                if (insights != null && insights.Videos.Count > 0)
                {
                    Console.WriteLine("Completed!");
                    msg = $"[Saving all shot thumbnails for video id: {videoid}. Please wait...";
                    Console.WriteLine(msg);

                    // Initialization for saving thumbnails to a local file folder
                    string foldername = null;
                    if (config["savefolder"]?.Length > 0)
                    {
                        // Create the selected director if it doesn't exist, the video ID is used as a subfolder
                        foldername = config["savefolder"].TrimEnd(new char[] { '/', '\\' });
                        DirectoryInfo folder = Directory.CreateDirectory(Path.Combine(foldername, videoid));
                        foldername = folder.FullName;
                    }

                    // Initialization for blob storage upload
                    // The container name is provided as a command line parameter
                    BlobContainerClient containerClient = null;
                    if (config["savecontainer"]?.Length > 0)
                    {
                        if (blobAccount.Length > 0 && blobConnectionString.Length > 0)
                        {
                            // Create a BlobServiceClient object which will be used to create a container client
                            BlobServiceClient blobServiceClient = new BlobServiceClient(blobConnectionString);

                            if (blobServiceClient != null)
                            {
                                // Create the container and return a container client object. The video ID is used to aggregate thumbnails by video.
                                // TODO: Do we need to insure uniqueness of the container name to be created/used in blob storage?
                                containerClient = blobServiceClient.GetBlobContainerClient($"{config["savecontainer"]}-{videoid}".ToLowerInvariant());
                                await containerClient.CreateIfNotExistsAsync().ConfigureAwait(false);

                                if ((await(containerClient?.ExistsAsync()).ConfigureAwait(false)) == true)
                                {
                                    // Prepare metadata to augment the blob container
                                    var blobMetadata = new Dictionary <string, string>()
                                    {
                                        { "videoid", videoid },
                                        { "videoname", insights.Name },
                                    };
                                    await containerClient.SetMetadataAsync(blobMetadata).ConfigureAwait(false);
                                }
                            }
                        }
                    }

                    // Cycle through each video in the playlist returned by VI
                    foreach (Video video in insights.Videos)
                    {
                        // Cycle through each shot indexed by VI
                        Console.WriteLine($"No of shots in video: {insights.Videos[0].Insights.Shots.Count}");
                        foreach (Shot shot in video.Insights.Shots)
                        {
                            // Cycle through each keyframe in every shot
                            foreach (Keyframe keyframe in shot.KeyFrames)
                            {
                                // Cycle through each thumbnail instance in a keyframe
                                foreach (Instance instance in keyframe.Instances)
                                {
                                    // Not all instances are guaranteed to have a thumbnail
                                    if (instance.ThumbnailId.Length > 0)
                                    {
                                        // Retrieve the thumbnail for that video
                                        using (MemoryStream thumbnail = await client.GetThumbnailAsync(videoid, instance.ThumbnailId).ConfigureAwait(false) as MemoryStream)
                                        {
                                            if (thumbnail != null && thumbnail.Length > 0)
                                            {
                                                using (var image = new Bitmap(thumbnail))
                                                {
                                                    string thumbfile = $"{videoid}_{shot.Id}_{keyframe.Id}_{thumbcount}.jpg";

                                                    // Saving the thumbnail to a folder
                                                    if (foldername?.Length > 0)
                                                    {
                                                        Console.WriteLine($"Saving thumbnail image file: {thumbfile}");
                                                        image.Save(Path.Combine(foldername, thumbfile));
                                                    }

                                                    // Saving the thumbnail to Azure blob storage
                                                    if (config["savecontainer"]?.Length > 0)
                                                    {
                                                        if (containerClient != null)
                                                        {
                                                            // Get a reference to a blob
                                                            BlobClient blobClient = containerClient.GetBlobClient(thumbfile);

                                                            Console.WriteLine($"Saving thumbnail image to blob storage: {thumbfile}");

                                                            // Open the file and upload its data
                                                            thumbnail.Position = 0;
                                                            await blobClient.UploadAsync(thumbnail, true).ConfigureAwait(false);

                                                            if ((await(blobClient?.ExistsAsync()).ConfigureAwait(false)) == true)
                                                            {
                                                                // Prepare metadata to augment the blob
                                                                var blobMetadata = new Dictionary <string, string>()
                                                                {
                                                                    { "videoid", videoid },
                                                                    { "videoname", insights.Name },
                                                                    { "shotid", shot.Id.ToString(CultureInfo.InvariantCulture) },
                                                                    { "keyframeid", keyframe.Id.ToString(CultureInfo.InvariantCulture) },
                                                                    { "starttime", instance.Start },
                                                                };
                                                                await blobClient.SetMetadataAsync(blobMetadata).ConfigureAwait(false);
                                                            }
                                                        }
                                                    }
                                                }
                                            }

                                            thumbnail.Close();
                                        }
                                    }

                                    thumbcount++;
                                }
                            }
                        }
                    }
                }

                // Reporting elapsed time for performance analytics
                DateTime endTimestamp = DateTime.Now;
                msg = $"[Elapsed time: {endTimestamp - startTimestamp:c}] Operation completed for video {videoid}. Total of {thumbcount} thumbnails extracted.";
                Console.WriteLine(msg);
            }

            // Exception likely raised by Video Indexer API calls.
            catch (WebException exc)
            {
                msg = $"Video Indexer API error retrieving indexed insights for video {videoid} in account {accountId}:"
                      + Environment.NewLine + exc.Message;
            }

            // Exception likely raised by calls to Azure Blob storage.
            catch (Azure.RequestFailedException exc)
            {
                msg = $"Azure Blob Storage error while saving thumbnails for video {videoid} in account {accountId}:"
                      + Environment.NewLine + exc.Message;
            }

            // Final fallback to report generic exceptions not captured above.
            // TODO: Add more specific exceptions to be captured above based on scenarios that crop up during testing.
            catch (Exception exc)
            {
                msg = $"General error retrieving indexed insights for video {videoid} in account {accountId}:"
                      + Environment.NewLine + exc.Message;
                Console.WriteLine(msg);
            }
        }