/* * Try sending some audio data to the Decklink. * Call only with current_audio_pkt != NULL. * Will set current_audio_pkt to NULL and delete the packet * if it is fully consumed. * Return number of samples consumed. */ int try_finish_current_audio_packet( ) { uint32_t n_consumed; uint32_t n_left; uint32_t buffer; deckLinkOutput->GetBufferedAudioSampleFrameCount(&buffer); fprintf(stderr, "audio buffer = %u ", buffer); assert(current_audio_pkt != NULL); n_left = current_audio_pkt->n_frames( ) - samples_written_from_current_audio_pkt; if (n_left == 0) { fprintf(stderr, "Audio warning: This should not happen!\n"); return 1; } if (deckLinkOutput->ScheduleAudioSamples( current_audio_pkt->sample( samples_written_from_current_audio_pkt ), n_left, 0, 0, &n_consumed) != S_OK) { throw std::runtime_error( "Failed to schedule audio samples" ); } if (n_consumed == n_left) { delete current_audio_pkt; current_audio_pkt = NULL; } else if (n_consumed < n_left) { samples_written_from_current_audio_pkt += n_consumed; } else { throw std::runtime_error("This should not happen"); } deckLinkOutput->GetBufferedAudioSampleFrameCount(&buffer); fprintf(stderr, "-> %u\n", buffer); return n_consumed; }
virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples( bool preroll ) { // Provide more audio samples to the DeckLink API HRESULT result = S_OK; uint32_t count = m_fifo->used / m_channels; uint32_t buffered = count; if ( count // Stay under preferred buffer level && ( S_OK == m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &buffered ) ) && buffered < m_maxAudioBuffer ) { uint32_t written = 0; buffered = m_maxAudioBuffer - buffered; count = buffered > count ? count : buffered; result = m_deckLinkOutput->ScheduleAudioSamples( m_fifo->buffer, count, 0, 0, &written ); if ( written ) sample_fifo_remove( m_fifo, written * m_channels ); } return result; }
HRESULT render( mlt_frame frame ) { HRESULT result = S_OK; // Get the audio double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ); if ( speed == 1.0 ) { mlt_audio_format format = mlt_audio_s16; int frequency = bmdAudioSampleRate48kHz; int samples = mlt_sample_calculator( m_fps, frequency, m_count ); int16_t *pcm = 0; if ( !mlt_frame_get_audio( frame, (void**) &pcm, &format, &frequency, &m_channels, &samples ) ) { int count = samples; if ( !m_isPrerolling ) { uint32_t audioCount = 0; uint32_t videoCount = 0; // Check for resync m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &audioCount ); m_deckLinkOutput->GetBufferedVideoFrameCount( &videoCount ); // Underflow typically occurs during non-normal speed playback. if ( audioCount < 1 || videoCount < 1 ) { // Upon switching to normal playback, buffer some frames faster than realtime. mlt_log_info( &m_consumer, "buffer underrun: audio buf %u video buf %u frames\n", audioCount, videoCount ); m_prerollCounter = 0; } // While rebuffering if ( isBuffering() ) { // Only append audio to reach the ideal level and not overbuffer. int ideal = ( m_preroll - 1 ) * bmdAudioSampleRate48kHz / m_fps; int actual = m_fifo->used / m_channels + audioCount; int diff = ideal / 2 - actual; count = diff < 0 ? 0 : diff < count ? diff : count; } } if ( count > 0 ) sample_fifo_append( m_fifo, pcm, count * m_channels ); } } // Create video frames while pre-rolling if ( m_isPrerolling ) { createFrame(); if ( !m_videoFrame ) { mlt_log_error( &m_consumer, "failed to create video frame\n" ); return S_FALSE; } } // Get the video if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "rendered") ) { mlt_image_format format = mlt_image_yuv422; uint8_t* image = 0; uint8_t* buffer = 0; if ( !mlt_frame_get_image( frame, &image, &format, &m_width, &m_height, 0 ) ) { m_videoFrame = (IDeckLinkMutableVideoFrame*) mlt_deque_pop_back( m_videoFrameQ ); m_videoFrame->GetBytes( (void**) &buffer ); if ( m_displayMode->GetFieldDominance() == bmdUpperFieldFirst ) // convert lower field first to top field first swab( image, buffer + m_width * 2, m_width * ( m_height - 1 ) * 2 ); else swab( image, buffer, m_width * m_height * 2 ); m_deckLinkOutput->ScheduleVideoFrame( m_videoFrame, m_count * m_duration, m_duration, m_timescale ); mlt_deque_push_front( m_videoFrameQ, m_videoFrame ); } } else { mlt_log_verbose( &m_consumer, "dropped video frame\n" ); } ++m_count; // Check for end of pre-roll if ( ++m_prerollCounter > m_preroll && m_isPrerolling ) { // Start audio and video output m_deckLinkOutput->EndAudioPreroll(); m_deckLinkOutput->StartScheduledPlayback( 0, m_timescale, 1.0 ); m_isPrerolling = false; } return result; }