private bool ReadNextSequence() { bufferLength = 0; Frames.Clear(); SequenceExtensionPresent = false; SequenceFrames = 0; SequenceStartFrame = CurrentFrame; if (!FindNextSequenceStart()) { LastError = ErrorCode.MPEG_ERROR_NOSEQUENCE; return(false); } int picture = 0; MPEGFrame newFrame = new MPEGFrame(); newFrame.StartIndex = bufferLength - 4; // -4 compensates for sequence start code newFrame.FrameNumber = CurrentFrame++; if (!ConsumeSequenceHeader()) { return(false); } if (!ConsumeExtensions(0)) { return(false); } int pictures = 0; bool done = false; while (!done) { uint startCode = reader.Peek32(); if (startCode == MPEG_CODE_GROUP_START) { newFrame.StartOfGOP = true; ConsumeGroupOfPicturesHeader(); ConsumeExtensions(1); } else if (startCode >= MPEG_CODE_SLICE_START_LOW && startCode <= MPEG_CODE_SLICE_START_HIGH) { ConsumeSlice(); } else if (startCode == MPEG_CODE_PICTURE_START) { picture++; if (picture > 1) { newFrame.EndIndex = bufferLength - 1; Frames.Add(newFrame); newFrame = new MPEGFrame(); newFrame.StartIndex = bufferLength; newFrame.FrameNumber = CurrentFrame++; } pictures++; ConsumePictureHeader(); if (PictureCodingType == 1) { newFrame.FrameType = 'I'; } else if (PictureCodingType == 2) { newFrame.FrameType = 'P'; } else if (PictureCodingType == 3) { newFrame.FrameType = 'B'; } newFrame.TemporalReference = TemporalReference; newFrame.PresentationNumber = SequenceStartFrame + TemporalReference; newFrame.VBVDelay = PictureVBVDelay; } else if (startCode == MPEG_CODE_EXTENSION_START) { ConsumeExtensions(2); } else if (startCode == MPEG_CODE_SEQUENCE_END) { // consume sequence_end_code ReadAndBuffer32(); done = true; } else { done = true; } } newFrame.EndIndex = bufferLength - 1; Frames.Add(newFrame); return(true); }
private ByteArray PesForFrame(int mpegStream, int index, double initialDTS) { ByteArray result = new ByteArray(); MPEGFrame frame = Frames[index]; result.Append((uint)(0x000001E0 + mpegStream)); result.Append((ushort)0x0000); // Transport stream PES packets don't need lengths if they're video // '10' (2 bits) 02 = 0x80 // PES_scrambling_control = '00' (2 bits) 04 = 0x00 // PES_priority = '0' (1 bit) 05 = 0x00 // data_alignment indicator = '1' (1 bit) 06 = 0x04 // copyright = '0' (1 bit) 07 = 0x00 // original_or_copy = '1' (1 bit) 08 = 0x01 // = 0x85 result.Append((byte)0x85); if (frame.FrameNumber == 0) { VBVDelay = frame.VBVDelay; } double frameDuration = 1.0 / SequenceFrameRate; double dts = (double)frame.FrameNumber * frameDuration + VBVDelay; // initialDTS; double pts = (double)(frame.PresentationNumber + 1) * frameDuration + VBVDelay; // initialDTS; if (frame.PresentationNumber == 0) { InitialPTS = pts; } ulong intDts = (ulong)Math.Round(90000.0 * dts); ulong intPts = (ulong)Math.Round(90000.0 * pts); //if ((double)intDts / 90000.0 != dts) // System.Diagnostics.Debugger.Break(); if (dts == pts) { // PTS_DTS_flags = '10' (2 bits) 02 = 0x80 // ESCR_flag = '0' (1 bit) 03 = 0x00 // ES_rate_flag = '0' (1 bit) 04 = 0x00 // DSM_trick_mode_flag = '0' (1 bit) 05 = 0x00 // additional_copy_info_flag = '0' (1 bit) 06 = 0x00 // PES_CRC_flag = '0' (1 bit) 07 = 0x00 // PES_extension_flag (1 bit) 08 = 0x00 // = 0x80 result.Append((byte)0x80); // if(PTS_DTS_flags == '10') // '0010' (4 bits) 04 // PTS[32..30] (3 bits) 07 // marker_bit = '1' (1 bit) 08 // PTS[29..15] (15 bits) 23 // marker_bit = '1' (1 bit) 24 // PTS[14..0] (15 bits) 39 // marker_bit = '1' (1 bit) 40 // PES_header_data_length = 40 bits or 5 bytes result.Append((byte)5); result.EnterBitMode(); result.AppendBits((byte)0x2, 3, 0); result.AppendBits(intPts, 32, 30); result.AppendBit(1); result.AppendBits(intPts, 29, 15); result.AppendBit(1); result.AppendBits(intPts, 14, 0); result.AppendBit(1); result.LeaveBitMode(); } else { // PTS_DTS_flags = '11' (2 bits) 02 = 0xC0 // ESCR_flag = '0' (1 bit) 03 = 0x00 // ES_rate_flag = '0' (1 bit) 04 = 0x00 // DSM_trick_mode_flag = '0' (1 bit) 05 = 0x00 // additional_copy_info_flag = '0' (1 bit) 06 = 0x00 // PES_CRC_flag = '0' (1 bit) 07 = 0x00 // PES_extension_flag (1 bit) 08 = 0x00 // = 0xC0 result.Append((byte)0xC0); // if(PTS_DTS_flags == '11') // '0011' (4 bits) 04 // PTS[32..30] (3 bits) 07 // marker_bit = '1' (1 bit) 08 // PTS[29..15] (15 bits) 23 // marker_bit = '1' (1 bit) 24 // PTS[14..0] (15 bits) 39 // marker_bit = '1' (1 bit) 40 // '0001' (4 bits) 44 // DTS[32..30] (3 bits) 47 // marker_bit = '1' (1 bit) 48 // DTS[29..15] (15 bits) 63 // marker_bit = '1' (1 bit) 64 // DTS[14..0] (15 bits) 79 // marker_bit = '1' (1 bit) 80 // PES_header_data_length = 80 bits or 10 bytes result.Append((byte)10); result.EnterBitMode(); result.AppendBits((byte)0x3, 3, 0); result.AppendBits(intPts, 32, 30); result.AppendBit(1); result.AppendBits(intPts, 29, 15); result.AppendBit(1); result.AppendBits(intPts, 14, 0); result.AppendBit(1); result.AppendBits((byte)0x1, 3, 0); result.AppendBits(intDts, 32, 30); result.AppendBit(1); result.AppendBits(intDts, 29, 15); result.AppendBit(1); result.AppendBits(intDts, 14, 0); result.AppendBit(1); result.LeaveBitMode(); } // Append the frame data result.Append(buffer, frame.StartIndex, frame.Length); // TODO : figure out what the heck the quad-byte alignment thing is in Cablelabs VoD /*int pesHeaderSize = 14; // just pts * if (pts != dts) * pesHeaderSize += 5; // adjust for dts * * while (((result.length - pesHeaderSize) % 4) != 0) * result.append((byte)0x00);*/ frame.PESPacket = result; frame.DTS = dts; frame.PTS = pts; return(result); }