/// <summary> /// Create a new PES packet manager. /// </summary> /// <param name="other">Template manager.</param> public Packet( Packet other ) : this( other.m_Manager, other.PID ) { // Clone the type m_Video = other.m_Video; // Copy flags IgnorePTS = other.IgnorePTS; }
/// <summary> /// Remove the next complete PES package from the waiting queue /// and <see cref="SendTo"/> the transport stream. /// </summary> /// <remarks> /// Only call this method if the queue is not empty. /// </remarks> /// <param name="packet">First packet already read from the queue.</param> /// <returns>Set if anything has been sent.</returns> private bool Dequeue( Packet packet ) { // Dequeue Pending.RemoveAt( 0 ); // Send all return packet.SendTo(); }
/// <summary> /// Append a complete PES package to the processing queue. /// </summary> /// <param name="buffer">A complete PES package.</param> public void Enqueue( Packet buffer ) { // Count m_LastPacket = DateTime.UtcNow; // Set flag if (!PTSMissing) if (IgnorePTS) PTSMissing = true; else if (buffer.Count > 0) PTSMissing = (buffer.PTS < 0); // Remember Pending.Add( buffer ); // Check if (Pending.Count > m_MaxQueue) m_MaxQueue = Pending.Count; }
/// <summary> /// Create a new transport stream identifier for a new stream /// in this transport stream. /// </summary> /// <param name="type">Type of the stream.</param> /// <param name="encoding">Encoding type of the stream.</param> /// <param name="isPCR">Set if the stream will be the PCR reference.</param> /// <param name="noPTS">Set if the stream should not participate in PTS synchronisation.</param> /// <param name="info">Information on the contents of a subtitle stream.</param> /// <param name="noPCR">Set to disable PCR from PTS generation.</param> /// <returns>A randomly choosen but unique transport stream identifier.</returns> private short AddStream( StreamTypes type, byte encoding, bool noPCR, bool noPTS, EPG.SubtitleInfo[] info, out bool isPCR ) { // Create pid short pid = NextPID++; // Make key int keyPID = pid; // Forward isPCR = ProgramMap.Add( type, encoding, pid, noPCR, info ); // Reload lock (m_Queue) { // Force PAT change PATSent = false; // Load Packet buffers = (Packet) m_Buffers[keyPID]; // Create new if (null == buffers) { // Create new buffers = new Packet( this, keyPID ); // Remember m_Buffers[keyPID] = buffers; } // Set up if (StreamTypes.Video == type) buffers.SetAudioVideo( true ); else if ((StreamTypes.Audio == type) || (StreamTypes.Private == type)) buffers.SetAudioVideo( false ); // May disable PTS synchronisation (e.g. for TeleText streams) buffers.IgnorePTS = noPTS; } // Report return pid; }
/// <summary> /// Send the buffer to the target streams. /// </summary> /// <param name="buf">Full buffer to send.</param> /// <param name="source">The originator of the buffer.</param> /// <returns>Set if buffer is not empty.</returns> internal bool SendBuffer( byte[] buf, Packet source ) { // Validate Debug.Assert( (buf.Length % FullSize) == 0 ); // Count m_Length += buf.Length; // Count sometimes if (source != null) { // Count bytes for audio and video only if (source.IsAudioOrVideo) m_AVLength += buf.Length; // See if PCR is now available if (source.PID == -m_PCRAvailable) m_PCRAvailable = source.PID; } // Has file output if (null != Target) { // Must synchronize WaitDisk(); // Start an asynchronous write operation m_Writer = Target.BeginWrite( buf, 0, buf.Length, null, null ); } // Has buffered output if (null != BufferedTarget) { // See if anyone is interested in PCR reports var pcrReport = OnWritingPCR; // Check mode if (pcrReport != null) if ((buf[3] & 0x20) != 0) if (buf[4] >= 1) if ((buf[5] & 0x10) != 0) pcrReport( BufferedTarget.FilePath, BufferedTarget.TotalBytesWritten, buf ); // Send to file BufferedTarget.Write( buf, 0, buf.Length ); } // See if there is a file switch pending var pendingSwitch = Interlocked.Exchange( ref PendingTarget, null ); // Activate the new one - this will enforce a flush on the previous file and may lead to corruption if (pendingSwitch != null) using (BufferedTarget) BufferedTarget = pendingSwitch; // Nothing to do if (buf.Length < 1) return false; // Forward to optional stream m_UDPStream.Send( buf ); // Read consumer var consumer = InProcessConsumer; // Finally send to in-process consumer if (null != consumer) consumer( buf ); // Found some return true; }
/// <summary> /// Send all buffered data to the transport stream. /// </summary> /// <param name="pid"></param> /// <param name="withPCR">Set to flush PCR, too.</param> private void Enqueue( int pid, bool withPCR ) { // Attach to the list Packet buffers = (Packet) m_Buffers[pid]; // Is empty if (null == buffers) return; // Collector packet Packet collect = null; // Create if not shutting down the stream if (!withPCR) { // Create new collect = new Packet( buffers ); // Clone PTS from PES collect.PTS = buffers.PTS; } else { // Flush queue while (buffers.HasQueue) buffers.Dequeue(); } // Mode bool isPCR = false; // Process all for (int ib = 0, imax = buffers.Count; ib < imax; ) { // Load next byte[] buf = buffers[ib++]; // Switch only if (null == buf) { // Mark isPCR = true; // Next continue; } // Last PCR belongs to next PES if (isPCR) if (ib == imax) if (!withPCR) { // Reset buffers.Clear(); // Append as PCR buffers.Add( null ); buffers.Add( buf ); // Remember collected data if (collect.Count > 0) buffers.Enqueue( collect ); // Finish return; } // Reset flag isPCR = false; // Check mode if (null == collect) { // Send to file immediately to clenaup all buffers SendBuffer( buf, buffers ); } else { // Save for later processing collect.Add( buf ); } } // Reset buffers.Clear(); // Remember collected data if (null != collect) buffers.Enqueue( collect ); }