示例#1
0
def get_pipeline_score(enc_in_format, csc_spec, encoder_spec, width, height,
                       scaling, target_quality, min_quality, target_speed,
                       min_speed, current_csce, current_ve,
                       client_score_delta):
    """
        Given an optional csc step (csc_format and csc_spec), and
        and a required encoding step (encoder_spec and width/height),
        we calculate a score of how well this matches our requirements:
        * our quality target "self._currend_quality"
        * our speed target "self._current_speed"
        * how expensive it would be to switch to this pipeline option
        Note: we know the current pipeline settings, so the "switching
        cost" will be lower for pipelines that share components with the
        current one.

        Can be called from any thread.
    """
    def clamp(v):
        return max(0, min(100, v))

    qscore = clamp(
        get_quality_score(enc_in_format, csc_spec, encoder_spec, scaling,
                          target_quality, min_quality))
    sscore = clamp(
        get_speed_score(enc_in_format, csc_spec, encoder_spec, scaling,
                        target_speed, min_speed))

    #how well the codec deals with larger screen sizes:
    sizescore = 100
    mpixels = width * height / (1024.0 * 1024.0)
    if mpixels > 1.0:
        #high size efficiency means sizescore stays high even with high number of mpixels,
        #ie: 1MPixels -> sizescore = 100
        #ie: 8MPixels -> sizescore = size_efficiency
        sdisc = (100 - encoder_spec.size_efficiency)
        sizescore = max(0, 100 - (mpixels - 1) / 7.0 * sdisc)

    #runtime codec adjustements:
    runtime_score = 100
    #score for "edge resistance" via setup cost:
    ecsc_score = 100

    csc_width = 0
    csc_height = 0
    if csc_spec:
        #OR the masks so we have a chance of making it work
        width_mask = csc_spec.width_mask & encoder_spec.width_mask
        height_mask = csc_spec.height_mask & encoder_spec.height_mask
        csc_width = width & width_mask
        csc_height = height & height_mask
        if enc_in_format == "RGB":
            #converting to "RGB" is often a waste of CPU
            #(can only get selected because the csc step will do scaling,
            # but even then, the YUV subsampling are better options)
            ecsc_score = 1
        elif current_csce is None or current_csce.get_dst_format()!=enc_in_format or \
           type(current_csce)!=csc_spec.codec_class or \
           current_csce.get_src_width()!=csc_width or current_csce.get_src_height()!=csc_height:
            #if we have to change csc, account for new csc setup cost:
            ecsc_score = max(0, 80 - csc_spec.setup_cost * 80.0 / 100.0)
        else:
            ecsc_score = 80
        ecsc_score += csc_spec.score_boost
        runtime_score *= csc_spec.get_runtime_factor()

        csc_scaling = scaling
        encoder_scaling = (1, 1)
        if scaling != (1, 1) and not csc_spec.can_scale:
            #csc cannot take care of scaling, so encoder will have to:
            encoder_scaling = scaling
            csc_scaling = (1, 1)
        if scaling != (1, 1):
            #if we are (down)scaling, we should prefer lossy pixel formats:
            v = LOSSY_PIXEL_FORMATS.get(enc_in_format, 1)
            qscore *= (v / 2)
        enc_width, enc_height = get_encoder_dimensions(encoder_spec, csc_width,
                                                       csc_height, scaling)
    else:
        #not using csc at all!
        ecsc_score = 100
        width_mask = encoder_spec.width_mask
        height_mask = encoder_spec.height_mask
        enc_width = width & width_mask
        enc_height = height & height_mask
        csc_scaling = None
        encoder_scaling = scaling

    if encoder_scaling != (1, 1) and not encoder_spec.can_scale:
        #we need the encoder to scale but it cannot do it, fail it:
        scorelog("scaling (%s) not supported by %s", encoder_scaling,
                 encoder_spec)
        return None

    if enc_width < encoder_spec.min_w or enc_height < encoder_spec.min_h:
        scorelog("video size %ix%i out of range for %s, min %ix%i", enc_width,
                 enc_height, encoder_spec.codec_type, encoder_spec.min_w,
                 encoder_spec.min_h)
        return None
    elif enc_width > encoder_spec.max_w or enc_height > encoder_spec.max_h:
        scorelog("video size %ix%i out of range for %s, max %ix%i", enc_width,
                 enc_height, encoder_spec.codec_type, encoder_spec.max_w,
                 encoder_spec.max_h)
        return None

    ee_score = 100
    if current_ve is None or current_ve.get_type()!=encoder_spec.codec_type or \
       current_ve.get_src_format()!=enc_in_format or \
       current_ve.get_width()!=enc_width or current_ve.get_height()!=enc_height:
        #account for new encoder setup cost:
        ee_score = 100 - encoder_spec.setup_cost
        ee_score += encoder_spec.score_boost
    #edge resistance score: average of csc and encoder score:
    er_score = (ecsc_score + ee_score) / 2.0
    score = int((qscore + sscore + er_score + sizescore + client_score_delta) *
                runtime_score / 100.0 / 4.0)
    scorelog(
        "get_score(%-7s, %-24r, %-24r, %5i, %5i) quality: %2i, speed: %2i, setup: %2i - %2i runtime: %2i scaling: %s / %s, encoder dimensions=%sx%s, sizescore=%3i, client score delta=%3i, score=%2i",
        enc_in_format, csc_spec, encoder_spec, width, height, qscore, sscore,
        ecsc_score, ee_score, runtime_score, scaling, encoder_scaling,
        enc_width, enc_height, sizescore, client_score_delta, score)
    return score, scaling, csc_scaling, csc_width, csc_height, csc_spec, enc_in_format, encoder_scaling, enc_width, enc_height, encoder_spec
示例#2
0
def get_pipeline_score(enc_in_format, csc_spec, encoder_spec, width, height, scaling,
                       target_quality, min_quality,
                       target_speed, min_speed,
                       current_csce, current_ve,
                       client_score_delta):
    """
        Given an optional csc step (csc_format and csc_spec), and
        and a required encoding step (encoder_spec and width/height),
        we calculate a score of how well this matches our requirements:
        * our quality target "self._currend_quality"
        * our speed target "self._current_speed"
        * how expensive it would be to switch to this pipeline option
        Note: we know the current pipeline settings, so the "switching
        cost" will be lower for pipelines that share components with the
        current one.

        Can be called from any thread.
    """
    def clamp(v):
        return max(0, min(100, v))
    qscore = clamp(get_quality_score(enc_in_format, csc_spec, encoder_spec, scaling, target_quality, min_quality))
    sscore = clamp(get_speed_score(enc_in_format, csc_spec, encoder_spec, scaling, target_speed, min_speed))

    #how well the codec deals with larger screen sizes:
    sizescore = 100
    mpixels = width*height/(1024.0*1024.0)
    if mpixels>1.0:
        #high size efficiency means sizescore stays high even with high number of mpixels,
        #ie: 1MPixels -> sizescore = 100
        #ie: 8MPixels -> sizescore = size_efficiency
        sdisc = (100-encoder_spec.size_efficiency)
        sizescore = max(0, 100-(mpixels-1)/7.0*sdisc)

    #runtime codec adjustements:
    runtime_score = 100
    #score for "edge resistance" via setup cost:
    ecsc_score = 100

    csc_width = 0
    csc_height = 0
    if csc_spec:
        #OR the masks so we have a chance of making it work
        width_mask = csc_spec.width_mask & encoder_spec.width_mask
        height_mask = csc_spec.height_mask & encoder_spec.height_mask
        csc_width = width & width_mask
        csc_height = height & height_mask
        if enc_in_format=="RGB":
            #converting to "RGB" is often a waste of CPU
            #(can only get selected because the csc step will do scaling,
            # but even then, the YUV subsampling are better options)
            ecsc_score = 1
        elif current_csce is None or current_csce.get_dst_format()!=enc_in_format or \
           type(current_csce)!=csc_spec.codec_class or \
           current_csce.get_src_width()!=csc_width or current_csce.get_src_height()!=csc_height:
            #if we have to change csc, account for new csc setup cost:
            ecsc_score = max(0, 80 - csc_spec.setup_cost*80.0/100.0)
        else:
            ecsc_score = 80
        ecsc_score += csc_spec.score_boost
        runtime_score *= csc_spec.get_runtime_factor()

        csc_scaling = scaling
        encoder_scaling = (1, 1)
        if scaling!=(1,1) and not csc_spec.can_scale:
            #csc cannot take care of scaling, so encoder will have to:
            encoder_scaling = scaling
            csc_scaling = (1, 1)
        if scaling!=(1, 1):
            #if we are (down)scaling, we should prefer lossy pixel formats:
            v = LOSSY_PIXEL_FORMATS.get(enc_in_format, 1)
            qscore *= (v/2)
        enc_width, enc_height = get_encoder_dimensions(csc_spec, encoder_spec, csc_width, csc_height, scaling)
    else:
        #not using csc at all!
        ecsc_score = 100
        width_mask = encoder_spec.width_mask
        height_mask = encoder_spec.height_mask
        enc_width = width & width_mask
        enc_height = height & height_mask
        csc_scaling = None
        encoder_scaling = scaling

    if encoder_scaling!=(1,1) and not encoder_spec.can_scale:
        #we need the encoder to scale but it cannot do it, fail it:
        scorelog("scaling (%s) not supported by %s", encoder_scaling, encoder_spec)
        return None

    ee_score = 100
    if current_ve is None or current_ve.get_type()!=encoder_spec.codec_type or \
       current_ve.get_src_format()!=enc_in_format or \
       current_ve.get_width()!=enc_width or current_ve.get_height()!=enc_height:
        #account for new encoder setup cost:
        ee_score = 100 - encoder_spec.setup_cost
        ee_score += encoder_spec.score_boost
    #edge resistance score: average of csc and encoder score:
    er_score = (ecsc_score + ee_score) / 2.0
    score = int((qscore+sscore+er_score+sizescore+client_score_delta)*runtime_score/100.0/4.0)
    scorelog("get_score(%-7s, %-24r, %-24r, %5i, %5i) quality: %2i, speed: %2i, setup: %2i runtime: %2i scaling: %s / %s, encoder dimensions=%sx%s, sizescore=%3i, client score delta=%3i, score=%2i",
             enc_in_format, csc_spec, encoder_spec, width, height,
             qscore, sscore, er_score, runtime_score, scaling, encoder_scaling, enc_width, enc_height, sizescore, client_score_delta, score)
    return score, scaling, csc_scaling, csc_width, csc_height, csc_spec, enc_in_format, encoder_scaling, enc_width, enc_height, encoder_spec