DeckLinkOutputAdapter(unsigned int card_index = 0, unsigned int norm_ = 0, RawFrame::PixelFormat pf_ = RawFrame::CbYCrY8422, bool enable_audio = false) : deckLink(NULL), deckLinkOutput(NULL), frame_counter(0), last_frame(NULL), in_pipe(OUT_PIPE_SIZE), audio_in_pipe(NULL) { norm = norm_; assert(norm < sizeof(norms) / sizeof(struct decklink_norm)); time_base = norms[norm].time_base; frame_duration = norms[norm].frame_duration; pf = pf_; bpf = convert_pf(pf_); deckLink = find_card(card_index); configure_card( ); open_card( ); preroll_video_frames(16); if (enable_audio) { setup_audio( ); } start_video( ); thread_priority_hack( ); fprintf(stderr, "DeckLink: initialized using norm %s\n", norms[norm].name); }
int write_token(token *buf) { open_card(); memcpy(data, buf, LEN); close_card(); return 1; }
int read_token(token *buf) { open_card(); memcpy(buf, data, LEN); close_card(); return 1; }
static void *open_input( void *ptr ) { obe_input_params_t *input = (obe_input_params_t*)ptr; obe_t *h = input->h; obe_device_t *device = input->device; obe_input_t *user_opts = &device->user_opts; decklink_ctx_t *decklink_ctx; obe_sdi_non_display_data_t *non_display_parser; struct decklink_status status; decklink_opts_t *decklink_opts = (decklink_opts_t*)calloc( 1, sizeof(*decklink_opts) ); if( !decklink_opts ) { fprintf( stderr, "Malloc failed\n" ); return NULL; } status.input = input; status.decklink_opts = decklink_opts; pthread_cleanup_push( close_thread, (void*)&status ); decklink_opts->num_channels = 16; decklink_opts->card_idx = user_opts->card_idx; decklink_opts->video_conn = user_opts->video_connection; decklink_opts->audio_conn = user_opts->audio_connection; decklink_opts->video_format = user_opts->video_format; decklink_ctx = &decklink_opts->decklink_ctx; decklink_ctx->device = device; decklink_ctx->h = h; decklink_ctx->last_frame_time = -1; non_display_parser = &decklink_ctx->non_display_parser; non_display_parser->device = device; /* TODO: wait for encoder */ if( open_card( decklink_opts ) < 0 ) return NULL; sleep( INT_MAX ); pthread_cleanup_pop( 1 ); return NULL; }
static void *probe_stream( void *ptr ) { obe_input_probe_t *probe_ctx = (obe_input_probe_t*)ptr; obe_t *h = probe_ctx->h; obe_input_t *user_opts = &probe_ctx->user_opts; obe_device_t *device; obe_int_input_stream_t *streams[MAX_STREAMS]; int cur_stream = 2; obe_sdi_non_display_data_t *non_display_parser; decklink_ctx_t *decklink_ctx; decklink_opts_t *decklink_opts = (decklink_opts_t*)calloc( 1, sizeof(*decklink_opts) ); if( !decklink_opts ) { fprintf( stderr, "Malloc failed\n" ); goto finish; } non_display_parser = &decklink_opts->decklink_ctx.non_display_parser; /* TODO: support multi-channel */ decklink_opts->num_channels = 16; decklink_opts->card_idx = user_opts->card_idx; decklink_opts->video_conn = user_opts->video_connection; decklink_opts->audio_conn = user_opts->audio_connection; decklink_opts->video_format = user_opts->video_format; decklink_opts->probe = non_display_parser->probe = 1; decklink_ctx = &decklink_opts->decklink_ctx; decklink_ctx->h = h; decklink_ctx->last_frame_time = -1; decklink_ctx = &decklink_opts->decklink_ctx; if( open_card( decklink_opts ) < 0 ) goto finish; sleep( 1 ); close_card( decklink_opts ); if( !decklink_opts->probe_success ) { fprintf( stderr, "[decklink] No valid frames received - check input format\n" ); goto finish; } /* TODO: probe for SMPTE 337M */ /* TODO: factor some of the code below out */ for( int i = 0; i < 2; i++ ) { streams[i] = (obe_int_input_stream_t*)calloc( 1, sizeof(*streams[i]) ); if( !streams[i] ) goto finish; /* TODO: make it take a continuous set of stream-ids */ pthread_mutex_lock( &h->device_list_mutex ); streams[i]->input_stream_id = h->cur_input_stream_id++; pthread_mutex_unlock( &h->device_list_mutex ); if( i == 0 ) { streams[i]->stream_type = STREAM_TYPE_VIDEO; streams[i]->stream_format = VIDEO_UNCOMPRESSED; streams[i]->width = decklink_opts->width; streams[i]->height = decklink_opts->height; streams[i]->timebase_num = decklink_opts->timebase_num; streams[i]->timebase_den = decklink_opts->timebase_den; streams[i]->csp = PIX_FMT_YUV422P10; streams[i]->interlaced = decklink_opts->interlaced; streams[i]->tff = decklink_opts->tff; streams[i]->sar_num = streams[i]->sar_den = 1; /* The user can choose this when encoding */ if( add_non_display_services( non_display_parser, streams[i], USER_DATA_LOCATION_FRAME ) < 0 ) goto finish; } else if( i == 1 ) { streams[i]->stream_type = STREAM_TYPE_AUDIO; streams[i]->stream_format = AUDIO_PCM; streams[i]->num_channels = 16; streams[i]->sample_format = AV_SAMPLE_FMT_S32P; /* TODO: support other sample rates */ streams[i]->sample_rate = 48000; } } if( non_display_parser->has_vbi_frame ) { streams[cur_stream] = (obe_int_input_stream_t*)calloc( 1, sizeof(*streams[cur_stream]) ); if( !streams[cur_stream] ) goto finish; pthread_mutex_lock( &h->device_list_mutex ); streams[cur_stream]->input_stream_id = h->cur_input_stream_id++; pthread_mutex_unlock( &h->device_list_mutex ); streams[cur_stream]->stream_type = STREAM_TYPE_MISC; streams[cur_stream]->stream_format = VBI_RAW; streams[cur_stream]->vbi_ntsc = decklink_opts->video_format == INPUT_VIDEO_FORMAT_NTSC; if( add_non_display_services( non_display_parser, streams[cur_stream], USER_DATA_LOCATION_DVB_STREAM ) < 0 ) goto finish; cur_stream++; } if( non_display_parser->has_ttx_frame ) { streams[cur_stream] = (obe_int_input_stream_t*)calloc( 1, sizeof(*streams[cur_stream]) ); if( !streams[cur_stream] ) goto finish; pthread_mutex_lock( &h->device_list_mutex ); streams[cur_stream]->input_stream_id = h->cur_input_stream_id++; pthread_mutex_unlock( &h->device_list_mutex ); streams[cur_stream]->stream_type = STREAM_TYPE_MISC; streams[cur_stream]->stream_format = MISC_TELETEXT; if( add_teletext_service( non_display_parser, streams[cur_stream] ) < 0 ) goto finish; cur_stream++; } if( non_display_parser->num_frame_data ) free( non_display_parser->frame_data ); device = new_device(); if( !device ) goto finish; device->num_input_streams = cur_stream; memcpy( device->streams, streams, device->num_input_streams * sizeof(obe_int_input_stream_t**) ); device->device_type = INPUT_DEVICE_DECKLINK; memcpy( &device->user_opts, user_opts, sizeof(*user_opts) ); /* add device */ add_device( h, device ); finish: if( decklink_opts ) free( decklink_opts ); free( probe_ctx ); return NULL; }