BMDDisplayMode getDisplayMode( mlt_profile profile, int vancLines ) { IDeckLinkDisplayModeIterator* iter = NULL; IDeckLinkDisplayMode* mode = NULL; BMDDisplayMode result = (BMDDisplayMode) bmdDisplayModeNotSupported; if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK ) { while ( !result && iter->Next( &mode ) == S_OK ) { int width = mode->GetWidth(); int height = mode->GetHeight(); BMDTimeValue duration; BMDTimeScale timescale; mode->GetFrameRate( &duration, ×cale ); double fps = (double) timescale / duration; int p = mode->GetFieldDominance() == bmdProgressiveFrame; m_topFieldFirst = mode->GetFieldDominance() == bmdUpperFieldFirst; m_colorspace = ( mode->GetFlags() & bmdDisplayModeColorspaceRec709 ) ? 709 : 601; mlt_log_verbose( getProducer(), "BMD mode %dx%d %.3f fps prog %d tff %d\n", width, height, fps, p, m_topFieldFirst ); if ( width == profile->width && p == profile->progressive && ( height + vancLines == profile->height || ( height == 486 && profile->height == 480 + vancLines ) ) && fps == mlt_profile_fps( profile ) ) result = mode->GetDisplayMode(); SAFE_RELEASE( mode ); } SAFE_RELEASE( iter ); } return result; }
IDeckLinkDisplayMode* getDisplayMode() { mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( getConsumer() ) ); IDeckLinkDisplayModeIterator* iter = NULL; IDeckLinkDisplayMode* mode = NULL; IDeckLinkDisplayMode* result = 0; if ( m_deckLinkOutput->GetDisplayModeIterator( &iter ) == S_OK ) { while ( !result && iter->Next( &mode ) == S_OK ) { m_width = mode->GetWidth(); m_height = mode->GetHeight(); mode->GetFrameRate( &m_duration, &m_timescale ); m_fps = (double) m_timescale / m_duration; int p = mode->GetFieldDominance() == bmdProgressiveFrame; mlt_log_verbose( getConsumer(), "BMD mode %dx%d %.3f fps prog %d\n", m_width, m_height, m_fps, p ); if ( m_width == profile->width && p == profile->progressive && (int) m_fps == (int) mlt_profile_fps( profile ) && ( m_height == profile->height || ( m_height == 486 && profile->height == 480 ) ) ) result = mode; else SAFE_RELEASE( mode ); } SAFE_RELEASE( iter ); } return result; }
/* lookup the field dominance corresponding to this BMDDisplayMode */ static RawFrame::FieldDominance find_dominance(BMDDisplayMode mode, IDeckLinkDisplayModeIterator *iterator) { IDeckLinkDisplayMode *imode; if (iterator->Next(&imode) != S_OK) { throw std::runtime_error("DeckLink: failed to iterate display modes"); } while (imode) { BMDFieldDominance fd = imode->GetFieldDominance( ); BMDDisplayMode thismode = imode->GetDisplayMode( ); imode->Release( ); if (thismode == mode) { switch (fd) { case bmdLowerFieldFirst: return RawFrame::BOTTOM_FIELD_FIRST; case bmdUpperFieldFirst: return RawFrame::TOP_FIELD_FIRST; case bmdProgressiveFrame: case bmdProgressiveSegmentedFrame: return RawFrame::PROGRESSIVE; default: return RawFrame::UNKNOWN; } } if (iterator->Next(&imode) != S_OK) { throw std::runtime_error("failed to iterate display modes"); } } /* no modes matched so we don't know dominance */ return RawFrame::UNKNOWN; }
int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; IDeckLinkDisplayModeIterator *itermode; IDeckLinkDisplayMode *mode; uint32_t format_code; HRESULT res; if (direction == DIRECTION_IN) { int ret; ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection); if (ret < 0) return ret; ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection); if (ret < 0) return ret; res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); } if (res!= S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); return AVERROR(EIO); } av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n\tformat_code\tdescription", avctx->filename); while (itermode->Next(&mode) == S_OK) { BMDTimeValue tb_num, tb_den; mode->GetFrameRate(&tb_num, &tb_den); format_code = av_bswap32(mode->GetDisplayMode()); av_log(avctx, AV_LOG_INFO, "\n\t%.4s\t\t%ldx%ld at %d/%d fps", (char*) &format_code, mode->GetWidth(), mode->GetHeight(), (int) tb_den, (int) tb_num); switch (mode->GetFieldDominance()) { case bmdLowerFieldFirst: av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break; case bmdUpperFieldFirst: av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break; } mode->Release(); } av_log(avctx, AV_LOG_INFO, "\n"); itermode->Release(); return 0; }
int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction) { struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; IDeckLinkDisplayModeIterator *itermode; IDeckLinkDisplayMode *mode; int i=0; HRESULT res; if (direction == DIRECTION_IN) { res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); } if (res!= S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); return AVERROR(EIO); } av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n", avctx->filename); while (itermode->Next(&mode) == S_OK) { BMDTimeValue tb_num, tb_den; mode->GetFrameRate(&tb_num, &tb_den); av_log(avctx, AV_LOG_INFO, "\t%d\t%ldx%ld at %d/%d fps", ++i,mode->GetWidth(), mode->GetHeight(), (int) tb_den, (int) tb_num); switch (mode->GetFieldDominance()) { case bmdLowerFieldFirst: av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break; case bmdUpperFieldFirst: av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break; } av_log(avctx, AV_LOG_INFO, "\n"); mode->Release(); } itermode->Release(); return 0; }
int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, decklink_direction_t direction, int num) { struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; BMDDisplayModeSupport support; IDeckLinkDisplayModeIterator *itermode; IDeckLinkDisplayMode *mode; int i = 1; HRESULT res; if (direction == DIRECTION_IN) { res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); } if (res!= S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); return AVERROR(EIO); } if (tb_num == 1) { tb_num *= 1000; tb_den *= 1000; } ctx->bmd_mode = bmdModeUnknown; while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) { BMDTimeValue bmd_tb_num, bmd_tb_den; int bmd_width = mode->GetWidth(); int bmd_height = mode->GetHeight(); mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den); if ((bmd_width == width && bmd_height == height && bmd_tb_num == tb_num && bmd_tb_den == tb_den) || i == num) { ctx->bmd_mode = mode->GetDisplayMode(); ctx->bmd_width = bmd_width; ctx->bmd_height = bmd_height; ctx->bmd_tb_den = bmd_tb_den; ctx->bmd_tb_num = bmd_tb_num; ctx->bmd_field_dominance = mode->GetFieldDominance(); av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n", bmd_width, bmd_height, (float)bmd_tb_den/(float)bmd_tb_num, (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":""); } mode->Release(); i++; } itermode->Release(); if (ctx->bmd_mode == bmdModeUnknown) return -1; if (direction == DIRECTION_IN) { if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, bmdVideoOutputFlagDefault, &support, NULL) != S_OK) return -1; } else { if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, bmdVideoOutputFlagDefault, &support, NULL) != S_OK) return -1; } if (support == bmdDisplayModeSupported) return 0; return -1; }
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; }
int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction, int num) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; BMDDisplayModeSupport support; IDeckLinkDisplayModeIterator *itermode; IDeckLinkDisplayMode *mode; int i = 1; HRESULT res; av_log(avctx, AV_LOG_DEBUG, "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, mode number %d, format code %s\n", width, height, tb_num, tb_den, field_order, direction, num, (cctx->format_code) ? cctx->format_code : "(unset)"); if (ctx->duplex_mode) { DECKLINK_BOOL duplex_supported = false; if (ctx->attr->GetFlag(BMDDeckLinkSupportsDuplexModeConfiguration, &duplex_supported) != S_OK) duplex_supported = false; if (duplex_supported) { res = ctx->cfg->SetInt(bmdDeckLinkConfigDuplexMode, ctx->duplex_mode == 2 ? bmdDuplexModeFull : bmdDuplexModeHalf); if (res != S_OK) av_log(avctx, AV_LOG_WARNING, "Setting duplex mode failed.\n"); else av_log(avctx, AV_LOG_VERBOSE, "Successfully set duplex mode to %s duplex.\n", ctx->duplex_mode == 2 ? "full" : "half"); } else { av_log(avctx, AV_LOG_WARNING, "Unable to set duplex mode, because it is not supported.\n"); } } if (direction == DIRECTION_IN) { int ret; ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection); if (ret < 0) return ret; ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection); if (ret < 0) return ret; res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); } if (res!= S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); return AVERROR(EIO); } char format_buf[] = " "; if (cctx->format_code) memcpy(format_buf, cctx->format_code, FFMIN(strlen(cctx->format_code), sizeof(format_buf))); BMDDisplayMode target_mode = (BMDDisplayMode)AV_RB32(format_buf); AVRational target_tb = av_make_q(tb_num, tb_den); ctx->bmd_mode = bmdModeUnknown; while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) { BMDTimeValue bmd_tb_num, bmd_tb_den; int bmd_width = mode->GetWidth(); int bmd_height = mode->GetHeight(); BMDDisplayMode bmd_mode = mode->GetDisplayMode(); BMDFieldDominance bmd_field_dominance = mode->GetFieldDominance(); mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den); AVRational mode_tb = av_make_q(bmd_tb_num, bmd_tb_den); if ((bmd_width == width && bmd_height == height && !av_cmp_q(mode_tb, target_tb) && field_order_eq(field_order, bmd_field_dominance)) || i == num || target_mode == bmd_mode) { ctx->bmd_mode = bmd_mode; ctx->bmd_width = bmd_width; ctx->bmd_height = bmd_height; ctx->bmd_tb_den = bmd_tb_den; ctx->bmd_tb_num = bmd_tb_num; ctx->bmd_field_dominance = bmd_field_dominance; av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n", bmd_width, bmd_height, 1/av_q2d(mode_tb), (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":""); } mode->Release(); i++; } itermode->Release(); if (ctx->bmd_mode == bmdModeUnknown) return -1; if (direction == DIRECTION_IN) { if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, bmdVideoOutputFlagDefault, &support, NULL) != S_OK) return -1; } else { if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, bmdVideoOutputFlagDefault, &support, NULL) != S_OK) return -1; } if (support == bmdDisplayModeSupported) return 0; return -1; }
static int Open(vlc_object_t *p_this) { demux_t *demux = (demux_t*)p_this; demux_sys_t *sys; int ret = VLC_EGENERIC; int card_index; int physical_channels = 0; int rate; BMDVideoInputFlags flags = bmdVideoInputFlagDefault; /* Only when selected */ if (*demux->psz_access == '\0') return VLC_EGENERIC; /* Set up demux */ demux->pf_demux = NULL; demux->pf_control = Control; demux->info.i_update = 0; demux->info.i_title = 0; demux->info.i_seekpoint = 0; demux->p_sys = sys = (demux_sys_t*)calloc(1, sizeof(demux_sys_t)); if (!sys) return VLC_ENOMEM; vlc_mutex_init(&sys->pts_lock); sys->tenbits = var_InheritBool(p_this, "decklink-tenbits"); IDeckLinkIterator *decklink_iterator = CreateDeckLinkIteratorInstance(); if (!decklink_iterator) { msg_Err(demux, "DeckLink drivers not found."); goto finish; } card_index = var_InheritInteger(demux, "decklink-card-index"); if (card_index < 0) { msg_Err(demux, "Invalid card index %d", card_index); goto finish; } for (int i = 0; i <= card_index; i++) { if (sys->card) sys->card->Release(); if (decklink_iterator->Next(&sys->card) != S_OK) { msg_Err(demux, "DeckLink PCI card %d not found", card_index); goto finish; } } const char *model_name; if (sys->card->GetModelName(&model_name) != S_OK) model_name = "unknown"; msg_Dbg(demux, "Opened DeckLink PCI card %d (%s)", card_index, model_name); if (sys->card->QueryInterface(IID_IDeckLinkInput, (void**)&sys->input) != S_OK) { msg_Err(demux, "Card has no inputs"); goto finish; } /* Set up the video and audio sources. */ if (sys->card->QueryInterface(IID_IDeckLinkConfiguration, (void**)&sys->config) != S_OK) { msg_Err(demux, "Failed to get configuration interface"); goto finish; } if (sys->card->QueryInterface(IID_IDeckLinkAttributes, (void**)&sys->attributes) != S_OK) { msg_Err(demux, "Failed to get attributes interface"); goto finish; } if (GetVideoConn(demux) || GetAudioConn(demux)) goto finish; BMDPixelFormat fmt; fmt = sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV; if (sys->attributes->GetFlag(BMDDeckLinkSupportsInputFormatDetection, &sys->autodetect) != S_OK) { msg_Err(demux, "Failed to query card attribute"); goto finish; } /* Get the list of display modes. */ IDeckLinkDisplayModeIterator *mode_it; if (sys->input->GetDisplayModeIterator(&mode_it) != S_OK) { msg_Err(demux, "Failed to enumerate display modes"); goto finish; } union { BMDDisplayMode id; char str[4]; } u; u.id = 0; char *mode; mode = var_CreateGetNonEmptyString(demux, "decklink-mode"); if (mode) sys->autodetect = false; // disable autodetection if mode was set if (sys->autodetect) { msg_Dbg(demux, "Card supports input format detection"); flags |= bmdVideoInputEnableFormatDetection; /* Enable a random format, we will reconfigure on format detection */ u.id = htonl(bmdModeHD1080p2997); } else { if (!mode || strlen(mode) < 3 || strlen(mode) > 4) { msg_Err(demux, "Invalid mode: \'%s\'", mode ? mode : ""); free(mode); goto finish; } msg_Dbg(demux, "Looking for mode \'%s\'", mode); memcpy(u.str, mode, 4); if (u.str[3] == '\0') u.str[3] = ' '; /* 'pal'\0 -> 'pal ' */ free(mode); } es_format_t video_fmt; video_fmt.video.i_width = 0; for (IDeckLinkDisplayMode *m;; m->Release()) { if ((mode_it->Next(&m) != S_OK) || !m) break; const char *mode_name; BMDTimeValue frame_duration, time_scale; uint32_t field_flags; const char *field = GetFieldDominance(m->GetFieldDominance(), &field_flags); BMDDisplayMode id = ntohl(m->GetDisplayMode()); if (m->GetName(&mode_name) != S_OK) mode_name = "unknown"; if (m->GetFrameRate(&frame_duration, &time_scale) != S_OK) { time_scale = 0; frame_duration = 1; } msg_Dbg(demux, "Found mode '%4.4s': %s (%dx%d, %.3f fps%s)", (char*)&id, mode_name, (int)m->GetWidth(), (int)m->GetHeight(), double(time_scale) / frame_duration, field); if (u.id == id) { video_fmt = GetModeSettings(demux, m); msg_Dbg(demux, "Using that mode"); } } mode_it->Release(); if (video_fmt.video.i_width == 0) { msg_Err(demux, "Unknown video mode `%4.4s\' specified.", (char*)&u.id); goto finish; } if (sys->input->EnableVideoInput(htonl(u.id), fmt, flags) != S_OK) { msg_Err(demux, "Failed to enable video input"); goto finish; } /* Set up audio. */ sys->channels = var_InheritInteger(demux, "decklink-audio-channels"); switch (sys->channels) { case 0: break; case 2: physical_channels = AOUT_CHANS_STEREO; break; case 8: physical_channels = AOUT_CHANS_7_1; break; //case 16: default: msg_Err(demux, "Invalid number of channels (%d), disabling audio", sys->channels); sys->channels = 0; } rate = var_InheritInteger(demux, "decklink-audio-rate"); if (rate > 0 && sys->channels > 0) { if (sys->input->EnableAudioInput(rate, bmdAudioSampleType16bitInteger, sys->channels) != S_OK) { msg_Err(demux, "Failed to enable audio input"); goto finish; } } sys->delegate = new DeckLinkCaptureDelegate(demux); sys->input->SetCallback(sys->delegate); if (sys->input->StartStreams() != S_OK) { msg_Err(demux, "Could not start streaming from SDI card. This could be caused " "by invalid video mode or flags, access denied, or card already in use."); goto finish; } msg_Dbg(demux, "added new video es %4.4s %dx%d", (char*)&video_fmt.i_codec, video_fmt.video.i_width, video_fmt.video.i_height); sys->video_es = es_out_Add(demux->out, &video_fmt); es_format_t audio_fmt; es_format_Init(&audio_fmt, AUDIO_ES, VLC_CODEC_S16N); audio_fmt.audio.i_channels = sys->channels; audio_fmt.audio.i_physical_channels = physical_channels; audio_fmt.audio.i_rate = rate; audio_fmt.audio.i_bitspersample = 16; audio_fmt.audio.i_blockalign = audio_fmt.audio.i_channels * audio_fmt.audio.i_bitspersample / 8; audio_fmt.i_bitrate = audio_fmt.audio.i_channels * audio_fmt.audio.i_rate * audio_fmt.audio.i_bitspersample; msg_Dbg(demux, "added new audio es %4.4s %dHz %dbpp %dch", (char*)&audio_fmt.i_codec, audio_fmt.audio.i_rate, audio_fmt.audio.i_bitspersample, audio_fmt.audio.i_channels); sys->audio_es = es_out_Add(demux->out, &audio_fmt); ret = VLC_SUCCESS; finish: if (decklink_iterator) decklink_iterator->Release(); if (ret != VLC_SUCCESS) Close(p_this); return ret; }
int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction, int num) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; BMDDisplayModeSupport support; IDeckLinkDisplayModeIterator *itermode; IDeckLinkDisplayMode *mode; int i = 1; HRESULT res; av_log(avctx, AV_LOG_DEBUG, "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, mode number %d, format code %s\n", width, height, tb_num, tb_den, field_order, direction, num, (cctx->format_code) ? cctx->format_code : "(unset)"); if (direction == DIRECTION_IN) { res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); } if (res!= S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); return AVERROR(EIO); } char format_buf[] = " "; if (cctx->format_code) memcpy(format_buf, cctx->format_code, FFMIN(strlen(cctx->format_code), sizeof(format_buf))); BMDDisplayMode target_mode = (BMDDisplayMode)AV_RB32(format_buf); AVRational target_tb = av_make_q(tb_num, tb_den); ctx->bmd_mode = bmdModeUnknown; while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) { BMDTimeValue bmd_tb_num, bmd_tb_den; int bmd_width = mode->GetWidth(); int bmd_height = mode->GetHeight(); BMDDisplayMode bmd_mode = mode->GetDisplayMode(); BMDFieldDominance bmd_field_dominance = mode->GetFieldDominance(); mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den); AVRational mode_tb = av_make_q(bmd_tb_num, bmd_tb_den); if ((bmd_width == width && bmd_height == height && !av_cmp_q(mode_tb, target_tb) && field_order_eq(field_order, bmd_field_dominance)) || i == num || target_mode == bmd_mode) { ctx->bmd_mode = bmd_mode; ctx->bmd_width = bmd_width; ctx->bmd_height = bmd_height; ctx->bmd_tb_den = bmd_tb_den; ctx->bmd_tb_num = bmd_tb_num; ctx->bmd_field_dominance = bmd_field_dominance; av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n", bmd_width, bmd_height, 1/av_q2d(mode_tb), (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":""); } mode->Release(); i++; } itermode->Release(); if (ctx->bmd_mode == bmdModeUnknown) return -1; if (direction == DIRECTION_IN) { if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, (BMDPixelFormat) cctx->raw_format, bmdVideoOutputFlagDefault, &support, NULL) != S_OK) return -1; } else { if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, bmdVideoOutputFlagDefault, &support, NULL) != S_OK) return -1; } if (support == bmdDisplayModeSupported) return 0; return -1; }