コード例 #1
0
        public RecordingMetadata ConvertPreviewMedia(ConversionConfiguration config)
        {
            // generate output directory
            if (Directory.Exists(config.OutputDirectory))
            {
                Directory.Delete(config.OutputDirectory, true);
            }

            Directory.CreateDirectory(config.OutputDirectory);

            // convert file
            ConvertVideoFiles(config, true);

            // generate recording object
            var finalRecording = new RecordingMetadata();

            finalRecording.FileName          = "slides.mp4";
            finalRecording.PresenterFileName = "talkinghead.mp4";
            finalRecording.StageVideo        = "stage.mp4";
            finalRecording.Slides            = BuildThumbnails(config, "slides.mp4");
            finalRecording.Duration          = FFmpegHelper.GetMediaLength(config.SlideVideoPath).TotalSeconds;

            FFmpegHelper.ExportThumbnail(5f, Path.Combine(config.OutputDirectory, "stage.mp4"), config.OutputDirectory, "thumbnail");

            return(finalRecording);
        }
コード例 #2
0
        public void FinalizeAnswer(string itemId, string answer)
        {
            string recId = Guid.NewGuid().ToString();
            // Create a dummy recording so that we can save it to the database
            Recording rec = new Recording
            {
                RecordingId  = recId,
                ItemId       = itemId,
                FileName     = $"{recId}-{Constants.MetadataWithoutRecording}",
                ClientId     = Preferences.Get(Constants.ClientIdKey, "unknown"),
                Timestamp    = DateTime.UtcNow,
                UploadStatus = UploadStatus.Pending
            };

            RecordingMetadata metadata = new RecordingMetadata(rec.RecordingId);

            metadata.ClientId           = rec.ClientId;
            metadata.ItemId             = rec.ItemId;
            metadata.RecordingTimestamp = rec.Timestamp;

            // Add user metadata based on the item view model
            var umd        = new UserMetadata();
            var userAnswer = new UserAnswer();

            userAnswer.ItemId = itemId;
            userAnswer.Value  = answer;
            umd.AddAnswer(userAnswer);

            metadata.User = umd;

            rec.Metadata = metadata.ToJsonString();

            App.Database.SaveRecordingAsync(rec);
            Debug.WriteLine($"Saved answer '{answer}', recording '{rec.RecordingId}', item '{itemId}'");
        }
コード例 #3
0
ファイル: AnalyseActivity.cs プロジェクト: AntieJ/blankdroid
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            HideTitleBar();

            _fileName         = Intent.GetStringExtra("FileNameClicked") ?? RecordingContext.filename;
            _baseDirectory    = ConfigService.BaseDirectory;
            _metadataService  = new MetadataService();
            _audioFileService = new AudioFileService();
            _audioPlayService = new AudioPlayService(_baseDirectory, _fileName);
            _metadata         = _metadataService.GetRecordingMetadata(_baseDirectory, _fileName);

            AnalysisContext.UpdateContext(_baseDirectory, _fileName);
            SetContentView(Resource.Layout.AnalyseActivity);
            SetupButtons();

            if (_metadata.StartedAt != null && _metadata.StartedAt != default(DateTime))
            {
                FindViewById <TextView>(Resource.Id.title).Text = _metadata.StartedAt.ToString("f");
            }
            else
            {
                var fullAudioPath = _audioFileService.GetFullPathToRecording(_baseDirectory, _fileName);
                FindViewById <TextView>(Resource.Id.title).Text = fullAudioPath.Replace(_baseDirectory, "");
            }
            _playing = false;
            SetPlayButtonIcon();
        }
コード例 #4
0
ファイル: AudioPlayService.cs プロジェクト: AntieJ/blankdroid
 public AudioPlayService(string baseDirectory, string fileName)
 {
     _metadataService  = new MetadataService();
     _audioFileService = new AudioFileService();
     _metadata         = _metadataService.GetRecordingMetadata(baseDirectory, fileName);
     _fullPathToAudio  = _audioFileService.GetFullPathToRecording(baseDirectory, fileName);
 }
コード例 #5
0
ファイル: MetadataService.cs プロジェクト: AntieJ/blankdroid
 public void UpdateMetadataFile(RecordingMetadata metadata, string baseDirectory, string fileName)
 {
     using (var fs = new FileStream(GetFullPathToMetadata(baseDirectory, fileName), FileMode.Open, FileAccess.Write))
     {
         string dataasstring = JsonConvert.SerializeObject(metadata);
         byte[] info         = new UTF8Encoding(true).GetBytes(dataasstring);
         fs.Write(info, 0, info.Length);
         fs.Close();
     }
 }
コード例 #6
0
        public async Task <UploadDescription> InitUploadAsync(Recording recording, RecordingMetadata metadata)
        {
            var uri = new Uri($"{appConfiguration.RecorderApiUrl}/{InitUploadUrlPath}");

            // The recordings are stored in the Documents folder. We only save the filename in the database
            // (because deleting and reinstalling the app may cause the full path to change), so we need to
            // construct the full pathname again:
            //var documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            //string fileName = Path.Combine(documentsFolder, recording.FileName);

            var fileName = Path.GetFileName(recording.FileName);

            JObject payload = new JObject(
                new JProperty("filename", fileName),
                new JProperty("metadata", metadata.ToJsonObject())
                );

            try
            {
                string payloadString = payload.ToString();
                Debug.WriteLine($"JSON payload = '{payloadString}'");
                Debug.WriteLine($"JSON payload length = {payloadString.Length} characters");
                var content = new StringContent(payloadString, Encoding.UTF8, "application/json");

                var request = new HttpRequestMessage()
                {
                    RequestUri = uri,
                    Method     = HttpMethod.Post,
                    Content    = content
                };
                request.Headers.Add("x-api-key", appConfiguration.RecorderApiKey);

                var response = await client.SendAsync(request);

                if (response.IsSuccessStatusCode)
                {
                    var responseContent = await response.Content.ReadAsStringAsync();

                    return(JsonConvert.DeserializeObject <UploadDescription>(responseContent, uploadDescriptionJsonSerializerSettings));
                }
                else
                {
                    Debug.WriteLine($"Post request to {uri.ToString()} failed, status: {response.StatusCode}, reason: {response.ReasonPhrase}");
                    throw new Exception("Failed to init upload");
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"              ERROR {ex.Message}");
                throw new Exception("Failed to init upload", ex);
            }
        }
コード例 #7
0
        public async Task <RecordingMetadata> CreateAsync(UserRecordingInput data)
        {
            var recordingEntry    = new RecordingEntry();
            var recordingMetadata = new RecordingMetadata();
            var id = Guid.NewGuid().ToString();

            recordingEntry.Recording      = data.Recording;
            recordingEntry.Id             = id;
            recordingMetadata.Title       = data.Title;
            recordingMetadata.Description = data.Description;
            recordingMetadata.CreatedBy   = User.FindFirst(ClaimTypes.NameIdentifier).Value;
            recordingMetadata.GivenName   = User.FindFirstValue(ClaimTypes.GivenName);
            recordingMetadata.Surname     = User.FindFirstValue(ClaimTypes.Surname);
            recordingMetadata.Id          = id;
            recordingMetadata.CreatedAt   = DateTimeOffset.Now;
            await _cosmosDbService.AddRecordingAsync(recordingEntry, recordingMetadata);

            return(recordingMetadata);
        }
コード例 #8
0
        public RecordingMetadata ConvertPreviewZoomMedia(ConversionConfiguration config)
        {
            // generate output directory
            if (Directory.Exists(config.OutputDirectory))
            {
                Directory.Delete(config.OutputDirectory, true);
            }

            Directory.CreateDirectory(config.OutputDirectory);

            // convert file
            ConvertZoomVideoFile(config, true);

            var targetVideoPath = Path.Combine(config.OutputDirectory, "slides.mp4");

            // generate preview
            var thumbOutDir = Path.Combine(config.OutputDirectory, "thumbs");

            Directory.CreateDirectory(thumbOutDir);

            string thumbName = FFmpegHelper.ExportThumbnail(5f, targetVideoPath, Path.Combine(config.OutputDirectory, "thumbs"), "0");

            // generate recording object
            var finalRecording = new RecordingMetadata();

            finalRecording.FileName = "slides.mp4";
            finalRecording.Slides   = new Slide[] { new Slide
                                                    {
                                                        StartPosition = 0,
                                                        Thumbnail     = "thumbs/" + thumbName,
                                                        Ocr           = ""
                                                    } };
            finalRecording.Duration = FFmpegHelper.GetMediaLength(targetVideoPath).TotalSeconds;

            FFmpegHelper.ExportThumbnail(5f, Path.Combine(config.OutputDirectory, "slides.mp4"), config.OutputDirectory, "thumbnail");

            return(finalRecording);
        }
コード例 #9
0
 public RecordingListTests()
 {
     this.data = TestHelper.Get <RecordingMetadata>("recording-search.xml", false);
 }
コード例 #10
0
        public void FinalizeRecording(string answer)
        {
            if (!IsRecording)
            {
                Debug.WriteLine("Skipping recording finalize since not recording");
                return;
            }

            Debug.WriteLine($"RecordingManager.FinalizeRecording, item ID = '{recording.ItemId}'");

            var file = recorder.Stop();

            RecordingMetadata metadata = new RecordingMetadata(recording.RecordingId)
            {
                ClientId                  = recording.ClientId,
                ItemId                    = recording.ItemId,
                RecordingTimestamp        = file.CreatedOn,
                RecordingDuration         = file.Duration,
                RecordingBitDepth         = file.BitDepth,
                RecordingSampleRate       = file.SampleRate,
                RecordingNumberOfChannels = file.NumberOfChannels,
                ContentType               = file.ContentType,
            };

            Debug.WriteLine($"ContentType = '{file.ContentType}'");

            // Explicitly set the User object to null for a recording
            metadata.User = null;

            string metadataString = metadata.ToJsonString();

            Debug.WriteLine($"After finalizing recording, metadata = '{metadataString}'");
            recording.FileName = file.FileName;
            recording.Metadata = metadataString;

            recording.UploadStatus = UploadStatus.Pending;
            App.Database.SaveRecordingAsync(recording);
            Debug.WriteLine($"Saved recording information for '{recording.RecordingId}' in the database");

            var dict = new Dictionary <string, string>
            {
                //{ AnalyticsParameterNamesConstants.RecordingId, metadata.RecordingId },
                { AnalyticsParameterNamesConstants.ClientId, metadata.ClientId },
                { AnalyticsParameterNamesConstants.ItemId, metadata.ItemId },
                { AnalyticsParameterNamesConstants.RecordingTimestamp, metadata.RecordingTimestamp.ToString("o") },
                { AnalyticsParameterNamesConstants.ClientPlatformName, metadata.ClientPlatformName },
                { AnalyticsParameterNamesConstants.ClientPlatformVersion, metadata.ClientPlatformVersion },
                { AnalyticsParameterNamesConstants.RecordingDuration, metadata.RecordingDuration.ToString() },
                { AnalyticsParameterNamesConstants.RecordingSpecification,
                  $"{metadata.RecordingSampleRate.ToString()}/{metadata.RecordingBitDepth.ToString()}/{metadata.RecordingNumberOfChannels.ToString()}" },
                { AnalyticsParameterNamesConstants.BuildType, appConfiguration.BuildType },
            };
            var app = Application.Current as App;

            app.AnalyticsEventTracker.SendEvent(AnalyticsEventNamesConstants.RecordingCompleted, dict);

            // Update the total seconds recorded
            int durationInSeconds = (int)Math.Floor(metadata.RecordingDuration);

            app.UpdateTotalRecorded(durationInSeconds);
        }
コード例 #11
0
        public async Task SynchronizePublishedRecordings(int lectureId)
        {
            var lecture = await _context.Lectures
                          .Include(x => x.Semester)
                          .SingleAsync(x => x.Id == lectureId);

            if (!lecture.Active)
            {
                return;
            }

            var recordings = await _context.Recordings
                             .Include(x => x.Chapters)
                             .Include(x => x.Outputs)
                             .Where(x => x.LectureId == lectureId)
                             .Where(x => x.Outputs.Any(x => x.Status == RecordingStatus.PUBLISHED))
                             .OrderBy(x => x.Sorting).ThenBy(x => x.UploadDate)
                             .ToListAsync();

            var lectureMetadata = new RecordingProcessor.Model.Lecture()
            {
                Name       = lecture.Title,
                Semester   = lecture.Semester.Name,
                Recordings = new List <RecordingMetadata>()
            };

            foreach (var recording in recordings)
            {
                var targetFolderName = "video/" + recording.Id.ToString();
                var legacy           = false;

                // generate metadata
                var metadata = new RecordingMetadata()
                {
                    Id          = recording.Title,
                    Name        = recording.Title,
                    Description = recording.Description,

                    Duration = recording.Duration,
                    Date     = recording.PublishDate.Value
                };

                // check outputs
                foreach (var output in recording.Outputs
                         .Where(x => x.Status == RecordingStatus.PUBLISHED)
                         .Where(x => x.JobType == typeof(ProcessRecordingJob).FullName))
                {
                    var configuration = JsonConvert.DeserializeObject <ProcessRecordingJobConfiguration>(output.JobConfiguration);

                    // 720p processed?
                    if (configuration.OutputType == ProcessRecordingOutputType.Default || configuration.OutputType == ProcessRecordingOutputType.Video_720p)
                    {
                        metadata.FileName          = targetFolderName + "/output_720p/slides.mp4";
                        metadata.StageVideo        = targetFolderName + "/output_720p/stage.mp4";
                        metadata.PresenterFileName = targetFolderName + "/output_720p/talkinghead.mp4";
                    }

                    // 1080p processed?
                    if (configuration.OutputType == ProcessRecordingOutputType.Video_1080P)
                    {
                        metadata.FileNameHd          = targetFolderName + "/output_1080p/slides.mp4";
                        metadata.StageVideoHd        = targetFolderName + "/output_1080p/stage.mp4";
                        metadata.PresenterFileNameHd = targetFolderName + "/output_1080p/talkinghead.mp4";
                    }

                    // legacy?
                    if (configuration.OutputType == ProcessRecordingOutputType.Legacy)
                    {
                        metadata.FileName          = "video/" + recording.CustomTargetName + "/slides.mp4";
                        metadata.StageVideo        = "video/" + recording.CustomTargetName + "/stage.mp4";
                        metadata.PresenterFileName = "video/" + recording.CustomTargetName + "/talkinghead.mp4";

                        legacy = true;
                    }
                }

                metadata.Slides = recording.Chapters.OrderBy(x => x.StartPosition).Select(x => new Slide()
                {
                    Thumbnail     = (legacy ? "video/" + recording.CustomTargetName + "/" : targetFolderName + "/output_720p/") + x.Thumbnail,
                    Ocr           = x.Text,
                    StartPosition = (float)x.StartPosition
                }).ToArray();

                lectureMetadata.Recordings.Add(metadata);
            }

            // update metadata
            var courseJsonMetadataFile = Path.Combine(lecture.PublishPath, "assets", "lecture.json");

            MetadataService.SaveSettings(lectureMetadata, courseJsonMetadataFile);

            // update lecture
            lecture.LastSynchronized = DateTime.Now;
            await _context.SaveChangesAsync();

            await UpdateLectureStatus();
        }
コード例 #12
0
 public async Task AddRecordingAsync(RecordingEntry recordingEntry, RecordingMetadata recordingMetadata)
 {
     await _containers["recordings"].CreateItemAsync(recordingEntry, new PartitionKey(recordingEntry.Id));
     await _containers["recording_metadata"].CreateItemAsync(recordingMetadata, new PartitionKey(recordingEntry.Id));
 }
コード例 #13
0
        public async Task Preview(int recordingId)
        {
            // get recording
            var recording = await _context.Recordings
                            .Include(x => x.Chapters)
                            .Include(x => x.Outputs)
                            .FirstOrDefaultAsync(x => x.Id == recordingId);

            if (recording == null)
            {
                return;
            }

            // create new recording output
            var recordingOutput = new RecordingOutput()
            {
                RecordingId      = recordingId,
                DateStarted      = DateTime.Now,
                Status           = RecordingStatus.PROCESSING,
                JobType          = typeof(PreviewRecordingJob).FullName,
                JobConfiguration = null
            };

            _context.RecordingOutputs.Add(recordingOutput);
            await _context.SaveChangesAsync();

            await UpdateLectureRecordingStatus();

            // get lecture
            var lecture = await _context.Lectures
                          .FindAsync(recording.LectureId);

            // start encoding preview
            if (recording.Type == RecordingType.GREEN_SCREEN_RECORDING || recording.Type == RecordingType.SIMPLE_RECORDING || recording.Type == RecordingType.ZOOM_RECORDING)
            {
                // file path is file?
                string outputFolder  = Path.Combine(lecture.ConvertedPath, recording.Id.ToString(), "preview");
                string inputFileName = "";

                if (File.Exists(recording.FilePath))
                {
                    inputFileName = recording.FilePath;
                }
                else if (recording.Type == RecordingType.ZOOM_RECORDING)
                {
                    inputFileName = Directory.GetFiles(recording.FilePath)
                                    .Where(x => x.EndsWith(".mp4"))
                                    .SingleOrDefault();
                }
                else
                {
                    var targetName = recording.CustomTargetName != null ? recording.CustomTargetName : "";

                    inputFileName = Directory.GetFiles(recording.FilePath)
                                    .Where(x => x.EndsWith(targetName + "_meta.json"))
                                    .SingleOrDefault();
                }

                if (inputFileName == null)
                {
                    throw new Exception("Could not find studio meta data.");
                }

                // convert files
                RecordingMetadata metaData = null;

                if (recording.Type == RecordingType.GREEN_SCREEN_RECORDING)
                {
                    metaData = ConvertStudioRecording(inputFileName, outputFolder);

                    recording.Duration = metaData.Duration;
                }
                else if (recording.Type == RecordingType.SIMPLE_RECORDING)
                {
                    metaData = ConvertSimpleRecording(inputFileName, outputFolder);

                    recording.Duration = metaData.Duration;
                }
                else if (recording.Type == RecordingType.ZOOM_RECORDING)
                {
                    metaData = ConvertZoomRecording(inputFileName, outputFolder);

                    recording.Duration = metaData.Duration;
                }

                if (metaData != null)
                {
                    _context.RecordingChapters.RemoveRange(recording.Chapters);

                    // add slides
                    foreach (var slide in metaData.Slides)
                    {
                        var chapter = new RecordingChapter()
                        {
                            Recording     = recording,
                            StartPosition = slide.StartPosition,
                            Text          = slide.Ocr,
                            Thumbnail     = slide.Thumbnail
                        };

                        _context.RecordingChapters.Add(chapter);
                    }
                }

                // set status
                recordingOutput.Status       = RecordingStatus.PROCESSED;
                recordingOutput.JobError     = null;
                recordingOutput.DateFinished = DateTime.Now;

                await _context.SaveChangesAsync();
                await UpdateLectureRecordingStatus();
            }
        }
コード例 #14
0
ファイル: AnalysisContext.cs プロジェクト: AntieJ/blankdroid
 public static void UpdateSamples(string baseLocation, string fileName)
 {
     _metadataService = new MetadataService();
     _metadata        = _metadataService.GetRecordingMetadata(baseLocation, fileName);
     UpdateSamples();
 }
コード例 #15
0
        public async Task Execute(ProcessRecordingJobConfiguration configuration)
        {
            // get recording
            var recording = await _context.Recordings
                            .Include(x => x.Chapters)
                            .Include(x => x.Outputs)
                            .FirstOrDefaultAsync(x => x.Id == configuration.RecordingId);

            if (recording == null)
            {
                return;
            }

            // create new recording output
            var recordingOutput = new RecordingOutput()
            {
                RecordingId      = configuration.RecordingId,
                DateStarted      = DateTime.Now,
                Status           = RecordingStatus.PROCESSING,
                JobType          = typeof(ProcessRecordingJob).FullName,
                JobConfiguration = JsonConvert.SerializeObject(configuration)
            };

            _context.RecordingOutputs.Add(recordingOutput);
            await _context.SaveChangesAsync();

            await UpdateLectureRecordingStatus();

            // get lecture
            var lecture = await _context.Lectures
                          .FindAsync(recording.LectureId);

            // start encoding
            if (recording.Type == RecordingType.GREEN_SCREEN_RECORDING || recording.Type == RecordingType.SIMPLE_RECORDING || recording.Type == RecordingType.ZOOM_RECORDING)
            {
                // file path is file?
                string outputFolder  = Path.Combine(lecture.ConvertedPath, recording.Id.ToString(), "output_" + recordingOutput.Id);
                string inputFileName = "";

                if (File.Exists(recording.FilePath))
                {
                    inputFileName = recording.FilePath;
                }
                else if (recording.Type == RecordingType.ZOOM_RECORDING)
                {
                    inputFileName = Directory.GetFiles(recording.FilePath)
                                    .Where(x => x.EndsWith(".mp4"))
                                    .SingleOrDefault();
                }
                else
                {
                    string targetName = recording.CustomTargetName != null ? recording.CustomTargetName : "";
                    inputFileName = Directory.GetFiles(recording.FilePath)
                                    .Where(x => x.EndsWith(targetName + "_meta.json"))
                                    .SingleOrDefault();
                }

                // create output directory
                Directory.CreateDirectory(outputFolder);

                if (inputFileName == null)
                {
                    recordingOutput.Status   = RecordingStatus.ERROR;
                    recordingOutput.JobError = "Could not find studio meta data.";
                    await _context.SaveChangesAsync();
                    await UpdateLectureRecordingStatus();

                    throw new Exception("Could not find studio meta data.");
                }

                try
                {
                    // convert files
                    RecordingMetadata metaData = null;

                    if (recording.Type == RecordingType.GREEN_SCREEN_RECORDING)
                    {
                        metaData = ConvertStudioRecording(inputFileName, outputFolder, GetDimension(configuration.OutputType));
                    }
                    else if (recording.Type == RecordingType.SIMPLE_RECORDING)
                    {
                        metaData = ConvertSimpleRecording(inputFileName, outputFolder, GetDimension(configuration.OutputType));
                    }
                    else if (recording.Type == RecordingType.ZOOM_RECORDING)
                    {
                        metaData = ConvertZoomRecording(inputFileName, outputFolder);
                    }

                    recordingOutput.Status       = RecordingStatus.PROCESSED;
                    recordingOutput.JobError     = null;
                    recordingOutput.DateFinished = DateTime.Now;

                    await _context.SaveChangesAsync();
                    await UpdateLectureRecordingStatus();
                }
                catch (Exception ex)
                {
                    recordingOutput.Status       = RecordingStatus.ERROR;
                    recordingOutput.JobError     = ex.Message;
                    recordingOutput.DateFinished = DateTime.Now;

                    await UpdateLectureRecordingStatus();

                    throw ex;
                }
            }
        }