public static SnmFile FromAviFile(string fileName) { if (!File.Exists(fileName)) { throw new FileNotFoundException(); } var snm = new SnmFile(); var aviManager = new AviManager(fileName); try { AudioStream audioStream = aviManager.GetWaveStream(); byte[] audioData = null; if (audioStream != null) { if (audioStream.ChannelsCount != 2 || audioStream.BitsPerSample != 16) { throw new InvalidDataException(); } if (audioStream.SamplesPerSecond != 22050 && audioStream.SamplesPerSecond != 44100) { throw new NotSupportedException(); } snm.AudioHeader = new SnmAudioHeader { Frequency = audioStream.SamplesPerSecond, NumChannels = audioStream.ChannelsCount }; audioData = audioStream.GetStreamData(); if (snm.AudioHeader.Frequency == 44100) { snm.AudioHeader.Frequency = 22050; audioData = SnmFile.ConvertAudio44100To22050(audioData); } } VideoStream videoStream = aviManager.GetVideoStream(); if (videoStream.BitsPerPixel != 24 && videoStream.BitsPerPixel != 32) { throw new NotSupportedException(); } snm.Header.FrameDelay = (int)(1000000 / videoStream.FrameRate + 0.5); snm.Header.Width = (short)videoStream.Width; snm.Header.Height = (short)videoStream.Height; snm.Header.NumFrames = (short)videoStream.FramesCount; for (int i = 0; i < videoStream.FramesCount; i++) { snm.VideoHeaders.Add(new SnmVideoHeader { Width = snm.Header.Width, Height = snm.Header.Height }); } videoStream.GetFrameOpen(); try { int fps = (1000000 + snm.Header.FrameDelay / 2) / snm.Header.FrameDelay; int samplesPerFrame = snm.AudioHeader.Frequency / fps; if (samplesPerFrame * fps != snm.AudioHeader.Frequency) { throw new InvalidDataException(); } for (int i = 0; i < videoStream.FramesCount; i++) { byte[] videoData = videoStream.GetFrameData(i); var frame = new SnmFrame(); if (audioData != null) { int audioPosition = i * samplesPerFrame * 4; int audioLength = Math.Min(samplesPerFrame * 4, audioData.Length - audioPosition); if (audioPosition < audioData.Length && audioLength != 0) { frame.Audio = new SnmAudioFrame { NumSamples = audioLength / 4 }; byte[] buffer = new byte[audioLength]; Array.Copy(audioData, audioPosition, buffer, 0, audioLength); //frame.Audio.Data = Imc.Vima.Compress(buffer, 2); frame.Audio.Data = buffer; } } if (videoData != null) { frame.Video = new SnmVideoFrame { Width = snm.Header.Width, Height = snm.Header.Height, RleOutputSize = snm.Header.Width * snm.Header.Height * 2, SubcodecId = (byte)videoStream.BitsPerPixel, Data = videoData }; //byte[] buffer; //if (videoStream.BitsPerPixel == 24) //{ // buffer = SnmFile.Convert24BppTo16Bpp(videoData); //} //else //{ // buffer = SnmFile.Convert32BppTo16Bpp(videoData); //} //byte subcodecId; //frame.Video.Data = Blocky16.Compress(buffer, out subcodecId); //frame.Video.SubcodecId = subcodecId; } snm.Frames.Add(frame); } } finally { videoStream.GetFrameClose(); } } finally { aviManager.Close(); } snm.Frames .AsParallel() .ForAll(frame => { if (frame.Audio != null) { frame.Audio.Data = Imc.Vima.Compress(frame.Audio.Data, 2); } if (frame.Video != null) { byte[] buffer; if (frame.Video.SubcodecId == 24) { buffer = SnmFile.Convert24BppTo16Bpp(frame.Video.Data); } else { buffer = SnmFile.Convert32BppTo16Bpp(frame.Video.Data); } frame.Video.Data = Blocky16.Compress(buffer, out byte subcodecId); frame.Video.SubcodecId = subcodecId; } }); return(snm); }
public static SnmFile FromFile(string fileName) { var snm = new SnmFile { FileName = fileName }; Stream filestream = null; try { filestream = new FileStream(fileName, FileMode.Open, FileAccess.Read); byte[] magic = new byte[2]; filestream.Read(magic, 0, 2); filestream.Seek(0, SeekOrigin.Begin); if (magic[0] == 0x1F && magic[1] == 0x8B) { filestream = new GZipStream(filestream, CompressionMode.Decompress); } using (BinaryReader file = new BinaryReader(filestream)) { filestream = null; if (Encoding.ASCII.GetString(file.ReadBytes(4)) != "SANM") { throw new InvalidDataException(); } // movie size file.ReadBigEndianInt32(); if (Encoding.ASCII.GetString(file.ReadBytes(4)) != "SHDR") { throw new InvalidDataException(); } int headerSize = file.ReadBigEndianInt32(); if (headerSize != SnmHeader.Size) { throw new InvalidDataException(); } snm.Header = new SnmHeader(); snm.Header.Read(file); if (Encoding.ASCII.GetString(file.ReadBytes(4)) != "FLHD") { throw new InvalidDataException(); } int flhdSize = file.ReadBigEndianInt32(); for (int flhdPosition = 0; flhdPosition < flhdSize;) { flhdPosition += 4; if (flhdPosition == flhdSize) { // unknown value file.ReadInt32(); } else { string flhdFourcc = Encoding.ASCII.GetString(file.ReadBytes(4)); switch (flhdFourcc) { case "Wave": { //if (snm.AudioHeader != null) //{ // throw new InvalidDataException(); //} int size = file.ReadBigEndianInt32(); flhdPosition += size + 4; snm.AudioHeader = new SnmAudioHeader(); snm.AudioHeader.Read(file, size); break; } case "Bl16": { int size = file.ReadBigEndianInt32(); flhdPosition += size + 4; SnmVideoHeader header = new SnmVideoHeader(); header.Read(file); snm.VideoHeaders.Add(header); break; } //default: // throw new InvalidDataException(); } } } string fourcc = Encoding.ASCII.GetString(file.ReadBytes(4)); if (fourcc == "ANNO") { int size = file.ReadBigEndianInt32(); snm.Annotation = Encoding.ASCII.GetString(file.ReadBytes(size)).TrimEnd('\0'); fourcc = Encoding.ASCII.GetString(file.ReadBytes(4)); } for (int i = 0; i < snm.Header.NumFrames; i++) { if (fourcc != "FRME") { throw new InvalidDataException(); } SnmFrame frame = new SnmFrame(); int frmeSize = file.ReadBigEndianInt32(); for (int frmePosition = 0; frmePosition < frmeSize;) { fourcc = Encoding.ASCII.GetString(file.ReadBytes(4)); frmePosition += 4; switch (fourcc) { case "Wave": { if (frame.Audio != null) { throw new InvalidDataException(); } int size = file.ReadBigEndianInt32(); frmePosition += size + 4; frame.Audio = new SnmAudioFrame(); frame.Audio.Read(file, size); break; } case "Bl16": { if (frame.Video != null) { throw new InvalidDataException(); } int size = file.ReadBigEndianInt32(); frmePosition += size + 4; frame.Video = new SnmVideoFrame(); frame.Video.Read(file, size); break; } default: { throw new InvalidDataException(); } } } snm.Frames.Add(frame); fourcc = Encoding.ASCII.GetString(file.ReadBytes(4)); } } } finally { if (filestream != null) { filestream.Dispose(); } } return(snm); }
public static SnmFile ConvertRead(string fileName) { if (string.IsNullOrEmpty(fileName)) { throw new ArgumentNullException(nameof(fileName)); } var snm = new SnmFile(); byte[] aviAudioDataBytes; try { aviAudioDataBytes = GetAviAudioBytes(fileName); } catch { aviAudioDataBytes = null; } InitializeSourceReader(fileName, out IMFSourceReader reader, out int videoStreamIndex, out int audioStreamIndex); var audioData = new MemoryStream(); try { GetSourceReaderAttributes(reader, out int width, out int height, out int fps); snm.AudioHeader = new SnmAudioHeader { Frequency = 22050, NumChannels = 2 }; snm.Header.FrameDelay = (int)(1000000 / fps + 0.5); snm.Header.Width = (short)width; snm.Header.Height = (short)height; snm.Header.NumFrames = 0; while (true) { byte[] bytes = ReadSample(reader, audioStreamIndex, out int streamIndex, out long timestamp); if (bytes == null) { break; } audioData.Write(bytes, 0, bytes.Length); } if (audioData.Length == 0 && aviAudioDataBytes != null) { audioData.Write(aviAudioDataBytes, 0, aviAudioDataBytes.Length); } while (true) { byte[] bytes = ReadSample(reader, videoStreamIndex, out int streamIndex, out long timestamp); if (bytes == null) { break; } snm.VideoHeaders.Add(new SnmVideoHeader { Width = snm.Header.Width, Height = snm.Header.Height }); var frame = new SnmFrame(); int audioPosition = snm.Header.NumFrames * snm.AudioHeader.Frequency / fps * 4; int audioLength = Math.Min(snm.AudioHeader.Frequency / fps * 4, (int)audioData.Length - audioPosition); if (audioPosition < audioData.Length && audioLength != 0) { frame.Audio = new SnmAudioFrame { NumSamples = audioLength / 4 }; byte[] buffer = new byte[audioLength]; audioData.Seek(audioPosition, SeekOrigin.Begin); audioData.Read(buffer, 0, buffer.Length); frame.Audio.Data = buffer; } frame.Video = new SnmVideoFrame { Width = snm.Header.Width, Height = snm.Header.Height, RleOutputSize = snm.Header.Width * snm.Header.Height * 2, SubcodecId = 32, Data = bytes }; snm.Frames.Add(frame); snm.Header.NumFrames++; } } finally { audioData.Dispose(); Marshal.ReleaseComObject(reader); } snm.Frames .AsParallel() .ForAll(frame => { if (frame.Audio != null) { frame.Audio.Data = Imc.Vima.Compress(frame.Audio.Data, 2); } if (frame.Video != null) { byte[] buffer = Convert32BppTo16Bpp(frame.Video.Data); frame.Video.Data = Blocky16.Compress(buffer, out byte subcodecId); frame.Video.SubcodecId = subcodecId; } }); return(snm); }