void ElementaryStream::Muxed (unsigned int bytes_muxed) { clockticks decode_time; if (bytes_muxed == 0 || MuxCompleted() ) return; /* Work through what's left of the current AU and the following AU's updating the info until we reach a point where an AU had to be split between packets. NOTE: It *is* possible for this loop to iterate. The DTS/PTS field for the packet in this case would have been given the that for the first AU to start in the packet. Whether Joe-Blow's hardware VCD player handles this properly is another matter of course! */ decode_time = RequiredDTS(); while (au_unsent < bytes_muxed) { AUMuxed(true); // Update stream specific tracking // of AUs muxed... bufmodel.Queued(au_unsent, decode_time); bytes_muxed -= au_unsent; new_au_next_sec = NextAU(); if( !new_au_next_sec ) return; decode_time = RequiredDTS(); }; // We've now reached a point where the current AU overran or // fitted exactly. We need to distinguish the latter case // so we can record whether the next packet starts with an // existing AU or not - info we need to decide what PTS/DTS // info to write at the start of the next packet. if (au_unsent > bytes_muxed) { AUMuxed(false); bufmodel.Queued( bytes_muxed, decode_time); au_unsent -= bytes_muxed; new_au_next_sec = false; } else // if (au_unsent == bytes_muxed) { AUMuxed(false); bufmodel.Queued(bytes_muxed, decode_time); new_au_next_sec = NextAU(); } }
void AudioStream::OutputSector ( ) { clockticks PTS; unsigned int max_packet_data; unsigned int actual_payload; unsigned int old_au_then_new_payload; PTS = RequiredDTS(); old_au_then_new_payload = muxinto.PacketPayload( *this, buffers_in_header, false, false ); bool last_packet = Lookahead() == 0; // Ensure we have access units data buffered to allow a sector to be // written. max_packet_data = 0; if( (muxinto.running_out && NextRequiredPTS() > muxinto.runout_PTS) || last_packet) { /* We're now in the last AU of a segment. So we don't want to go beyond it's end when writing sectors. Hence we limit packet payload size to (remaining) AU length. */ max_packet_data = au_unsent+StreamHeaderSize(); } /* CASE: packet starts with new access unit */ if (new_au_next_sec) { actual_payload = muxinto.WritePacket ( max_packet_data, *this, buffers_in_header, PTS, 0, TIMESTAMPBITS_PTS); } /* CASE: packet starts with old access unit, no new one */ /* starts in this very same packet */ else if (!(new_au_next_sec) && (au_unsent >= old_au_then_new_payload)) { actual_payload = muxinto.WritePacket ( max_packet_data, *this, buffers_in_header, 0, 0, TIMESTAMPBITS_NO ); } /* CASE: packet starts with old access unit, a new one */ /* starts in this very same packet */ else /* !(new_au_next_sec) && (au_unsent < old_au_then_new_payload)) */ { /* is there another access unit anyway ? */ if( !last_packet ) { PTS = NextRequiredDTS(); actual_payload = muxinto.WritePacket ( max_packet_data, *this, buffers_in_header, PTS, 0, TIMESTAMPBITS_PTS ); } else { actual_payload = muxinto.WritePacket ( max_packet_data, *this, buffers_in_header, 0, 0, TIMESTAMPBITS_NO ); }; } ++nsec; buffers_in_header = always_buffers_in_header; }
bool VideoStream::MuxPossible( clockticks currentSCR ) { return ( ElementaryStream::MuxPossible(currentSCR) && RequiredDTS() < currentSCR + max_STD_buffer_delay ); }
void VideoStream::OutputSector ( ) { unsigned int max_packet_payload; unsigned int actual_payload; unsigned int old_au_then_new_payload; clockticks DTS,PTS; int autype; max_packet_payload = 0; /* 0 = Fill sector */ /* I-frame aligning. For the last AU of segment or for formats with ACCESS-POINT sectors where I-frame (and preceding headers) are sector aligned. We need to look ahead to see how much we may put into the current packet without without touching the next I-frame (which is supposed to be placed at the start of its own sector). N.b.runout_PTS is the PTS of the after which the next I frame marks the start of the next sequence. */ if( muxinto.sector_align_iframeAUs || muxinto.running_out ) { max_packet_payload = ExcludeNextIFramePayload(); } /* Figure out the threshold payload size below which we can fit more than one AU into a packet N.b. because fitting more than one in imposses an overhead of additional header fields so there is a dead spot where we *have* to stuff the packet rather than start fitting in an extra AU. Slightly over-conservative in the case of the last packet... */ old_au_then_new_payload = muxinto.PacketPayload( *this, buffers_in_header, true, true); /* CASE: Packet starts with new access unit */ if (new_au_next_sec ) { autype = AUType(); // Some types of output format (e.g. DVD) require special // control sectors before the sector starting a new GOP // N.b. this implies muxinto.sector_align_iframeAUs // if( gop_control_packet && autype == IFRAME ) { OutputGOPControlSector(); } // // If we demand every AU should have its own timestamp // We can't start two in the same sector... // if( dtspts_for_all_au && max_packet_payload == 0 ) max_packet_payload = au_unsent; PTS = RequiredPTS(); DTS = RequiredDTS(); actual_payload = muxinto.WritePacket ( max_packet_payload, *this, NewAUBuffers(autype), PTS, DTS, NewAUTimestamps(autype) ); muxinto.IndexLastPacket(*this, autype ); } /* CASE: Packet begins with old access unit, no new one */ /* can begin in the very same packet */ else if ( au_unsent >= old_au_then_new_payload || (max_packet_payload != 0 && au_unsent >= max_packet_payload) ) { actual_payload = muxinto.WritePacket( au_unsent, *this, false, 0, 0, TIMESTAMPBITS_NO ); // No new frame starts so no indexing... } /* CASE: Packet begins with old access unit, a new one */ /* could begin in the very same packet */ else /* if ( !new_au_next_sec && (au_unsent < old_au_then_new_payload)) */ { /* Is there a new access unit ? */ if( Lookahead() != 0 ) { autype = NextAUType(); if( dtspts_for_all_au && max_packet_payload == 0 ) max_packet_payload = au_unsent + Lookahead()->length; PTS = NextRequiredPTS(); DTS = NextRequiredDTS(); actual_payload = muxinto.WritePacket ( max_packet_payload, *this, NewAUBuffers(autype), PTS, DTS, NewAUTimestamps(autype) ); muxinto.IndexLastPacket(*this, autype ); } else { actual_payload = muxinto.WritePacket ( au_unsent, *this, false, 0, 0, TIMESTAMPBITS_NO); } } ++nsec; buffers_in_header = always_buffers_in_header; }
unsigned int LPCMStream::ReadPacketPayload(uint8_t *dst, unsigned int to_read) { unsigned int header_size = LPCMStream::StreamHeaderSize(); bitcount_t read_start = bs.GetBytePos(); unsigned int bytes_read = bs.GetBytes( dst+header_size, to_read-header_size ); bs.Flush( read_start ); clockticks decode_time; bool starting_frame_found = false; uint8_t starting_frame_index = 0; int starting_frame_offset = (new_au_next_sec || au_unsent > bytes_read ) ? 0 : au_unsent; unsigned int frames = 0; unsigned int bytes_muxed = bytes_read; if (bytes_muxed == 0 || MuxCompleted() ) { goto completion; } /* Work through what's left of the current frames and the following frames's updating the info until we reach a point where an frame had to be split between packets. The DTS/PTS field for the packet in this case would have been given the that for the first AU to start in the packet. */ decode_time = RequiredDTS(); while (au_unsent < bytes_muxed) { assert( bytes_muxed > 1 ); bufmodel.Queued(au_unsent, decode_time); bytes_muxed -= au_unsent; if( new_au_next_sec ) { ++frames; if( ! starting_frame_found ) { starting_frame_index = static_cast<uint8_t>(au->dorder % 20); starting_frame_found = true; } } if( !NextAU() ) { goto completion; } new_au_next_sec = true; decode_time = RequiredDTS(); }; // We've now reached a point where the current AU overran or // fitted exactly. We need to distinguish the latter case so we // can record whether the next packet starts with the tail end of // // an already started frame or a new one. We need this info to // decide what PTS/DTS info to write at the start of the next // packet. if (au_unsent > bytes_muxed) { if( new_au_next_sec ) ++frames; bufmodel.Queued( bytes_muxed, decode_time); au_unsent -= bytes_muxed; new_au_next_sec = false; } else // if (au_unsent == bytes_muxed) { bufmodel.Queued(bytes_muxed, decode_time); if( new_au_next_sec ) ++frames; new_au_next_sec = NextAU(); } completion: // Generate the LPCM header... // Note the index counts from the low byte of the offset so // the smallest value is 1! dst[0] = LPCM_SUB_STR_0 + stream_num; dst[1] = frames; dst[2] = (starting_frame_offset+4)>>8; dst[3] = (starting_frame_offset+4)&0xff; unsigned int bps_code; switch( bits_per_sample ) { case 16 : bps_code = 0; break; case 20 : bps_code = 1; break; case 24 : bps_code = 2; break; default : bps_code = 3; break; } dst[4] = starting_frame_index; unsigned int bsf_code = (samples_per_second == 48000) ? 0 : 1; unsigned int channels_code = channels - 1; dst[5] = (bps_code << 6) | (bsf_code << 4) | channels_code; dst[6] = dynamic_range_code; return bytes_read+header_size; }