/// <summary> /// Connects to Azure Video Indexer using a the credentials retrieved from appsettings.json . /// </summary> /// <param name="accountid">Video Indexer user account ID.</param> /// <param name="apikey">API key for this VI account.</param> /// <param name="location">Azure region where this VI account is located.</param> /// <returns>Status message about the connection to VI.</returns> private static async Task ConnectToAccount(string accountid, string apikey, string location) { string msg; try { // Azure Video Indexer Account ID and API KEY are set in the UI if (accountid.Length == 0) { Console.WriteLine(UIErrorCredentialsMissingAccountID); return; } if (apikey.Length == 0) { Console.WriteLine(UIErrorCredentialsMissingAPIKey); return; } client = new VideoIndexer(); if (client != null) { // TODO: Add a mechanism to refresh the account access token if it expires (how long does it last?) accountAccessToken = await client.GetAccountAccessTokenAsync(accountid, apikey, location).ConfigureAwait(false); if (accountAccessToken != null) { msg = $"Video Indexer connection authorized: {accountAccessToken.Substring(0, 80)}..."; } else { msg = UIErrorAuthorizationSettings; } } else { msg = UIErrorDependency; } } catch (WebException exc) { msg = UIErrorVideoIndexerAPI + Environment.NewLine + exc.Message; } catch (Exception exc) { msg = UIErrorAuthorizationGeneral + Environment.NewLine + exc.Message; } Console.WriteLine(msg); }
public async Task VideoIndexerUploadsVideo() { var sasKey = Guid.NewGuid().ToString(); var jobId = new Random(Environment.TickCount).Next(1000, 99999).ToString(); var indexer = new VideoIndexer(new FakeVideoBlobClient(sasKey), new FakeVideoIndexerClient(sasKey, jobId)); var outputJobId = await Helpers.QuerySkill( indexer.RunVideoIndexer, new { metadata_storage_path = "aHR0cHM6Ly9rbXZncmZzdHIuYmxvYi5jb3JlLndpbmRvd3MubmV0L2RvY3VtZW50cy9waXBlbGluZS5tcDQ1", metadata_storage_name = "pipeline.mp4" }, "jobId" ) as string; Assert.AreEqual(jobId, outputJobId); }
public async Task <ActionResult> Index() { // when the page loads for the first time, we load the default settings from the config file if (HttpContextProvider.Current.Session["VideoIndexerAccountId"] == null) { HttpContextProvider.Current.Session["VideoIndexerAccountId"] = ConfigurationManager.AppSettings["VideoIndexerAccountId"]; } if (HttpContextProvider.Current.Session["VideoIndexerSubscriptionKey"] == null) { HttpContextProvider.Current.Session["VideoIndexerSubscriptionKey"] = ConfigurationManager.AppSettings["VideoIndexerSubscriptionKey"]; } if (HttpContextProvider.Current.Session["VideoIndexerLocation"] == null) { HttpContextProvider.Current.Session["VideoIndexerLocation"] = ConfigurationManager.AppSettings["VideoIndexerLocation"]; } if (HttpContextProvider.Current.Session["TranslationLang"] == null) { HttpContextProvider.Current.Session["TranslationLang"] = ConfigurationManager.AppSettings["TranslationLang"]; } CloudStorageAccount account = null; try { account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]); } catch (Exception exc) { ViewBag.ErrorMsg = exc.ToString(); Functions.SendProgress("Error:" + exc.Message, 0, 1); return(View()); } CloudBlobClient client = account.CreateCloudBlobClient(); string videoId = (string)System.Web.HttpContext.Current.Session["videoId"]; // Pass a list of blob URIs in ViewBag List <BlobInfo> blobs = new List <BlobInfo>(); if (videoId != null) { CloudBlobContainer container = client.GetContainerReference(videoId); List <IListBlobItem> blobsList = new List <IListBlobItem>(); try { blobsList = container.ListBlobs(prefix: dirHighRes + "/", useFlatBlobListing: true).ToList(); } catch (Exception exc) { ViewBag.ErrorMsg = exc.ToString(); videoId = null; Functions.SendProgress("Error:" + exc.Message, 0, 1); } foreach (IListBlobItem item in blobsList) { var blob = item as CloudBlockBlob; if (blob != null) { blob.FetchAttributes(); // Get blob metadata var description = blob.Metadata.ContainsKey("Description") ? blob.Metadata["Description"] : "(no description)"; var descriptionTranslated = blob.Metadata.ContainsKey("DescriptionTranslated") ? HttpUtility.HtmlDecode(blob.Metadata["DescriptionTranslated"]) : null; string confidence = blob.Metadata.ContainsKey("Confidence") ? Double.Parse(blob.Metadata["Confidence"], CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture) + "%" : null; TimeSpan?adjustedStart = blob.Metadata.ContainsKey("AdjustedStart") ? (TimeSpan?)TimeSpan.Parse(blob.Metadata["AdjustedStart"], CultureInfo.InvariantCulture) : (TimeSpan?)null; int? index = blob.Metadata.ContainsKey("Index") ? (int?)(int.Parse(blob.Metadata["Index"], CultureInfo.InvariantCulture)) : null; blobs.Add(new BlobInfo() { ImageUri = blob.Uri.ToString(), ThumbnailUri = blob.Uri.ToString().Replace("/" + dirHighRes + "/", "/" + dirLowRes + "/"), Description = description, DescriptionTranslated = descriptionTranslated != null ? Encoding.UTF8.GetString(Convert.FromBase64String(descriptionTranslated)) : null, Confidence = confidence, AdjustedStart = adjustedStart, Index = index }); } } var speakerS = ConfigurationManager.AppSettings["SpeakerStatsFeature"]; if (speakerS != null && bool.Parse(speakerS)) { List <SpeakerStats> SpeakersStatsBuilder = new List <SpeakerStats>(); // Reading insights about speakers CloudBlockBlob insightsBlob = container.GetBlockBlobReference(dirInsights + "/" + fileInsights); try { string jsonData = await insightsBlob.DownloadTextAsync().ConfigureAwait(false); dynamic jObj = JObject.Parse(jsonData); dynamic speakers = jObj.videos[0].insights.speakers; foreach (dynamic speaker in speakers) { TimeSpan duration = new TimeSpan(); foreach (dynamic inst in speaker.instances) { duration += DateTime.Parse((string)inst.end, CultureInfo.InvariantCulture) - DateTime.Parse((string)inst.start, CultureInfo.InvariantCulture); } SpeakersStatsBuilder.Add(new SpeakerStats() { Name = (string)speaker.name, Duration = duration }); } ViewBag.SpeakerStats = SpeakersStatsBuilder.Count > 0 ? SpeakersStatsBuilder.OrderByDescending(s => s.Duration) : null; } catch { } } } ViewBag.Blobs = blobs.OrderBy(bl => bl.Index).ToArray(); ViewBag.VideoId = videoId; ViewBag.VideoIndexerAccountId = HttpContextProvider.Current.Session["VideoIndexerAccountId"]; ViewBag.VideoIndexerSubscriptionKey = HttpContextProvider.Current.Session["VideoIndexerSubscriptionKey"]; ViewBag.VideoIndexerLocation = HttpContextProvider.Current.Session["VideoIndexerLocation"]; ViewBag.TranslationLang = HttpContextProvider.Current.Session["TranslationLang"]; if (videoId != null) { try { VideoIndexer myVI = new VideoIndexer( (string)HttpContextProvider.Current.Session["VideoIndexerAccountId"], (string)HttpContextProvider.Current.Session["VideoIndexerLocation"], (string)HttpContextProvider.Current.Session["VideoIndexerSubscriptionKey"]); ViewBag.VideoAccessToken = Task.Run(async() => await myVI.GetVideoAccessTokenAsync(videoId).ConfigureAwait(false)).GetAwaiter().GetResult(); ViewBag.PlayerWidgetUrl = Task.Run(async() => await myVI.GetPlayerWidgetAsync(videoId).ConfigureAwait(false)).GetAwaiter().GetResult(); ViewBag.VideoInsightsWidgetUrl = Task.Run(async() => await myVI.GetVideoInsightsWidgetAsync(videoId, false).ConfigureAwait(false)).GetAwaiter().GetResult(); } catch (Exception exc) { ViewBag.ErrorMsg = exc.ToString(); Functions.SendProgress("Error in VideoIndexer:" + exc.Message, 0, 1); } } return(View()); }
// 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"); }
/// <summary> /// Connects to Azure Video Indexer using a user account and API KEY. /// </summary> /// <param name="sender">The XAML control which raised the event.</param> /// <param name="e">Event parameters.</param> private async void BtnConnect_Click(object sender, RoutedEventArgs e) { string msg; try { // Azure Video Indexer Account ID and API KEY are set in the UI this.accountId = this.txtAccountID.Text.Trim(); if (this.accountId.Length == 0) { msg = "Account ID is missing. Please verify that you entered a valid Azure Video Indexer account ID and try again."; this.PostStatusMessage(msg); return; } this.apiKey = this.txtAPIkey.Text.Trim(); if (this.apiKey.Length == 0) { msg = "API key is missing. Please verify that you entered a valid Azure Video Indexer API key and try again."; this.PostStatusMessage(msg); return; } this.accountLocation = this.txtRegion.Text.Trim(); if (this.accountLocation.Length == 0) { msg = "Account region is missing. Please verify that you entered a valid Azure Video Indexer account region and try again."; this.PostStatusMessage(msg); return; } this.client = new VideoIndexer(); // TODO: Add a mechanism to refresh the account access token if it expires (how long does it last?) this.accountAccessToken = await this.client.GetAccountAccessTokenAsync(this.accountId, this.apiKey, this.accountLocation).ConfigureAwait(false); if (this.accountAccessToken != null) { msg = "Video Indexer connection authorized: " + this.accountAccessToken.Substring(0, 100) + "..."; await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { this.btnGetVideos.IsEnabled = true; this.btnUploadVideo.IsEnabled = true; }); } else { msg = "Authorization error. Please verify that you entered valid Azure Video Indexer credentials and try again."; } } catch (WebException exc) { msg = "Video Indexer API error. Please verify that you entered valid Azure Video Indexer credentials and try again. Error:" + Environment.NewLine + exc.Message; } catch (Exception exc) { msg = "General authorization error. Please verify that you entered valid Azure Video Indexer credentials and try again. Error:" + Environment.NewLine + exc.Message; } this.PostStatusMessage(msg); }