internal void SearchFramesByMagicPhase2(OnSearchProgressDelegate progressCallback) { m_Index = new AdvFramesIndex(); int percentCompleted; int lastPercentCompleted = -1; int framesRecovered = 0; long startTimeTicks = -1; m_CandidateFrameOffsets.Add(new RecoveredFrameHeader() { Position = m_FileReader.BaseStream.Length }); ushort[,] prevFramePixels = null; for (int i = 0; i < m_CandidateFrameOffsets.Count - 1; i++) { RecoveredFrameHeader frameInfo1 = m_CandidateFrameOffsets[i]; RecoveredFrameHeader frameInfo2 = m_CandidateFrameOffsets[i + 1]; if (startTimeTicks == -1) { startTimeTicks = frameInfo1.StartExposureUT.Ticks; } m_Index.Index.Add(new AdvFramesIndexEntry() { ElapsedTime = new TimeSpan(frameInfo1.StartExposureUT.Ticks - startTimeTicks), Offset = frameInfo1.Position, Length = (uint)(frameInfo2.Position - frameInfo1.Position) }); try { object[] data = GetFrameSectionData(framesRecovered, prevFramePixels); AdvImageData imageData = (AdvImageData)data[0]; AdvStatusData statusData = (AdvStatusData)data[1]; int frameWidth = imageData.ImageData.GetLength(0); int frameHeight = imageData.ImageData.GetLength(1); Trace.WriteLine(string.Format("Recovered frame #{0} with LayoutId {1} and {2} status tags. Dimentions: {3}x{4} pixels", framesRecovered, imageData.LayoutId, statusData.TagValues.Count, frameWidth, frameHeight)); // NOTE: Doesn't have to be right, just need something so we read the pixels prevFramePixels = imageData.ImageData; framesRecovered++; } catch (Exception) { m_Index.Index.RemoveAt(m_Index.Index.Count - 1); } percentCompleted = (int)(100.0 * i / (m_CandidateFrameOffsets.Count - 1)); if (lastPercentCompleted < percentCompleted) { progressCallback(percentCompleted, framesRecovered); lastPercentCompleted = percentCompleted; } } }
internal void SearchFramesByMagicPhase2(OnSearchProgressDelegate progressCallback) { m_Index = new AdvFramesIndex(); int percentCompleted; int lastPercentCompleted = -1; int framesRecovered = 0; long startTimeTicks = -1; m_CandidateFrameOffsets.Add(new RecoveredFrameHeader() { Position = m_FileReader.BaseStream.Length }); ushort[,] prevFramePixels = null; for(int i = 0; i < m_CandidateFrameOffsets.Count - 1; i ++) { RecoveredFrameHeader frameInfo1 = m_CandidateFrameOffsets[i]; RecoveredFrameHeader frameInfo2 = m_CandidateFrameOffsets[i + 1]; if (startTimeTicks == -1) startTimeTicks = frameInfo1.StartExposureUT.Ticks; m_Index.Index.Add(new AdvFramesIndexEntry() { ElapsedTime = new TimeSpan(frameInfo1.StartExposureUT.Ticks - startTimeTicks), Offset = frameInfo1.Position, Length = (uint)(frameInfo2.Position - frameInfo1.Position) }); try { object[] data = GetFrameSectionData(framesRecovered, prevFramePixels); AdvImageData imageData = (AdvImageData)data[0]; AdvStatusData statusData = (AdvStatusData)data[1]; int frameWidth = imageData.ImageData.GetLength(0); int frameHeight = imageData.ImageData.GetLength(1); Trace.WriteLine(string.Format("Recovered frame #{0} with LayoutId {1} and {2} status tags. Dimentions: {3}x{4} pixels", framesRecovered, imageData.LayoutId, statusData.TagValues.Count, frameWidth, frameHeight)); // NOTE: Doesn't have to be right, just need something so we read the pixels prevFramePixels = imageData.ImageData; framesRecovered++; } catch(Exception) { m_Index.Index.RemoveAt(m_Index.Index.Count - 1); } percentCompleted = (int)(100.0 * i / (m_CandidateFrameOffsets.Count - 1)); if (lastPercentCompleted < percentCompleted) { progressCallback(percentCompleted, framesRecovered); lastPercentCompleted = percentCompleted; } } }
internal void SearchFramesByMagicPhase1(OnSearchProgressDelegate progressCallback) { long bytesToSearch = m_InputFile.Length - 5 - m_RecoveryOffset; m_CandidateFrameOffsets.Clear(); int percentCompleted; int lastPercentCompleted = -1; int MIN_FRAME_SIZE = 12 + 4; for (long i = 0; i < bytesToSearch; i++) { m_InputFile.Seek(m_RecoveryOffset + i, SeekOrigin.Begin); uint frameDataMagic = m_FileReader.ReadUInt32(); if(frameDataMagic == 0xEE0122FF) { try { byte[] data = m_FileReader.ReadBytes(MIN_FRAME_SIZE); // Read the timestamp and exposure long frameTimeMsSince2010 = (long)data[0] + (((long)data[1]) << 8) + (((long)data[2]) << 16) + (((long)data[3]) << 24) + (((long)data[4]) << 32) + (((long)data[5]) << 40) + (((long)data[6]) << 48) + (((long)data[7]) << 56); int exposure = data[8] + (data[9] << 8) + (data[10] << 16) + (data[11] << 24); DateTime startExposure = ADV_ZERO_DATE_REF.AddMilliseconds(frameTimeMsSince2010); double exposureMS = exposure / 10.0; if (startExposure.Year < 2010 || startExposure.Year > 2100) continue; if (exposureMS < 0 || exposureMS > 60 * 1000) continue; m_CandidateFrameOffsets.Add(new RecoveredFrameHeader() { Position = m_RecoveryOffset + i, StartExposureUT = startExposure, ExposureMilliseconds = exposureMS }); int sectionDataLength = data[12] + (data[13] << 8) + (data[14] << 16) + (data[15] << 24); m_InputFile.Seek(m_RecoveryOffset + i + 4 + 12 + sectionDataLength + 4, SeekOrigin.Begin); byte tagValuesCount = m_FileReader.ReadByte(); for (int j = 0; j < tagValuesCount; j++) { m_FileReader.ReadByte(); byte len = m_FileReader.ReadByte(); m_FileReader.ReadBytes(len); } // NOTE: The next frame should begin somewhere in the next 32 bytes long nextFrameSearchStartPos = m_FileReader.BaseStream.Position; for (int j = 0; j < 32; j++) { m_InputFile.Seek(nextFrameSearchStartPos + j, SeekOrigin.Begin); uint frameDataMagic2 = m_FileReader.ReadUInt32(); if (frameDataMagic2 == 0xEE0122FF) { // We found it! i = nextFrameSearchStartPos + j - m_RecoveryOffset - 1; break; } } } catch { } } percentCompleted = (int)(100.0 * i / bytesToSearch); if (lastPercentCompleted < percentCompleted) { progressCallback(percentCompleted, m_CandidateFrameOffsets.Count); lastPercentCompleted = percentCompleted; } } }
internal bool SaveAsAviFile(string fileName, int firstFrame, int lastFrame, AdvToAviConverter converter, bool tryCodec, double msPerFrame, double addedGamma, OnSearchProgressDelegate progressCallback) { IAviSaver saver = AdvToAviConverterFactory.CreateConverter(converter); saver.CloseAviFile(); if (!saver.StartNewAviFile(fileName, (int) ImageSection.Width, (int) ImageSection.Height, 8, 25, tryCodec)) { progressCallback(100, 0); return false; } try { int aviFrameNo = 0; AdvFramesIndexEntry firstFrameIdx = m_Index.Index[firstFrame]; double startingTimeMilliseconds = firstFrameIdx.ElapsedTime.TotalMilliseconds; bool isAavFile = AdvFileTags["FSTF-TYPE"] == "AAV"; double effFrameDuration = double.NaN; try { effFrameDuration = 1000 / double.Parse(AdvFileTags["EFFECTIVE-FRAME-RATE"]); } catch { } if (isAavFile && m_Index.Index[lastFrame].ElapsedTime.Ticks == 0 && (double.IsNaN(effFrameDuration) || double.IsInfinity(effFrameDuration))) { MessageBox.Show( "This AAV video format is too old or the AAV file is corrupted. It cannot be converted to AVI", "Tangra 3", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if ((isAavFile && !double.IsNaN(effFrameDuration)) || !isAavFile && m_Index.Index[lastFrame].ElapsedTime.Ticks != 0) { // Sampling can be done as we have sufficient timing information } else { MessageBox.Show( "There is insufficient timing information in this file to convert it to AVI. This could be caused by an old file format.", "Tangra 3", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } progressCallback(5, 0); for (int i = firstFrame; i <= lastFrame; i++) { AdvFramesIndexEntry frame = m_Index.Index[i]; AdvImageData currentImageData; AdvStatusData currentStatusData; Bitmap currentBitmap; using (Pixelmap pixmap = GetFrameData(i, out currentImageData, out currentStatusData, out currentBitmap)) { int lastRepeatedAviFrameNo = 0; if (isAavFile && !double.IsNaN(effFrameDuration)) { lastRepeatedAviFrameNo = (int)Math.Round(((i - firstFrame) * effFrameDuration) / msPerFrame); } else if (!isAavFile && frame.ElapsedTime.Ticks != 0) lastRepeatedAviFrameNo = (int)Math.Round((frame.ElapsedTime.TotalMilliseconds - startingTimeMilliseconds) / msPerFrame); while (aviFrameNo < lastRepeatedAviFrameNo) { if (!saver.AddAviVideoFrame(pixmap, addedGamma, ImageSection.Adv16NormalisationValue)) { progressCallback(100, 0); return false; } aviFrameNo++; } if (currentBitmap != null) currentBitmap.Dispose(); } int percDone = (int)Math.Min(90, 90 * (i - firstFrame) * 1.0 / (lastFrame - firstFrame + 1)); progressCallback(5 + percDone, 0); } } finally { saver.CloseAviFile(); progressCallback(100, 0); } return false; }
internal void ExportStatusSectionToCSV(string fileName, int firstFrame, int lastFrame, OnSearchProgressDelegate progressCallback) { progressCallback(5, 0); //string folder = Path.GetDirectoryName(fileName); bool headerAppended = false; using (FileStream fsOutput = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write)) using(TextWriter writer = new StreamWriter(fsOutput)) { for (int i = firstFrame; i <= lastFrame; i++) { object[] data = GetFrameSectionData(i, null); AdvImageData imageData = (AdvImageData)data[0]; AdvStatusData statusData = (AdvStatusData)data[1]; //using(FileStream fs = new FileStream(string.Format("{0}\\{1}.pix", folder, i), FileMode.CreateNew, FileAccess.Write)) //using (BinaryWriter wrt = new BinaryWriter(fs)) //{ // for (int y = 0; y < ImageSection.Height; y++) // { // for (int x = 0; x < ImageSection.Width; x++) // { // ushort val = imageData.ImageData[x, y]; // wrt.Write(val); // } // } //} string headerRow; string nextRow = StatusDataToCsvRow(imageData, statusData, i, out headerRow); if (!headerAppended) { writer.WriteLine(headerRow); headerAppended = true; } writer.WriteLine(nextRow); int percDone = (int)Math.Min(90, 90 * (i - firstFrame) * 1.0 / (lastFrame - firstFrame + 1)); progressCallback(5 + percDone, 0); } progressCallback(95, 0); writer.Flush(); } }
internal bool CropAdvFile(string fileName, int firstFrame, int lastFrame, OnSearchProgressDelegate progressCallback) { using (var fsr = new FileStream(m_FileName, FileMode.Open, FileAccess.Read)) using (var reader = new BinaryReader(fsr)) using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) using (var writer = new BinaryWriter(fs)) { AdvFramesIndexEntry firstEntry = m_Index.Index[0]; CopyRawBytes(reader, 0, firstEntry.Offset, writer); progressCallback(5, 0); AdvFramesIndexEntry firstEntryToCopy = m_Index.Index[firstFrame]; long zeroTicks = firstEntryToCopy.ElapsedTime.Ticks; var newIndex = new List<AdvFramesIndexEntry>(); for (int i = firstFrame; i <= lastFrame; i++) { AdvFramesIndexEntry frameToCopy = m_Index.Index[i]; var copiedFrame = new AdvFramesIndexEntry() { Offset = writer.BaseStream.Position, Length = frameToCopy.Length }; long nextFrameStartPos = i == m_Index.NumberOfFrames - 1 ? m_Index.TableOffset : m_Index.Index[i + 1].Offset; CopyRawBytes(reader, frameToCopy.Offset, nextFrameStartPos - frameToCopy.Offset, writer); copiedFrame.ElapsedTime = new TimeSpan(frameToCopy.ElapsedTime.Ticks - zeroTicks); newIndex.Add(copiedFrame); int percDone = (int)Math.Min(90, 90 * (i - firstFrame) * 1.0 / (lastFrame - firstFrame + 1)); progressCallback(5 + percDone, 0); } long indexTableOffset = writer.BaseStream.Position; progressCallback(95, 0); writer.Write((uint)newIndex.Count); // Save the new INDEX foreach (AdvFramesIndexEntry newIndexEntry in newIndex) { writer.Write((uint)Math.Round(newIndexEntry.ElapsedTime.TotalMilliseconds)); writer.Write((long)newIndexEntry.Offset); writer.Write((uint)newIndexEntry.Length); } long userMetadataTablePosition = writer.BaseStream.Position; if (fsr.Length > m_UserMetadataTableOffset) { CopyRawBytes(reader, m_UserMetadataTableOffset, fsr.Length - m_UserMetadataTableOffset, writer); } writer.BaseStream.Seek(5, SeekOrigin.Begin); writer.Write((uint)newIndex.Count); writer.Write(indexTableOffset); writer.BaseStream.Seek(8, SeekOrigin.Current); writer.Write(userMetadataTablePosition); writer.BaseStream.Flush(); progressCallback(100, 0); } return false; }
internal void ExportStatusSectionToCSV(string fileName, int firstFrame, int lastFrame, OnSearchProgressDelegate progressCallback) { progressCallback(5, 0); //string folder = Path.GetDirectoryName(fileName); bool headerAppended = false; using (FileStream fsOutput = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write)) using (TextWriter writer = new StreamWriter(fsOutput)) { for (int i = firstFrame; i <= lastFrame; i++) { object[] data = GetFrameSectionData(i, null); AdvImageData imageData = (AdvImageData)data[0]; AdvStatusData statusData = (AdvStatusData)data[1]; //using(FileStream fs = new FileStream(string.Format("{0}\\{1}.pix", folder, i), FileMode.CreateNew, FileAccess.Write)) //using (BinaryWriter wrt = new BinaryWriter(fs)) //{ // for (int y = 0; y < ImageSection.Height; y++) // { // for (int x = 0; x < ImageSection.Width; x++) // { // ushort val = imageData.ImageData[x, y]; // wrt.Write(val); // } // } //} string headerRow; string nextRow = StatusDataToCsvRow(imageData, statusData, i, out headerRow); if (!headerAppended) { writer.WriteLine(headerRow); headerAppended = true; } writer.WriteLine(nextRow); int percDone = (int)Math.Min(90, 90 * (i - firstFrame) * 1.0 / (lastFrame - firstFrame + 1)); progressCallback(5 + percDone, 0); } progressCallback(95, 0); writer.Flush(); } }
internal bool CropAdvFile(string fileName, int firstFrame, int lastFrame, OnSearchProgressDelegate progressCallback) { using (var fsr = new FileStream(m_FileName, FileMode.Open, FileAccess.Read)) using (var reader = new BinaryReader(fsr)) using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) using (var writer = new BinaryWriter(fs)) { AdvFramesIndexEntry firstEntry = m_Index.Index[0]; CopyRawBytes(reader, 0, firstEntry.Offset, writer); progressCallback(5, 0); AdvFramesIndexEntry firstEntryToCopy = m_Index.Index[firstFrame]; long zeroTicks = firstEntryToCopy.ElapsedTime.Ticks; var newIndex = new List <AdvFramesIndexEntry>(); for (int i = firstFrame; i <= lastFrame; i++) { AdvFramesIndexEntry frameToCopy = m_Index.Index[i]; var copiedFrame = new AdvFramesIndexEntry() { Offset = writer.BaseStream.Position, Length = frameToCopy.Length }; long nextFrameStartPos = i == m_Index.NumberOfFrames - 1 ? m_Index.TableOffset : m_Index.Index[i + 1].Offset; CopyRawBytes(reader, frameToCopy.Offset, nextFrameStartPos - frameToCopy.Offset, writer); copiedFrame.ElapsedTime = new TimeSpan(frameToCopy.ElapsedTime.Ticks - zeroTicks); newIndex.Add(copiedFrame); int percDone = (int)Math.Min(90, 90 * (i - firstFrame) * 1.0 / (lastFrame - firstFrame + 1)); progressCallback(5 + percDone, 0); } long indexTableOffset = writer.BaseStream.Position; progressCallback(95, 0); writer.Write((uint)newIndex.Count); // Save the new INDEX foreach (AdvFramesIndexEntry newIndexEntry in newIndex) { writer.Write((uint)Math.Round(newIndexEntry.ElapsedTime.TotalMilliseconds)); writer.Write((long)newIndexEntry.Offset); writer.Write((uint)newIndexEntry.Length); } long userMetadataTablePosition = writer.BaseStream.Position; if (fsr.Length > m_UserMetadataTableOffset) { CopyRawBytes(reader, m_UserMetadataTableOffset, fsr.Length - m_UserMetadataTableOffset, writer); } writer.BaseStream.Seek(5, SeekOrigin.Begin); writer.Write((uint)newIndex.Count); writer.Write(indexTableOffset); writer.BaseStream.Seek(8, SeekOrigin.Current); writer.Write(userMetadataTablePosition); writer.BaseStream.Flush(); progressCallback(100, 0); } return(false); }
internal bool SaveAsAviFile(string fileName, int firstFrame, int lastFrame, AdvToAviConverter converter, bool tryCodec, double msPerFrame, double addedGamma, OnSearchProgressDelegate progressCallback) { IAviSaver saver = AdvToAviConverterFactory.CreateConverter(converter); saver.CloseAviFile(); if (!saver.StartNewAviFile(fileName, (int)ImageSection.Width, (int)ImageSection.Height, 8, 25, tryCodec)) { progressCallback(100, 0); return(false); } try { int aviFrameNo = 0; AdvFramesIndexEntry firstFrameIdx = m_Index.Index[firstFrame]; double startingTimeMilliseconds = firstFrameIdx.ElapsedTime.TotalMilliseconds; bool isAavFile = AdvFileTags["FSTF-TYPE"] == "AAV"; double effFrameDuration = double.NaN; try { effFrameDuration = 1000 / double.Parse(AdvFileTags["EFFECTIVE-FRAME-RATE"]); } catch { } if (isAavFile && m_Index.Index[lastFrame].ElapsedTime.Ticks == 0 && (double.IsNaN(effFrameDuration) || double.IsInfinity(effFrameDuration))) { MessageBox.Show( "This AAV video format is too old or the AAV file is corrupted. It cannot be converted to AVI", "Tangra 3", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } if ((isAavFile && !double.IsNaN(effFrameDuration)) || !isAavFile && m_Index.Index[lastFrame].ElapsedTime.Ticks != 0) { // Sampling can be done as we have sufficient timing information } else { MessageBox.Show( "There is insufficient timing information in this file to convert it to AVI. This could be caused by an old file format.", "Tangra 3", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } progressCallback(5, 0); for (int i = firstFrame; i <= lastFrame; i++) { AdvFramesIndexEntry frame = m_Index.Index[i]; AdvImageData currentImageData; AdvStatusData currentStatusData; Bitmap currentBitmap; using (Pixelmap pixmap = GetFrameData(i, out currentImageData, out currentStatusData, out currentBitmap)) { int lastRepeatedAviFrameNo = 0; if (isAavFile && !double.IsNaN(effFrameDuration)) { lastRepeatedAviFrameNo = (int)Math.Round(((i - firstFrame) * effFrameDuration) / msPerFrame); } else if (!isAavFile && frame.ElapsedTime.Ticks != 0) { lastRepeatedAviFrameNo = (int)Math.Round((frame.ElapsedTime.TotalMilliseconds - startingTimeMilliseconds) / msPerFrame); } while (aviFrameNo < lastRepeatedAviFrameNo) { if (!saver.AddAviVideoFrame(pixmap, addedGamma, ImageSection.Adv16NormalisationValue)) { progressCallback(100, 0); return(false); } aviFrameNo++; } if (currentBitmap != null) { currentBitmap.Dispose(); } } int percDone = (int)Math.Min(90, 90 * (i - firstFrame) * 1.0 / (lastFrame - firstFrame + 1)); progressCallback(5 + percDone, 0); } } finally { saver.CloseAviFile(); progressCallback(100, 0); } return(false); }
internal void SearchFramesByMagicPhase1(OnSearchProgressDelegate progressCallback) { long bytesToSearch = m_InputFile.Length - 5 - m_RecoveryOffset; m_CandidateFrameOffsets.Clear(); int percentCompleted; int lastPercentCompleted = -1; int MIN_FRAME_SIZE = 12 + 4; for (long i = 0; i < bytesToSearch; i++) { m_InputFile.Seek(m_RecoveryOffset + i, SeekOrigin.Begin); uint frameDataMagic = m_FileReader.ReadUInt32(); if (frameDataMagic == 0xEE0122FF) { try { byte[] data = m_FileReader.ReadBytes(MIN_FRAME_SIZE); // Read the timestamp and exposure long frameTimeMsSince2010 = (long)data[0] + (((long)data[1]) << 8) + (((long)data[2]) << 16) + (((long)data[3]) << 24) + (((long)data[4]) << 32) + (((long)data[5]) << 40) + (((long)data[6]) << 48) + (((long)data[7]) << 56); int exposure = data[8] + (data[9] << 8) + (data[10] << 16) + (data[11] << 24); DateTime startExposure = ADV_ZERO_DATE_REF.AddMilliseconds(frameTimeMsSince2010); double exposureMS = exposure / 10.0; if (startExposure.Year < 2010 || startExposure.Year > 2100) { continue; } if (exposureMS < 0 || exposureMS > 60 * 1000) { continue; } m_CandidateFrameOffsets.Add(new RecoveredFrameHeader() { Position = m_RecoveryOffset + i, StartExposureUT = startExposure, ExposureMilliseconds = exposureMS }); int sectionDataLength = data[12] + (data[13] << 8) + (data[14] << 16) + (data[15] << 24); m_InputFile.Seek(m_RecoveryOffset + i + 4 + 12 + sectionDataLength + 4, SeekOrigin.Begin); byte tagValuesCount = m_FileReader.ReadByte(); for (int j = 0; j < tagValuesCount; j++) { m_FileReader.ReadByte(); byte len = m_FileReader.ReadByte(); m_FileReader.ReadBytes(len); } // NOTE: The next frame should begin somewhere in the next 32 bytes long nextFrameSearchStartPos = m_FileReader.BaseStream.Position; for (int j = 0; j < 32; j++) { m_InputFile.Seek(nextFrameSearchStartPos + j, SeekOrigin.Begin); uint frameDataMagic2 = m_FileReader.ReadUInt32(); if (frameDataMagic2 == 0xEE0122FF) { // We found it! i = nextFrameSearchStartPos + j - m_RecoveryOffset - 1; break; } } } catch { } } percentCompleted = (int)(100.0 * i / bytesToSearch); if (lastPercentCompleted < percentCompleted) { progressCallback(percentCompleted, m_CandidateFrameOffsets.Count); lastPercentCompleted = percentCompleted; } } }