private void WriteVBRHeader(bool isPlaceholder) { var buff = new byte[GetFrameLength(_mpegVersion, 64000, _sampleRate, 0)]; if (!isPlaceholder) { uint header = _firstFrameHeader; int dataOffset = GetFrameDataOffset(_mpegVersion, _channelMode); header &= 0xFFFF0DFF; // Clear bitrate and padding fields header |= 0x00010000; // Set protection bit (indicates that CRC is NOT present) header |= (uint)((_mpegVersion == 3) ? 5 : 8) << 12; // 64 kbit/sec General.CopyBytes(buff, 0, BitConverterBE.GetBytes(header)); General.CopyBytes(buff, dataOffset, BitConverterBE.GetBytes(0x58696E67)); // "Xing" General.CopyBytes(buff, dataOffset + 4, BitConverterBE.GetBytes((uint)0x7)); // Flags General.CopyBytes(buff, dataOffset + 8, BitConverterBE.GetBytes((uint)_frameOffsets.Count)); // Frame count General.CopyBytes(buff, dataOffset + 12, BitConverterBE.GetBytes(_totalFrameLength)); // File length for (int i = 0; i < 100; i++) { int frameIndex = (int)((i / 100.0) * _frameOffsets.Count); buff[dataOffset + 16 + i] = (byte)((_frameOffsets[frameIndex] / (double)_totalFrameLength) * 256.0); } } _fs.Write(buff, 0, buff.Length); }
private uint ReadUInt32() { var x = new byte[4]; _fs.Read(x, 0, 4); _fileOffset += 4; return BitConverterBE.ToUInt32(x, 0); }
private void WritePage() { if (_packetList.Count == 0) { return; } FlushPage(false); WriteToPage(BitConverterBE.GetBytes(0x4F676753U), 0, 4); // "OggS" WriteToPage(0); // Stream structure version WriteToPage((byte)((_pageSequenceNumber == 0) ? 0x02 : 0)); // Page flags WriteToPage(_packetList[_packetList.Count - 1].GranulePosition); // Position in samples WriteToPage((uint)_serialNumber); // Stream serial number WriteToPage(_pageSequenceNumber); // Page sequence number WriteToPage((uint)0); // Checksum WriteToPage((byte)_packetList.Count); // Page segment count foreach (OggPacket packet in _packetList) { WriteToPage((byte)packet.Data.Length); } foreach (OggPacket packet in _packetList) { WriteToPage(packet.Data, 0, packet.Data.Length); } _packetList.Clear(); _packetListDataSize = 0; _pageSequenceNumber++; }
public void WriteChunk(byte[] chunk, uint timeStamp) { if (chunk.Length < 1) { return; } if (chunk[0] == 0) { // Header if (chunk.Length < 3) { return; } ulong bits = (ulong)BitConverterBE.ToUInt16(chunk, 1) << 48; _aacProfile = BitHelper.Read(ref bits, 5) - 1; _sampleRateIndex = BitHelper.Read(ref bits, 4); _channelConfig = BitHelper.Read(ref bits, 4); if ((_aacProfile < 0) || (_aacProfile > 3)) { throw new ExtractionException("Unsupported AAC profile."); } if (_sampleRateIndex > 12) { throw new ExtractionException("Invalid AAC sample rate index."); } if (_channelConfig > 6) { throw new ExtractionException("Invalid AAC channel configuration."); } } else { // Audio data int dataSize = chunk.Length - 1; ulong bits = 0; // Reference: WriteADTSHeader from FAAC's bitstream.c BitHelper.Write(ref bits, 12, 0xFFF); BitHelper.Write(ref bits, 1, 0); BitHelper.Write(ref bits, 2, 0); BitHelper.Write(ref bits, 1, 1); BitHelper.Write(ref bits, 2, _aacProfile); BitHelper.Write(ref bits, 4, _sampleRateIndex); BitHelper.Write(ref bits, 1, 0); BitHelper.Write(ref bits, 3, _channelConfig); BitHelper.Write(ref bits, 1, 0); BitHelper.Write(ref bits, 1, 0); BitHelper.Write(ref bits, 1, 0); BitHelper.Write(ref bits, 1, 0); BitHelper.Write(ref bits, 13, 7 + dataSize); BitHelper.Write(ref bits, 11, 0x7FF); BitHelper.Write(ref bits, 2, 0); _fs.Write(BitConverterBE.GetBytes(bits), 1, 7); _fs.Write(chunk, 1, dataSize); } }
private uint ReadUInt24() { var x = new byte[4]; _fs.Read(x, 1, 3); _fileOffset += 3; return(BitConverterBE.ToUInt32(x, 0)); }
public void WriteChunk(byte[] chunk, uint timeStamp, int frameType) { int offset, len; offset = 0; len = chunk.Length; if (_codecID == 4) { offset = 1; len -= 1; } if (_codecID == 5) { offset = 4; if (len >= 4) { int alphaOffset = (int)BitConverterBE.ToUInt32(chunk, 0) & 0xFFFFFF; if (!_isAlphaWriter) { len = alphaOffset; } else { offset += alphaOffset; len -= offset; } } else { len = 0; } } len = Math.Max(len, 0); len = Math.Min(len, chunk.Length - offset); _index.Add((frameType == 1) ? (uint)0x10 : 0); _index.Add(_moviDataSize + 4); _index.Add((uint)len); if ((_width == 0) && (_height == 0)) { GetFrameSize(chunk); } WriteFourCC("00dc"); _bw.Write(len); _bw.Write(chunk, offset, len); if ((len % 2) != 0) { _bw.Write((byte)0); len++; } _moviDataSize += (uint)len + 8; _frameCount++; }
private void GetFrameSize(byte[] chunk) { switch (_codecID) { case 2: { // Reference: flv_h263_decode_picture_header from libavcodec's h263.c if (chunk.Length < 10) { return; } if ((chunk[0] != 0) || (chunk[1] != 0)) { return; } ulong x = BitConverterBE.ToUInt64(chunk, 2); int format; if (BitHelper.Read(ref x, 1) != 1) { return; } BitHelper.Read(ref x, 5); BitHelper.Read(ref x, 8); format = BitHelper.Read(ref x, 3); switch (format) { case 0: _width = BitHelper.Read(ref x, 8); _height = BitHelper.Read(ref x, 8); break; case 1: _width = BitHelper.Read(ref x, 16); _height = BitHelper.Read(ref x, 16); break; case 2: _width = 352; _height = 288; break; case 3: _width = 176; _height = 144; break; case 4: _width = 128; _height = 96; break; case 5: _width = 320; _height = 240; break; case 6: _width = 160; _height = 120; break; default: return; } } break; case 5: case 4: { // Reference: vp6_parse_header from libavcodec's vp6.c int skip = (_codecID == 4) ? 1 : 4; if (chunk.Length < (skip + 8)) { return; } ulong x = BitConverterBE.ToUInt64(chunk, skip); int deltaFrameFlag = BitHelper.Read(ref x, 1); int quant = BitHelper.Read(ref x, 6); int separatedCoeffFlag = BitHelper.Read(ref x, 1); int subVersion = BitHelper.Read(ref x, 5); int filterHeader = BitHelper.Read(ref x, 2); int interlacedFlag = BitHelper.Read(ref x, 1); if (deltaFrameFlag != 0) { return; } if ((separatedCoeffFlag != 0) || (filterHeader == 0)) { BitHelper.Read(ref x, 16); } _height = BitHelper.Read(ref x, 8) * 16; _width = BitHelper.Read(ref x, 8) * 16; // chunk[0] contains the width and height (4 bits each, respectively) that should // be cropped off during playback, which will be non-zero if the encoder padded // the frames to a macroblock boundary. But if you use this adjusted size in the // AVI header, DirectShow seems to ignore it, and it can cause stride or chroma // alignment problems with VFW if the width/height aren't multiples of 4. if (!_isAlphaWriter) { int cropX = chunk[0] >> 4; int cropY = chunk[0] & 0x0F; if (((cropX != 0) || (cropY != 0)) && !_isAlphaWriter) { _warnings.Add(String.Format("Suggested cropping: {0} pixels from right, {1} pixels from bottom.", cropX, cropY)); } } } break; } }
private void ParseMP3Frames(byte[] buff) { int[] MPEG1BitRate = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 }; int[] MPEG2XBitRate = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }; int[] MPEG1SampleRate = { 44100, 48000, 32000, 0 }; int[] MPEG20SampleRate = { 22050, 24000, 16000, 0 }; int[] MPEG25SampleRate = { 11025, 12000, 8000, 0 }; int offset = 0; int length = buff.Length; while (length >= 4) { ulong header; int mpegVersion, layer, bitRate, sampleRate, padding, channelMode; int frameLen; header = (ulong)BitConverterBE.ToUInt32(buff, offset) << 32; if (BitHelper.Read(ref header, 11) != 0x7FF) { break; } mpegVersion = BitHelper.Read(ref header, 2); layer = BitHelper.Read(ref header, 2); BitHelper.Read(ref header, 1); bitRate = BitHelper.Read(ref header, 4); sampleRate = BitHelper.Read(ref header, 2); padding = BitHelper.Read(ref header, 1); BitHelper.Read(ref header, 1); channelMode = BitHelper.Read(ref header, 2); if ((mpegVersion == 1) || (layer != 1) || (bitRate == 0) || (bitRate == 15) || (sampleRate == 3)) { break; } bitRate = ((mpegVersion == 3) ? MPEG1BitRate[bitRate] : MPEG2XBitRate[bitRate]) * 1000; if (mpegVersion == 3) { sampleRate = MPEG1SampleRate[sampleRate]; } else if (mpegVersion == 2) { sampleRate = MPEG20SampleRate[sampleRate]; } else { sampleRate = MPEG25SampleRate[sampleRate]; } frameLen = GetFrameLength(mpegVersion, bitRate, sampleRate, padding); if (frameLen > length) { break; } bool isVBRHeaderFrame = false; if (_frameOffsets.Count == 0) { // Check for an existing VBR header just to be safe (I haven't seen any in FLVs) int o = offset + GetFrameDataOffset(mpegVersion, channelMode); if (BitConverterBE.ToUInt32(buff, o) == 0x58696E67) { // "Xing" isVBRHeaderFrame = true; _delayWrite = false; _hasVBRHeader = true; } } if (!isVBRHeaderFrame) { if (_firstBitRate == 0) { _firstBitRate = bitRate; _mpegVersion = mpegVersion; _sampleRate = sampleRate; _channelMode = channelMode; _firstFrameHeader = BitConverterBE.ToUInt32(buff, offset); } else if (!_isVBR && (bitRate != _firstBitRate)) { _isVBR = true; if (_hasVBRHeader) { } else if (_delayWrite) { WriteVBRHeader(true); _writeVBRHeader = true; _delayWrite = false; } else { _warnings.Add("Detected VBR too late, cannot add VBR header."); } } } _frameOffsets.Add(_totalFrameLength + (uint)offset); offset += frameLen; length -= frameLen; } _totalFrameLength += (uint)buff.Length; }
public void WriteChunk(byte[] chunk, uint timeStamp, int frameType) { if (chunk.Length < 4) { return; } // Reference: decode_frame from libavcodec's h264.c if (chunk[0] == 0) { // Headers if (chunk.Length < 10) { return; } int offset, spsCount, ppsCount; offset = 8; _nalLengthSize = (chunk[offset++] & 0x03) + 1; spsCount = chunk[offset++] & 0x1F; ppsCount = -1; while (offset <= chunk.Length - 2) { if ((spsCount == 0) && (ppsCount == -1)) { ppsCount = chunk[offset++]; continue; } if (spsCount > 0) { spsCount--; } else if (ppsCount > 0) { ppsCount--; } else { break; } int len = BitConverterBE.ToUInt16(chunk, offset); offset += 2; if (offset + len > chunk.Length) { break; } _fs.Write(_startCode, 0, _startCode.Length); _fs.Write(chunk, offset, len); offset += len; } } else { // Video data int offset = 4; if (_nalLengthSize != 2) { _nalLengthSize = 4; } while (offset <= chunk.Length - _nalLengthSize) { int len = (_nalLengthSize == 2) ? BitConverterBE.ToUInt16(chunk, offset) : (int)BitConverterBE.ToUInt32(chunk, offset); offset += _nalLengthSize; if (offset + len > chunk.Length) { break; } _fs.Write(_startCode, 0, _startCode.Length); _fs.Write(chunk, offset, len); offset += len; } } }