Example #1
0
YETI_Result File::load(DataBuffer & buffer)
{
    InputStreamReference input;
    YETI_CHECK_WARNING(get_input_stream(input));

    return input->load(buffer);
}
Example #2
0
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;
};
Example #3
0
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;
}