private static bool CompletePcs(PcsData pcs, Dictionary <int, List <OdsData> > bitmapObjects, Dictionary <int, List <PaletteInfo> > palettes) { if (pcs?.PcsObjects == null || palettes == null) { return(false); } if (pcs.PcsObjects.Count == 0) { return(true); } if (!palettes.ContainsKey(pcs.PaletteId)) { return(false); } pcs.PaletteInfos = new List <PaletteInfo>(palettes[pcs.PaletteId]); pcs.BitmapObjects = new List <List <OdsData> >(); for (int index = 0; index < pcs.PcsObjects.Count; index++) { int objId = pcs.PcsObjects[index].ObjectId; if (!bitmapObjects.ContainsKey(objId)) { return(false); } pcs.BitmapObjects.Add(bitmapObjects[objId]); } return(true); }
public static Image <Rgba32> GetRgba32(this PcsData pcsData) { if (pcsData.PcsObjects.Count == 1) { return(SupDecoder.DecodeImage(pcsData.PcsObjects[0], pcsData.BitmapObjects[0], pcsData.PaletteInfos)); } var r = System.Drawing.Rectangle.Empty; for (var ioIndex = 0; ioIndex < pcsData.PcsObjects.Count; ioIndex++) { var ioRect = new System.Drawing.Rectangle(pcsData.PcsObjects[ioIndex].Origin, pcsData.BitmapObjects[ioIndex][0].Size); r = r.IsEmpty ? ioRect : System.Drawing.Rectangle.Union(r, ioRect); } var mergedBmp = new Image <Rgba32>(r.Width, r.Height); for (var ioIndex = 0; ioIndex < pcsData.PcsObjects.Count; ioIndex++) { var offset = pcsData.PcsObjects[ioIndex].Origin - new System.Drawing.Size(r.Location); using (var singleBmp = SupDecoder.DecodeImage(pcsData.PcsObjects[ioIndex], pcsData.BitmapObjects[ioIndex], pcsData.PaletteInfos)) { mergedBmp.Mutate(b => b.DrawImage(singleBmp, new SixLabors.ImageSharp.Point(offset.X, offset.Y), 0)); } } return(mergedBmp); }
private PcsData CreatePcsData(DaegunPacketClass _packet) { DaegunPacket packet = _packet.Packet; PcsData pcs = new PcsData(); pcs.deviceId = $"DS{packet.sSiteId}_PCS{packet.Pcs.PcsNumber}"; pcs.groupId = 1; pcs.siteId = packet.sSiteId; pcs.groupName = "PCS_SYSTEM"; pcs.freq = packet.Pcs.Frequency; pcs.acVltR = packet.Pcs.AC_line_voltage.R; pcs.acVltS = packet.Pcs.AC_line_voltage.S; pcs.acVltT = packet.Pcs.AC_line_voltage.T; pcs.actPwrCmdLmtLowChg = 0; pcs.actPwrCmdLmtLowDhg = 0; pcs.actPwrCmdLmtHighChg = packet.Bsc.ChargePowerLimit; pcs.actPwrCmdLmtHighDhg = packet.Bsc.DischargePowerLimit; pcs.actPwr = packet.Pcs.ActivePower; pcs.acCrtLow = 0; pcs.acCrtHigh = packet.Bsc.DischargeCurrentLimit; pcs.acCrtR = packet.Pcs.AC_phase_current.R; pcs.acCrtS = packet.Pcs.AC_phase_current.S; pcs.acCrtT = packet.Pcs.AC_phase_current.T; pcs.rctPwr = packet.Pcs.ReactivePower; pcs.pf = packet.Pcs.PowerFactor; pcs.timestamp = _packet.Timestamp; return(pcs); }
private async void StoreDb(CancellationToken token) { try { if (insertBatchList.Count == 0) { return; } List <PcsData> pcsDatas = new List <PcsData>(); List <BmsData> bmsDatas = new List <BmsData>(); List <PvData> pvDatas = new List <PvData>(); foreach (var packet in insertBatchList) { PcsData pcs = CreatePcsData(packet); pcsDatas.Add(pcs); bmsDatas.Add(CreateBmsData(packet)); pvDatas.Add(CreatePvData(packet)); } using (var session = _da.SessionFactory.OpenStatelessSession()) { using (var transact = session.BeginTransaction()) { foreach (var pcs in pcsDatas) { await session.InsertAsync(pcs, token); } foreach (var bms in bmsDatas) { await session.InsertAsync(bms, token); } foreach (var pv in pvDatas) { await session.InsertAsync(pv, token); } await transact.CommitAsync(token); } } insertBatchList.Clear(); } catch (Exception ex) { _logger.LogError(ex, ex.Message); } }
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); }
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; }
private static bool CompletePcs(PcsData pcs, Dictionary<int, List<OdsData>> bitmapObjects, Dictionary<int, List<PaletteInfo>> palettes) { if (pcs == null || pcs.PcsObjects == null || palettes == null) return false; if (pcs.PcsObjects.Count == 0) return true; if (!palettes.ContainsKey(pcs.PaletteId)) return false; pcs.PaletteInfos = new List<PaletteInfo>(palettes[pcs.PaletteId]); pcs.BitmapObjects = new List<List<OdsData>>(); for (int index = 0; index < pcs.PcsObjects.Count; index++) { int objId = pcs.PcsObjects[index].ObjectId; if (!bitmapObjects.ContainsKey(objId)) return false; pcs.BitmapObjects.Add(bitmapObjects[objId]); } return true; }
public static List <PcsData> ParseBluRaySup(Stream ms, StringBuilder log, bool fromMatroskaFile, Dictionary <int, List <PaletteInfo> > lastPalettes = null) { long position = ms.Position; int segmentCount = 0; var palettes = new Dictionary <int, List <PaletteInfo> >(); bool forceFirstOds = true; var bitmapObjects = new Dictionary <int, List <OdsData> >(); PcsData latestPcs = null; var pcsList = new List <PcsData>(); var headerBuffer = fromMatroskaFile ? new byte[3] : new byte[HeaderSize]; while (ms.Read(headerBuffer, 0, headerBuffer.Length) == headerBuffer.Length) { var segment = fromMatroskaFile ? ParseSegmentHeaderFromMatroska(headerBuffer) : ParseSegmentHeader(headerBuffer, log); position += headerBuffer.Length; try { // Read segment data var buffer = new byte[segment.Size]; var bytesRead = ms.Read(buffer, 0, buffer.Length); if (bytesRead < buffer.Length) { break; } #if DEBUG log.Append(segmentCount + ": "); #endif switch (segment.Type) { case 0x14: // Palette if (latestPcs != null) { #if DEBUG log.AppendLine($"0x14 - Palette - PDS offset={position} size={segment.Size}"); #endif var pds = ParsePds(buffer, segment); #if DEBUG log.AppendLine(pds.Message); #endif if (pds.PaletteInfo != null) { if (!palettes.ContainsKey(pds.PaletteId)) { palettes[pds.PaletteId] = new List <PaletteInfo>(); } else { if (latestPcs.PaletteUpdate) { palettes[pds.PaletteId].RemoveAt(palettes[pds.PaletteId].Count - 1); } else { #if DEBUG log.AppendLine("Extra Palette"); #endif } } palettes[pds.PaletteId].Add(pds.PaletteInfo); } } break; case 0x15: // Image bitmap data if (latestPcs != null) { #if DEBUG log.AppendLine($"0x15 - Bitmap data - ODS offset={position} size={segment.Size}"); #endif var ods = ParseOds(buffer, segment, forceFirstOds); #if DEBUG log.AppendLine(ods.Message); #endif if (!latestPcs.PaletteUpdate) { List <OdsData> odsList; if (ods.IsFirst) { odsList = new List <OdsData> { ods }; bitmapObjects[ods.ObjectId] = odsList; } else { if (bitmapObjects.TryGetValue(ods.ObjectId, out odsList)) { odsList.Add(ods); } else { #if DEBUG log.AppendLine($"INVALID ObjectId {ods.ObjectId} in ODS, offset={position}"); #endif } } } else { #if DEBUG log.AppendLine($"Bitmap Data Ignore due to PaletteUpdate offset={position}"); #endif } forceFirstOds = false; } break; case 0x16: // Picture time codes if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes.Count > 0 ? palettes : lastPalettes)) { pcsList.Add(latestPcs); } } #if DEBUG log.AppendLine($"0x16 - Picture codes, offset={position} size={segment.Size}"); #endif forceFirstOds = true; var nextPcs = ParsePicture(buffer, segment); if (nextPcs.StartTime > 0 && pcsList.Count > 0 && pcsList.Last().EndTime == 0) { pcsList.Last().EndTime = nextPcs.StartTime; } #if DEBUG log.AppendLine(nextPcs.Message); #endif latestPcs = nextPcs; if (latestPcs.CompositionState == CompositionState.EpochStart) { bitmapObjects.Clear(); palettes.Clear(); } break; case 0x17: // Window display if (latestPcs != null) { #if DEBUG log.AppendLine($"0x17 - Window display offset={position} size={segment.Size}"); #endif int windowCount = buffer[0]; int offset = 0; for (int nextWindow = 0; nextWindow < windowCount; nextWindow++) { int windowId = buffer[1 + offset]; int x = BigEndianInt16(buffer, 2 + offset); int y = BigEndianInt16(buffer, 4 + offset); int width = BigEndianInt16(buffer, 6 + offset); int height = BigEndianInt16(buffer, 8 + offset); log.AppendLine(string.Format("WinId: {4}, X: {0}, Y: {1}, Width: {2}, Height: {3}", x, y, width, height, windowId)); offset += 9; } } break; case 0x80: forceFirstOds = true; #if DEBUG log.AppendLine($"0x80 - END offset={position} size={segment.Size}"); #endif if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes.Count > 0 ? palettes : lastPalettes)) { pcsList.Add(latestPcs); } latestPcs = null; } break; default: #if DEBUG log.AppendLine($"0x?? - END offset={position} UNKNOWN SEGMENT TYPE={segment.Type}"); #endif break; } } catch (IndexOutOfRangeException e) { log.Append($"Index of of range at pos {position - headerBuffer.Length}: {e.StackTrace}"); } position += segment.Size; segmentCount++; } if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes.Count > 0 ? palettes : lastPalettes)) { pcsList.Add(latestPcs); } } for (int pcsIndex = 1; pcsIndex < pcsList.Count; pcsIndex++) { var prev = pcsList[pcsIndex - 1]; if (prev.EndTime == 0) { prev.EndTime = pcsList[pcsIndex].StartTime; } } pcsList.RemoveAll(pcs => pcs.PcsObjects.Count == 0); foreach (var pcs in pcsList) { foreach (var odsList in pcs.BitmapObjects) { if (odsList.Count > 1) { int bufSize = 0; foreach (var ods in odsList) { bufSize += ods.Fragment.ImagePacketSize; } byte[] buf = new byte[bufSize]; int offset = 0; foreach (var ods in odsList) { Buffer.BlockCopy(ods.Fragment.ImageBuffer, 0, buf, offset, ods.Fragment.ImagePacketSize); offset += ods.Fragment.ImagePacketSize; } odsList[0].Fragment.ImageBuffer = buf; odsList[0].Fragment.ImagePacketSize = bufSize; while (odsList.Count > 1) { odsList.RemoveAt(1); } } } } for (int pcsIndex = pcsList.Count - 1; pcsIndex > 0; pcsIndex--) { var cur = pcsList[pcsIndex]; var prev = pcsList[pcsIndex - 1]; if (Math.Abs(prev.EndTime - cur.StartTime) < 10 && prev.Size.Width == cur.Size.Width && prev.Size.Height == cur.Size.Height) { if (cur.BitmapObjects.Count > 0 && cur.BitmapObjects[0].Count > 0 && prev.BitmapObjects.Count > 0 && prev.BitmapObjects[0].Count > 0 && ByteArraysEqual(cur.BitmapObjects[0][0].Fragment.ImageBuffer, prev.BitmapObjects[0][0].Fragment.ImageBuffer)) { prev.EndTime = cur.EndTime; pcsList.RemoveAt(pcsIndex); } } } // save last palette if (lastPalettes != null && palettes.Count > 0) { lastPalettes.Clear(); foreach (var palette in palettes) { lastPalettes.Add(palette.Key, palette.Value); } } return(pcsList); }
private static bool CompletePcs(PcsData pcs, Dictionary<int, List<OdsData>> bitmapObjects, Dictionary<int, List<PaletteInfo>> palettes) { if (pcs == null || pcs.PcsObjects == null || palettes == null) { return false; } if (pcs.PcsObjects.Count == 0) { return true; } if (!palettes.ContainsKey(pcs.PaletteId)) { return false; } pcs.PaletteInfos = new List<PaletteInfo>(palettes[pcs.PaletteId]); pcs.BitmapObjects = new List<List<OdsData>>(); foreach (int objId in pcs.PcsObjects.Select(t => t.ObjectId)) { if (!bitmapObjects.ContainsKey(objId)) { return false; } pcs.BitmapObjects.Add(bitmapObjects[objId]); } return true; }
public static List <PcsData> ParseBluRaySup(Stream ms, StringBuilder log, bool fromMatroskaFile) { SupSegment segment; long position = ms.Position; int segmentCount = 0; var palettes = new Dictionary <int, List <PaletteInfo> >(); bool forceFirstOds = true; var bitmapObjects = new Dictionary <int, List <OdsData> >(); PcsData latestPcs = null; int latestCompNum = -1; var pcsList = new List <PcsData>(); byte[] buffer; byte[] headerBuffer; if (fromMatroskaFile) { headerBuffer = new byte[3]; } else { headerBuffer = new byte[HeaderSize]; } while (position < ms.Length) { ms.Seek(position, SeekOrigin.Begin); // Read segment header ms.Read(headerBuffer, 0, headerBuffer.Length); if (fromMatroskaFile) { segment = ParseSegmentHeaderFromMatroska(headerBuffer); } else { segment = ParseSegmentHeader(headerBuffer, log); } position += headerBuffer.Length; // Read segment data buffer = new byte[segment.Size]; ms.Read(buffer, 0, buffer.Length); log.Append(segmentCount + ": "); switch (segment.Type) { case 0x14: // Palette if (latestPcs != null) { log.AppendLine(string.Format("0x14 - Palette - PDS offset={0} size={1}", position, segment.Size)); PdsData pds = ParsePds(buffer, segment); log.AppendLine(pds.Message); if (pds.PaletteInfo != null) { if (!palettes.ContainsKey(pds.PaletteId)) { palettes[pds.PaletteId] = new List <PaletteInfo>(); } else { if (latestPcs.PaletteUpdate) { palettes[pds.PaletteId].RemoveAt(palettes[pds.PaletteId].Count - 1); } else { log.AppendLine("Extra Palette"); } } palettes[pds.PaletteId].Add(pds.PaletteInfo); } } break; case 0x15: // Image bitmap data if (latestPcs != null) { log.AppendLine(string.Format("0x15 - Bitmap data - ODS offset={0} size={1}", position, segment.Size)); OdsData ods = ParseOds(buffer, segment, forceFirstOds); log.AppendLine(ods.Message); if (!latestPcs.PaletteUpdate) { List <OdsData> odsList; if (ods.IsFirst) { odsList = new List <OdsData>(); odsList.Add(ods); bitmapObjects[ods.ObjectId] = odsList; } else { if (bitmapObjects.TryGetValue(ods.ObjectId, out odsList)) { odsList.Add(ods); } else { log.AppendLine(string.Format("INVALID ObjectId {0} in ODS, offset={1}", ods.ObjectId, position)); } } } else { log.AppendLine(string.Format("Bitmap Data Ignore due to PaletteUpdate offset={0}", position)); } forceFirstOds = false; } break; case 0x16: // Picture time codes if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes)) { pcsList.Add(latestPcs); } latestPcs = null; } log.AppendLine(string.Format("0x16 - Picture codes, offset={0} size={1}", position, segment.Size)); forceFirstOds = true; PcsData nextPcs = ParsePicture(buffer, segment); log.AppendLine(nextPcs.Message); latestPcs = nextPcs; latestCompNum = nextPcs.CompNum; if (latestPcs.CompositionState == CompositionState.EpochStart) { bitmapObjects.Clear(); palettes.Clear(); } break; case 0x17: // Window display if (latestPcs != null) { log.AppendLine(string.Format("0x17 - Window display offset={0} size={1}", position, segment.Size)); int windowCount = buffer[0]; int offset = 0; for (int nextWindow = 0; nextWindow < windowCount; nextWindow++) { int windowId = buffer[1 + offset]; int x = BigEndianInt16(buffer, 2 + offset); int y = BigEndianInt16(buffer, 4 + offset); int width = BigEndianInt16(buffer, 6 + offset); int height = BigEndianInt16(buffer, 8 + offset); log.AppendLine(string.Format("WinId: {4}, X: {0}, Y: {1}, Width: {2}, Height: {3}", x, y, width, height, windowId)); offset += 9; } } break; case 0x80: forceFirstOds = true; log.AppendLine(string.Format("0x80 - END offset={0} size={1}", position, segment.Size)); if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes)) { pcsList.Add(latestPcs); } latestPcs = null; } break; default: log.AppendLine(string.Format("0x?? - END offset={0} UNKOWN SEGMENT TYPE={1}", position, segment.Type)); break; } position += segment.Size; segmentCount++; } if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes)) { pcsList.Add(latestPcs); } latestPcs = null; } for (int pcsIndex = 1; pcsIndex < pcsList.Count; pcsIndex++) { pcsList[pcsIndex - 1].EndTime = pcsList[pcsIndex].StartTime; } pcsList.RemoveAll(pcs => pcs.PcsObjects.Count == 0); foreach (PcsData pcs in pcsList) { foreach (List <OdsData> odsList in pcs.BitmapObjects) { if (odsList.Count > 1) { int bufSize = 0; foreach (OdsData ods in odsList) { bufSize += ods.Fragment.ImagePacketSize; } byte[] buf = new byte[bufSize]; int offset = 0; foreach (OdsData ods in odsList) { Buffer.BlockCopy(ods.Fragment.ImageBuffer, 0, buf, offset, ods.Fragment.ImagePacketSize); offset += ods.Fragment.ImagePacketSize; } odsList[0].Fragment.ImageBuffer = buf; odsList[0].Fragment.ImagePacketSize = bufSize; while (odsList.Count > 1) { odsList.RemoveAt(1); } } } } for (int pcsIndex = pcsList.Count - 1; pcsIndex > 0; pcsIndex--) { var cur = pcsList[pcsIndex]; var prev = pcsList[pcsIndex - 1]; if (Math.Abs(prev.EndTime - cur.StartTime) < 10 && prev.Size.Width == cur.Size.Width && prev.Size.Height == cur.Size.Height) { if (cur.BitmapObjects.Count > 0 && cur.BitmapObjects[0].Count > 0 && prev.BitmapObjects.Count > 0 && prev.BitmapObjects[0].Count > 0 && ByteArraysEqual(cur.BitmapObjects[0][0].Fragment.ImageBuffer, prev.BitmapObjects[0][0].Fragment.ImageBuffer)) { prev.EndTime = cur.EndTime; pcsList.RemoveAt(pcsIndex); } } } return(pcsList); }
public static List <PcsData> ParseBluRaySup(Stream ms, StringBuilder log, bool fromMatroskaFile, Dictionary <int, List <PaletteInfo> > lastPalettes, Dictionary <int, List <OdsData> > bitmapObjects) { long position = ms.Position; int segmentCount = 0; var palettes = new Dictionary <int, List <PaletteInfo> >(); bool forceFirstOds = true; PcsData latestPcs = null; var pcsList = new List <PcsData>(); var headerBuffer = fromMatroskaFile ? new byte[3] : new byte[HeaderSize]; while (ms.Read(headerBuffer, 0, headerBuffer.Length) == headerBuffer.Length) { var segment = fromMatroskaFile ? ParseSegmentHeaderFromMatroska(headerBuffer) : ParseSegmentHeader(headerBuffer, log); position += headerBuffer.Length; try { // Read segment data var buffer = new byte[segment.Size]; var bytesRead = ms.Read(buffer, 0, buffer.Length); if (bytesRead < buffer.Length) { break; } #if DEBUG log.Append(segmentCount + ": "); #endif switch (segment.Type) { case 0x14: // Palette if (latestPcs != null) { #if DEBUG log.AppendLine($"0x14 - Palette - PDS offset={position} size={segment.Size}"); #endif var pds = ParsePds(buffer, segment); #if DEBUG log.AppendLine(pds.Message); #endif if (pds.PaletteInfo != null) { if (!palettes.ContainsKey(pds.PaletteId)) { palettes[pds.PaletteId] = new List <PaletteInfo>(); } else { if (latestPcs.PaletteUpdate) { palettes[pds.PaletteId].RemoveAt(palettes[pds.PaletteId].Count - 1); } else { #if DEBUG log.AppendLine("Extra Palette"); #endif } } palettes[pds.PaletteId].Add(pds.PaletteInfo); } } break; case 0x15: // Object Definition Segment (image bitmap data) if (latestPcs != null) { #if DEBUG log.AppendLine($"0x15 - Bitmap data - ODS offset={position} size={segment.Size}"); #endif var ods = ParseOds(buffer, segment, forceFirstOds); #if DEBUG log.AppendLine(ods.Message); #endif if (!latestPcs.PaletteUpdate) { List <OdsData> odsList; if (ods.IsFirst) { odsList = new List <OdsData> { ods }; bitmapObjects[ods.ObjectId] = odsList; } else { if (bitmapObjects.TryGetValue(ods.ObjectId, out odsList)) { odsList.Add(ods); } else { #if DEBUG log.AppendLine($"INVALID ObjectId {ods.ObjectId} in ODS, offset={position}"); #endif } } } else { #if DEBUG log.AppendLine($"Bitmap Data Ignore due to PaletteUpdate offset={position}"); #endif } forceFirstOds = false; } break; case 0x16: // Picture time codes if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes.Count > 0 ? palettes : lastPalettes)) { pcsList.Add(latestPcs); } } #if DEBUG log.AppendLine($"0x16 - Picture codes, offset={position} size={segment.Size}"); #endif forceFirstOds = true; var nextPcs = ParsePicture(buffer, segment); if (nextPcs.StartTime > 0 && pcsList.Count > 0 && pcsList.Last().EndTime == 0) { pcsList.Last().EndTime = nextPcs.StartTime; } #if DEBUG log.AppendLine(nextPcs.Message); #endif latestPcs = nextPcs; if (latestPcs.CompositionState == CompositionState.EpochStart) { bitmapObjects.Clear(); palettes.Clear(); } break; case 0x17: // Window display if (latestPcs != null) { #if DEBUG log.AppendLine($"0x17 - Window display offset={position} size={segment.Size}"); #endif int windowCount = buffer[0]; int offset = 0; for (int nextWindow = 0; nextWindow < windowCount; nextWindow++) { int windowId = buffer[1 + offset]; int x = BigEndianInt16(buffer, 2 + offset); int y = BigEndianInt16(buffer, 4 + offset); int width = BigEndianInt16(buffer, 6 + offset); int height = BigEndianInt16(buffer, 8 + offset); log.AppendLine(string.Format("WinId: {4}, X: {0}, Y: {1}, Width: {2}, Height: {3}", x, y, width, height, windowId)); offset += 9; } } break; case 0x80: forceFirstOds = true; #if DEBUG log.AppendLine($"0x80 - END offset={position} size={segment.Size}"); #endif if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes.Count > 0 ? palettes : lastPalettes)) { pcsList.Add(latestPcs); } latestPcs = null; } break; default: #if DEBUG log.AppendLine($"0x?? - END offset={position} UNKNOWN SEGMENT TYPE={segment.Type}"); #endif break; } } catch (IndexOutOfRangeException e) { log.Append($"Index of of range at pos {position - headerBuffer.Length}: {e.StackTrace}"); } position += segment.Size; segmentCount++; } if (latestPcs != null) { if (CompletePcs(latestPcs, bitmapObjects, palettes.Count > 0 ? palettes : lastPalettes)) { pcsList.Add(latestPcs); } } for (int pcsIndex = 1; pcsIndex < pcsList.Count; pcsIndex++) { var prev = pcsList[pcsIndex - 1]; if (prev.EndTime == 0) { prev.EndTime = pcsList[pcsIndex].StartTime; } } pcsList.RemoveAll(pcs => pcs.PcsObjects.Count == 0); foreach (var pcs in pcsList) { foreach (var odsList in pcs.BitmapObjects) { if (odsList.Count > 1) { int bufSize = 0; foreach (var ods in odsList) { bufSize += ods.Fragment.ImagePacketSize; } byte[] buf = new byte[bufSize]; int offset = 0; foreach (var ods in odsList) { Buffer.BlockCopy(ods.Fragment.ImageBuffer, 0, buf, offset, ods.Fragment.ImagePacketSize); offset += ods.Fragment.ImagePacketSize; } odsList[0].Fragment.ImageBuffer = buf; odsList[0].Fragment.ImagePacketSize = bufSize; while (odsList.Count > 1) { odsList.RemoveAt(1); } } } } if (!Configuration.Settings.SubtitleSettings.BluRaySupSkipMerge || Configuration.Settings.SubtitleSettings.BluRaySupForceMergeAll) { // Merge images that are the same (probably due to fade) // First we find groups with same pixels var removeIndices = new List <DeleteIndex>(); var deleteNo = 0; for (var pcsIndex = pcsList.Count - 1; pcsIndex > 0; pcsIndex--) { var cur = pcsList[pcsIndex]; var prev = pcsList[pcsIndex - 1]; if (Math.Abs(prev.EndTime - cur.StartTime) < 10 && prev.Size.Width == cur.Size.Width && prev.Size.Height == cur.Size.Height) { if (cur.BitmapObjects.Count > 0 && cur.BitmapObjects[0].Count > 0 && prev.BitmapObjects.Count == cur.BitmapObjects.Count && prev.BitmapObjects[0].Count == cur.BitmapObjects[0].Count) { var remove = true; for (var k = 0; k < cur.BitmapObjects.Count; k++) { var c = cur.BitmapObjects[k]; var p = prev.BitmapObjects[k]; if (p.Count == c.Count) { for (var j = 0; j < c.Count; j++) { if (!ByteArraysEqual(c[j].Fragment.ImageBuffer, p[j].Fragment.ImageBuffer)) { remove = false; break; } } } else { remove = false; break; } } if (remove) { if (!removeIndices.Any(p => p.Number == deleteNo && p.Index == pcsIndex - 1)) { removeIndices.Add(new DeleteIndex { Number = deleteNo, Index = pcsIndex - 1 }); } if (!removeIndices.Any(p => p.Number == deleteNo && p.Index == pcsIndex)) { removeIndices.Add(new DeleteIndex { Number = deleteNo, Index = pcsIndex }); } } else { deleteNo++; } } } else { deleteNo++; } } // Use the middle image of each group with same pixels int mergeCount = removeIndices.GroupBy(p => p.Number).Count(); foreach (var group in removeIndices.GroupBy(p => p.Number).OrderBy(p => p.Key)) { var arr = group.OrderByDescending(p => p.Index).ToArray(); var middle = (int)Math.Round(group.Count() / 2.0); var middleElement = arr[middle]; if (!QualifiesForMerge(arr, pcsList, mergeCount)) { // Don't know really how to do this... so "QualifiesForMerge" is mostly guessing // See https://github.com/SubtitleEdit/subtitleedit/issues/5713 continue; } pcsList[middleElement.Index].StartTime = pcsList[arr.Last().Index].StartTime; pcsList[middleElement.Index].EndTime = pcsList[arr.First().Index].EndTime; foreach (var deleteIndex in group.OrderByDescending(p => p.Index)) { if (deleteIndex != middleElement) { pcsList.RemoveAt(deleteIndex.Index); } } } } // save last palette if (lastPalettes != null && palettes.Count > 0) { lastPalettes.Clear(); foreach (var palette in palettes) { lastPalettes.Add(palette.Key, palette.Value); } } return(pcsList); }