transrate.c

来自「VLC媒体播放程序」· C语言 代码 · 共 2,148 行 · 第 1/5 页

C
2,148
字号
        //LOGF("\n\to: %i c: %i n: %i\n", quantizer_scale, last_coded_scale, new_quantizer_scale);        NEXT_MACROBLOCK;        mba_inc = 0;        for( ;; )        {            if (bs->i_bit_in_cache >= 0x10000000)            {                mba = MBA_5 + (UBITS (bs->i_bit_in_cache, 5) - 2);                break;            }            else if (bs->i_bit_in_cache >= 0x03000000)            {                mba = MBA_11 + (UBITS (bs->i_bit_in_cache, 11) - 24);                break;            }            else if( UBITS (bs->i_bit_in_cache, 11 ) == 8 )            {                /* macroblock_escape */                mba_inc += 33;                bs_copy( bs, 11);            }            else            {                /* EOS or error */                return;            }        }        bs_copy( bs, mba->len);        mba_inc += mba->mba;        while( mba_inc-- )        {            NEXT_MACROBLOCK;        }    }}/////---- end ext mpeg codestatic int do_next_start_code( transrate_t *tr ){    bs_transrate_t *bs = &tr->bs;    uint8_t ID;    // get start code    ID = bs->p_c[0];    /* Copy one byte */    *bs->p_w++ = *bs->p_c++;    if (ID == 0x00) // pic header    {        tr->picture_coding_type = (bs->p_c[1] >> 3) & 0x7;        bs->p_c[1] |= 0x7; bs->p_c[2] = 0xFF; bs->p_c[3] |= 0xF8; // vbv_delay is now 0xFFFF        memcpy(bs->p_w, bs->p_c, 4);        bs->p_c += 4;        bs->p_w += 4;    }    else if (ID == 0xB3) // seq header    {        tr->horizontal_size_value = (bs->p_c[0] << 4) | (bs->p_c[1] >> 4);        tr->vertical_size_value = ((bs->p_c[1] & 0xF) << 8) | bs->p_c[2];        if(!tr->horizontal_size_value || !tr->vertical_size_value )        {            return -1;        }        memcpy(bs->p_w, bs->p_c, 8 );        bs->p_c += 8;        bs->p_w += 8;    }    else if (ID == 0xB5) // extension    {        if ((bs->p_c[0] >> 4) == 0x8) // pic coding ext        {            tr->f_code[0][0] = (bs->p_c[0] & 0xF) - 1;            tr->f_code[0][1] = (bs->p_c[1] >> 4) - 1;            tr->f_code[1][0] = (bs->p_c[1] & 0xF) - 1;            tr->f_code[1][1] = (bs->p_c[2] >> 4) - 1;            /* tr->intra_dc_precision = (bs->p_c[2] >> 2) & 0x3; */            tr->picture_structure = bs->p_c[2] & 0x3;            tr->frame_pred_frame_dct = (bs->p_c[3] >> 6) & 0x1;            tr->concealment_motion_vectors = (bs->p_c[3] >> 5) & 0x1;            tr->q_scale_type = (bs->p_c[3] >> 4) & 0x1;            tr->intra_vlc_format = (bs->p_c[3] >> 3) & 0x1;            /* tr->alternate_scan = (bs->p_c[3] >> 2) & 0x1; */            memcpy(bs->p_w, bs->p_c, 5);            bs->p_c += 5;            bs->p_w += 5;        }        else        {            *bs->p_w++ = *bs->p_c++;        }    }    else if (ID == 0xB8) // gop header    {        memcpy(bs->p_w, bs->p_c, 4);        bs->p_c += 4;        bs->p_w += 4;    }    else if ((ID >= 0x01) && (ID <= 0xAF)) // slice    {        uint8_t *outTemp = bs->p_w, *inTemp = bs->p_c;#if 0        if( ( tr->picture_coding_type == B_TYPE && tr->quant_corr <  2.5f ) || // don't recompress if we're in advance!            ( tr->picture_coding_type == P_TYPE && tr->quant_corr < -2.5f ) ||            ( tr->picture_coding_type == I_TYPE && tr->quant_corr < -5.0f ) )#else        if( ( tr->picture_coding_type == B_TYPE ) ||            ( tr->picture_coding_type == P_TYPE && tr->level_p ) ||            ( tr->picture_coding_type == I_TYPE && tr->level_i ) )#endif        {            if( !tr->horizontal_size_value || !tr->vertical_size_value )            {                return -1;            }            // init bit buffer            bs->i_bit_in_cache = 0; bs->i_bit_in = 0;            bs->i_bit_out_cache = 0; bs->i_bit_out = BITS_IN_BUF;            // get 32 bits            bs_refill( bs );            bs_refill( bs );            bs_refill( bs );            bs_refill( bs );            // begin bit level recoding            mpeg2_slice(tr, ID);            bs_flush_read( bs );            bs_flush_write( bs );            // end bit level recoding            /* Basic sanity checks --Meuuh */            if (bs->p_c > bs->p_r || bs->p_w > bs->p_rw)            {                return -1;            }            /*LOGF("type: %s code: %02i in : %6i out : %6i diff : %6i fact: %2.2f\n",            (picture_coding_type == I_TYPE ? "I_TYPE" : (picture_coding_type == P_TYPE ? "P_TYPE" : "B_TYPE")),            ID,  bs->p_c - inTemp, bs->p_w - outTemp, (bs->p_w - outTemp) - (bs->p_c - inTemp), (float)(bs->p_c - inTemp) / (float)(bs->p_w - outTemp));*/            if (bs->p_w - outTemp > bs->p_c - inTemp) // yes that might happen, rarely            {                /*LOGF("*** slice bigger than before !! (type: %s code: %i in : %i out : %i diff : %i)\n",                (picture_coding_type == I_TYPE ? "I_TYPE" : (picture_coding_type == P_TYPE ? "P_TYPE" : "B_TYPE")),                ID, bs->p_c - inTemp, bs->p_w - outTemp, (bs->p_w - outTemp) - (bs->p_c - inTemp));*/                // in this case, we'll just use the original slice !                memcpy(outTemp, inTemp, bs->p_c - inTemp);                bs->p_w = outTemp + (bs->p_c - inTemp);                // adjust bs->i_byte_out                bs->i_byte_out -= (bs->p_w - outTemp) - (bs->p_c - inTemp);            }        }    }    return 0;}static void process_frame( sout_stream_t *p_stream,                           sout_stream_id_t *id, sout_buffer_t *in, sout_buffer_t **out ){    transrate_t *tr = &id->tr;    bs_transrate_t *bs = &tr->bs;    sout_buffer_t       *p_out;    double              next_fact_x = 1.0;    /* The output buffer can't be bigger than the input buffer. */    p_out = sout_BufferNew( p_stream->p_sout, in->i_size );    p_out->i_length = in->i_length;    p_out->i_dts    = in->i_dts;    p_out->i_pts    = in->i_pts;    sout_BufferChain( out, p_out );    bs->p_rw = bs->p_ow = bs->p_w = p_out->p_buffer;    bs->p_c = bs->p_r = in->p_buffer;    bs->p_r += in->i_size + 4;    bs->p_rw += in->i_size;    *(in->p_buffer + in->i_size) = 0;    *(in->p_buffer + in->i_size + 1) = 0;    *(in->p_buffer + in->i_size + 2) = 1;    *(in->p_buffer + in->i_size + 3) = 0;    /* Calculate how late we are */    tr->quant_corr = 0.0 + B_HANDICAP;    tr->level_i = 0;    tr->level_p = 0;    bs->i_byte_in = in->i_size;    bs->i_byte_out  = 0;    if (tr->i_current_gop_size - in->i_size > 100)    {        if (tr->i_wanted_gop_size == in->i_size)        {            next_fact_x = 1.0;        }        else if ( tr->i_wanted_gop_size < in->i_size )        {            /* We're really late */            next_fact_x = 10.0;        }        else        {            next_fact_x = ((double)(tr->i_current_gop_size - in->i_size)) /                          (tr->i_wanted_gop_size - in->i_size);        }        if (next_fact_x > QUANT_I)        {            tr->level_i = 1;        }        if (next_fact_x > QUANT_P)        {            tr->level_p = 1 + (next_fact_x - QUANT_P) / (QUANT_P_INC);        }    }    if ( tr->i_wanted_gop_size < 0 )    {        /* We're really late */        tr->current_fact_x = 3.0;    }    else    {        tr->current_fact_x = ((double)(tr->i_current_gop_size) /                              (tr->i_wanted_gop_size));    }    for ( ; ; )    {        uint8_t *p_end = &in->p_buffer[in->i_size];        /* Search next start code */        for( ;; )        {            if( bs->p_c < p_end - 3 && bs->p_c[0] == 0 && bs->p_c[1] == 0 && bs->p_c[2] == 1 )            {                /* Next start code */                break;            }            else if( bs->p_c < p_end - 6 &&                     bs->p_c[0] == 0 && bs->p_c[1] == 0 && bs->p_c[2] == 0 &&                     bs->p_c[3] == 0 && bs->p_c[4] == 0 && bs->p_c[5] == 0 )            {                /* remove stuffing (looking for 6 0x00 bytes) */                bs->p_c++;            }            else            {                /* Copy */                *bs->p_w++ = *bs->p_c++;            }            if( bs->p_c >= p_end)            {                break;            }        }        if( bs->p_c >= p_end )        {            break;        }        /* Copy the start code */        memcpy(bs->p_w, bs->p_c, 3 );        bs->p_c += 3;        bs->p_w += 3;        if (do_next_start_code( tr ) )        {            /* Error */            break;        }        tr->quant_corr = (((bs->i_byte_in - (bs->p_r - 4 - bs->p_c)) / tr->fact_x) - (bs->i_byte_out + (bs->p_w - bs->p_ow))) / REACT_DELAY + B_HANDICAP;    }    bs->i_byte_out += bs->p_w - bs->p_ow;    p_out->i_size = bs->p_w - bs->p_ow;    tr->i_current_gop_size -= in->i_size;    tr->i_wanted_gop_size -= p_out->i_size;    tr->i_new_gop_size += bs->i_byte_out;#if 0    msg_Dbg( p_stream, "%d: %d -> %d (r: %f, n:%f, corr:%f)",             tr->picture_coding_type, in->i_size, p_out->i_size,             (float)in->i_size / p_out->i_size,             next_fact_x, tr->quant_corr);#endif}static int transrate_video_process( sout_stream_t *p_stream,               sout_stream_id_t *id, sout_buffer_t *in, sout_buffer_t **out ){    transrate_t    *tr = &id->tr;    bs_transrate_t *bs = &tr->bs;    vlc_bool_t     b_gop = VLC_FALSE;    *out = NULL;    if( GetDWBE( in->p_buffer ) != 0x100 )    {        uint8_t *p = in->p_buffer;        uint8_t *p_end = &in->p_buffer[in->i_size];        uint32_t code = GetDWBE( p );        /* We may have a GOP */        while( p < p_end - 4 )        {            if( code == 0x1b8 )            {                b_gop = VLC_TRUE;                break;            }            else if( code == 0x100 )            {                break;            }            code = ( code << 8 )|p[4];            p++;        }    }    if( b_gop && id->i_next_gop_duration >= 300000 )    {        while ( id->p_current_buffer != NULL )        {            sout_buffer_t * p_next = id->p_current_buffer->p_next;            if ( tr->fact_x == 1.0 )            {                bs->i_byte_out += id->p_current_buffer->i_size;                id->p_current_buffer->p_next = NULL;                sout_BufferChain( out, id->p_current_buffer );            }            else            {                process_frame( p_stream, id, id->p_current_buffer, out );                sout_BufferDelete(p_stream->p_sout, id->p_current_buffer);            }            id->p_current_buffer = p_next;        }        if ( id->i_next_gop_duration )        {            mtime_t i_bitrate = (mtime_t)id->i_next_gop_size * 8000                                    / (id->i_next_gop_duration / 1000);            static mtime_t i_old_bitrate = 0;            static mtime_t i_old_duration = 0;            if (i_old_bitrate && tr->fact_x != 1.0)            {                mtime_t i_new_bitrate = tr->i_new_gop_size * 8000 / (i_old_duration / 1000);                if (i_new_bitrate > p_stream->p_sys->i_vbitrate + 300000)                    msg_Err(p_stream, "%lld -> %lld (%f, r:%f)",                            i_old_bitrate, i_new_bitrate, tr->fact_x,                            (float)i_old_bitrate / i_new_bitrate);#if 0                else                    msg_Dbg(p_stream, "%lld -> %lld (%f, r:%f)",                            i_old_bitrate, i_new_bitrate, tr->fact_x,                            (float)i_old_bitrate / i_new_bitrate);#endif            }            i_old_bitrate = i_bitrate;            i_old_duration = id->i_next_gop_duration;            if ( i_bitrate > p_stream->p_sys->i_vbitrate )            {                tr->fact_x = (double)i_bitrate / p_stream->p_sys->i_vbitrate;            }            else            {                tr->fact_x = 1.0;            }            id->tr.i_current_gop_size = id->i_next_gop_size;            id->tr.i_wanted_gop_size = (p_stream->p_sys->i_vbitrate)                                    * (id->i_next_gop_duration / 1000) / 8000;            id->tr.i_new_gop_size = 0;            id->p_current_buffer = id->p_next_gop;            id->p_next_gop = NULL;            id->i_next_gop_duration = 0;            id->i_next_gop_size = 0;        }    }    /* Store the buffer for the next GOP. */    sout_BufferChain( &id->p_next_gop, in );    id->i_next_gop_duration += in->i_length;    id->i_next_gop_size += in->i_size;    if ( id->p_current_buffer != NULL )    {        sout_buffer_t * p_next = id->p_current_buffer->p_next;        if ( tr->fact_x == 1.0 )        {            bs->i_byte_out += id->p_current_buffer->i_size;            id->p_current_buffer->p_next = NULL;            sout_BufferChain( out, id->p_current_buffer );        }        else        {            process_frame( p_stream, id, id->p_current_buffer, out );            sout_BufferDelete(p_stream->p_sout, id->p_current_buffer);        }        id->p_current_buffer = p_next;    }    return VLC_SUCCESS;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?