/// <summary> /// parse an PDS packet which contain palette info /// </summary> /// <param name="buffer">Buffer of raw byte data, starting right after segment</param> /// <param name="segment">object containing info about the current segment</param> /// <param name="pic">SubPicture object containing info about the current caption</param> /// <param name="msg">reference to message string</param> /// <returns>number of valid palette entries (-1 for fault)</returns> private static int ParsePds(byte[] buffer, SupSegment segment, BluRaySupPicture pic, string[] msg) { int paletteId = buffer[0]; // 8bit palette ID (0..7) // 8bit palette version number (incremented for each palette change) int paletteUpdate = buffer[1]; if (pic.Palettes == null) { pic.Palettes = new List <List <PaletteInfo> >(); for (int i = 0; i < 8; i++) { pic.Palettes.Add(new List <PaletteInfo>()); } } if (paletteId > 7) { msg[0] = "Illegal palette id at offset " + ToolBox.ToHex(buffer, 0, 8); return(-1); } List <PaletteInfo> al = pic.Palettes[paletteId]; if (al == null) { al = new List <PaletteInfo>(); } PaletteInfo p = new PaletteInfo(); p.PaletteSize = (segment.Size - 2) / 5; p.PaletteBuffer = new byte[p.PaletteSize * 5]; Buffer.BlockCopy(buffer, 2, p.PaletteBuffer, 0, p.PaletteSize * 5); // save palette buffer in palette object al.Add(p); msg[0] = "ID: " + paletteId + ", update: " + paletteUpdate + ", " + p.PaletteSize + " entries"; return(p.PaletteSize); }
/// <summary> /// parse an PDS packet which contain palette info /// </summary> /// <param name="buffer">Buffer of raw byte data, starting right after segment</param> /// <param name="segment">object containing info about the current segment</param> /// <returns>number of valid palette entries (-1 for fault)</returns> private static PdsData ParsePds(byte[] buffer, SupSegment segment) { int paletteId = buffer[0]; // 8bit palette ID (0..7) // 8bit palette version number (incremented for each palette change) int paletteUpdate = buffer[1]; var p = new PaletteInfo { PaletteSize = (segment.Size - 2) / 5 }; if (p.PaletteSize <= 0) { return(new PdsData { Message = "Empty palette" }); } p.PaletteBuffer = new byte[p.PaletteSize * 5]; Buffer.BlockCopy(buffer, 2, p.PaletteBuffer, 0, p.PaletteSize * 5); // save palette buffer in palette object return(new PdsData { Message = "PalId: " + paletteId + ", update: " + paletteUpdate + ", " + p.PaletteSize + " entries", PaletteId = paletteId, PaletteVersion = paletteUpdate, PaletteInfo = p, }); }
private static SupSegment ParseSegmentHeaderFromMatroska(byte[] buffer) { var segment = new SupSegment(); segment.Type = buffer[0]; segment.Size = BigEndianInt16(buffer, 1); return(segment); }
/// <summary> /// Matroska bd sup skips first 9 bytes as timecodes are in Matroska structure /// </summary> /// <param name="buffer"></param> /// <param name="log"></param> /// <returns></returns> private static SupSegment ReadSegmentFromMatroska(byte[] buffer, StringBuilder log) { SupSegment segment = new SupSegment(); // segment.PtsTimestamp = BigEndianInt32(buffer, 2); // read PTS // segment.DtsTimestamp = BigEndianInt32(buffer, 6); // read PTS segment.Type = buffer[0]; segment.Size = BigEndianInt16(buffer, 1); return(segment); }
/// <summary> /// Parse an PCS packet which contains width/height info /// </summary> /// <param name="segment">object containing info about the current segment</param> /// <param name="pic">SubPicture object containing info about the current caption</param> /// <param name="msg">reference to message string</param> /// <param name="buffer">Raw data buffer, starting right after segment</param> private static void ParsePcs(SupSegment segment, BluRaySupPicture pic, string[] msg, byte[] buffer) { if (segment.Size >= 4) { pic.Width = BigEndianInt16(buffer, 0); // video_width pic.Height = BigEndianInt16(buffer, 2); // video_height int type = buffer[4]; // hi nibble: frame_rate, lo nibble: reserved int num = BigEndianInt16(buffer, 5); // composition_number // skipped: // 8bit composition_state: 0x00: normal, 0x40: acquisition point // 0x80: epoch start, 0xC0: epoch continue, 6bit reserved // 8bit palette_update_flag (0x80), 7bit reserved int palId = buffer[9]; // 8bit palette_id_ref int coNum = buffer[10]; // 8bit number_of_composition_objects (0..2) if (coNum > 0) { // composition_object: int objId = BigEndianInt16(buffer, 11); // 16bit object_id_ref msg[0] = "palID: " + palId + ", objID: " + objId; if (pic.ImageObjects == null) { pic.ImageObjects = new List <ImageObject>(); } ImageObject imgObj; if (objId >= pic.ImageObjects.Count) { imgObj = new ImageObject(); pic.ImageObjects.Add(imgObj); } else { imgObj = pic.GetImageObject(objId); } imgObj.PaletteId = palId; pic.ObjectId = objId; // skipped: 8bit window_id_ref if (segment.Size >= 0x13) { pic.FramesPerSecondType = type; // object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved int forcedCropped = buffer[14]; pic.CompositionNumber = num; pic.IsForced = ((forcedCropped & 0x40) == 0x40); imgObj.XOffset = BigEndianInt16(buffer, 15); // composition_object_horizontal_position imgObj.YOffset = BigEndianInt16(buffer, 17); // composition_object_vertical_position // if (object_cropped_flag==1) // 16bit object_cropping_horizontal_position // 16bit object_cropping_vertical_position // 16bit object_cropping_width // object_cropping_height } } } }
private static PcsData ParsePicture(byte[] buffer, SupSegment segment) { if (buffer.Length < 11) { return(new PcsData { CompositionState = CompositionState.Invalid }); } var sb = new StringBuilder(); var pcs = new PcsData { Size = new Size(BigEndianInt16(buffer, 0), BigEndianInt16(buffer, 2)), FramesPerSecondType = buffer[4], CompNum = BigEndianInt16(buffer, 5), CompositionState = GetCompositionState(buffer[7]), StartTime = segment.PtsTimestamp, PaletteUpdate = buffer[8] == 0x80, PaletteId = buffer[9] }; // hi nibble: frame_rate, lo nibble: reserved // 8bit palette_update_flag (0x80), 7bit reserved // 8bit palette_id_ref int compositionObjectCount = buffer[10]; // 8bit number_of_composition_objects (0..2) sb.AppendFormat("CompNum: {0}, Pts: {1}, State: {2}, PalUpdate: {3}, PalId {4}", pcs.CompNum, ToolBox.PtsToTimeString(pcs.StartTime), pcs.CompositionState, pcs.PaletteUpdate, pcs.PaletteId); if (pcs.CompositionState == CompositionState.Invalid) { sb.Append("Illegal composition state Invalid"); } else { int offset = 0; pcs.PcsObjects = new List <PcsObject>(); for (int compObjIndex = 0; compObjIndex < compositionObjectCount; compObjIndex++) { var pcsObj = ParsePcs(buffer, offset); pcs.PcsObjects.Add(pcsObj); sb.AppendLine(); sb.AppendFormat("ObjId: {0}, WinId: {1}, Forced: {2}, X: {3}, Y: {4}", pcsObj.ObjectId, pcsObj.WindowId, pcsObj.IsForced, pcsObj.Origin.X, pcsObj.Origin.Y); offset += 8; } } pcs.Message = sb.ToString(); return(pcs); }
/// <summary> /// Parse an PCS packet which contains width/height info /// </summary> /// <param name="segment">object containing info about the current segment</param> /// <param name="pic">SubPicture object containing info about the current caption</param> /// <param name="msg">reference to message string</param> /// <param name="buffer">Raw data buffer, starting right after segment</param> private static PcsObject ParsePcs(byte[] buffer, SupSegment segment, int offset) { var pcs = new PcsObject(); // composition_object: pcs.ObjectId = BigEndianInt16(buffer, 11 + offset); // 16bit object_id_ref pcs.WindowId = buffer[13 + offset]; // skipped: 8bit window_id_ref // object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved int forcedCropped = buffer[14 + offset]; pcs.IsForced = ((forcedCropped & 0x40) == 0x40); pcs.Origin = new Point(BigEndianInt16(buffer, 15 + offset), BigEndianInt16(buffer, 17 + offset)); return(pcs); }
/// <summary> /// parse an ODS packet which contain the image data /// </summary> /// <param name="buffer">raw byte date, starting right after segment</param> /// <param name="segment">object containing info about the current segment</param> /// <param name="pic">SubPicture object containing info about the current caption</param> /// <param name="msg">reference to message string</param> /// <returns>true if this is a valid new object (neither invalid nor a fragment)</returns> private static OdsData ParseOds(byte[] buffer, SupSegment segment, bool forceFirst) { int objId = BigEndianInt16(buffer, 0); // 16bit object_id int objVer = buffer[2]; // 16bit object_id nikse - index 2 or 1??? int objSeq = buffer[3]; // 8bit first_in_sequence (0x80), // last_in_sequence (0x40), 6bits reserved bool first = ((objSeq & 0x80) == 0x80) || forceFirst; bool last = (objSeq & 0x40) == 0x40; var info = new ImageObjectFragment(); if (first) { int width = BigEndianInt16(buffer, 7); // object_width int height = BigEndianInt16(buffer, 9); // object_height info.ImagePacketSize = segment.Size - 11; // Image packet size (image bytes) info.ImageBuffer = new byte[info.ImagePacketSize]; Buffer.BlockCopy(buffer, 11, info.ImageBuffer, 0, info.ImagePacketSize); return(new OdsData { IsFirst = true, Size = new Size(width, height), ObjectId = objId, ObjectVersion = objVer, Fragment = info, Message = "ObjId: " + objId + ", ver: " + objVer + ", seq: " + (first ? "first" : "") + ((first && last) ? "/" : "") + (last ? "" + "last" : "") + ", width: " + width + ", height: " + height, }); } else { info.ImagePacketSize = segment.Size - 4; info.ImageBuffer = new byte[info.ImagePacketSize]; Buffer.BlockCopy(buffer, 4, info.ImageBuffer, 0, info.ImagePacketSize); return(new OdsData { IsFirst = false, ObjectId = objId, ObjectVersion = objVer, Fragment = info, Message = "Continued ObjId: " + objId + ", ver: " + objVer + ", seq: " + (last ? "" + "last" : ""), }); } }
private static SupSegment ParseSegmentHeader(byte[] buffer, StringBuilder log) { var segment = new SupSegment(); if (buffer[0] == 0x50 && buffer[1] == 0x47) // 80 + 71 - P G { segment.PtsTimestamp = BigEndianInt32(buffer, 2); // read PTS segment.DtsTimestamp = BigEndianInt32(buffer, 6); // read PTS segment.Type = buffer[10]; segment.Size = BigEndianInt16(buffer, 11); } else { log.AppendLine("Unable to read segment - PG missing!"); } return(segment); }
private static SupSegment ParseSegmentHeaderFromMatroska(byte[] buffer) { var segment = new SupSegment(); segment.Type = buffer[0]; segment.Size = BigEndianInt16(buffer, 1); return segment; }
private static SupSegment ParseSegmentHeader(byte[] buffer, StringBuilder log) { var segment = new SupSegment(); if (buffer[0] == 0x50 && buffer[1] == 0x47) // 80 + 71 - P G { segment.PtsTimestamp = BigEndianInt32(buffer, 2); // read PTS segment.DtsTimestamp = BigEndianInt32(buffer, 6); // read PTS segment.Type = buffer[10]; segment.Size = BigEndianInt16(buffer, 11); } else { log.AppendLine("Unable to read segment - PG missing!"); } return segment; }
private static PcsData ParsePicture(byte[] buffer, SupSegment segment) { var sb = new StringBuilder(); var pcs = new PcsData(); pcs.Size = new Size(BigEndianInt16(buffer, 0), BigEndianInt16(buffer, 2)); pcs.FramesPerSecondType = buffer[4]; // hi nibble: frame_rate, lo nibble: reserved pcs.CompNum = BigEndianInt16(buffer, 5); pcs.CompositionState = GetCompositionState(buffer[7]); pcs.StartTime = segment.PtsTimestamp; // 8bit palette_update_flag (0x80), 7bit reserved pcs.PaletteUpdate = (buffer[8] == 0x80); pcs.PaletteId = buffer[9]; // 8bit palette_id_ref int compositionObjectCount = buffer[10]; // 8bit number_of_composition_objects (0..2) sb.AppendFormat("CompNum: {0}, Pts: {1}, State: {2}, PalUpdate: {3}, PalId {4}", pcs.CompNum, ToolBox.PtsToTimeString(pcs.StartTime), pcs.CompositionState, pcs.PaletteUpdate, pcs.PaletteId); if (pcs.CompositionState == CompositionState.Invalid) { sb.Append("Illegal composition state Invalid"); } else { int offset = 0; pcs.PcsObjects = new List<PcsObject>(); for (int compObjIndex = 0; compObjIndex < compositionObjectCount; compObjIndex++) { PcsObject pcsObj = ParsePcs(buffer, offset); pcs.PcsObjects.Add(pcsObj); sb.AppendLine(); sb.AppendFormat("ObjId: {0}, WinId: {1}, Forced: {2}, X: {3}, Y: {4}", pcsObj.ObjectId, pcsObj.WindowId, pcsObj.IsForced, pcsObj.Origin.X, pcsObj.Origin.Y); offset += 8; } } pcs.Message = sb.ToString(); return pcs; }
/// <summary> /// parse an PDS packet which contain palette info /// </summary> /// <param name="buffer">Buffer of raw byte data, starting right after segment</param> /// <param name="segment">object containing info about the current segment</param> /// <returns>number of valid palette entries (-1 for fault)</returns> private static PdsData ParsePds(byte[] buffer, SupSegment segment) { int paletteId = buffer[0]; // 8bit palette ID (0..7) // 8bit palette version number (incremented for each palette change) int paletteUpdate = buffer[1]; var p = new PaletteInfo(); p.PaletteSize = (segment.Size - 2) / 5; if (p.PaletteSize <= 0) return new PdsData { Message = "Empty palette" }; p.PaletteBuffer = new byte[p.PaletteSize * 5]; Buffer.BlockCopy(buffer, 2, p.PaletteBuffer, 0, p.PaletteSize * 5); // save palette buffer in palette object return new PdsData { Message = "PalId: " + paletteId + ", update: " + paletteUpdate + ", " + p.PaletteSize + " entries", PaletteId = paletteId, PaletteVersion = paletteUpdate, PaletteInfo = p, }; }
/// <summary> /// parse an ODS packet which contain the image data /// </summary> /// <param name="buffer">raw byte date, starting right after segment</param> /// <param name="segment">object containing info about the current segment</param> /// <returns>true if this is a valid new object (neither invalid nor a fragment)</returns> private static OdsData ParseOds(byte[] buffer, SupSegment segment, bool forceFirst) { int objId = BigEndianInt16(buffer, 0); // 16bit object_id int objVer = buffer[2]; // 16bit object_id nikse - index 2 or 1??? int objSeq = buffer[3]; // 8bit first_in_sequence (0x80), // last_in_sequence (0x40), 6bits reserved bool first = ((objSeq & 0x80) == 0x80) || forceFirst; bool last = (objSeq & 0x40) == 0x40; var info = new ImageObjectFragment(); if (first) { int width = BigEndianInt16(buffer, 7); // object_width int height = BigEndianInt16(buffer, 9); // object_height info.ImagePacketSize = segment.Size - 11; // Image packet size (image bytes) info.ImageBuffer = new byte[info.ImagePacketSize]; Buffer.BlockCopy(buffer, 11, info.ImageBuffer, 0, info.ImagePacketSize); return new OdsData { IsFirst = true, Size = new Size(width, height), ObjectId = objId, ObjectVersion = objVer, Fragment = info, Message = "ObjId: " + objId + ", ver: " + objVer + ", seq: first" + (last ? "/" : "") + (last ? "" + "last" : "") + ", width: " + width + ", height: " + height, }; } else { info.ImagePacketSize = segment.Size - 4; info.ImageBuffer = new byte[info.ImagePacketSize]; Buffer.BlockCopy(buffer, 4, info.ImageBuffer, 0, info.ImagePacketSize); return new OdsData { IsFirst = false, ObjectId = objId, ObjectVersion = objVer, Fragment = info, Message = "Continued ObjId: " + objId + ", ver: " + objVer + ", seq: " + (last ? "" + "last" : ""), }; } }
/// <summary> /// Parse an PCS packet which contains width/height info /// </summary> /// <param name="segment">object containing info about the current segment</param> /// <param name="pic">SubPicture object containing info about the current caption</param> /// <param name="msg">reference to message string</param> /// <param name="buffer">Raw data buffer, starting right after segment</param> private static PcsObject ParsePcs(byte[] buffer, SupSegment segment, int offset) { var pcs = new PcsObject(); // composition_object: pcs.ObjectId = BigEndianInt16(buffer, 11 + offset); // 16bit object_id_ref pcs.WindowId = buffer[13 + offset]; // skipped: 8bit window_id_ref // object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved int forcedCropped = buffer[14 + offset]; pcs.IsForced = ((forcedCropped & 0x40) == 0x40); pcs.Origin = new Point(BigEndianInt16(buffer, 15 + offset), BigEndianInt16(buffer, 17 + offset)); return pcs; }
/// <summary> /// parse an ODS packet which contain the image data /// </summary> /// <param name="buffer">raw byte date, starting right after segment</param> /// <param name="segment">object containing info about the current segment</param> /// <param name="pic">SubPicture object containing info about the current caption</param> /// <param name="msg">reference to message string</param> /// <returns>true if this is a valid new object (neither invalid nor a fragment)</returns> private static bool ParseOds(byte[] buffer, SupSegment segment, BluRaySupPicture pic, string[] msg) { ImageObjectFragment info; int objId = BigEndianInt16(buffer, 0); // 16bit object_id int objVer = buffer[2]; // 16bit object_id nikse - index 2 or 1??? int objSeq = buffer[3]; // 8bit first_in_sequence (0x80), // last_in_sequence (0x40), 6bits reserved bool first = (objSeq & 0x80) == 0x80; bool last = (objSeq & 0x40) == 0x40; if (pic.ImageObjects == null) { pic.ImageObjects = new List <ImageObject>(); } ImageObject imgObj; if (objId >= pic.ImageObjects.Count) { imgObj = new ImageObject(); pic.ImageObjects.Add(imgObj); } else { imgObj = pic.GetImageObject(objId); } if (imgObj.Fragments == null || first) { // 8bit object_version_number // skipped: // 24bit object_data_length - full RLE buffer length (including 4 bytes size info) int width = BigEndianInt16(buffer, 7); // object_width int height = BigEndianInt16(buffer, 9); // object_height if (width <= pic.Width && height <= pic.Height) { imgObj.Fragments = new List <ImageObjectFragment>(); info = new ImageObjectFragment(); info.ImagePacketSize = segment.Size - 11; // Image packet size (image bytes) info.ImageBuffer = new byte[info.ImagePacketSize]; Buffer.BlockCopy(buffer, 11, info.ImageBuffer, 0, info.ImagePacketSize); imgObj.Fragments.Add(info); imgObj.BufferSize = info.ImagePacketSize; imgObj.Height = height; imgObj.Width = width; msg[0] = "ID: " + objId + ", update: " + objVer + ", seq: " + (first ? "first" : "") + ((first && last) ? "/" : "") + (last ? "" + "last" : ""); return(true); } System.Diagnostics.Debug.Print("Invalid image size - ignored"); return(false); } // object_data_fragment // skipped: // 16bit object_id // 8bit object_version_number // 8bit first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved info = new ImageObjectFragment(); info.ImagePacketSize = segment.Size - 4; info.ImageBuffer = new byte[info.ImagePacketSize]; Buffer.BlockCopy(buffer, 4, info.ImageBuffer, 0, info.ImagePacketSize); imgObj.Fragments.Add(info); imgObj.BufferSize += info.ImagePacketSize; // total size (may contain several packets) msg[0] = "ID: " + objId + ", update: " + objVer + ", seq: " + (first ? "first" : "") + ((first && last) ? "/" : "") + (last ? "" + "last" : ""); return(false); }