/// <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, 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); }
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> /// Decode caption from the input stream /// </summary> /// <returns>bitmap of the decoded caption</returns> public static Bitmap DecodeImage(PcsObject pcs, IList<OdsData> data, List<PaletteInfo> palettes) { if (pcs == null || data == null || data.Count == 0) return new Bitmap(1, 1); int w = data[0].Size.Width; int h = data[0].Size.Height; var bm = new FastBitmap(new Bitmap(w, h)); bm.LockImage(); BluRaySupPalette pal = DecodePalette(palettes); int index = 0; int ofs = 0; int xpos = 0; byte[] buf = data[0].Fragment.ImageBuffer; index = 0; do { int b = buf[index++] & 0xff; if (b == 0 && index < buf.Length) { b = buf[index++] & 0xff; if (b == 0) { // next line ofs = (ofs / w) * w; if (xpos < w) ofs += w; xpos = 0; } else { int size; if ((b & 0xC0) == 0x40) { if (index < buf.Length) { // 00 4x xx -> xxx zeroes size = ((b - 0x40) << 8) + (buf[index++] & 0xff); Color c = Color.FromArgb(pal.GetArgb(0)); for (int i = 0; i < size; i++) PutPixel(bm, ofs++, c); xpos += size; } } else if ((b & 0xC0) == 0x80) { if (index < buf.Length) { // 00 8x yy -> x times value y size = (b - 0x80); b = buf[index++] & 0xff; Color c = Color.FromArgb(pal.GetArgb(b)); for (int i = 0; i < size; i++) PutPixel(bm, ofs++, c); xpos += size; } } else if ((b & 0xC0) != 0) { if (index < buf.Length) { // 00 cx yy zz -> xyy times value z size = ((b - 0xC0) << 8) + (buf[index++] & 0xff); b = buf[index++] & 0xff; Color c = Color.FromArgb(pal.GetArgb(b)); for (int i = 0; i < size; i++) PutPixel(bm, ofs++, c); xpos += size; } } else { // 00 xx -> xx times 0 Color c = Color.FromArgb(pal.GetArgb(0)); for (int i = 0; i < b; i++) PutPixel(bm, ofs++, c); xpos += b; } } } else { PutPixel(bm, ofs++, b, pal); xpos++; } } while (index < buf.Length); bm.UnlockImage(); return bm.GetBitmap(); }
/// <summary> /// Parse an PCS packet which contains width/height info /// </summary> /// <param name="buffer">Raw data buffer, starting right after segment</param> private static PcsObject ParsePcs(byte[] buffer, 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> /// Decode caption from the input stream /// </summary> /// <returns>bitmap of the decoded caption</returns> public static Bitmap DecodeImage(PcsObject pcs, IList <OdsData> data, List <PaletteInfo> palettes) { if (pcs == null || data == null || data.Count == 0) { return(new Bitmap(1, 1)); } int w = data[0].Size.Width; int h = data[0].Size.Height; if (w <= 0 || h <= 0 || data[0].Fragment.ImageBuffer.Length == 0) { return(new Bitmap(1, 1)); } var bm = new FastBitmap(new Bitmap(w, h)); bm.LockImage(); var pal = DecodePalette(palettes); int ofs = 0; int xpos = 0; var index = 0; byte[] buf = data[0].Fragment.ImageBuffer; do { int b = buf[index++] & 0xff; if (b == 0 && index < buf.Length) { b = buf[index++] & 0xff; if (b == 0) { // next line ofs = ofs / w * w; if (xpos < w) { ofs += w; } xpos = 0; } else { int size; if ((b & 0xC0) == 0x40) { if (index < buf.Length) { // 00 4x xx -> xxx zeroes size = ((b - 0x40) << 8) + (buf[index++] & 0xff); var c = Color.FromArgb(pal.GetArgb(0)); for (int i = 0; i < size; i++) { PutPixel(bm, ofs++, c); } xpos += size; } } else if ((b & 0xC0) == 0x80) { if (index < buf.Length) { // 00 8x yy -> x times value y size = (b - 0x80); b = buf[index++] & 0xff; var c = Color.FromArgb(pal.GetArgb(b)); for (int i = 0; i < size; i++) { PutPixel(bm, ofs++, c); } xpos += size; } } else if ((b & 0xC0) != 0) { if (index < buf.Length) { // 00 cx yy zz -> xyy times value z size = ((b - 0xC0) << 8) + (buf[index++] & 0xff); b = buf[index++] & 0xff; var c = Color.FromArgb(pal.GetArgb(b)); for (int i = 0; i < size; i++) { PutPixel(bm, ofs++, c); } xpos += size; } } else { // 00 xx -> xx times 0 var c = Color.FromArgb(pal.GetArgb(0)); for (int i = 0; i < b; i++) { PutPixel(bm, ofs++, c); } xpos += b; } } } else { PutPixel(bm, ofs++, b, pal); xpos++; } } while (index < buf.Length); bm.UnlockImage(); return(bm.GetBitmap()); }
/// <summary> /// Decode caption from the input stream /// </summary> /// <returns>bitmap of the decoded caption</returns> public static Image <Rgba32> DecodeImage(PcsObject pcs, IList <OdsData> data, List <PaletteInfo> palettes) { if (pcs == null || data == null || data.Count == 0) { return(new Image <Rgba32>(1, 1)); } int w = data[0].Size.Width; int h = data[0].Size.Height; var pal = BluRaySupParser.SupDecoder.DecodePalette(palettes); var bm = new Image <Rgba32>(w, h); bm.TryGetSinglePixelSpan(out var pixelSpan); int ofs = 0; int xpos = 0; var index = 0; byte[] buf = data[0].Fragment.ImageBuffer; do { int b = buf[index++] & 0xff; if (b == 0 && index < buf.Length) { b = buf[index++] & 0xff; if (b == 0) { // next line ofs = (ofs / w) * w; if (xpos < w) { ofs += w; } xpos = 0; } else { int size; if ((b & 0xC0) == 0x40) { if (index < buf.Length) { // 00 4x xx -> xxx zeroes size = ((b - 0x40) << 8) + (buf[index++] & 0xff); var c = GetColorFromInt(pal.GetArgb(0)); for (int i = 0; i < size; i++) { PutPixel(pixelSpan, ofs++, c); } xpos += size; } } else if ((b & 0xC0) == 0x80) { if (index < buf.Length) { // 00 8x yy -> x times value y size = (b - 0x80); b = buf[index++] & 0xff; var c = GetColorFromInt(pal.GetArgb(b)); for (int i = 0; i < size; i++) { PutPixel(pixelSpan, ofs++, c); } xpos += size; } } else if ((b & 0xC0) != 0) { if (index < buf.Length) { // 00 cx yy zz -> xyy times value z size = ((b - 0xC0) << 8) + (buf[index++] & 0xff); b = buf[index++] & 0xff; var c = GetColorFromInt(pal.GetArgb(b)); for (int i = 0; i < size; i++) { PutPixel(pixelSpan, ofs++, c); } xpos += size; } } else { // 00 xx -> xx times 0 var c = GetColorFromInt(pal.GetArgb(0)); for (int i = 0; i < b; i++) { PutPixel(pixelSpan, ofs++, c); } xpos += b; } } } else { PutPixel(pixelSpan, ofs++, b, pal); xpos++; } } while (index < buf.Length); return(bm); }