Пример #1
0
        /// <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);
        }
Пример #2
0
        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");
        }
Пример #5
0
        /// <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);
        }