public static string DownloadVideo(string videoUrl) { string path = GetLocalPath(videoUrl); if (File.Exists(path)) { Logger.Log("File already exists."); } else { Logger.Log("Requesting video: " + videoUrl + " ..."); string directory = Path.GetDirectoryName(path); if (directory != String.Empty && !Directory.Exists(directory)) { // Edge case! Ensure a file doesn't also exist already with that name. if (File.Exists(directory)) { const string prefix = "_tmp_"; directory = prefix + directory; path = prefix + path; } Directory.CreateDirectory(directory); } WebClient client = new WebClient(); client.DownloadFile(videoUrl, path); } Logger.Log("File is here: " + path); return(path); }
public Guid?GetSkierTagId(SkiVideoEntity video) { try { if (string.IsNullOrEmpty(video.Skier)) { return(null); } string skier = video.Skier.Trim(); var tag = m_tags.Where(t => t.Name == skier).FirstOrDefault(); if (tag == null) { if (HasEnoughOfSkier(skier)) { tag = m_trainingApi.CreateTag(m_projectId, skier); m_tags.Add(tag); } } return(tag.Id); } catch (Exception e) { Logger.Log($"Unable to get SkierTag for {video.Skier}\n" + e); return(null); } }
private async Task GetCreationTimeAsync() { Logger.Log($"Getting creation time from video {_sourceVideoUrl}..."); _creationTime = await _videoTasks.GetCreationTimeAsync(); Logger.Log($"Creation time is {_creationTime}"); }
private CoursePass CreatePass(List<Measurement> measurements) { if (this.m_course == null) FindCourse(measurements); if (this.m_course == null) { Logger.Log("Unable to find a course for this ski run."); return null; } if (m_rope == null) m_rope = Rope.Default; CoursePass pass = new CoursePass(m_course, m_rope, CenterLineDegreeOffset); for (int i = 0; i < measurements.Count; i++) { Measurement current = measurements[i]; current.BoatPosition = pass.CoursePositionFromGeo(current.BoatGeoCoordinate); if (current.BoatPosition == CoursePosition.Empty) continue; CalculateInCourse(pass, measurements, i); CalculateCurrent(measurements, i); pass.Track(current); // If the handle has passed the 55s, we're done here. if (current.HandlePosition.Y > Course.LengthM) break; } CalculateCoursePassSpeed(pass); return pass; }
/// <summary> /// Returns prediction or null if an error occurs. /// </summary> public virtual string Predict(string thumbnailUrl) { Logger.Log($"Making a prediction of {CustomVisionModelName} for: " + thumbnailUrl); predictionApi = new CustomVisionPredictionClient() { ApiKey = CustomVisionKey, Endpoint = CustomVisionEndPoint }; try { PredictionModels.ImageUrl thumbnail = new PredictionModels.ImageUrl(CropThumbnailUrl + thumbnailUrl); var result = predictionApi.ClassifyImageUrl(ProjectId, CustomVisionModelName, thumbnail); //LogPredicitions(result.Predictions); return(GetHighestRankedPrediction(result.Predictions)); } catch (PredictionModels.CustomVisionErrorException e) { Logger.Log($"Error making prediction for {thumbnailUrl}\n\t" + e.Response.Content, e); return(null); } }
private Task <string> TrimAndSilenceAsync(CoursePass pass) { Logger.Log($"Trimming and silencing video {_sourceVideoUrl}..."); double start = 0, duration = 0, total = 0; if (_timeOverrides != null) { start = _timeOverrides.Start; duration = _timeOverrides.Duration; total = start + duration; } else { if (pass == null) { throw new ApplicationException( "CoursePass was not found and no pass overrides were available for " + $"{_sourceVideoUrl}"); } start = pass.GetSecondsAtEntry(); duration = pass.GetDurationSeconds(); total = pass.GetTotalSeconds(); } return(_videoTasks.TrimAndSilenceVideoAsync(start, duration, total)); }
private static string CreateImage(string jsonPath, double clOffset, double rope, CourseCoordinates coords) { CoursePass pass; CoursePassFactory factory = new CoursePassFactory(); factory.CenterLineDegreeOffset = clOffset; factory.RopeLengthOff = rope; factory.Course55Coordinates = coords; if (jsonPath.StartsWith("http")) { pass = factory.FromUrl(jsonPath); } else { pass = factory.FromFile(jsonPath); } if (pass == null) { throw new ApplicationException($"Unable to create a pass for {jsonPath}"); } string imagePath = GetImagePath(jsonPath); CoursePassImage image = new CoursePassImage(pass); Bitmap bitmap = image.Draw(); bitmap.Save(imagePath, ImageFormat.Png); Logger.Log(string.Format("Gate precision == {0} for {1}", pass.GetGatePrecision(), jsonPath)); Logger.Log("Wrote image to: " + imagePath); return(imagePath); }
/// <summary> /// Listens to service bus queue and processes videos as they arrive. /// </summary> private static void Listen(string queueName, bool openDeadLetter) { VideoUploadListener listener = new VideoUploadListener(queueName, openDeadLetter); EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.ManualReset); EventHandler Reset = (o, e) => { listener.Stop(); ewh.Set(); }; AppDomain.CurrentDomain.ProcessExit += Reset; listener.Completed += Reset; // Force to only listen for 1 message, then exit. listener.Start(); if (Console.WindowHeight > 0) { Logger.Log("Press any key to cancel."); Console.ReadKey(); ewh.Set(); } else { Logger.Log("Waiting until signaled to close."); } // Wait until signalled. ewh.WaitOne(); Logger.Log($"Done listening for events."); AppDomain.CurrentDomain.ProcessExit -= Reset; }
private void OnProgress(object sender, ConversionProgressEventArgs e) { // Grab every 10th progress update. if (e.Frame % 10 == 0) { Logger.Log($"{_localVideoPath} -- Processed frame {e.Frame} @{e.ProcessedDuration}"); } }
public void AddMetadata(SkiVideoEntity entity, string json) { string blobName = GetBlobName(entity.Url, entity.RecordedTime); string jsonUrl = UploadMeasurements(blobName, json); entity.JsonUrl = jsonUrl; AddTableEntity(entity); Logger.Log("Uploaded metadata for video:" + entity.Url); }
private async Task ExtractMetadataAsync() { Logger.Log($"Extracting metadata from video {_sourceVideoUrl}..."); await Task.Run(() => { _json = MetadataExtractor.Extract.ExtractMetadata(_localVideoPath); }); Logger.Log("Extracted metadata."); }
private static async Task DeleteGoogleVideoAsync(GoogleStorage gstore, Storage storage, SkiVideoEntity video) { Logger.Log($"Deleting {video.HotUrl} recorded @ {video.RecordedTime}."); await gstore.DeleteAsync(video.HotUrl); video.HotUrl = ""; storage.UpdateMetadata(video); Logger.Log($"Metadata updated for video recorded @ {video.RecordedTime}."); }
public Task NotifyAsync(string skier, string video) { Logger.Log($"Notifying of {video}"); string value = Newtonsoft.Json.JsonConvert.SerializeObject( new { Skier = skier, Video = video } ); byte[] bytes = Encoding.ASCII.GetBytes(value); return(_queueClient.SendAsync(new Message(bytes))); }
private async Task <string> DownloadVideoAsync() { string localPath = null; await Task.Run(() => { Logger.Log($"Downloading video {_sourceVideoUrl}..."); localPath = Cloud.Storage.DownloadVideo(_sourceVideoUrl); }); return(localPath); }
private async Task <string> RemoveAudioAsync(string inputFile) { string outputFile = AppendToFileName(inputFile, "s"); string parameters = $"-i {inputFile} -c copy -an {outputFile}"; await _ffmpeg.ExecuteAsync(parameters); Logger.Log($"Removed Audio: {outputFile}"); return(outputFile); }
async Task ProcessMessagesAsync(Message message, CancellationToken token) { if (_queueClient.IsClosedOrClosing) { Logger.Log("Queue is closing, abandoning message."); await _queueClient.AbandonAsync(message.SystemProperties.LockToken); return; } string videoUrl = ""; try { // Process the message. Logger.Log($"Received message: SequenceNumber:{message.SystemProperties.SequenceNumber} Body:{Encoding.UTF8.GetString(message.Body)}"); string json = Encoding.UTF8.GetString(message.Body); videoUrl = QueueMessageParser.GetUrl(json); Logger.Log($"Received this videoUrl: {videoUrl}"); if (videoUrl.EndsWith("test.MP4")) { throw new ApplicationException("Something broke, fail safe for testing exceptions!"); } SkiVideoProcessor processor = new SkiVideoProcessor(videoUrl); await processor.ProcessAsync(); await _queueClient.CompleteAsync(message.SystemProperties.LockToken); } catch (Exception e) { if (message.SystemProperties.DeliveryCount <= 2) { Logger.Log($"Abandoned message.", e); // abandon and allow another to try in case of transient errors await _queueClient.AbandonAsync(message.SystemProperties.LockToken); } else { Logger.Log($"Dead lettering message.", e); await _queueClient.DeadLetterAsync(message.SystemProperties.LockToken, e.Message, e.InnerException?.Message); } } finally { Logger.Log($"Message handler completed for {videoUrl}."); if (Completed != null) { Completed(this, null); } } }
/// <summary> /// This is just a way to review and drain the deadletter queue. /// </summary> void ReadDeadLetter() { _queueClient.RegisterMessageHandler((message, cancel) => { Logger.Log($"Dead letter message: {Encoding.UTF8.GetString(message.Body)}"); Logger.Log($"Reason: {message.UserProperties["DeadLetterReason"]}"); return(Task.CompletedTask); }, new MessageHandlerOptions(ExceptionReceivedHandler) { AutoComplete = true }); }
//TODO: Consolidate these two storage upload methods. private async Task <string> UploadVideoAsync(Task <string> trimAndSilence, Task getCreationTime) { await getCreationTime; // Ensure creation time has been generated. string processedVideoPath = await trimAndSilence; Logger.Log($"Uploading video {processedVideoPath}..."); string videoUrl = _storage.UploadVideo(processedVideoPath, _creationTime); Logger.Log($"Video uploaded to {videoUrl}"); return(videoUrl); }
private async Task <string> UploadThumbnailAsync(Task <string> createThumbnail, Task getCreationTime) { await getCreationTime; // Ensure creation time has been generated. string localThumbnailPath = await createThumbnail; Logger.Log($"Uploading thumbnail {localThumbnailPath}..."); string thumbnailUrl = _storage.UploadThumbnail(localThumbnailPath, _creationTime); Logger.Log($"Uploaded thumbnail to {thumbnailUrl}"); return(thumbnailUrl); }
public VideoProcessedNotifier(string queueName = DefaultQueueName) { string serviceBusConnectionString = Environment.GetEnvironmentVariable(ENV_SERVICEBUS); if (string.IsNullOrWhiteSpace(serviceBusConnectionString)) { throw new ApplicationException($"Missing service bus connection string in env variable: {ENV_SERVICEBUS}"); } _queueClient = new QueueClient(serviceBusConnectionString, queueName); Logger.Log($"Connected to queue {queueName}"); }
private void LogPredicitions(IList <PredictionModels.PredictionModel> predictions) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine(); foreach (var c in predictions) { sb.Append($"\t{c.TagName}: {c.Probability:P1}\n"); } Logger.Log(sb.ToString()); }
private void SendBatch() { try { Logger.Log($"Sending batch of {entries.Count} urls to train."); var batch = new TrainingModels.ImageUrlCreateBatch(entries); trainingApi.CreateImagesFromUrls(ProjectId, batch); } catch (Exception e) { Logger.Log("Error writing ML training batch.", e); } }
public void Start() { if (_deadLetterMode) { Logger.Log($"Reading dead letter messages..."); ReadDeadLetter(); } else { RegisterOnMessageHandlerAndReceiveMessages(); Logger.Log($"Listening for messages..."); } }
public void UpdateCourse(Course course) { const string coursePartitionKey = "cochituate"; if (course == null) { throw new ApplicationException("You must pass a course object to update."); } CloudTableClient client = _account.CreateCloudTableClient(); CloudTable table = client.GetTableReference(COURSETABLE); // Get existing entity, if one exists. TableQuery <CourseEntity> query = new TableQuery <CourseEntity>() .Where($"PartitionKey eq '{coursePartitionKey}' and RowKey eq '{course.Name}'"); var result = table.ExecuteQuerySegmentedAsync(query, null); result.Wait(); CourseEntity entity = result.Result.FirstOrDefault(); if (entity != null) { entity.FriendlyName = course.FriendlyName; entity.Course55EntryCL = course.Course55EntryCL; entity.Course55ExitCL = course.Course55ExitCL; } else { entity = new CourseEntity(); entity.FriendlyName = course.FriendlyName; entity.PartitionKey = coursePartitionKey; entity.RowKey = course.Name; entity.Course55EntryCL = course.Course55EntryCL; entity.Course55ExitCL = course.Course55ExitCL; } TableOperation insert = TableOperation.InsertOrReplace(entity); Task createTask = table.CreateIfNotExistsAsync(); createTask.Wait(); Task insertTask = table.ExecuteAsync(insert); insertTask.Wait(); Logger.Log($"Inserted course: {entity.RowKey}"); }
private static async Task UpdateThumbnailAsync(Storage storage, SkiVideoEntity video) { Logger.Log($"Updating thumbnail for {video.PartitionKey}, {video.RowKey}"); double thumbnailAtSeconds = 0; // video.EntryTime; string localVideoPath = Storage.DownloadVideo(video.HotUrl ?? video.Url); VideoTasks _videoTasks = new VideoTasks(localVideoPath); string localThumbnailPath = await _videoTasks.GetThumbnailAsync(thumbnailAtSeconds); string modifiedThumbnailPath = localThumbnailPath.Replace("_ts.PNG", ".PNG"); System.IO.File.Move(localThumbnailPath, modifiedThumbnailPath); string thumbnailUrl = storage.UploadThumbnail(modifiedThumbnailPath, video.RecordedTime); Logger.Log($"New thumbnail at {thumbnailUrl}"); }
private static async Task UpdateThumbnailsAsync() { Storage storage = new Storage(); List <SkiVideoEntity> videos = await storage.GetAllMetdataAsync(); var selectedVideos = videos.OrderByDescending(v => v.RecordedTime).Take(5); foreach (var video in selectedVideos) { try { await UpdateThumbnailAsync(storage, video); } catch (Exception e) { Logger.Log($"Unable to update thumbnail for {video.PartitionKey}, {video.RowKey}", e); } } }
public bool LoadVideoJson() { try { string localJson = Storage.DownloadVideo(_videoJsonUrl); Logger.Log($"Found override json: {_videoJsonUrl}"); VideoTime obj = FromJsonFile(localJson); this.Start = obj.Start; this.Duration = obj.Duration; } catch (System.Net.WebException) { Logger.Log("No json override found for " + _videoJsonUrl); return(false); } return(true); }
private void DrawCoursePass() { int i = 0; // FirstInCourse(_pass.Measurements); int last = _pass.Measurements.Count - 2; // LastInCourse(_pass.Measurements); HandleMeasurements handleMeasurements = new HandleMeasurements(this); for (; i < last; i++) { var m = _pass.Measurements[i]; if (m.BoatPosition == CoursePosition.Empty) { Logger.Log($"Out of course {i}"); continue; } DrawBoat(m, i); DrawHandle(m, i); handleMeasurements.Draw(m, i); } }
public void Stop() { lock (_queueClient) { if (!_queueClient.IsClosedOrClosing) { var task = _queueClient.CloseAsync(); System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess(); long peakMemory = process.PeakWorkingSet64; Logger.Log($"Stopping... Peak memory was: {(peakMemory/1024/1024).ToString("F1")} mb"); task.Wait(); } else { Logger.Log("Queue already closing."); } } }
private void CalculateCoursePassSpeed(CoursePass pass) { if (pass.Exit == null || pass.Entry == null) { Logger.Log("Skiping course pass speed calculation since Entry or Exit are null."); return; } TimeSpan duration = pass.Exit.Timestamp.Subtract(pass.Entry.Timestamp); double distance = pass.Exit.BoatGeoCoordinate.GetDistanceTo( pass.Entry.BoatGeoCoordinate); if (duration == null || duration.Seconds <= 0 || distance <= 0) { throw new ApplicationException("Could not calculate time and distance for course entry/exit."); } double speedMps = distance / duration.TotalSeconds; pass.AverageBoatSpeed = Math.Round(speedMps * CoursePass.MPS_TO_MPH, 1); }