/** * Rearranges audio blocks in correct number of samples. * @note (FIXME) This is left here for historical reasons. It belongs in the * output code. Besides, this operation should be avoided if possible. */ static block_t *aout_OutputSlice (audio_output_t *p_aout) { aout_packet_t *p = aout_packet (p_aout); aout_fifo_t *p_fifo = &p->partial; const unsigned samples = p->samples; assert( samples > 0 ); /* Retrieve the date of the next buffer. */ date_t exact_start_date = p->fifo.end_date; mtime_t start_date = date_Get( &exact_start_date ); /* Check if there is enough data to slice a new buffer. */ aout_buffer_t *p_buffer = p_fifo->p_first; if( p_buffer == NULL ) return NULL; /* Find the earliest start date available. */ if ( start_date == VLC_TS_INVALID ) { start_date = p_buffer->i_pts; date_Set( &exact_start_date, start_date ); } /* Compute the end date for the new buffer. */ mtime_t end_date = date_Increment( &exact_start_date, samples ); /* Check that we have enough samples (TODO merge with next loop). */ for( unsigned available = 0; available < samples; ) { p_buffer = p_buffer->p_next; if( p_buffer == NULL ) return NULL; available += p_buffer->i_nb_samples; } if( AOUT_FMT_LINEAR( &p_aout->format ) ) { const unsigned framesize = p_aout->format.i_bytes_per_frame; /* Build packet with adequate number of samples */ unsigned needed = samples * framesize; p_buffer = block_Alloc( needed ); if( unlikely(p_buffer == NULL) ) /* XXX: should free input buffers */ return NULL; p_buffer->i_nb_samples = samples; for( uint8_t *p_out = p_buffer->p_buffer; needed > 0; ) { aout_buffer_t *p_inbuf = p_fifo->p_first; if( unlikely(p_inbuf == NULL) ) { msg_Err( p_aout, "packetization error" ); vlc_memset( p_out, 0, needed ); break; } const uint8_t *p_in = p_inbuf->p_buffer; size_t avail = p_inbuf->i_nb_samples * framesize; if( avail > needed ) { vlc_memcpy( p_out, p_in, needed ); p_fifo->p_first->p_buffer += needed; p_fifo->p_first->i_buffer -= needed; needed /= framesize; p_fifo->p_first->i_nb_samples -= needed; mtime_t t = needed * CLOCK_FREQ / p_aout->format.i_rate; p_fifo->p_first->i_pts += t; p_fifo->p_first->i_length -= t; break; } vlc_memcpy( p_out, p_in, avail ); needed -= avail; p_out += avail; /* Next buffer */ aout_BufferFree( aout_FifoPop( p_fifo ) ); } } else p_buffer = aout_FifoPop( p_fifo ); p_buffer->i_pts = start_date; p_buffer->i_length = end_date - start_date; return p_buffer; }
/** * Dequeues the next audio packet (a.k.a. audio fragment). * The audio output plugin must first call aout_PacketPlay() to queue the * decoded audio samples. Typically, audio_output_t.pf_play is set to, or calls * aout_PacketPlay(). * @note This function is considered legacy. Please do not use this function in * new audio output plugins. * @param p_aout audio output instance * @param start_date expected PTS of the audio packet */ block_t *aout_PacketNext (audio_output_t *p_aout, mtime_t start_date) { aout_packet_t *p = aout_packet (p_aout); aout_fifo_t *p_fifo = &p->fifo; block_t *p_buffer; const bool b_can_sleek = !AOUT_FMT_LINEAR(&p_aout->format); const mtime_t now = mdate (); const mtime_t threshold = (b_can_sleek ? start_date : now) - AOUT_MAX_PTS_DELAY; vlc_mutex_lock( &p->lock ); if( p->pause_date != VLC_TS_INVALID ) goto out; /* paused: do not dequeue buffers */ for (;;) { p_buffer = p_fifo->p_first; if (p_buffer == NULL) goto out; /* nothing to play */ if (p_buffer->i_pts >= threshold) break; /* Drop the audio sample if the audio output is really late. * In the case of b_can_sleek, we don't use a resampler so we need to * be a lot more severe. */ msg_Dbg (p_aout, "audio output is too slow (%"PRId64" us): " " trashing %"PRId64" us", threshold - p_buffer->i_pts, p_buffer->i_length); block_Release (aout_FifoPop (p_fifo)); } mtime_t delta = start_date - p_buffer->i_pts; /* This assumes that all buffers have the same duration. This is true * since aout_PacketPlay() (aout_OutputSlice()) is used. */ if (0 >= delta + p_buffer->i_length) { if (!p->starving) { msg_Dbg (p_aout, "audio output is starving (%"PRId64"), " "playing silence", delta); p->starving = true; } goto out; /* nothing to play _yet_ */ } p->starving = false; p_buffer = aout_FifoPop( p_fifo ); if (!b_can_sleek && (delta < -AOUT_MAX_PTS_ADVANCE || AOUT_MAX_PTS_DELAY < delta)) { msg_Warn (p_aout, "audio output out of sync, " "adjusting dates (%"PRId64" us)", delta); aout_FifoMoveDates (&p->partial, delta); aout_FifoMoveDates (p_fifo, delta); p->time_report = delta; } vlc_mutex_unlock( &p->lock ); return p_buffer; out: vlc_mutex_unlock( &p->lock ); return NULL; }