seqencoder.cc

来自「Motion JPEG编解码器源代码」· CC 代码 · 共 620 行 · 第 1/2 页

CC
620
字号
	if( encparams.fieldpic )	{		picture->Adjust2ndField();		mjpeg_debug("Field %s (%d)",				   (picture->pict_struct == TOP_FIELD) ? "top" : "bot",				   picture->pict_struct			);        if( encparams.encoding_parallelism > 0 )        {            despatcher.Despatch( picture, &MacroBlock::Encode );            despatcher.WaitForCompletion();        }        else        {            picture->EncodeMacroBlocks();        }		picture->QuantiseAndEncode(ratecontroller);		picture->Reconstruct();	}	mjpeg_info("Frame %5d %5d %c q=%3.2f sum act=%8.5f %s",                picture->decode,                picture->input,			   pict_type_char[picture->pict_type],               picture->AQ,               picture->sum_avg_act,               picture->pad ? "PAD" : "   "        );			}/********************* * * Init - Setup worker threads an set internal encoding state for * beginning of stream = beginning of first sequence.  Do no actual * encoding or I/O....  *  N.b. It is *critical* that the reference and b * picture buffers are at least two larger than the number of encoding * worker threads.  The despatcher thread *must* have to halt to wait * for free worker threads *before* it re-uses the record for the * Picture record for the oldest frame that could still be needed by * active worker threads. *  *  Buffers sizes are given by encparams.max_active_ref_frames and *  encparams.max_active_b_frames * ********************/ void SeqEncoder::Init(){    //    // Setup the parallel job despatcher...    //    despatcher.Init( encparams.mb_width,                      encparams.mb_height2,                      encparams.encoding_parallelism );	old_ref_picture = 0;    new_ref_picture = GetPicture();	ReleasePicture( new_ref_picture );	ratecontroller.InitSeq(false);    ss.Init(  );}/********************* * * EncodeStream - Where it all happens.  This is the top-level loop * that despatches all the encoding work.  Encoding is always performed * two-pass.  * Pass 1: a first encoding that determines the GOP * structure, but may only do rough-and-ready bit allocatino that is  * visually sub-optimal and/or may violate the specified maximum bit-rate. *  * Pass 2: Pictures from Pass1 are, if necessary, re-quantised and the results * coded to accurate achieve good bit-allocation and satisfy bit-rate limits. *  * In 'single-pass mode' pass 2 re-encodes only if it 'has to'. * In 'look-ahead mode' pass 2 always re-encodes. * In 'Pass 1 of two-pass mode' Pass-2 simply dumps frame complexity and motion * estimation data from Pass-1. * In 'Pass 2 of two-pass mode' Pass-1 rebuilds frames based on ME and complexity * data from  a 'Pass 1 of two-pass mode' run and Pass-2 does some final optimisation. * * N.b. almost all the interesting stuff occurs in the Pass1 encoding. If selected: * - A GOP may be low-passed and re-encoded if it looks like excessive quantisation  * is needed.  * - GOP length is determined (P frames with mostly intra-coded blocks are turned * into I-frames. * * NOTE: Eventually there will be support for Pass2 to occur in seperate threads... *  ********************/ void SeqEncoder::EncodeStream(){    //    // Repeated calls to TransformFrame build up the queue of    // Encoded with quantisation controlled by the    // pass1 rate controller.    do     {        // If we have Pass2 work to do        if( pass2queue.size() != 0 )        {            Pass2EncodeFrame();        }        else        {            Pass1EncodeFrame();            ss.Next( BitsAfterMux() );         }    } while( pass2queue.size() != 0 ||  ss.FrameInStream() < reader.NumberOfFrames() );    assert( pass2queue.size() == 0 );    assert( pass1coded.size() == 0 );    StreamEnd();}Picture *SeqEncoder::GetPicture(){    if( free_pictures.size() == 0 )        return new Picture(encparams,  writer , quantizer);    else    {        Picture *free = free_pictures.back();        free_pictures.pop_back();        return free;    }}void SeqEncoder::ReleasePicture( Picture *picture ){    free_pictures.push_back( picture );}/********************* * * Pass1EncodeFrame - Do a unit of work in building up a queue of * Pass-1 encoded frame's. * * A Picture is encoded based on a normal (maximum) length GOP with quantisation * determined by Pass1 rate controller. *  * If the Picture is a P-frame and is almost entirely intra-coded the picture is * converted to an I-frame and the current GOP ended early. * * Once a GOP is succesfully completed its Picture's are transferred to the * pass2queue for Pass-2 encoding. * *********************/   void SeqEncoder::Pass1EncodeFrame(){    old_picture = cur_picture;        if ( ss.b_idx == 0 ) // I or P Frame (First frame in B-group)    {        old_ref_picture = new_ref_picture;        new_ref_picture = cur_picture = GetPicture();        cur_picture->fwd_org = old_ref_picture->org_img;        cur_picture->fwd_rec = old_ref_picture->rec_img;        cur_picture->fwd_ref_frame = old_ref_picture;        cur_picture->bwd_ref_frame = 0;    }    else    {        cur_picture = GetPicture();        cur_picture->fwd_org = old_ref_picture->org_img;        cur_picture->fwd_rec = old_ref_picture->rec_img;        cur_picture->bwd_org = new_ref_picture->org_img;        cur_picture->bwd_rec = new_ref_picture->rec_img;        cur_picture->fwd_ref_frame = old_ref_picture;        cur_picture->bwd_ref_frame = new_ref_picture;    }    cur_picture->SetEncodingParams(ss, reader.NumberOfFrames() );    reader.ReadFrame( cur_picture->input, cur_picture->org_img );    EncodePicture( cur_picture );    if( cur_picture->end_seq )        mjpeg_info( "Sequence end inserted");#ifdef DEBUG    writeframe(cur_picture->temp_ref+ss.gop_start_frame,cur_picture->rec_img);#endif     // Hard-wired simple 1-pass encoder!!!    //cur_picture->Commit();    pass1coded.push_back( cur_picture );        // Figure out how many pictures can be queued on to pass 2 encoding    int to_queue = 0;    int i;    if( cur_picture->end_seq )    {        // If end of sequence we flush everything as next GOP won't refer to this frame        to_queue = pass1coded.size();    }    else if( ss.b_idx == 0  )    // I or P Frame (First frame in B-group)    {            // Decide if a P frame really should have been an I-frame, and re-encoded        // as such if necessary        if( cur_picture->IntraCodedBlocks() > 0.8 && ss.g_idx >= encparams.N_min )        {            mjpeg_info( "DEVEL: GOP split point found here... %.0f%% intra coded",                         cur_picture->IntraCodedBlocks() * 100.0 );            //ss.ForceIFrame();            //cur_picture->SetEncodingParams(ss, reader.NumberOfFrames());            //ReEncodePicture( cur_picture );        }        // We have a new fwd reference picture: anything decoded before        // will no longer be referenced and can be passed on.        for( i = 0; i < pass1coded.size();  ++i )        {            if( pass1coded[i] == old_ref_picture)                 break;        }        to_queue = i == pass1coded.size() ? 0 : i;    }     for( i = 0; i < to_queue; ++i )    {        pass2queue.push_back( pass1coded.front() );        pass1coded.pop_front();    }    }/***********************   BitsAfterMux    -   Estimate the size of the multiplexed stream based*                   on video stream size and estimate overheads for other*                   components**********************/uint64_t    SeqEncoder::BitsAfterMux() const{    double frame_periods;    uint64_t bits_after_mux;    if( encparams.pulldown_32 )        frame_periods = (double)ss.FrameInStream()*(5.0/4.0);    else        frame_periods = (double)ss.FrameInStream();    //    //    For VBR we estimate total bits based on actual stream size and    //    an estimate for the other streams based on time.    //    For CBR we do *both* based on time to account for padding during    //    muxing.        if( encparams.quant_floor > 0.0 )       // VBR        bits_after_mux =             writer.BitCount() +  (uint64_t)((frame_periods / encparams.frame_rate) * encparams.nonvid_bit_rate);    else                                    // CBR        bits_after_mux =             (uint64_t)((frame_periods / encparams.frame_rate) * (encparams.nonvid_bit_rate + encparams.bit_rate));    return bits_after_mux;}   /********************* * * Pass2EncodeFrame - Take a frame from pass2queue if necessary * requantize and re-encode then commit the result. * *********************/   void SeqEncoder::Pass2EncodeFrame(){    Picture *cur_pass2_picture = pass2queue.front();    pass2queue.pop_front();    // Simple single-pass encoding (look-ahead coming soon)    cur_pass2_picture->Commit();    ReleasePicture( cur_pass2_picture );}void SeqEncoder::StreamEnd(){    uint64_t bits_after_mux = BitsAfterMux();    mjpeg_info( "Guesstimated final muxed size = %lld\n", bits_after_mux/8 );        int i;    for( i = 0; i < free_pictures.size(); ++i )    {        delete free_pictures[i];    }}/*  * Local variables: *  c-file-style: "stroustrup" *  tab-width: 4 *  indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

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