void setup_audio( ) { /* FIXME hard coded default */ n_channels = 2; audio_in_pipe = new Pipe<AudioPacket *>(OUT_PIPE_SIZE); /* FIXME magic 29.97 related number */ /* Set up empty audio packet for prerolling */ current_audio_pkt = new AudioPacket(48000, n_channels, 2, 25626); samples_written_from_current_audio_pkt = 0; assert(deckLinkOutput != NULL); if (deckLinkOutput->SetAudioCallback(this) != S_OK) { throw std::runtime_error( "Failed to set DeckLink audio callback" ); } if (deckLinkOutput->EnableAudioOutput( bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, n_channels, bmdAudioOutputStreamContinuous) != S_OK) { throw std::runtime_error( "Failed to enable DeckLink audio output" ); } audio_preroll_done = 0; if (deckLinkOutput->BeginAudioPreroll( ) != S_OK) { throw std::runtime_error( "Failed to begin DeckLink audio preroll" ); } while (audio_preroll_done == 0) { /* FIXME: busy wait */ } if (deckLinkOutput->EndAudioPreroll( ) != S_OK) { throw std::runtime_error( "Failed to end DeckLink audio preroll" ); } }
void setup_audio( ) { IOAudioPacket preroll_audio(8008, n_channels); preroll_audio.zero( ); audio_in_pipe = new Pipe<IOAudioPacket *>(OUT_PIPE_SIZE); audio_fifo = new AudioFIFO<int16_t>(n_channels); audio_fifo->add_packet(&preroll_audio); assert(deckLinkOutput != NULL); if (deckLinkOutput->SetAudioCallback(this) != S_OK) { throw std::runtime_error( "Failed to set DeckLink audio callback" ); } if (deckLinkOutput->EnableAudioOutput( bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, n_channels, bmdAudioOutputStreamContinuous) != S_OK) { throw std::runtime_error( "Failed to enable DeckLink audio output" ); } audio_preroll_done = 0; if (deckLinkOutput->BeginAudioPreroll( ) != S_OK) { throw std::runtime_error( "Failed to begin DeckLink audio preroll" ); } while (audio_preroll_done == 0) { /* FIXME: busy wait */ } if (deckLinkOutput->EndAudioPreroll( ) != S_OK) { throw std::runtime_error( "Failed to end DeckLink audio preroll" ); } }
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; }