YETI_Result File::load(DataBuffer & buffer) { InputStreamReference input; YETI_CHECK_WARNING(get_input_stream(input)); return input->load(buffer); }
int obe_start( obe_t *h ) { obe_int_input_stream_t *input_stream; obe_vid_filter_params_t *vid_filter_params; obe_aud_filter_params_t *aud_filter_params; obe_vid_enc_params_t *vid_enc_params; obe_aud_enc_params_t *aud_enc_params; obe_output_params_t *out_params; obe_input_func_t input; obe_aud_enc_func_t audio_encoder; obe_output_func_t output; int num_samples = 0; /* TODO: a lot of sanity checks */ /* TODO: decide upon thread priorities */ /* Setup mutexes and cond vars */ pthread_mutex_init( &h->devices[0]->device_mutex, NULL ); pthread_mutex_init( &h->drop_mutex, NULL ); obe_init_queue( &h->enc_smoothing_queue ); obe_init_queue( &h->mux_queue ); obe_init_queue( &h->mux_smoothing_queue ); obe_init_queue( &h->output_queue ); pthread_mutex_init( &h->obe_clock_mutex, NULL ); pthread_cond_init( &h->obe_clock_cv, NULL ); if( h->devices[0]->device_type == INPUT_URL ) { //input = lavf_input; fprintf( stderr, "URL input is not supported currently \n" ); goto fail; } #if HAVE_DECKLINK else if( h->devices[0]->device_type == INPUT_DEVICE_DECKLINK ) input = decklink_input; #endif else if( h->devices[0]->device_type == INPUT_DEVICE_LINSYS_SDI ) input = linsys_sdi_input; else { fprintf( stderr, "Invalid input device \n" ); goto fail; } output = ip_output; /* Open Output Thread */ out_params = calloc( 1, sizeof(*out_params) ); if( !out_params ) { fprintf( stderr, "Malloc failed \n" ); goto fail; } memcpy( &out_params->output_opts, &h->output_opts, sizeof(h->output_opts) ); if( h->output_opts.target ) { out_params->output_opts.target = malloc( strlen( h->output_opts.target ) + 1 ); if( !out_params->output_opts.target ) { fprintf( stderr, "Malloc failed \n" ); goto fail; } strcpy( out_params->output_opts.target, h->output_opts.target ); } out_params->h = h; if( pthread_create( &h->output_thread, NULL, output.open_output, (void*)out_params ) < 0 ) { fprintf( stderr, "Couldn't create output thread \n" ); goto fail; } /* Open Encoder Threads */ for( int i = 0; i < h->num_output_streams; i++ ) { if( h->output_streams[i].stream_action == STREAM_ENCODE ) { h->encoders[h->num_encoders] = calloc( 1, sizeof(obe_encoder_t) ); if( !h->encoders[h->num_encoders] ) { fprintf( stderr, "Malloc failed \n" ); goto fail; } obe_init_queue( &h->encoders[h->num_encoders]->queue ); h->encoders[h->num_encoders]->output_stream_id = h->output_streams[i].output_stream_id; if( h->output_streams[i].stream_format == VIDEO_AVC ) { x264_param_t *x264_param = &h->output_streams[i].avc_param; if( h->obe_system == OBE_SYSTEM_TYPE_LOWEST_LATENCY ) { /* This doesn't need to be particularly accurate since x264 calculates the correct value internally */ x264_param->rc.i_vbv_buffer_size = (double)x264_param->rc.i_vbv_max_bitrate * x264_param->i_fps_den / x264_param->i_fps_num; } vid_enc_params = calloc( 1, sizeof(*vid_enc_params) ); if( !vid_enc_params ) { fprintf( stderr, "Malloc failed \n" ); goto fail; } vid_enc_params->h = h; vid_enc_params->encoder = h->encoders[h->num_encoders]; h->encoders[h->num_encoders]->is_video = 1; memcpy( &vid_enc_params->avc_param, &h->output_streams[i].avc_param, sizeof(x264_param_t) ); if( pthread_create( &h->encoders[h->num_encoders]->encoder_thread, NULL, x264_encoder.start_encoder, (void*)vid_enc_params ) < 0 ) { fprintf( stderr, "Couldn't create encode thread \n" ); goto fail; } } else if( h->output_streams[i].stream_format == AUDIO_AC_3 || h->output_streams[i].stream_format == AUDIO_E_AC_3 || h->output_streams[i].stream_format == AUDIO_AAC || h->output_streams[i].stream_format == AUDIO_MP2 ) { audio_encoder = h->output_streams[i].stream_format == AUDIO_MP2 ? twolame_encoder : lavc_encoder; num_samples = h->output_streams[i].stream_format == AUDIO_MP2 ? MP2_NUM_SAMPLES : h->output_streams[i].stream_format == AUDIO_AAC ? AAC_NUM_SAMPLES : AC3_NUM_SAMPLES; aud_enc_params = calloc( 1, sizeof(*aud_enc_params) ); if( !aud_enc_params ) { fprintf( stderr, "Malloc failed \n" ); goto fail; } aud_enc_params->h = h; aud_enc_params->encoder = h->encoders[h->num_encoders]; aud_enc_params->stream = &h->output_streams[i]; input_stream = get_input_stream( h, h->output_streams[i].input_stream_id ); aud_enc_params->input_sample_format = input_stream->sample_format; aud_enc_params->sample_rate = input_stream->sample_rate; /* TODO: check the bitrate is allowed by the format */ h->output_streams[i].sdi_audio_pair = MAX( h->output_streams[i].sdi_audio_pair, 0 ); /* Choose the optimal number of audio frames per PES * TODO: This should be set after the encoder has told us the frame size */ if( !h->output_streams[i].ts_opts.frames_per_pes && h->obe_system == OBE_SYSTEM_TYPE_GENERIC && h->output_streams[i].stream_format != AUDIO_E_AC_3 ) { int buf_size = h->output_streams[i].stream_format == AUDIO_MP2 || h->output_streams[i].stream_format == AUDIO_AAC ? MISC_AUDIO_BS : AC3_BS_DVB; if( buf_size == AC3_BS_DVB && ( h->mux_opts.ts_type == OBE_TS_TYPE_CABLELABS || h->mux_opts.ts_type == OBE_TS_TYPE_ATSC ) ) buf_size = AC3_BS_ATSC; /* AAC does not have exact frame sizes but this should be a good approximation */ int single_frame_size = (double)num_samples * 125 * h->output_streams[i].bitrate / input_stream->sample_rate; if( h->output_streams[i].aac_opts.aac_profile == AAC_HE_V1 || h->output_streams[i].aac_opts.aac_profile == AAC_HE_V2 ) single_frame_size <<= 1; int frames_per_pes = MAX( buf_size / single_frame_size, 1 ); frames_per_pes = MIN( frames_per_pes, 6 ); h->output_streams[i].ts_opts.frames_per_pes = aud_enc_params->frames_per_pes = frames_per_pes; } else h->output_streams[i].ts_opts.frames_per_pes = aud_enc_params->frames_per_pes = 1; if( pthread_create( &h->encoders[h->num_encoders]->encoder_thread, NULL, audio_encoder.start_encoder, (void*)aud_enc_params ) < 0 ) { fprintf( stderr, "Couldn't create encode thread \n" ); goto fail; } } h->num_encoders++; } } if( h->obe_system == OBE_SYSTEM_TYPE_GENERIC ) { /* Open Encoder Smoothing Thread */ if( pthread_create( &h->enc_smoothing_thread, NULL, enc_smoothing.start_smoothing, (void*)h ) < 0 ) { fprintf( stderr, "Couldn't create encoder smoothing thread \n" ); goto fail; } } /* Open Mux Smoothing Thread */ if( pthread_create( &h->mux_smoothing_thread, NULL, mux_smoothing.start_smoothing, (void*)h ) < 0 ) { fprintf( stderr, "Couldn't create mux smoothing thread \n" ); goto fail; } /* Open Mux Thread */ obe_mux_params_t *mux_params = calloc( 1, sizeof(*mux_params) ); if( !mux_params ) { fprintf( stderr, "Malloc failed \n" ); goto fail; } mux_params->h = h; mux_params->device = h->devices[0]; mux_params->num_output_streams = h->num_output_streams; mux_params->output_streams = h->output_streams; if( pthread_create( &h->mux_thread, NULL, ts_muxer.open_muxer, (void*)mux_params ) < 0 ) { fprintf( stderr, "Couldn't create mux thread \n" ); goto fail; } /* Open Filter Thread */ for( int i = 0; i < h->devices[0]->num_input_streams; i++ ) { input_stream = h->devices[0]->streams[i]; if( input_stream && ( input_stream->stream_type == STREAM_TYPE_VIDEO || input_stream->stream_type == STREAM_TYPE_AUDIO ) ) { h->filters[h->num_filters] = calloc( 1, sizeof(obe_filter_t) ); if( !h->filters[h->num_filters] ) goto fail; obe_init_queue( &h->filters[h->num_filters]->queue ); h->filters[h->num_filters]->num_stream_ids = 1; h->filters[h->num_filters]->stream_id_list = malloc( sizeof(*h->filters[h->num_filters]->stream_id_list) ); if( !h->filters[h->num_filters]->stream_id_list ) { fprintf( stderr, "Malloc failed\n" ); goto fail; } h->filters[h->num_filters]->stream_id_list[0] = input_stream->input_stream_id; if( input_stream->stream_type == STREAM_TYPE_VIDEO ) { vid_filter_params = calloc( 1, sizeof(*vid_filter_params) ); if( !vid_filter_params ) { fprintf( stderr, "Malloc failed\n" ); goto fail; } vid_filter_params->h = h; vid_filter_params->filter = h->filters[h->num_filters]; vid_filter_params->input_stream = input_stream; vid_filter_params->target_csp = h->output_streams[i].avc_param.i_csp & X264_CSP_MASK; if( pthread_create( &h->filters[h->num_filters]->filter_thread, NULL, video_filter.start_filter, vid_filter_params ) < 0 ) { fprintf( stderr, "Couldn't create video filter thread \n" ); goto fail; } } else { aud_filter_params = calloc( 1, sizeof(*aud_filter_params) ); if( !aud_filter_params ) { fprintf( stderr, "Malloc failed\n" ); goto fail; } aud_filter_params->h = h; aud_filter_params->filter = h->filters[h->num_filters]; if( pthread_create( &h->filters[h->num_filters]->filter_thread, NULL, audio_filter.start_filter, aud_filter_params ) < 0 ) { fprintf( stderr, "Couldn't create filter thread \n" ); goto fail; } } h->num_filters++; } } /* Open Input Thread */ obe_input_params_t *input_params = calloc( 1, sizeof(*input_params) ); if( !input_params ) { fprintf( stderr, "Malloc failed\n" ); goto fail; } input_params->h = h; input_params->device = h->devices[0]; /* TODO: in the future give it only the streams which are necessary */ input_params->num_output_streams = h->num_output_streams; input_params->output_streams = h->output_streams; input_params->audio_samples = num_samples; if( pthread_create( &h->devices[0]->device_thread, NULL, input.open_input, (void*)input_params ) < 0 ) { fprintf( stderr, "Couldn't create input thread \n" ); goto fail; } h->is_active = 1; return 0; fail: obe_close( h ); return -1; };
int obe_populate_avc_encoder_params( obe_t *h, int input_stream_id, x264_param_t *param ) { obe_int_input_stream_t *stream = get_input_stream( h, input_stream_id ); if( !stream ) { fprintf( stderr, "Could not find stream \n" ); return -1; } if( stream->stream_type != STREAM_TYPE_VIDEO ) { fprintf( stderr, "Stream type is not video \n" ); return -1; } if( !param ) { fprintf( stderr, "Invalid parameter pointer \n" ); return -1; } if( h->obe_system == OBE_SYSTEM_TYPE_LOWEST_LATENCY || h->obe_system == OBE_SYSTEM_TYPE_LOW_LATENCY ) x264_param_default_preset( param, "veryfast", "zerolatency" ); else x264_param_default( param ); param->b_deterministic = 0; param->b_vfr_input = 0; param->b_pic_struct = 1; param->b_open_gop = 1; param->rc.i_rc_method = X264_RC_ABR; param->i_width = stream->width; param->i_height = stream->height; param->i_fps_num = stream->timebase_den; param->i_fps_den = stream->timebase_num; param->b_interlaced = stream->interlaced; if( param->b_interlaced ) param->b_tff = stream->tff; /* A reasonable default. x264 won't go higher than this parameter irrespective of speedcontrol */ if( h->obe_system == OBE_SYSTEM_TYPE_GENERIC ) param->i_frame_reference = 4; if( stream->sar_num && stream->sar_den ) { param->vui.i_sar_width = stream->sar_num; param->vui.i_sar_height = stream->sar_den; } param->vui.i_overscan = 2; if( ( param->i_fps_num == 25 || param->i_fps_num == 50 ) && param->i_fps_den == 1 ) { param->vui.i_vidformat = 1; // PAL param->vui.i_colorprim = 5; // BT.470-2 bg param->vui.i_transfer = 5; // BT.470-2 bg param->vui.i_colmatrix = 5; // BT.470-2 bg param->i_keyint_max = param->i_fps_num == 50 ? 48 : 24; } else if( ( param->i_fps_num == 30000 || param->i_fps_num == 60000 ) && param->i_fps_den == 1001 ) { param->vui.i_vidformat = 2; // NTSC param->vui.i_colorprim = 6; // BT.601-6 param->vui.i_transfer = 6; // BT.601-6 param->vui.i_colmatrix = 6; // BT.601-6 param->i_keyint_max = param->i_fps_num / 1000; } else { param->vui.i_vidformat = 5; // undefined param->vui.i_colorprim = 2; // undefined param->vui.i_transfer = 2; // undefined param->vui.i_colmatrix = 2; // undefined } /* Change to BT.709 for HD resolutions */ if( param->i_width >= 1280 && param->i_height >= 720 ) { param->vui.i_colorprim = 1; param->vui.i_transfer = 1; param->vui.i_colmatrix = 1; } x264_param_apply_profile( param, X264_BIT_DEPTH == 10 ? "high10" : "high" ); param->i_nal_hrd = X264_NAL_HRD_FAKE_VBR; param->b_aud = 1; param->i_log_level = X264_LOG_INFO; //param->rc.f_vbv_buffer_init = 0.1; if( h->obe_system == OBE_SYSTEM_TYPE_GENERIC ) { param->sc.f_speed = 1.0; param->sc.b_alt_timer = 1; if( param->i_width >= 1280 && param->i_height >= 720 ) param->sc.max_preset = 7; /* on the conservative side for HD */ else param->sc.max_preset = 10; param->rc.i_lookahead = param->i_keyint_max; } return 0; }