幀類型決策-scenecut()

scenecut_internal

/*
	只判斷p1相對於p0是否進是兩幅不同的場景
	若是若是不同的場景就返回1,否則0

	分別計算將p1作爲I幀的開銷intra_cost 和 p1作爲P幀以p0爲參考幀時的開銷inter_cost
	若inter_cost >= (1.0 - f_bias) * intra_cost,則認定p1相對p0是不同的場景
*/
static int scenecut_internal( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int real_scenecut )
{
    x264_frame_t *frame = frames[p1];	//取p1幀

    /* Don't do scenecuts on the right view of a frame-packed video. */
    if( real_scenecut && h->param.i_frame_packing == 5 && (frame->i_frame&1) )
        return 0;

    slicetype_frame_cost( h, a, frames, p0, p1, p1 );	//計算當前幀作爲P幀的開銷

    int icost = frame->i_cost_est[0][0];	//得到幀內預測的開銷
    int pcost = frame->i_cost_est[p1-p0][0];//得到幀間預測的開銷
    float f_bias;
    int i_gop_size = frame->i_frame - h->lookahead->i_last_keyframe;//得到GOP的大小,即當前幀-上一個關鍵幀
    float f_thresh_max = h->param.i_scenecut_threshold / 100.0;	//得到場景切換的閾值,即max
    /* magic numbers pulled out of thin air */
    float f_thresh_min = f_thresh_max * 0.25;	//得到場景切換閾值的最小值,即min=max*0.25
    int res;

    if( h->param.i_keyint_min == h->param.i_keyint_max )	//若關鍵幀之間的最大最小距離相等,即爲一個定值
        f_thresh_min = f_thresh_max;	//則最大最小場景切換閾值爲定值=max
	
	//根據當前幀距離上一個關鍵幀的距離來計算f_bias
    if( i_gop_size <= h->param.i_keyint_min / 4 || h->param.b_intra_refresh )
		//當前幀距離上一個關鍵幀的距離 <= 關鍵幀之間最小距離的1/4 ,或允許使用幀內預測進行刷新
        f_bias = f_thresh_min / 4;
    else if( i_gop_size <= h->param.i_keyint_min )
		//關鍵幀之間最小距離的1/4 < 當前幀距離上一個關鍵幀的距離 <= 關鍵幀之間最小距離
        f_bias = f_thresh_min * i_gop_size / h->param.i_keyint_min;
    else
    {
        f_bias = f_thresh_min
                 + ( f_thresh_max - f_thresh_min )
                 * ( i_gop_size - h->param.i_keyint_min )
                 / ( h->param.i_keyint_max - h->param.i_keyint_min );
    }

	//P幀的開銷 >= (1.0-f_bias) * I幀的開銷?
    res = pcost >= (1.0 - f_bias) * icost;

    if( res && real_scenecut )	//若res且real_scenenut,則判定爲不同的場景,輸出log
    {
        int imb = frame->i_intra_mbs[p1-p0];
        int pmb = NUM_MBS - imb;
        x264_log( h, X264_LOG_DEBUG, "scene cut at %d Icost:%d Pcost:%d ratio:%.4f bias:%.4f gop:%d (imb:%d pmb:%d)\n",
                  frame->i_frame,
                  icost, pcost, 1. - (double)pcost / icost,
                  f_bias, i_gop_size, imb, pmb );
    }

	/* 若P幀的開銷 >= (1.0-f_bias) * I幀的開銷,則判定爲p1相對p0是不同的場景,返回1
	 * 否則認爲是相同的場景,返回0. */
    return res;
}

scenecut

static int scenecut( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int real_scenecut, int num_frames, int i_max_search )
{
    /* Only do analysis during a normal scenecut check. */
    if( real_scenecut && h->param.i_bframe )	//允許B幀且real_scenecut?
    {
        int origmaxp1 = p0 + 1;
        /* Look ahead to avoid coding short flashes as scenecuts. */
        if( h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS )	//使用viterbi最優路徑進行B幀自適應選擇
            /* Don't analyse any more frames than the trellis would have covered. */
            origmaxp1 += h->param.i_bframe;	//
        else
            origmaxp1++;
        int maxp1 = X264_MIN( origmaxp1, num_frames );	//選擇min作爲maxpl

        /* Where A and B are scenes: AAAAAABBBAAAAAA
         * If BBB is shorter than (maxp1-p0), it is detected as a flash
         * and not considered a scenecut. 
		 *
		 * 當B場景的長度小於maxp1-p0,那麼將被視爲一個場景閃現,不被考慮成場景切換
		 * 提出問題:若AAAAAAAAAAAABBBAAAAAABBBAAAAAABBBAAAAAAAAA呢?這樣我覺得第
		 * 一個B定爲場景切換幀應該是一個不錯的選擇,可以考慮優化. */
        for( int curp1 = p1; curp1 <= maxp1; curp1++ )	//遍歷p1到maxp1
            if( !scenecut_internal( h, a, frames, p0, curp1, 0 ) )	//若curp1相對於p0沒有場景切換
                /* Any frame in between p0 and cur_p1 cannot be a real scenecut. */
				//從p0到當前curp1內的所有幀都不可作爲一個場景切換幀
                for( int i = curp1; i > p0; i-- )
                    frames[i]->b_scenecut = 0;

        /* Where A-F are scenes: AAAAABBCCDDEEFFFFFF
         * If each of BB ... EE are shorter than (maxp1-p0), they are
         * detected as flashes and not considered scenecuts.
         * Instead, the first F frame becomes a scenecut.
         * If the video ends before F, no frame becomes a scenecut. 
		 * 
		 * 若每一個場景B/C/.../E都短於maxp1-p0,那麼他們都被視爲一個場景閃現
		 * 不被考慮成場景切換,第一幀F被視爲場景切換. */
        for( int curp0 = p0; curp0 <= maxp1; curp0++ )	//從p0一直遍歷到maxp1 
            if( origmaxp1 > i_max_search || (curp0 < maxp1 && scenecut_internal( h, a, frames, curp0, maxp1, 0 )) )
                /* If cur_p0 is the p0 of a scenecut, it cannot be the p1 of a scenecut. */
                    frames[curp0]->b_scenecut = 0;
    }

    /* Ignore frames that are part of a flash, i.e. cannot be real scenecuts. */
    if( !frames[p1]->b_scenecut )	//若p1不被允許作爲場景切換
        return 0;

	//返回p1相對p0是否進行了場景切換
    return scenecut_internal( h, a, frames, p0, p1, real_scenecut );
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章