/// <summary> /// IsNALBlockFormat /// Determine whether _contents have byte counts. /// </summary> /// <returns>True if byte counts are found.</returns> public static bool IsNALBlockFormat(BinaryReader reader, uint size, out uint totalSize) { uint count = CPUGenderDependencies.UINT(reader.ReadUInt32()); totalSize = size; // size is unchanged if (count == 0) { reader.BaseStream.Position -= 4; return(false); } else if (count == 1) { return(false); // count cannot be 1 } else if (count > size) { reader.BaseStream.Position -= 4; return(false); } byte b = reader.ReadByte(); byte c = reader.ReadByte(); if (!CheckNALUType(b, c)) { reader.BaseStream.Position -= 6; return(false); } reader.BaseStream.Position += ((int)(count - 2)); // ignore all subsequent bytes totalSize = size - count; return(true); }
/// <summary> /// H264Stream /// Used by Players to convert from blocks (which has byte counts) to a bit stream delimited by 001 or 0001. /// </summary> /// <param name="inFirst">Is this the first block? If so, insert SPS and PPS (CodecPrivateData) into the bit stream.</param> /// <param name="inCodecPrivateData">CodecPrivateData taken from containing MP4.</param> /// <param name="inStream">Input block stream.</param> /// <param name="inStart">Starting location in the input block stream.</param> /// <param name="inSize">Count of bytes to process.</param> /// <returns></returns> public static Stream H264Stream(bool inFirst, String inCodecPrivateData, Stream inStream, uint inStart, uint inSize) { Stream stream = new MemoryStream(); // ag ag = A_0 as ag; //string methodName = "ProcessH264"; if (inFirst) { string str2 = inCodecPrivateData; // ag.c()[MediaStreamAttributeKeys.CodecPrivateData]; byte[] buffer = HexStringToBytes(str2); if (buffer != null) { int index = 0; stream.WriteByte(0); stream.WriteByte(0); stream.WriteByte(0); stream.WriteByte(1); // Tracing.Trace(a, methodName, TraceArea.MediaStreamSource, TraceLevel.Verbose, "Appending sps & pps for {0}", new object[] { A_2.b() }); index = 4; while (index < buffer.Length) { if (((buffer[index] == 0) && (buffer[index + 1] == 0)) && ((buffer[index + 2] == 0) && (1 == buffer[index + 3]))) { break; } stream.WriteByte(buffer[index++]); } index += 4; stream.WriteByte(0); stream.WriteByte(0); stream.WriteByte(0); stream.WriteByte(1); stream.Write(buffer, index, buffer.Length - index); } } ulong num2 = (ulong)inSize; inStream.Seek((long)inStart, SeekOrigin.Begin); BinaryReader reader = new BinaryReader(inStream); // FIXME: Need to check for occurrence of 001 within data. If found replace by data replacement token that prevents // false detection of start token. As it stands, there is a possibility of a false token in the data that could make the output // invalid. while (num2 > 4L) { ulong num3 = CPUGenderDependencies.UINT(reader.ReadUInt32()); num2 -= ((ulong)4L) + num3; stream.WriteByte(0); stream.WriteByte(0); stream.WriteByte(0); stream.WriteByte(1); int count = (int)num3; stream.Write(reader.ReadBytes(count), 0, count); } return(stream); }
/// <summary> /// IsBitStream /// Determine whether the input stream contains H264 bit stream (as opposed to blocks). /// </summary> /// <param name="mdatStream">Input H264 stream.</param> /// <returns></returns> public static bool IsBitStream(Stream mdatStream) { BinaryReader reader = new BinaryReader(mdatStream); uint first4ByteValue = CPUGenderDependencies.UINT(reader.ReadUInt32()); if ((first4ByteValue < 512) && (first4ByteValue > 255) && CheckNALUType((byte)first4ByteValue, (byte)0)) // first 3 byte pattern is 001 { return(true); // H264 bit stream } return(false); }
/// <summary> /// InsertAccessUnitDelimiter /// NALU type 9 may be necessary for MediaElement to play a video stream. /// </summary> /// <param name="inStream">Input stream with Position set to beginning of a H264 block.</param> public static Stream InsertAccessUnitDelimiter(BinaryReader inStream, long offset, uint size) { inStream.BaseStream.Position = offset; uint count = 0; byte[] bytes = new byte[4]; byte[] copyBytes = new byte[4]; byte[] byteCount2 = new byte[4]; byteCount2[0] = 0; byteCount2[1] = 0; byteCount2[2] = 0; byteCount2[3] = 2; byte NALByte; Stream stream = new MemoryStream(); for (; inStream.BaseStream.Position < (offset + size);) { count = CPUGenderDependencies.UINT(inStream.ReadUInt32()); if ((count == 0) || (count > (inStream.BaseStream.Length - inStream.BaseStream.Position))) { return(stream); } NALByte = inStream.ReadByte(); byte NALUType = (byte)(NALUTypeMask & NALByte); byte NALRefIDC = (byte)(RefIDCMask & NALByte); if ((MSBMask & NALByte) != 0) { return(stream); // MSB must be zero } switch (NALUType) { case 1: if (NALRefIDC == 0) { return(stream); } stream.Write(byteCount2, 0, 4); stream.WriteByte((byte)9); stream.WriteByte((byte)48); break; case 2: case 3: case 4: break; // FIXME: just pass 2, 3, and 4 through? case 5: // IDR if (NALRefIDC == 0) { return(stream); } stream.Write(byteCount2, 0, 4); stream.WriteByte((byte)9); stream.WriteByte((byte)16); break; case 6: // supplemental enhancement information (SEI) case 7: // sequence parameter set (SPS) case 8: // picture parameter set (PPS) if (NALRefIDC != 0) { return(stream); } break; case 9: // access unit delimiter // This is what we're trying to insert. // It's already there, so // use input stream as output, and we're done. return(inStream.BaseStream); case 10: // end of sequence if (NALRefIDC != 0) { return(stream); } break; case 11: // end of stream if (NALRefIDC != 0) { return(stream); } break; case 12: // filler break; default: return(stream); } stream.Write(copyBytes, 0, 4); stream.WriteByte(NALByte); stream.Write(inStream.ReadBytes((int)count - 5), 0, (int)count - 5); } return(stream); }