private string GetChannelName(MaterialFolderIndexRecord aIndexRecord)
        {
            switch (aIndexRecord.DataType)
            {
            case DataType.Audio:
                return("Audio");

            case DataType.Text:
                return("Text");
            }
            return("Camera");
        }
        public void AddRecord(MaterialFolderIndexRecord aRecord)
        {
            if (aRecord.ChannelId == ChannelId.Number && aRecord.DataType == ChannelId.DataType)
            {
                Records.Add(aRecord);

                if (Begin == DateTime.MinValue || aRecord.BeginTimestamp < Begin)
                {
                    Begin = aRecord.BeginTimestamp;
                }

                if (End == DateTime.MinValue || aRecord.EndTimestamp > End)
                {
                    End = aRecord.EndTimestamp;
                }
            }
        }
        private bool ProcessFile(Guid aFolderId, string aSourceFilePath, MaterialFolderIndexRecord aNewRecord, TimeInterval aInterval, string aNewFilePath)
        {
            bool result       = false;
            bool waitforIntra = true;
            Guid clientGuid   = Guid.NewGuid();

            try
            {
                using (FileStream file = File.OpenRead(aSourceFilePath))
                {
                    using (IMaterialFile newFile = MaterialFileFactory.CreateMaterialFile(aFolderId, aNewRecord, aNewFilePath))
                    {
                        int    readBytes        = 0;
                        int    startFrameOffset = 0;
                        bool   startFound       = false;
                        byte[] buffer           = new byte[16 * 1024];

                        DateTime    lastFrameTimeStamp = DateTime.MinValue;
                        List <byte> frameBuffer        = new List <byte>();
                        do
                        {
                            if (_stopTask.IsCancellationRequested)
                            {
                                return(false);
                            }

                            startFrameOffset = 0;
                            readBytes        = file.Read(buffer, 0, buffer.Length);

                            for (int pos = 0; pos < readBytes - Constants.FrameStart.Length; ++pos)
                            {
                                if (IsEqual(buffer, pos, Constants.FrameStart))
                                {
                                    startFound       = true;
                                    startFrameOffset = pos;
                                    frameBuffer.Clear();
                                }

                                if (IsEqual(buffer, pos, Constants.FrameEnd))
                                {
                                    int endFramePos = pos + Constants.FrameEnd.Length;
                                    CopyBuffer(frameBuffer, buffer, startFrameOffset, endFramePos);

                                    startFound       = false;
                                    startFrameOffset = 0;

                                    Frame frame = null;
                                    try
                                    {
                                        using (MemoryStream stream = new MemoryStream(frameBuffer.ToArray()))
                                        {
                                            try
                                            {
                                                frame = new Frame();
                                                frame.Deserialize(stream);
                                            }
                                            catch
                                            {
                                                continue;
                                            }

                                            if (frame.Metadata.Timestamp <= lastFrameTimeStamp)
                                            {
                                                // Skip old frames
                                                continue;
                                            }

                                            if (frame.Metadata.ChannelId != aNewRecord.ChannelId || frame.DataType != aNewRecord.DataType)
                                            {
                                                // Skip other data
                                                continue;
                                            }

                                            if (waitforIntra && !frame.Metadata.IsIntra)
                                            {
                                                // Skip non intra if we wait intra
                                                continue;
                                            }

                                            waitforIntra = false;

                                            if (aInterval.Contains(frame.Metadata.Timestamp))
                                            {
                                                MaterialPosition position    = null;
                                                WriteStatus      writeStatus = newFile.Write(frame, ref position);
                                                if (writeStatus == WriteStatus.OK)
                                                {
                                                    // Update material folder index record
                                                    if (aNewRecord.BeginTimestamp.Ticks == 0)
                                                    {
                                                        aNewRecord.BeginTimestamp = frame.Metadata.Timestamp;
                                                    }
                                                    aNewRecord.EndTimestamp = frame.Metadata.Timestamp;

                                                    // Update result
                                                    result = true;

                                                    // Add to frame times
                                                    lastFrameTimeStamp = frame.Metadata.Timestamp;
                                                }
                                                else
                                                {
                                                    SendError($"Write frame error, status: {writeStatus}, source file {aSourceFilePath}, destination file {aNewFilePath}!");
                                                    waitforIntra = true;
                                                }
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        SendError(ex.Message);
                                        waitforIntra = true;
                                    }
                                    finally
                                    {
                                        frame?.Release();
                                    }
                                }
                            }

                            if (startFound)
                            {
                                CopyBuffer(frameBuffer, buffer, startFrameOffset, buffer.Length);
                            }
                        } while (readBytes > 0);
                    }
                }
            }
            catch (Exception ex)
            {
                SendError(ex.Message);
            }
            return(result);
        }
 private bool ShouldSkipFile(MaterialFolderIndexRecord aRecord, TimeInterval aTimeInterval)
 {
     return(aRecord.EndTimestamp < aTimeInterval.Begin || aRecord.BeginTimestamp > aTimeInterval.End);
 }
        private void ProcessSelectedChannels(IEnumerable <Channel> aChannels, TimeInterval aTimeInterval)
        {
            try
            {
                IEnumerable <Channel> channels = aChannels.Where(x => x.IsChecked);
                int count = channels.Count();
                if (count == 0)
                {
                    return;
                }

                string destination = Path.Combine(DestinationPath, $"Export_{DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff")}");

                if (!Directory.Exists(destination))
                {
                    Directory.CreateDirectory(destination);
                }

                ArchiveInfo archiveInfo = new ArchiveInfo();

                // Set material file id
                int materialFileId = 0;

                // Create new material folder index
                MaterialFolderIndex index = new MaterialFolderIndex()
                {
                    MaterialFolderId = Guid.NewGuid()
                };

                double progress        = 0;
                double channelProgress = 100.0 / count;

                var parallelOptions = new ParallelOptions()
                {
                    MaxDegreeOfParallelism = 1
                };

                Parallel.ForEach(channels, parallelOptions, (channel) =>
                {
                    if (_stopTask.IsCancellationRequested)
                    {
                        return;
                    }

                    var files           = channel.Records.Where(x => !ShouldSkipFile(x, aTimeInterval)).OrderBy(x => x.BeginTimestamp);
                    double fileProgress = channelProgress / files.Count();

                    foreach (var fileIndexRecord in files)
                    {
                        if (_stopTask.IsCancellationRequested)
                        {
                            return;
                        }

                        string sourceFilePath = Path.Combine(SelectedPath, Helpers.GetFileName(fileIndexRecord.MaterialFileId));

                        if (File.Exists(sourceFilePath))
                        {
                            var fileId = Interlocked.Increment(ref materialFileId);

                            // Generate new file name
                            string newFilePath = Path.Combine(destination, Helpers.GetFileName(fileId));

                            _logger.Info($"Source file: {sourceFilePath}, destination file: {newFilePath}");

                            if (File.Exists(newFilePath))
                            {
                                File.SetAttributes(newFilePath, FileAttributes.Normal);
                                File.Delete(newFilePath);
                            }

                            MaterialFolderIndexRecord indexRecord = new MaterialFolderIndexRecord()
                            {
                                ChannelId      = fileIndexRecord.ChannelId,
                                DataType       = fileIndexRecord.DataType,
                                ChannelType    = ChannelType.Material,
                                MaterialFileId = fileId
                            };

                            if (ProcessFile(index.MaterialFolderId, sourceFilePath, indexRecord, aTimeInterval, newFilePath))
                            {
                                lock (_indexLock)
                                {
                                    // Update index
                                    index.IndexRecords.Add(indexRecord);

                                    // Update arhive info
                                    archiveInfo.UpdateArchiveInfo(indexRecord, new AdditionalInfo()
                                    {
                                        Name = GetChannelName(indexRecord) + " " + indexRecord.ChannelId
                                    });

                                    // Flush index time limits
                                    indexRecord.Flush();

                                    // Update file info
                                    archiveInfo.UpdateFileInfo(newFilePath);
                                }
                            }
                        }

                        lock (_progressLock)
                        {
                            progress += fileProgress;
                            SendProgress(progress);
                        }
                    }
                });

                if (index.IndexRecords.Count > 0 && !_stopTask.IsCancellationRequested)
                {
                    SaveMaterialFolderIndex(index, destination);
                    ArchiveInfo.SaveArchiveInfo(archiveInfo, destination);
                }
            }
            catch (Exception ex)
            {
                SendError(ex.Message);
            }
            finally
            {
                SendExportCompleted();
            }
        }