public static async Task Run([EventGridTrigger] JObject eventGridEvent, TraceWriter log, ExecutionContext executionContext) { Guid newReqId = Guid.NewGuid(); bool result = true; string reqId = string.Empty; try { log.Info($"Start RedactorProcessing requestId: {newReqId} {eventGridEvent.ToString(Formatting.Indented)} ticks: {DateTime.Now.Ticks}"); var eventGrid = eventGridEvent.ToObject <Event <VideoAssetData> >(); reqId = eventGrid.Data.RequestId; IAsset asset = FaceHelper.GetAsset(eventGrid.Data.AssetName); if (asset != null) { string assetName = eventGrid.Data.JobName + "_" + eventGrid.Data.Step; string configFile = Directory.GetParent(executionContext.FunctionDirectory).FullName + "\\config.json"; await FaceHelper.RunFaceRedactionJob(asset, assetName, configFile, log); log.Info($"request {newReqId} for {reqId} started redactor process send event grid to start copy process ticks: {DateTime.Now.Ticks}"); } else { log.Info($"request {newReqId} for {reqId} didn't start redactor no related asset name {eventGrid.Data.AssetName} ticks: {DateTime.Now.Ticks}"); } } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {newReqId} for {reqId}, ticks: {DateTime.Now.Ticks}", ex); result = false; } string succeed = result ? "" : "unsuccessful"; log.Info($"Finished {succeed} RedactorProcessing requestId: {newReqId} for {reqId} ticks: {DateTime.Now.Ticks}"); }
public static async Task Run([EventGridTrigger] JObject eventGridEvent, TraceWriter log) { Guid newReqId = Guid.NewGuid(); bool result = true; string reqId = string.Empty; try { log.Info($"Start EncodeProcessing requestId: {newReqId} {eventGridEvent.ToString(Formatting.Indented)} ticks: {DateTime.Now.Ticks}"); var eventGrid = eventGridEvent.ToObject <Event <VideoAssetData> >(); reqId = eventGrid.Data.RequestId; IAsset asset = FaceHelper.GetAsset(eventGrid.Data.AssetName); if (asset != null) { string assetName = eventGrid.Data.JobName + "_" + VideoAnalysisSteps.Encode; await FaceHelper.EncodeToAdaptiveBitrateMP4Set(asset, assetName, ConfigurationManager.AppSettings["AMSPreset"]); log.Info($"request {newReqId} for {reqId} started encode process, send event grid to start redactor process ticks: {DateTime.Now.Ticks}"); } else { log.Info($"request {newReqId} for {reqId} didn't start encode no related asset name {eventGrid.Data.AssetName} ticks: {DateTime.Now.Ticks}"); } } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {newReqId} for {reqId}, ticks: {DateTime.Now.Ticks}", ex); result = false; } string succeed = result ? "" : "unsuccessful"; log.Info($"Finished {succeed} EncodeProcessing requestId: {newReqId} for {reqId} ticks: {DateTime.Now.Ticks}"); }
public static async Task Run([EventGridTrigger] JObject eventGridEvent, [Blob("{data.url}", FileAccess.Read, Connection = "myblobconn")] Stream incomingThumbnail, [DocumentDB("YOUR_COSMOS_DB_NAME", "YOUR_STREAN_COLLECTION_NAME", CreateIfNotExists = false, ConnectionStringSetting = "myCosmosDBConnection")] IAsyncCollector <object> outputItem, TraceWriter log) { Guid requestID = Guid.NewGuid(); log.Info($"Start TriggerByStreamThumnail request id: {requestID} ticks: {DateTime.Now.Ticks}"); string eventdetails = eventGridEvent.ToString(); bool result = true; try { string url = eventGridEvent["data"]["url"].ToString(); string[] splitted = url.Split('/'); if (splitted.Length > 1) { string name = splitted[splitted.Length - 1]; string videoname = splitted[splitted.Length - 2]; string[] splittedfilename = videoname.Split('-'); if (splittedfilename.Length == 2) { string source = splittedfilename[0]; result = await FaceHelper.RunDetect(requestID, ConfigurationManager.AppSettings["apis"], name, source, incomingThumbnail, ConfigurationManager.AppSettings["streamsourcecontainername"], ConfigurationManager.AppSettings["streamresultcontainername"], outputItem, log, videoname); } else { throw new IncorrectFileName(name); } } else { throw new IncorrectFileName(url); } } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {requestID}, ticks: {DateTime.Now.Ticks}", ex); result = false; } string succeed = result ? "" : "unsuccessful"; log.Info($"Finished {succeed} TriggerByStreamThumnail requestId: {requestID} details: {eventdetails} ticks: {DateTime.Now.Ticks}"); }
public static async Task Run([EventGridTrigger] JObject eventGridEvent, TraceWriter log, ExecutionContext executionContext) { Guid newReqId = Guid.NewGuid(); bool result = true; string reqId = string.Empty; try { log.Info($"Start CopyFaceProcessing requestId: {newReqId} {eventGridEvent.ToString(Formatting.Indented)} ticks: {DateTime.Now.Ticks}"); var eventGrid = eventGridEvent.ToObject <Event <VideoAssetData> >(); reqId = eventGrid.Data.RequestId; IAsset asset = FaceHelper.GetAsset(eventGrid.Data.AssetName); if (asset != null) { Func <string, bool> op = FaceHelper.IsPictureType; if (eventGrid.Data.PrevStep == VideoAnalysisSteps.Subclip) { op = FaceHelper.IsVideoType; } string container = eventGrid.Data.ContainerName; string sourceConn = ConfigurationManager.AppSettings["myamsconn"]; string targetConn = ConfigurationManager.AppSettings["myblobconn"]; await FaceHelper.CopyFromAssetToBlob(asset, sourceConn, targetConn, container, eventGrid.Data.VideoName, op); log.Info($"request {newReqId} for {reqId} completed copy process to {container} ticks: {DateTime.Now.Ticks}"); } else { log.Info($"request {newReqId} for {reqId} didn't start copy no related asset name {eventGrid.Data.AssetName} ticks: {DateTime.Now.Ticks}"); } } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {newReqId} for {reqId}, ticks: {DateTime.Now.Ticks}", ex); result = false; } string succeed = result ? "" : "unsuccessful"; log.Info($"Finished {succeed} CopyFaceProcessing requestId: {newReqId} for {reqId} ticks: {DateTime.Now.Ticks}"); }
public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log) { Guid requestId = Guid.NewGuid(); log.Info($"Notification webhook started, request {requestId} RequestUri={req.RequestUri}"); try { Task <byte[]> taskForRequestBody = req.Content.ReadAsByteArrayAsync(); byte[] requestBody = await taskForRequestBody; string jsonContent = await req.Content.ReadAsStringAsync(); log.Info($"Notification webhook request {requestId} Request Body = {jsonContent}"); IEnumerable <string> values = null; if (req.Headers.TryGetValues("ms-signature", out values)) { byte[] signingKey = Convert.FromBase64String(FaceHelper.SigningKey); string signatureFromHeader = values.FirstOrDefault(); if (VerifyWebHookRequestSignature(requestBody, signatureFromHeader, signingKey)) { string requestMessageContents = Encoding.UTF8.GetString(requestBody); NotificationMessage msg = JsonConvert.DeserializeObject <NotificationMessage>(requestMessageContents); if (VerifyHeaders(req, msg, log)) { string newJobStateStr = (string)msg.Properties.Where(j => j.Key == "NewState").FirstOrDefault().Value; if (newJobStateStr == "Finished") { log.Info($"Notification webhook finished for request Id:{requestId}"); IJob job = FaceHelper.MediaContext.Jobs.Where(j => j.Id == msg.Properties["JobId"]).FirstOrDefault(); if (job != null) { if (job.OutputMediaAssets.Count > 0) { IAsset asset = job.OutputMediaAssets[job.OutputMediaAssets.Count - 1]; //always we want to take the last output string strStep = asset.Name.Substring(asset.Name.LastIndexOf('_') + 1); string jobName = asset.Name.Substring(0, asset.Name.LastIndexOf('_')); string videoname = jobName.Substring(0, jobName.LastIndexOf('_')) + ".mp4"; //TODO fix string requestid = jobName.Substring(jobName.LastIndexOf('_') + 1); log.Info($"Notification webhook finished duration: {job.RunningDuration} for request Id:{requestId} details: {strStep} {jobName} {videoname}"); VideoAnalysisSteps step; if (Enum.TryParse(strStep, out step)) { HttpClient client = FaceHelper.GetHttpClientForVideo(log); VideoAnalysisSteps nextStep = VideoAnalysisSteps.Unknown; string containerName = string.Empty; switch (step) { case VideoAnalysisSteps.Encode: nextStep = VideoAnalysisSteps.Redactor; break; case VideoAnalysisSteps.Redactor: containerName = ConfigurationManager.AppSettings["videoresultcontainername"]; nextStep = VideoAnalysisSteps.Copy; break; case VideoAnalysisSteps.LiveRedactor: containerName = ConfigurationManager.AppSettings["streamresultcontainername"]; nextStep = VideoAnalysisSteps.Copy; break; } if (nextStep != VideoAnalysisSteps.Unknown) { await new SendToEventGrid(log, client).SendVideoData(new VideoAssetData() { RequestId = requestid, AssetName = asset.Name, JobName = jobName, VideoName = videoname, ContainerName = containerName, Step = nextStep, PrevStep = step, TimeStamp = DateTime.UtcNow }); //copy the subclip video to stream container in case it was set in the setting if ((step == VideoAnalysisSteps.LiveRedactor) && (ConfigurationManager.AppSettings["copysubclip"] == "1") && (job.OutputMediaAssets.Count > 1)) { await new SendToEventGrid(log, client).SendVideoData(new VideoAssetData() { RequestId = requestid, AssetName = job.OutputMediaAssets[job.OutputMediaAssets.Count - 2].Name, //assume that the second from the last item is the subclip output JobName = jobName, VideoName = videoname, ContainerName = ConfigurationManager.AppSettings["streamsourcecontainername"], Step = VideoAnalysisSteps.Copy, PrevStep = VideoAnalysisSteps.Subclip, TimeStamp = DateTime.UtcNow }); } } else { log.Info($"Notification webhookfor request Id:{requestId} didn't find next step: {nextStep}"); } } else { log.Info($"Notification webhookfor request Id:{requestId} didn't cast step: {strStep}"); } } else { log.Info($"Notification webhookfor request Id:{requestId} didn't find output asset for job: {job.Name}"); } } else { log.Info($"Notification webhookfor request Id:{requestId} didn't find jobid: {msg.Properties["JobId"]}"); } } return(req.CreateResponse(HttpStatusCode.OK, string.Empty)); } else { log.Info($"Notification webhook for VerifyHeaders request {requestId} failed."); return(req.CreateResponse(HttpStatusCode.BadRequest, "VerifyHeaders failed.")); } } else { log.Info($"Notification webhook for VerifyWebHookRequestSignature request {requestId} failed."); return(req.CreateResponse(HttpStatusCode.BadRequest, "VerifyWebHookRequestSignature failed.")); } } } catch (Exception ex) { log.Info($"Notification webhook for request Id:{requestId} failed with exception {ex.Message}"); return(req.CreateResponse(HttpStatusCode.BadRequest, "Exception Error " + ex.Message)); } log.Info($"Notification webhook for request Id:{requestId} failed"); return(req.CreateResponse(HttpStatusCode.BadRequest, "Generic Error")); }
public static async Task Run([EventGridTrigger] JObject eventGridEvent, [Blob("{data.url}", FileAccess.Read, Connection = "myblobconn")] Stream incomingVideo, TraceWriter log) { Guid requestID = Guid.NewGuid(); log.Info($"Start TriggerByVideoUploadFunc request id: {requestID} ticks: {DateTime.Now.Ticks}"); string eventdetails = eventGridEvent.ToString(); bool result = true; try { string url = eventGridEvent["data"]["url"].ToString(); string name = url.Substring(url.LastIndexOf('/') + 1); string nameWithoutExtension = name.Substring(0, name.IndexOf('.')); string[] splittedfilename = name.Split('-'); if (splittedfilename.Length == 2) { string jobName = nameWithoutExtension + "_" + requestID; string assetName = nameWithoutExtension + "_" + requestID + "_" + VideoAnalysisSteps.Upload; log.Info($"started uploaded new asset for {requestID} ticks: {DateTime.Now.Ticks}"); IAsset asset = FaceHelper.CreateAssetAndUploadSingleFile(incomingVideo, assetName, AssetCreationOptions.None); log.Info($"completed uploaded asset for {requestID} send event grid to start encode process ticks: {DateTime.Now.Ticks}"); HttpClient client = FaceHelper.GetHttpClientForVideo(log); await new SendToEventGrid(log, client).SendVideoData(new VideoAssetData() { RequestId = requestID.ToString(), ContainerName = string.Empty, AssetName = asset.Name, JobName = jobName, VideoName = name, Step = VideoAnalysisSteps.Encode, PrevStep = VideoAnalysisSteps.Upload, TimeStamp = DateTime.UtcNow }); /* API V3 Not working for now */ //ConfigWrapper config = new ConfigWrapper(); //IAzureMediaServicesClient client = FaceHelper.CreateMediaServicesClient(config); //client.LongRunningOperationRetryTimeout = 2; //string uniqueness = Guid.NewGuid().ToString().Substring(0, 13); //string jobName = FaceHelper.GenerateJobNameByUnique(nameWithoutExtension, uniqueness); //string jobName = "job-" + uniqueness; //string outputAssetName = "output-" + uniqueness; //string inputAssetName = "input-" + uniqueness; //string adaptiveStreamingTransformName = ConfigurationManager.AppSettings["AdaptiveStreamingTransformName"]; //EncoderNamedPreset encodePreset = ConfigurationManager.AppSettings["EncoderPreset"]; //log.Info($"init job encode process {requestID} jobName: {jobName} input: {inputAssetName} output: {outputAssetName} ticks: {DateTime.Now.Ticks}"); //Transform transform = FaceHelper.EnsureEncoderTransformExists(client, // config.ResourceGroup, config.AccountName, adaptiveStreamingTransformName, encodePreset, log); //log.Info($"after get transform for encode process {requestID} jobName: {jobName} ticks: {DateTime.Now.Ticks}"); //FaceHelper.CreateInputAsset(client, config.ResourceGroup, config.AccountName, inputAssetName, name, incomingVideo); //log.Info($"after create input asset for encode process {requestID} jobName: {jobName} ticks: {DateTime.Now.Ticks}"); //JobInput jobInput = new JobInputAsset(assetName: inputAssetName); //log.Info($"before create output asset for encode process {requestID} jobName: {jobName} ticks: {DateTime.Now.Ticks}"); //Asset outputAsset = FaceHelper.CreateOutputAsset(client, config.ResourceGroup, config.AccountName, outputAssetName); //log.Info($"after create output asset for encode process {requestID} jobName: {jobName} input: {inputAssetName} output: {outputAssetName}"); //FaceHelper.SubmitJob(client, config.ResourceGroup, config.AccountName, // adaptiveStreamingTransformName, jobName, jobInput, outputAssetName); //log.Info($"after submit job encode process {requestID} jobName: {jobName} input: {inputAssetName} output: {outputAssetName} ticks: {DateTime.Now.Ticks}"); } else { throw new IncorrectFileName(name); } } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {requestID}, details: {eventdetails}, ticks: {DateTime.Now.Ticks}", ex); result = false; } string succeed = result ? "" : "unsuccessful"; log.Info($"Finished {succeed} TriggerByVideoUploadFunc requestId: {requestID} ticks: {DateTime.Now.Ticks}"); }
public static async Task Run([CosmosDBTrigger( databaseName: "YOUR_COSMOS_DB_NAME", collectionName: "YOUR_PHOTO_COLLECTION_NAME", ConnectionStringSetting = "myCosmosDBConnection", LeaseCollectionName = "leases", CreateLeaseCollectionIfNotExists = true)] IReadOnlyList <Document> documents, TraceWriter log) { Guid requestID = Guid.NewGuid(); string strException = string.Empty; log.Info($"Processing SaveResultImage request id: {requestID} document count: {documents.Count} ticks: {DateTime.Now.Ticks}"); try { BlobManager blobManager = new BlobManager(ConfigurationManager.AppSettings["myblobconn"]); if (documents != null && documents.Count > 0) { for (int i = 0; i < documents.Count; i++) { var doc = JsonConvert.DeserializeObject <FaceIdentifyResult>(documents[i].ToString()); if (doc.DetectResultList.Length > 0) { using (MemoryStream stream = await blobManager.DownloadAsync(doc.ContainerName, doc.BlobName)) { for (int j = 0; j < doc.DetectResultList.Length; j++) { log.Info($"Save new face candidate {requestID} face id: {doc.DetectResultList[j].FaceId} ticks: {DateTime.Now.Ticks}"); string resultBlobName = doc.DetectResultList[j].FaceBlobName; //TODO : find better way to calc the x,y int x = doc.DetectResultList[j].FaceRectangle.Left - 100; int y = doc.DetectResultList[j].FaceRectangle.Top - 100; int width = (int)Math.Round(doc.DetectResultList[j].FaceRectangle.Width * 2.5); int height = (int)Math.Round(doc.DetectResultList[j].FaceRectangle.Height * 2.5); Rectangle sourceRectangle = new Rectangle(x, y, width, height); Rectangle destinationRectangle = new Rectangle(0, 0, width, height); Bitmap croppedImage = new Bitmap(destinationRectangle.Width, destinationRectangle.Height, PixelFormat.Format24bppRgb); using (Bitmap src = Image.FromStream(stream) as Bitmap) { croppedImage.SetResolution(src.HorizontalResolution, src.VerticalResolution); using (Graphics g = Graphics.FromImage(croppedImage)) { g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.CompositingQuality = CompositingQuality.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality; g.PixelOffsetMode = PixelOffsetMode.HighQuality; g.DrawImage(src, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); using (var newStream = FaceHelper.ToStream(croppedImage, src.RawFormat)) { Task t1 = blobManager.UploadAsync(doc.ResultContainerName, resultBlobName, newStream); t1.Wait(); } } } } } } else { log.Info($"SaveResultImage requestId: {requestID} no detection for {doc.BlobName} ticks: {DateTime.Now.Ticks}"); } } } else { log.Info($"SaveResultImage requestId: {requestID} no documents received ticks: {DateTime.Now.Ticks}"); } } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {requestID}, ticks: {DateTime.Now.Ticks}", ex); strException = "unsuccessfully"; } log.Info($"Finished {strException} SaveResultImage requestId: {requestID} ticks: {DateTime.Now.Ticks}"); }
public static ManifestTimingData GetManifestTimingData(IAsset asset, TraceWriter log) { ManifestTimingData response = new ManifestTimingData() { IsLive = false, Error = false, TimestampOffset = 0, TimestampList = new List <ulong>() }; try { ILocator mytemplocator = null; Uri myuri = FaceHelper.GetValidOnDemandURI(asset); if (myuri == null) { mytemplocator = CreatedTemporaryOnDemandLocator(asset); myuri = FaceHelper.GetValidOnDemandURI(asset); } if (myuri != null) { XDocument manifest = XDocument.Load(myuri.ToString()); var smoothmedia = manifest.Element("SmoothStreamingMedia"); var videotrack = smoothmedia.Elements("StreamIndex").Where(a => a.Attribute("Type").Value == "video"); string timescalefrommanifest = smoothmedia.Attribute("TimeScale").Value; if (videotrack.FirstOrDefault().Attribute("TimeScale") != null) // there is timescale value in the video track. Let's take this one. { timescalefrommanifest = videotrack.FirstOrDefault().Attribute("TimeScale").Value; } ulong timescale = ulong.Parse(timescalefrommanifest); response.TimeScale = (ulong?)timescale; if (videotrack.FirstOrDefault().Element("c").Attribute("t") != null) { response.TimestampOffset = ulong.Parse(videotrack.FirstOrDefault().Element("c").Attribute("t").Value); } else { response.TimestampOffset = 0; // no timestamp, so it should be 0 } ulong totalduration = 0; ulong durationpreviouschunk = 0; ulong durationchunk; int repeatchunk; foreach (var chunk in videotrack.Elements("c")) { durationchunk = chunk.Attribute("d") != null?ulong.Parse(chunk.Attribute("d").Value) : 0; repeatchunk = chunk.Attribute("r") != null?int.Parse(chunk.Attribute("r").Value) : 1; totalduration += durationchunk * (ulong)repeatchunk; if (chunk.Attribute("t") != null) { //totalduration = ulong.Parse(chunk.Attribute("t").Value) - response.TimestampOffset; // new timestamp, perhaps gap in live stream.... response.TimestampList.Add(ulong.Parse(chunk.Attribute("t").Value)); } else { response.TimestampList.Add(response.TimestampList[response.TimestampList.Count() - 1] + durationpreviouschunk); } for (int i = 1; i < repeatchunk; i++) { response.TimestampList.Add(response.TimestampList[response.TimestampList.Count() - 1] + durationchunk); } durationpreviouschunk = durationchunk; } response.TimestampEndLastChunk = response.TimestampList[response.TimestampList.Count() - 1] + durationpreviouschunk; if (smoothmedia.Attribute("IsLive") != null && smoothmedia.Attribute("IsLive").Value == "TRUE") { // Live asset.... No duration to read (but we can read scaling and compute duration if no gap) response.IsLive = true; response.AssetDuration = TimeSpan.FromSeconds((double)totalduration / ((double)timescale)); } else { totalduration = ulong.Parse(smoothmedia.Attribute("Duration").Value); response.AssetDuration = TimeSpan.FromSeconds((double)totalduration / ((double)timescale)); } } else { response.Error = true; } if (mytemplocator != null) { mytemplocator.Delete(); } } catch (Exception) { response.Error = true; } return(response); }
public static async Task <bool> RunDetect(Guid requestID, string apis, string name, string source, Stream incomingPicture, string sourceContainerName, string resultContainerName, IAsyncCollector <object> outputItem, TraceWriter log, string videoName = null) { string apikey = string.Empty; try { string[] apiArr = apis.Split(','); int randomApi = FaceHelper.Instance.Next(0, apiArr.Length); apikey = apiArr[randomApi]; log.Info($"RunDetect request id: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}"); Tuple <HttpClient, PolicyWrap <HttpResponseMessage> > tuple = FaceHelper.HttpClientList.GetOrAdd(apikey, new Tuple <HttpClient, PolicyWrap <HttpResponseMessage> >( new HttpClient(), FaceHelper.DefineAndRetrieveResiliencyStrategy(log))); HttpClient client = tuple.Item1; PolicyWrap <HttpResponseMessage> policy = tuple.Item2; IDatabase cache = FaceHelper.Connection.GetDatabase(int.Parse(FaceHelper.Connection.GetDatabase(1).StringGet(apikey))); //the large group id it's based on the mac address we get - each MAC address can work with different face api group string largegroupid = ConfigurationManager.AppSettings[source]; if (videoName == null) { log.Info($"Detecting {name} requestId: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}"); } else { log.Info($"Detecting thumbnail {name} from {videoName} requestId: {requestID} apiKey: {apikey} ticks: {DateTime.Now.Ticks}"); } byte[] pictureImage; // Convert the incoming image stream to a byte array. using (var br = new BinaryReader(incomingPicture)) { pictureImage = br.ReadBytes((int)incomingPicture.Length); } var detectionResult = await new FaceDetect(log, client).DetectFaces(pictureImage, apikey, requestID, policy); if ((detectionResult != null) && (detectionResult.Length > 0)) { //prepare identify request int maxCandidate = int.Parse(ConfigurationManager.AppSettings["maxNumOfCandidatesReturned"]); double threshold = double.Parse(ConfigurationManager.AppSettings["confidenceThreshold"]); var identifyResquest = new FaceIdentifyRequest() { ConfidenceThreshold = threshold, MaxNumOfCandidatesReturned = maxCandidate, LargePersonGroupId = largegroupid, FaceIds = detectionResult.Select(s => s.FaceId).ToArray() }; var identifyResult = await new FaceIdentify(log, client).IdentifyFaces(identifyResquest, apikey, requestID, policy); if ((identifyResult == null) || (identifyResult.Length == 0)) { log.Info($"No identification result requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}"); } var personResult = new PersonDetails(log, client); //merging results and find person name for (int i = 0; i < detectionResult.Length; i++) { if (videoName == null) { detectionResult[i].FaceBlobName = string.Concat(detectionResult[i].FaceId, "_", name); } else { detectionResult[i].FaceBlobName = videoName + "/" + name; } if ((identifyResult != null) && (identifyResult.Length > 0)) { detectionResult[i].Candidates = identifyResult[i].Candidates; for (int j = 0; j < detectionResult[i].Candidates.Length; j++) { string personid = detectionResult[i].Candidates[j].PersonId.ToString(); string personName = cache.StringGet(largegroupid + "-" + personid); if (string.IsNullOrEmpty(personName) == true) { log.Info($"Missing cache requestId: {requestID} apiKey: {apikey} personId: {personid} ticks: {DateTime.Now.Ticks}"); var tPerson = await personResult.GetPersonName(personid, apikey, largegroupid, requestID, policy); personName = tPerson.Name; cache.StringSet(largegroupid + "-" + personid, personName, null, When.Always); } detectionResult[i].Candidates[j].PersonName = new InternalPersonDetails() { PersonId = detectionResult[i].Candidates[j].PersonId, Name = personName }; } } } } else { log.Info($"No dectection result requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}"); //in case of video, we want to create a link to the face detected by AMS (Azure Media Services) although face api didn't recognize it if (videoName != null) { detectionResult = new FaceDetectResult[1] { new FaceDetectResult() { FaceBlobName = videoName + "/" + name } } } ; } string blobname = videoName ?? name; var actionResult = new FaceIdentifyResult() { BlobName = blobname, ContainerName = sourceContainerName, ResultContainerName = resultContainerName, BlobLength = incomingPicture.Length, CreatedDateTime = DateTime.UtcNow, RequestId = requestID, ApiKey = apikey, LargeGroupId = largegroupid, Source = source, DetectResultList = detectionResult }; string strResult = JsonConvert.SerializeObject(actionResult); await outputItem.AddAsync(strResult); } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {requestID}, apiKey:{apikey} ticks: {DateTime.Now.Ticks}", ex); return(false); } return(true); }
public static HttpClient GetHttpClientForVideo(TraceWriter log) { Tuple <HttpClient, PolicyWrap <HttpResponseMessage> > tuple = HttpClientList.GetOrAdd("video", new Tuple <HttpClient, PolicyWrap <HttpResponseMessage> >( new HttpClient(), FaceHelper.DefineAndRetrieveResiliencyStrategy(log))); return(tuple.Item1); }
public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log) { Guid requestID = Guid.NewGuid(); try { log.Info($"LoadPersonGroup was triggered request id {requestID}"); string largepersongroupid = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "groupid", true) == 0) .Value; if (largepersongroupid == null) { // Get request body dynamic data = await req.Content.ReadAsAsync <object>(); largepersongroupid = data?.groupid; } if (largepersongroupid != null) { string apis = ConfigurationManager.AppSettings["apis"]; string[] apiArr = apis.Split(','); if (apiArr.Length > 0) { _loadPersonClient = _loadPersonClient ?? new HttpClient(); PolicyWrap <HttpResponseMessage> resilientPolicy = FaceHelper.DefineAndRetrieveResiliencyStrategy(log); int i; //setting the map of api to database in database 1 IDatabase cache = Connection.GetDatabase(1); for (i = 1; i <= apiArr.Length; i++) { cache.StringSet(apiArr[i - 1], i + 1); } var personResult = new ListPersonGroup(log, _loadPersonClient); for (i = 1; i <= apiArr.Length; i++) { bool isComplete = false; string lastPerson = string.Empty; Task <InternalPersonDetails[]> task; List <InternalPersonDetails> personList = new List <InternalPersonDetails>(); cache = Connection.GetDatabase(i + 1); while (!isComplete) { task = personResult.GetListPersonGroup(lastPerson, apiArr[i - 1], largepersongroupid, requestID, resilientPolicy); task.Wait(); if (task.Result.Length < 1000) { isComplete = true; } if (task.Result.Length > 0) { lastPerson = task.Result[task.Result.Length - 1].PersonId.ToString(); personList.AddRange(task.Result.ToList()); } int loop = task.Result.Length / 100; var tmplist = task.Result.ToList(); int k = 0, len = 0; for (k = 0; k < loop; k++) { var tmpinnerlist = tmplist.GetRange(k * 100, 100); len += tmpinnerlist.Count; cache.StringSet(tmpinnerlist.Select(s => new KeyValuePair <RedisKey, RedisValue>(largepersongroupid + "-" + s.PersonId, s.Name)).ToArray(), When.Always); } if (tmplist.Count - len > 0) { var tmpinnerlist = tmplist.GetRange(k * 100, tmplist.Count - len); cache.StringSet(tmpinnerlist.Select(s => new KeyValuePair <RedisKey, RedisValue>(largepersongroupid + "-" + s.PersonId, s.Name)).ToArray(), When.Always); } } } return(req.CreateResponse(HttpStatusCode.OK, "Redis loaded successfully")); } else { string msg = "List of Api setting is empty"; log.Error($"Error-LoadPersonGroup: {msg} requestId: {requestID} ticks: {DateTime.Now.Ticks}"); return(req.CreateResponse(HttpStatusCode.BadRequest, "List of Api setting is empty")); } } else { string msg = "Please pass a large person group id on the query string or in the request body"; log.Error($"Error-LoadPersonGroup: {msg} requestId: {requestID} ticks: {DateTime.Now.Ticks}"); return(req.CreateResponse(HttpStatusCode.BadRequest, msg)); } } catch (Exception e) { log.Error($"Exception-LoadPersonGroup: {e.Message} requestId: {requestID} ticks: {DateTime.Now.Ticks}", e); return(req.CreateResponse(HttpStatusCode.BadRequest, e.Message)); } }
public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log, ExecutionContext execContext) { Guid requestID = Guid.NewGuid(); log.Info($"Start TriggerLiveStream request id: {requestID} ticks: {DateTime.Now.Ticks}"); int lastTableId = 0; int intervalsec = 60; TimeSpan starttime = TimeSpan.FromSeconds(0); try { string triggerStart = DateTime.UtcNow.ToString("o"); string jsonContent = await req.Content.ReadAsStringAsync(); dynamic data = JsonConvert.DeserializeObject(jsonContent); log.Info($"TriggerLiveStream request id: {requestID} content: {jsonContent}"); if (data.channelName == null || data.programName == null) { log.Error($"TriggerLiveStream request id: {requestID} no channel name and program name in the input object"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Please pass channel name and program name in the input object (channelName, programName)" })); } if (data.intervalSec != null) { intervalsec = (int)data.intervalSec; } string restApiEndpoint = ConfigurationManager.AppSettings["AMSRESTAPIEndpoint"]; // find the Channel, Program and Asset string channelName = (string)data.channelName; var channel = FaceHelper.MediaContext.Channels.Where(c => c.Name == channelName).FirstOrDefault(); if (channel == null) { log.Error($"TriggerLiveStream request id: {requestID} channel not found"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Channel not found" })); } string programName = (string)data.programName; var program = channel.Programs.Where(p => p.Name == programName).FirstOrDefault(); if (program == null) { log.Error($"TriggerLiveStream request id: {requestID} program not found"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Program not found" })); } string programState = program.State.ToString(); string programid = program.Id; var asset = FaceHelper.GetAssetFromProgram(programid); if (asset == null) { log.Info($"TriggerLiveStream Program asset not found for program {programid}"); return(req.CreateResponse(HttpStatusCode.BadRequest, new { error = "Program asset not found" })); } log.Info($"TriggerLiveStream request id: {requestID} using program asset Id : {asset.Id}"); CloudTable table = FaceHelper.GetCloudTable(ConfigurationManager.AppSettings["myamsconn"], "liveanalytics"); var lastendtimeInTable = FaceHelper.RetrieveLastEndTime(table, programid); var assetmanifestdata = FaceHelper.GetManifestTimingData(asset, log); //log.Info($"request id: {requestID} timestamps: " + string.Join(",", assetmanifestdata.TimestampList.Select(n => n.ToString()).ToArray())); var livetime = TimeSpan.FromSeconds((double)assetmanifestdata.TimestampEndLastChunk / (double)assetmanifestdata.TimeScale); starttime = FaceHelper.ReturnTimeSpanOnGOP(assetmanifestdata, livetime.Subtract(TimeSpan.FromSeconds(intervalsec))); log.Info($"TriggerLiveStream request id: {requestID} value starttime: {starttime} livetime: {livetime}"); if (lastendtimeInTable != null) { string lastProgramState = lastendtimeInTable.ProgramState; var lastendtimeInTableValue = TimeSpan.Parse(lastendtimeInTable.LastEndTime); lastTableId = int.Parse(lastendtimeInTable.Id); log.Info($"TriggerLiveStream request id: {requestID} value id retrieved: {lastTableId} ProgramState: {lastProgramState} lastendtimeInTable: {lastendtimeInTableValue}"); if (lastendtimeInTableValue != null) { var delta = (livetime - lastendtimeInTableValue - TimeSpan.FromSeconds(intervalsec)).Duration(); log.Info($"TriggerLiveStream request id: {requestID} delta: {delta}"); if (delta < (TimeSpan.FromSeconds(3 * intervalsec))) // less than 3 times the normal duration { starttime = lastendtimeInTableValue; log.Info($"TriggerLiveStream request id: {requestID} value new starttime : {starttime}"); } } } TimeSpan duration = livetime - starttime; log.Info($"TriggerLiveStream request id: {requestID} value duration: {duration}"); string fileName = channelName + "-" + programName + "_" + requestID + ".mp4"; string configurationSubclip = File.ReadAllText(Directory.GetParent(execContext.FunctionDirectory).FullName + "\\streamconfig.json").Replace("0:00:00.000000", starttime.Subtract(TimeSpan.FromMilliseconds(100)).ToString()).Replace("0:00:30.000000", duration.Add(TimeSpan.FromMilliseconds(200)).ToString()) .Replace("ArchiveTopBitrate_{Basename}.mp4", fileName); string configurationRedactor = File.ReadAllText(Directory.GetParent(execContext.FunctionDirectory).FullName + "\\config.json"); int priority = 10; if (data.priority != null) { priority = (int)data.priority; } string outputAssetSubclip = fileName + "_" + VideoAnalysisSteps.Subclip; string outputAssetLiveRedactor = fileName + "_" + VideoAnalysisSteps.LiveRedactor; await FaceHelper.RunSubclippingWithRedactor(asset, fileName, outputAssetSubclip, outputAssetLiveRedactor, priority, configurationSubclip, configurationRedactor); log.Info($"TriggerLiveStream request id: {requestID} filename: {fileName} job Submitted"); lastTableId++; FaceHelper.UpdateLastEndTime(table, starttime + duration, programid, lastTableId, program.State); } catch (Exception ex) { log.Error($"Exception Message: {ex.Message}, requestId: {requestID}, ticks: {DateTime.Now.Ticks}", ex); return(req.CreateResponse(HttpStatusCode.BadRequest, "Completed with error sub cliping " + ex.Message)); } return(req.CreateResponse(HttpStatusCode.OK, "Complete OK sub cliping")); }
private async Task <FaceDetectResult[]> MakeFaceDetectRequest(byte[] imageBytes, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { _log.Info($"Making detect request requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); string strResult = string.Empty; FaceDetectResult[] result = null; // Request parameters. const string requestParameters = "returnFaceId=true&returnFaceLandmarks=false"; // Get the API URL and the API key from settings. var uriBase = ConfigurationManager.AppSettings["faceDetectApiUrl"]; // Configure the HttpClient request headers. _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey); //_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Assemble the URI for the REST API Call. var uri = uriBase + "?" + requestParameters; try { // Execute the REST API call, implementing our resiliency strategy. HttpResponseMessage response = await policy.ExecuteAsync(() => _client.PostAsync(uri, FaceHelper.GetImageHttpContent(imageBytes))); // Get the JSON response. strResult = await response.Content.ReadAsStringAsync(); result = await response.Content.ReadAsAsync <FaceDetectResult[]>(); _log.Info($"detect completed: {strResult} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); } catch (BrokenCircuitException bce) { _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce); } catch (Exception e) { _log.Error($"Critical error-MakeFaceDetectRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e); } return(result); }
private async Task <FaceDetectResult[]> MakeFaceIdentifyRequest(FaceIdentifyRequest req, string apiKey, Guid requestId, PolicyWrap <HttpResponseMessage> policy) { string strResult = string.Empty; StringBuilder faceids = new StringBuilder(); req.FaceIds.ToList().ForEach(s => faceids.Append(s + " ")); _log.Info($"Making identify request faceids: {faceids} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); FaceDetectResult[] result = null; // Get the API URL and the API key from settings. var uri = ConfigurationManager.AppSettings["faceIdentifyApiUrl"]; // Configure the HttpClient request headers. _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey); //_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); try { // Execute the REST API call, implementing our resiliency strategy. HttpResponseMessage response = await policy.ExecuteAsync(() => _client.PostAsync(uri, FaceHelper.GetIdentifyHttpContent(req))); // Get the JSON response. strResult = await response.Content.ReadAsStringAsync(); result = await response.Content.ReadAsAsync <FaceDetectResult[]>(); _log.Info($"identify completed: {strResult} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}"); } catch (BrokenCircuitException bce) { _log.Error($"Could not contact the Face API service due to the following error: {bce.Message} requestId: {requestId} apiKey:{apiKey} ticks: {DateTime.Now.Ticks}", bce); } catch (Exception e) { _log.Error($"Critical error-MakeFaceIdentifyRequest: {e.Message} requestId: {requestId} apiKey:{apiKey} string result:{strResult} ticks: {DateTime.Now.Ticks}", e); } return(result); }