/// <summary> /// Write the RIFF. /// </summary> /// <param name="w">The writer.</param> public override void Write(FileWriter w) { //Init. using (RiffWriter rw = new RiffWriter(w.BaseStream)) { //Init file. rw.InitFile("WAVE"); //Format block. rw.StartChunk("fmt "); rw.Write((ushort)1); rw.Write((ushort)Audio.Channels.Count); rw.Write(SampleRate); uint bitsPerSample = Audio.EncodingType.Equals(typeof(PCM16)) ? 16u : 8u; rw.Write((uint)(SampleRate * Audio.Channels.Count * (bitsPerSample / 8))); rw.Write((ushort)(bitsPerSample / 8 * Audio.Channels.Count)); rw.Write((ushort)bitsPerSample); rw.EndChunk(); //Sample block. if (Loops) { rw.StartChunk("smpl"); rw.Write(new uint[2]); rw.Write((uint)(1d / SampleRate * 1000000000)); rw.Write((uint)60); rw.Write(new uint[3]); rw.Write((uint)1); rw.Write(new uint[3]); rw.Write(LoopStart /* * bitsPerSample / 8*/); rw.Write(LoopEnd /* * bitsPerSample / 8*/); rw.Write((ulong)0); rw.EndChunk(); } //Data block. Audio.ChangeBlockSize((int)bitsPerSample / 8); rw.StartChunk("data"); w.Position = rw.Position; Audio.Write(w); rw.Position = w.Position; while (rw.Position % 2 != 0) { rw.Write((byte)0); } rw.EndChunk(); //Close file. rw.CloseFile(); Audio.ChangeBlockSize(-1); } }
private static int WriteVideoStreamHeader(RiffWriter rw, VideoStreamInfo vsi) { rw.BeginChunk(AviDemux.ID_strh); int offset = (int)rw.binaryWriter.Seek(0, SeekOrigin.Current); var bw = rw.binaryWriter; bw.Write(AviDemux.FCC_vids); bw.Write(vsi.codecFourCC); bw.Write((int)0); // dwFlags bw.Write((short)0); // wPriority bw.Write((short)0); // wLanguage bw.Write((int)0); // dwInitialFrames int scale, rate; FindScaleAndRate(out scale, out rate, vsi.framerate); bw.Write(scale); // dwScale bw.Write(rate); // dwRate bw.Write((int)0); // dwStart bw.Write(vsi.frameCount); // dwLength. that's how many frames will be in this RIFF element, written over later bw.Write((int)0); // dwSuggestedBufferSize, not suggesting any value bw.Write((int)-1); // dwQuality = -1 meaning "default quality" bw.Write((int)0); // dwSampleSize = 0 for video bw.Write((short)0); bw.Write((short)0); bw.Write((short)vsi.width); bw.Write((short)vsi.height); rw.EndChunk(); return(offset); }
private static int WriteDmlhHeader(RiffWriter rw, int totalFrames) { rw.BeginChunk(AviDemux.ID_dmlh); int offset = (int)rw.binaryWriter.Seek(0, SeekOrigin.Current); rw.binaryWriter.Write(totalFrames); // will be written over later rw.EndChunk(); return(offset); }
private static void WriteChunkIndex(RiffWriter rw, AviStreamIndex index, int superIndexChunkOffset, ref int superIndexEntryCount, long indexBaseOffset, int maxSuperindexEntries) { var bw = rw.binaryWriter; // the offset where this index will be written long streamIndexOffset = bw.Seek(0, SeekOrigin.Current); // update stream superindex superIndexEntryCount++; if (superIndexEntryCount > maxSuperindexEntries) { throw new MpException("Not enough space was reserved for superindex. Please increase maxSuperindexEntries"); } bw.Seek(superIndexChunkOffset + 1 * 4, SeekOrigin.Begin); bw.Write(superIndexEntryCount); // overwrite nEntriesInUse bw.Seek(superIndexChunkOffset + 6 * 4 + (superIndexEntryCount - 1) * 16, SeekOrigin.Begin); bw.Write(streamIndexOffset); bw.Write(32 + 8 * index.entries.Count); // dwSize bw.Write(index.entries.Count); // dwDuration in stream ticks. @todo this is OK only for video, for audio stream this should be ??? // write stream chunk index // @xxx MSDN suggests not seeking BaseStream when using BinaryWriter, but there are no Seek(long) // in BinaryWriter. According to this forum post, BinaryWriter.Seek is just a wrapper // to BinaryWriter.BaseStream.Seek, so all should be ok. // http://www.pcreview.co.uk/forums/binarywriter-seek-vs-binarywriter-basestream-seek-t1223754.html bw.BaseStream.Seek(streamIndexOffset, SeekOrigin.Begin); rw.BeginChunk((RiffParser.ToFourCC("ix__") & 0x0000FFFF) | ((index.streamId << 16) & 0xFFFF0000)); bw.Write((short)2); // wLongsPerEntry is always 2 here bw.Write((byte)0); // bIndexSubType is always 0 here bw.Write((byte)AviStreamIndex.Type.CHUNKS); // bIndexType = AVI_INDEX_OF_CHUNKS bw.Write(index.entries.Count); // nEntriesInUse. bw.Write(index.streamId); // dwChunkId ("##dc" and similar) bw.Write(indexBaseOffset); // qwBaseOffset bw.Write((int)0); // dwReserved3 foreach (var entry in index.entries) { long offset = entry.chunkOffset - indexBaseOffset; if (offset > int.MaxValue) { throw new MpException("Internal error. Can't write index, because chunk offset won't fit into 31 bits: " + offset); } bw.Write((uint)offset); // bit31==0 indicating that this is a keyframe bw.Write(entry.chunkLength); } rw.EndChunk(); index.globalOffset += index.entries.Count; index.entries.Clear(); }
private static void WriteAudioFormatHeader(RiffWriter rw, AudioStreamInfo asi) { rw.BeginChunk(AviDemux.ID_strf); var bw = rw.binaryWriter; bw.Write((ushort)asi.audioFormat); // wFormatTag bw.Write((short)asi.channels); // nChannels bw.Write(asi.sampleRate); // nSamplesPerSec bw.Write(asi.sampleRate * asi.sampleSize * asi.channels); // nAvgBytesPerSec @xxx true for PCM audio only, but this is a "soft" property bw.Write((short)asi.sampleSize); // nBlockAlign bw.Write((short)(8 * asi.sampleSize / asi.channels)); // wBitsPerSample bw.Write((short)0); // cbSize. no extra coded info rw.EndChunk(); }
private static int WriteDummySuperIndex(RiffWriter rw, uint streamId, int entriesToReserve) { rw.BeginChunk(AviDemux.ID_indx); int offset = (int)rw.binaryWriter.Seek(0, SeekOrigin.Current); var bw = rw.binaryWriter; bw.Write((short)4); // wLongsPerEntry is always 4 for super index bw.Write((byte)0); // bIndexSubType is always 0 for super index bw.Write((byte)AviStreamIndex.Type.SUPERINDEX); // bIndexType = AVI_INDEX_OF_INDEXES bw.Write((int)0); // nEntriesInUse. this'll be updated later! bw.Write(streamId); // dwChunkId ("##dc" and similar) // write 3 reserved UINTs and reserve some space for entries bw.Write(new byte[4 * 3 + entriesToReserve * 16]); rw.EndChunk(); return(offset); }
private static void WriteVideoFormatHeader(RiffWriter rw, VideoStreamInfo vsi) { rw.BeginChunk(AviDemux.ID_strf); var bw = rw.binaryWriter; bw.Write((int)40); // biSize bw.Write(vsi.width); // biWidth bw.Write(vsi.height); // biHeight bw.Write((short)1); // biPlanes bw.Write((short)vsi.bitsPerPixel); bw.Write(vsi.codecFourCC); // biCompression bw.Write(vsi.width * vsi.height * vsi.bitsPerPixel / 8); // biSizeImage bw.Write((int)0); // biXPelsPerMeter bw.Write((int)0); // biYPelsPerMeter bw.Write((int)0); // biClrUsed bw.Write((int)0); // biClrImportant rw.EndChunk(); }
private static int WriteMainHeader(RiffWriter rw, VideoStreamInfo vsi, bool hasAudioStream) { rw.BeginChunk(AviDemux.ID_avih); int offset = (int)rw.binaryWriter.Seek(0, SeekOrigin.Current); var bw = rw.binaryWriter; bw.Write(Mathf.RoundToInt(1000000f / vsi.framerate)); // swMicroSecPerFrame bw.Write((int)0); // dwMaxBytesPerSec bw.Write((int)0); // dwPaddingGranularity bw.Write((int)(AVIMainHeader.AVIF_HASINDEX | AVIMainHeader.AVIF_MUSTUSEINDEX)); // dwFlags. Maybe use AVIMainHeader.AVIF_MUSTUSEINDEX too? bw.Write(vsi.frameCount); // dwTotalFrames. this will be written over later! bw.Write((int)0); // dwInitialFrames bw.Write(hasAudioStream ? 2 : 1); bw.Write((int)0); // dwSuggestedBufferSize, not suggesting any value bw.Write(vsi.width); bw.Write(vsi.height); bw.Write((long)0); // dwReserver0 and dwReserver1 bw.Write((long)0); // dwReserver2 and dwReserver3 rw.EndChunk(); return(offset); }
private static int WriteAudioStreamHeader(RiffWriter rw, AudioStreamInfo asi) { rw.BeginChunk(AviDemux.ID_strh); int offset = (int)rw.binaryWriter.Seek(0, SeekOrigin.Current); var bw = rw.binaryWriter; bw.Write(AviDemux.FCC_auds); bw.Write(asi.codecFourCC); bw.Write((int)0); // dwFlags bw.Write((short)0); // wPriority bw.Write((short)0); // wLanguage bw.Write((int)0); // dwInitialFrames bw.Write((int)1); // dwScale bw.Write(asi.sampleRate); // dwRate @xxx This is true for PCM audio only! bw.Write((int)0); // dwStart bw.Write(asi.sampleCount); // dwLength. will be written over later bw.Write((int)0); // dwSuggestedBufferSize, not suggesting it bw.Write((int)-1); // dwQuality = -1 meaning "default quality" bw.Write(asi.sampleSize); // dwSampleSize bw.Write((long)0); // rcFrame rw.EndChunk(); return(offset); }
private static void WriteVideoFormatHeader(RiffWriter rw, VideoStreamInfo vsi) { rw.BeginChunk (AviDemux.ID_strf); var bw = rw.binaryWriter; bw.Write ((int)40); // biSize bw.Write (vsi.width); // biWidth bw.Write (vsi.height); // biHeight bw.Write ((short)1); // biPlanes bw.Write ((short)vsi.bitsPerPixel); bw.Write (vsi.codecFourCC); // biCompression bw.Write (vsi.width * vsi.height * vsi.bitsPerPixel / 8); // biSizeImage bw.Write ((int)0); // biXPelsPerMeter bw.Write ((int)0); // biYPelsPerMeter bw.Write ((int)0); // biClrUsed bw.Write ((int)0); // biClrImportant rw.EndChunk (); }
/// <summary> /// Write the file. /// </summary> /// <param name="w2">The file writer.</param> public override void Write(FileWriter w2) { //Use a RIFF writer. using (RiffWriter w = new RiffWriter(w2.BaseStream)) { //Init file. w.InitFile("DLS "); //Instrument count. w.StartChunk("colh"); w.Write((uint)Instruments.Count); w.EndChunk(); //Instruments. w.StartListChunk("lins"); foreach (var inst in Instruments) { w.StartListChunk("ins "); w.StartChunk("insh"); w.Write((uint)inst.Regions.Count); w.Write(inst.BankId); w.Write(inst.InstrumentId); w.EndChunk(); w.StartListChunk("lrgn"); foreach (Region r in inst.Regions) { w.StartListChunk("rgn2"); w.StartChunk("rgnh"); w.Write(r.NoteLow); w.Write(r.NoteHigh); w.Write(r.VelocityLow); w.Write(r.VelocityHigh); w.Write((ushort)(r.DoublePlayback ? 1 : 0)); w.Write((ushort)r.KeyGroup); w.Write(r.Layer); w.EndChunk(); w.StartChunk("wsmp"); w.Write((uint)0x14); w.Write((ushort)r.RootNote); w.Write(r.Tuning); w.Write(r.Gain); uint flags = 0; if (r.NoTruncation) { flags |= 0b1; } if (r.NoCompression) { flags |= 0b10; } w.Write(flags); w.Write((uint)(r.Loops ? 1 : 0)); if (r.Loops) { w.Write((uint)0x10); w.Write((uint)(r.LoopAndRelease ? 1 : 0)); w.Write(r.LoopStart); w.Write(r.LoopLength); } w.EndChunk(); w.StartChunk("wlnk"); ushort flg = 0; if (r.PhaseMaster) { flg |= 0b1; } if (r.MultiChannel) { flg |= 0b10; } w.Write(flg); w.Write(r.PhaseGroup); w.Write(r.ChannelFlags); w.Write(r.WaveId); w.EndChunk(); w.StartListChunk("lar2"); foreach (var a in r.Articulators) { w.StartChunk("art2"); w.Write((uint)8); w.Write((uint)a.Connections.Count); foreach (var c in a.Connections) { w.Write((ushort)c.SourceConnection); w.Write(c.ControlConnection); w.Write((ushort)c.DestinationConnection); w.Write((ushort)c.TransformConnection); w.Write(c.Scale); } w.EndChunk(); } w.EndChunk(); w.EndChunk(); } w.EndChunk(); if (inst.Name != "") { w.StartListChunk("INFO"); w.StartChunk("INAM"); w.Write(inst.Name.ToCharArray()); w.Write("\0".ToCharArray()); int len = inst.Name.Length + 1; while (len % 4 != 0) { w.Write((byte)0); len++; } w.EndChunk(); w.EndChunk(); } w.EndChunk(); } w.EndChunk(); //Pointer table initializing. w.StartChunk("ptbl"); w.Write((uint)8); w.Write((uint)Waves.Count); long ptblStart = w.BaseStream.Position; w.Write(new byte[Waves.Count * 4]); w.EndChunk(); //Write waves. w.StartListChunk("wvpl"); long waveTableStart = w.BaseStream.Position; int waveNum = 0; foreach (var wav in Waves) { long wBak = w.BaseStream.Position; w.BaseStream.Position = ptblStart + waveNum++ *4; w.Write((uint)(wBak - waveTableStart)); w.BaseStream.Position = wBak; w.WriteWave(wav); } w.EndChunk(); //Write info. w.StartListChunk("INFO"); w.StartChunk("INAM"); w.Write("Instrument Set".ToCharArray()); w.EndChunk(); w.EndChunk(); //Close file. w.CloseFile(); } }
private static void WriteAudioFormatHeader(RiffWriter rw, AudioStreamInfo asi) { rw.BeginChunk (AviDemux.ID_strf); var bw = rw.binaryWriter; bw.Write ((ushort)asi.audioFormat); // wFormatTag bw.Write ((short)asi.channels); // nChannels bw.Write (asi.sampleRate); // nSamplesPerSec bw.Write (asi.sampleRate * asi.sampleSize * asi.channels); // nAvgBytesPerSec @xxx true for PCM audio only, but this is a "soft" property bw.Write ((short)asi.sampleSize); // nBlockAlign bw.Write ((short)(8 * asi.sampleSize / asi.channels)); // wBitsPerSample bw.Write ((short)0); // cbSize. no extra coded info rw.EndChunk (); }
/// <summary> /// Write the file. /// </summary> /// <param name="w2">The writer.</param> public override void Write(FileWriter w2) { //Use a RIFF writer. using (RiffWriter w = new RiffWriter(w2.BaseStream)) { //Start file. w.InitFile("sfbk"); //Start INFO. w.StartListChunk("INFO"); //Version. w.StartChunk("ifil"); w.Write((ushort)2); w.Write((ushort)1); w.EndChunk(); //Sound engine. w.StartChunk("isng"); w.WriteNullTerminated(SoundEngine); w.Align(2); w.EndChunk(); //Bank name. w.StartChunk("INAM"); w.WriteNullTerminated(BankName); w.Align(2); w.EndChunk(); //ROM name. if (!RomName.Equals("")) { w.StartChunk("irom"); w.WriteNullTerminated(RomName); w.Align(2); w.EndChunk(); } //ROM version. if (RomVersion != null) { w.StartChunk("iver"); w.Write(RomVersion.Item1); w.Write(RomVersion.Item2); w.EndChunk(); } //Creation date. if (!CreationDate.Equals("")) { w.StartChunk("ICRD"); w.WriteNullTerminated(CreationDate); w.Align(2); w.EndChunk(); } //Sound designer. if (!SoundDesigner.Equals("")) { w.StartChunk("IENG"); w.WriteNullTerminated(SoundDesigner); w.Align(2); w.EndChunk(); } //Product. if (!Product.Equals("")) { w.StartChunk("IPRD"); w.WriteNullTerminated(Product); w.Align(2); w.EndChunk(); } //Copyright. if (!Copyright.Equals("")) { w.StartChunk("ICOP"); w.WriteNullTerminated(Copyright); w.Align(2); w.EndChunk(); } //Comment. if (!Comment.Equals("")) { w.StartChunk("ICMT"); w.WriteNullTerminated(Comment); w.Align(2); w.EndChunk(); } //Tools. if (!Tools.Equals("")) { w.StartChunk("ISFT"); w.WriteNullTerminated(Tools); w.Align(2); w.EndChunk(); } //End INFO. w.EndChunk(); //Sample block. w.StartListChunk("sdta"); w.StartChunk("smpl"); long waveTableStart = w.Position; Dictionary <SampleItem, long> samplePositions = new Dictionary <SampleItem, long>(); foreach (var s in Samples) { samplePositions.Add(s, w.Position); w.Write(new short[s.Wave.Audio.NumSamples]); w.Write(new short[46]); } w.EndChunk(); w.EndChunk(); //The hydra. w.StartListChunk("pdta"); //Presets. w.StartChunk("phdr"); ushort currBagIndex = 0; List <Zone> zones = new List <Zone>(); foreach (var p in Presets) { p.ReadingBagIndex = currBagIndex; currBagIndex += (ushort)p.NumZones; w.Write(p); zones.AddRange(p.GetAllZones()); } w.Write(new Preset() { Name = "EOP", Bank = 255, PresetNumber = 255, ReadingBagIndex = currBagIndex }); w.EndChunk(); //Preset bags. w.StartChunk("pbag"); ushort currGenIndex = 0; ushort currModIndex = 0; foreach (var z in zones) { w.Write(currGenIndex); w.Write(currModIndex); currGenIndex += (ushort)z.Generators.Count; currModIndex += (ushort)z.Modulators.Count; } w.Write(currGenIndex); w.Write(currModIndex); w.EndChunk(); //Preset modulators. w.StartChunk("pmod"); foreach (var z in zones) { foreach (var v in z.Modulators) { w.Write(v); } } w.Write(new Modulator()); w.EndChunk(); //Preset generators. w.StartChunk("pgen"); foreach (var z in zones) { foreach (var v in z.Generators) { w.Write(v); } } w.Write(new Generator()); w.EndChunk(); //Instruments. w.StartChunk("inst"); currBagIndex = 0; zones = new List <Zone>(); foreach (var p in Instruments) { p.ReadingBagIndex = currBagIndex; currBagIndex += (ushort)p.NumZones; w.Write(p); zones.AddRange(p.GetAllZones()); } w.Write(new Instrument() { Name = "EOI", ReadingBagIndex = currBagIndex }); w.EndChunk(); //Instrument bags. w.StartChunk("ibag"); currGenIndex = 0; currModIndex = 0; foreach (var z in zones) { w.Write(currGenIndex); w.Write(currModIndex); currGenIndex += (ushort)z.Generators.Count; currModIndex += (ushort)z.Modulators.Count; } w.Write(currGenIndex); w.Write(currModIndex); w.EndChunk(); //Instrument modulators. w.StartChunk("imod"); foreach (var z in zones) { foreach (var v in z.Modulators) { w.Write(v); } } w.Write(new Modulator()); w.EndChunk(); //Instrument generators. w.StartChunk("igen"); foreach (var z in zones) { foreach (var v in z.Generators) { w.Write(v); } } w.Write(new Generator()); w.EndChunk(); //Samples. w.StartChunk("shdr"); foreach (var s in Samples) { w.CurrentOffset = samplePositions[s]; w.StructureOffsets.Push(waveTableStart); w.Write(s); } w.Write("EOS".ToCharArray()); w.Write(new byte[0x2B]); w.EndChunk(); //End the hydra. w.EndChunk(); //Close file. w.CloseFile(); } }
private static int WriteVideoStreamHeader(RiffWriter rw, VideoStreamInfo vsi) { rw.BeginChunk (AviDemux.ID_strh); int offset = (int)rw.binaryWriter.Seek (0, SeekOrigin.Current); var bw = rw.binaryWriter; bw.Write (AviDemux.FCC_vids); bw.Write (vsi.codecFourCC); bw.Write ((int)0); // dwFlags bw.Write ((short)0); // wPriority bw.Write ((short)0); // wLanguage bw.Write ((int)0); // dwInitialFrames int scale, rate; FindScaleAndRate (out scale, out rate, vsi.framerate); bw.Write (scale); // dwScale bw.Write (rate); // dwRate bw.Write ((int)0); // dwStart bw.Write (vsi.frameCount); // dwLength. that's how many frames will be in this RIFF element, written over later bw.Write ((int)0); // dwSuggestedBufferSize, not suggesting any value bw.Write ((int)-1); // dwQuality = -1 meaning "default quality" bw.Write ((int)0); // dwSampleSize = 0 for video bw.Write ((short)0); bw.Write ((short)0); bw.Write ((short)vsi.width); bw.Write ((short)vsi.height); rw.EndChunk (); return offset; }
private static int WriteMainHeader(RiffWriter rw, VideoStreamInfo vsi, bool hasAudioStream) { rw.BeginChunk (AviDemux.ID_avih); int offset = (int)rw.binaryWriter.Seek (0, SeekOrigin.Current); var bw = rw.binaryWriter; bw.Write (Mathf.RoundToInt (1000000f / vsi.framerate)); // swMicroSecPerFrame bw.Write ((int)0); // dwMaxBytesPerSec bw.Write ((int)0); // dwPaddingGranularity bw.Write ((int)(AVIMainHeader.AVIF_HASINDEX | AVIMainHeader.AVIF_MUSTUSEINDEX)); // dwFlags. Maybe use AVIMainHeader.AVIF_MUSTUSEINDEX too? bw.Write (vsi.frameCount); // dwTotalFrames. this will be written over later! bw.Write ((int)0); // dwInitialFrames bw.Write (hasAudioStream ? 2 : 1); bw.Write ((int)0); // dwSuggestedBufferSize, not suggesting any value bw.Write (vsi.width); bw.Write (vsi.height); bw.Write ((long)0); // dwReserver0 and dwReserver1 bw.Write ((long)0); // dwReserver2 and dwReserver3 rw.EndChunk (); return offset; }
private static int WriteDummySuperIndex(RiffWriter rw, uint streamId, int entriesToReserve) { rw.BeginChunk (AviDemux.ID_indx); int offset = (int)rw.binaryWriter.Seek (0, SeekOrigin.Current); var bw = rw.binaryWriter; bw.Write ((short)4); // wLongsPerEntry is always 4 for super index bw.Write ((byte)0); // bIndexSubType is always 0 for super index bw.Write ((byte)AviStreamIndex.Type.SUPERINDEX); // bIndexType = AVI_INDEX_OF_INDEXES bw.Write ((int)0); // nEntriesInUse. this'll be updated later! bw.Write (streamId); // dwChunkId ("##dc" and similar) // write 3 reserved UINTs and reserve some space for entries bw.Write (new byte[4 * 3 + entriesToReserve * 16]); rw.EndChunk (); return offset; }
private static int WriteDmlhHeader(RiffWriter rw, int totalFrames) { rw.BeginChunk (AviDemux.ID_dmlh); int offset = (int)rw.binaryWriter.Seek (0, SeekOrigin.Current); rw.binaryWriter.Write (totalFrames); // will be written over later rw.EndChunk (); return offset; }
private static void WriteChunkIndex(RiffWriter rw, AviStreamIndex index, int superIndexChunkOffset, ref int superIndexEntryCount, long indexBaseOffset, int maxSuperindexEntries) { var bw = rw.binaryWriter; // the offset where this index will be written long streamIndexOffset = bw.Seek (0, SeekOrigin.Current); // update stream superindex superIndexEntryCount++; if (superIndexEntryCount > maxSuperindexEntries) { throw new MpException ("Not enough space was reserved for superindex. Please increase maxSuperindexEntries"); } bw.Seek (superIndexChunkOffset + 1 * 4, SeekOrigin.Begin); bw.Write (superIndexEntryCount); // overwrite nEntriesInUse bw.Seek (superIndexChunkOffset + 6 * 4 + (superIndexEntryCount - 1) * 16, SeekOrigin.Begin); bw.Write (streamIndexOffset); bw.Write (32 + 8 * index.entries.Count); // dwSize bw.Write (index.entries.Count); // dwDuration in stream ticks. @todo this is OK only for video, for audio stream this should be ??? // write stream chunk index // @xxx MSDN suggests not seeking BaseStream when using BinaryWriter, but there are no Seek(long) // in BinaryWriter. According to this forum post, BinaryWriter.Seek is just a wrapper // to BinaryWriter.BaseStream.Seek, so all should be ok. // http://www.pcreview.co.uk/forums/binarywriter-seek-vs-binarywriter-basestream-seek-t1223754.html bw.BaseStream.Seek (streamIndexOffset, SeekOrigin.Begin); rw.BeginChunk ((RiffParser.ToFourCC ("ix__") & 0x0000FFFF) | ((index.streamId << 16) & 0xFFFF0000)); bw.Write ((short)2); // wLongsPerEntry is always 2 here bw.Write ((byte)0); // bIndexSubType is always 0 here bw.Write ((byte)AviStreamIndex.Type.CHUNKS); // bIndexType = AVI_INDEX_OF_CHUNKS bw.Write (index.entries.Count); // nEntriesInUse. bw.Write (index.streamId); // dwChunkId ("##dc" and similar) bw.Write (indexBaseOffset); // qwBaseOffset bw.Write ((int)0); // dwReserved3 foreach (var entry in index.entries) { long offset = entry.chunkOffset - indexBaseOffset; if (offset > int.MaxValue) { throw new MpException ("Internal error. Can't write index, because chunk offset won't fit into 31 bits: " + offset); } bw.Write ((uint)offset); // bit31==0 indicating that this is a keyframe bw.Write (entry.chunkLength); } rw.EndChunk (); index.globalOffset += index.entries.Count; index.entries.Clear (); }
private static int WriteAudioStreamHeader(RiffWriter rw, AudioStreamInfo asi) { rw.BeginChunk (AviDemux.ID_strh); int offset = (int)rw.binaryWriter.Seek (0, SeekOrigin.Current); var bw = rw.binaryWriter; bw.Write (AviDemux.FCC_auds); bw.Write (asi.codecFourCC); bw.Write ((int)0); // dwFlags bw.Write ((short)0); // wPriority bw.Write ((short)0); // wLanguage bw.Write ((int)0); // dwInitialFrames bw.Write ((int)1); // dwScale bw.Write (asi.sampleRate); // dwRate @xxx This is true for PCM audio only! bw.Write ((int)0); // dwStart bw.Write (asi.sampleCount); // dwLength. will be written over later bw.Write ((int)0); // dwSuggestedBufferSize, not suggesting it bw.Write ((int)-1); // dwQuality = -1 meaning "default quality" bw.Write (asi.sampleSize); // dwSampleSize bw.Write ((long)0); // rcFrame rw.EndChunk (); return offset; }