/// <summary> /// Updates the CC Packet State Buffer and Renders it. /// </summary> /// <param name="channel">The channel.</param> /// <param name="clockPosition">The clock position.</param> public void Render(CaptionsChannel channel, TimeSpan clockPosition) { if (Buffer.UpdateState(channel, clockPosition)) { PaintBuffer(); } }
/// <summary> /// Updates the state using the packets that were demuxed into the specified channel. /// This can be called outside the GUI thread. /// </summary> /// <param name="channel">The channel.</param> /// <param name="clockPosition">The clock position.</param> /// <returns>A boolean to determine if the display needs repainting.</returns> public bool UpdateState(CaptionsChannel channel, TimeSpan clockPosition) { lock (SyncLock) { var needsRepaint = false; // Reset the buffer state if the channels don't match or if we have a timeout if (channel != Channel || DateTime.UtcNow.Subtract(LastReceiveTime).TotalSeconds > TimeoutSeconds) { Reset(); Channel = channel; needsRepaint = true; } if (channel == CaptionsChannel.CCP) { return(needsRepaint); } // Dequeue packets for all channels but only process the current channel packets List <ClosedCaptionPacket> packets = null; for (var c = 1; c <= 4; c++) { var currentChannel = (CaptionsChannel)c; var dequeuedPackets = DequeuePackets(ChannelPacketBuffer[currentChannel], clockPosition.Ticks); if (currentChannel == Channel) { packets = dequeuedPackets; } } // Check if we have at least 1 dequeued packet if (packets == null || packets.Count <= 0) { return(needsRepaint); } // Update the last received time LastReceiveTime = DateTime.UtcNow; // Start processing the dequeued packets for the given channel foreach (var packet in packets) { // Skip duplicated control codes if (CurrentPacket != null && CurrentPacket.IsRepeatedControlCode(packet)) { CurrentPacket = packet; continue; } // Update the current packet (we need this to detect duplicated control codes) CurrentPacket = packet; // Now, go ahead and process the packet updating the state switch (packet.PacketType) { case CaptionsPacketType.Color: { if (StateMode == ParserStateMode.Buffered || StateMode == ParserStateMode.Scrolling) { if (packet.Color == CaptionsColor.ForegroundBlackUnderline) { IsUnderlined = true; } if (packet.Color == CaptionsColor.WhiteItalics) { IsItalics = true; } } break; } case CaptionsPacketType.MidRow: { if (StateMode == ParserStateMode.Buffered || StateMode == ParserStateMode.Scrolling) { IsItalics = packet.IsItalics; IsUnderlined = packet.IsUnderlined; } break; } case CaptionsPacketType.Command: { if (ProcessCommandPacket(packet)) { needsRepaint = true; } break; } case CaptionsPacketType.Preamble: { ProcessPreamblePacket(packet); break; } case CaptionsPacketType.Tabs: { if (StateMode == ParserStateMode.Scrolling || StateMode == ParserStateMode.Buffered) { CursorColumnIndex += packet.Tabs; } break; } case CaptionsPacketType.Text: { if (ProcessTextPacket(packet)) { needsRepaint = true; } break; } case CaptionsPacketType.XdsClass: { // Change state back and forth StateMode = packet.XdsClass == CaptionsXdsClass.EndAll ? ParserStateMode.None : ParserStateMode.XDS; break; } case CaptionsPacketType.PrivateCharset: case CaptionsPacketType.Unrecognized: case CaptionsPacketType.NullPad: default: { break; } } } return(needsRepaint); } }