Fixed #2984304. Fix compilation errors reported by gcc 4.5.0.
[dirac-research.git] / libdirac_encoder / seq_compress.cpp
blobcb4cd5b6c0d641104de1f38b333b7a6824c2723e
1 /* ***** BEGIN LICENSE BLOCK *****
3 * $Id$ $Name$
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License
8 * Version 1.1 (the "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14 * the specific language governing rights and limitations under the License.
16 * The Original Code is BBC Research and Development code.
18 * The Initial Developer of the Original Code is the British Broadcasting
19 * Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 2004.
21 * All Rights Reserved.
23 * Contributor(s): Thomas Davies (Original Author),
24 * Scott R Ladd,
25 * Anuradha Suraparaju,
26 * Andrew Kennedy
27 * Myo Tun (Brunel University, myo.tun@brunel.ac.uk)
29 * Alternatively, the contents of this file may be used under the terms of
30 * the GNU General Public License Version 2 (the "GPL"), or the GNU Lesser
31 * Public License Version 2.1 (the "LGPL"), in which case the provisions of
32 * the GPL or the LGPL are applicable instead of those above. If you wish to
33 * allow use of your version of this file only under the terms of the either
34 * the GPL or LGPL and not to allow others to use your version of this file
35 * under the MPL, indicate your decision by deleting the provisions above
36 * and replace them with the notice and other provisions required by the GPL
37 * or LGPL. If you do not delete the provisions above, a recipient may use
38 * your version of this file under the terms of any one of the MPL, the GPL
39 * or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include <libdirac_encoder/seq_compress.h>
43 #include <libdirac_encoder/prefilter.h>
45 using namespace dirac;
47 SequenceCompressor::SequenceCompressor( StreamPicInput* pin ,
48 EncoderParams& encp,
49 DiracByteStream& dirac_byte_stream):
50 m_all_done(false),
51 m_just_finished(true),
52 m_srcparams(pin->GetSourceParams()),
53 m_encparams(encp),
54 m_predparams(encp.GetPicPredParams()),
55 m_L1_sep(encp.L1Sep()),
56 m_pparams(m_srcparams.CFormat(),
57 m_encparams.Xl(),
58 m_encparams.Yl(),
59 m_encparams.LumaDepth(),
60 m_encparams.ChromaDepth() ),
61 m_pic_in(pin),
62 m_current_display_pnum(-1),
63 m_current_code_pnum(0),
64 m_show_pnum(-1),m_last_picture_read(-1),
65 m_gop_start_num(0),
66 m_delay(1),
67 m_qmonitor( m_encparams ),
68 m_pcoder( m_encparams ),
69 m_dirac_byte_stream(dirac_byte_stream),
70 m_eos_signalled(false)
72 // Set up the compression of the sequence
74 //TBD: put into the constructor for EncoderParams
75 m_encparams.SetEntropyFactors( new EntropyCorrector(m_encparams.TransformDepth()) );
77 // Set up generic picture parameters
78 m_pparams.SetUsingAC(m_encparams.UsingAC() );
80 // Set up a rate controller if rate control being used
81 if (m_encparams.TargetRate() != 0)
82 m_ratecontrol = new RateController(m_encparams.TargetRate(),
83 m_pic_in->GetSourceParams(), encp);
85 // Copy in the block parameters in case we want to change them dynamically
86 m_basic_olb_params2 = &m_predparams.LumaBParams(2);
87 m_basic_olb_params1 = new OLBParams( 2*m_predparams.LumaBParams(2).Xblen(),
88 2*m_predparams.LumaBParams(2).Yblen(),
89 2*m_predparams.LumaBParams(2).Xbsep(),
90 2*m_predparams.LumaBParams(2).Ybsep() );
92 m_basic_olb_params0 = new OLBParams( 4*m_predparams.LumaBParams(2).Xblen(),
93 4*m_predparams.LumaBParams(2).Yblen(),
94 4*m_predparams.LumaBParams(2).Xbsep(),
95 4*m_predparams.LumaBParams(2).Ybsep() );
98 m_intra_olbp = new OLBParams( 2*m_basic_olb_params2->Xbsep() ,
99 2*m_basic_olb_params2->Ybsep() ,
100 m_basic_olb_params2->Xbsep() ,
101 m_basic_olb_params2->Ybsep() );
103 SetMotionParameters();
107 void SequenceCompressor::SetMotionParameters(){
109 if ( m_encparams.TargetRate() != 0 ){
110 OLBParams new_olb_params = *m_basic_olb_params2;
112 if (m_encparams.Qf()<2.5)
113 new_olb_params = *m_basic_olb_params1;
114 else if (m_encparams.Qf()<1.5)
115 new_olb_params = *m_basic_olb_params0;
117 m_predparams.SetBlockSizes( new_olb_params , m_srcparams.CFormat() );
121 int xl = m_encparams.Xl();
122 int yl = m_encparams.Yl();
124 // Make sure we have enough macroblocks to cover the pictures
125 m_predparams.SetXNumSB( (xl+m_predparams.LumaBParams(0).Xbsep()-1)/
126 m_predparams.LumaBParams(0).Xbsep() );
127 m_predparams.SetYNumSB( (yl+m_predparams.LumaBParams(0).Ybsep()-1)/
128 m_predparams.LumaBParams(0).Ybsep() );
130 m_predparams.SetXNumBlocks( 4 * m_predparams.XNumSB() );
131 m_predparams.SetYNumBlocks( 4 * m_predparams.YNumSB() );
135 SequenceCompressor::~SequenceCompressor()
137 delete m_intra_olbp;
138 delete m_basic_olb_params1;
139 delete m_basic_olb_params0;
141 if ( m_encparams.Verbose())
142 MakeSequenceReport();
144 //TBD: put into the destructor for EncoderParams
145 delete &m_encparams.EntropyFactors();
147 if (m_encparams.TargetRate()!=0)
148 delete m_ratecontrol;
151 bool SequenceCompressor::CanEncode()
153 const int queue_size = std::max( 4 , 2*m_encparams.L1Sep() );
155 if (m_eos_signalled)
157 if (m_encparams.NumL1() > 0)
160 * Long-GOP sequence
162 int field_factor = m_encparams.PictureCodingMode() ? 2 : 1;
163 int last_frame_read = m_last_picture_read/field_factor;
164 int current_code_fnum = m_current_code_pnum/field_factor;
166 if ((last_frame_read >= (current_code_fnum + (last_frame_read%m_encparams.L1Sep()))))
167 return true;
170 * Encode the remaining picture in the frame buffer. We check if
171 * the reference pictures are available and modify the picture sort
172 * accordingly.
174 if (current_code_fnum <= last_frame_read)
176 m_current_display_pnum = m_current_code_pnum;
177 return true;
180 else
182 if (m_last_picture_read >= m_current_display_pnum)
183 return true;
186 else
188 if (m_last_picture_read >= m_current_display_pnum + queue_size)
189 return true;
191 return false;
194 const EncPicture* SequenceCompressor::CompressNextPicture()
197 // This function codes the next picture in coding order and returns the next picture in display order
198 // In general these will differ, and because of re-ordering there is a m_delay which needs to be imposed.
199 // This creates problems at the start and at the end of the sequence which must be dealt with.
200 // At the start we just keep outputting picture 0. At the end you will need to loop for longer to get all
201 // the pictures out. It's up to the calling function to do something with the decoded pictures as they
202 // come out - write them to screen or to file, or whatever.
204 // current_pnum is the number of the current picture being coded in display order
205 // m_current_code_pnum is the number of the current picture in coding order. This function increments
206 // m_current_code_pnum by 1 each time and works out what the number is in display order.
207 // m_show_pnum is the index of the picture number that can be shown when current_pnum has been coded.
208 // Var m_delay is the m_delay caused by reordering (as distinct from buffering)
210 TESTM (m_last_picture_read >= 0, "Data loaded before calling CompressNextPicture");
212 const int field_factor = m_encparams.FieldCoding() ? 2 : 1;
214 // If we have a scheduled P picture, reset the P separation to normal
215 if ( m_encparams.L1Sep()!=m_L1_sep ){
216 if ( (m_current_code_pnum-field_factor) % (m_encparams.L1Sep()*field_factor)==0 )
217 m_L1_sep = m_encparams.L1Sep();
220 m_current_display_pnum = CodedToDisplay( m_current_code_pnum );
221 m_show_pnum = std::max( m_current_code_pnum - m_delay , 0 );
223 if ( CanEncode() )
226 // Compress the picture//
227 ///////////////////////
229 const std::vector<int>& queue_members = m_enc_pbuffer.Members();
231 EncPicture* current_pic = &m_enc_pbuffer.GetPicture( m_current_display_pnum );
232 PictureParams* current_pp = &current_pic->GetPparams();
234 // 1. Set the picture type and refs for all the pictures in the queue not already encoded
235 for (size_t i=0; i<queue_members.size(); ++i){
236 int pnum = queue_members[i];
237 EncPicture& enc_pic = m_enc_pbuffer.GetPicture(pnum);
239 if ( (enc_pic.GetStatus() & DONE_SET_PTYPE) == 0 ){
240 PictureParams& pparams = enc_pic.GetPparams();
241 // only look one subgroup ahead
242 if ((m_encparams.NumL1() == 0) || pparams.PictureNum() < m_current_display_pnum + m_encparams.L1Sep() ){
243 SetPicTypeAndRefs( pparams );
244 enc_pic.UpdateStatus( DONE_SET_PTYPE );
249 /* Do motion estimation and compensation if inter*/
250 bool is_a_cut( false );
252 //2. Set up block sizes etc
253 SetMotionParameters();
255 // Loop over the whole queue and ...
256 for (size_t i=0; i<queue_members.size(); ++i){
257 int pnum = queue_members[i];
258 EncPicture& enc_pic = m_enc_pbuffer.GetPicture(pnum);
260 if ( ( enc_pic.GetStatus() & DONE_SET_PTYPE) != 0 ){
261 PictureParams& pparams = enc_pic.GetPparams();
263 if ( pparams.PicSort().IsInter() ){
264 // 3.Initialise motion data
265 if ( ( enc_pic.GetStatus() & DONE_ME_INIT) == 0 ){
266 enc_pic.InitMEData( m_predparams , pparams.NumRefs() );
267 enc_pic.UpdateStatus( DONE_ME_INIT );
270 // 4. Do pixel-accurate motion estimation
271 if ( ( enc_pic.GetStatus() & DONE_PEL_ME) == 0 ){
272 m_pcoder.PixelME( m_enc_pbuffer, pnum );
273 enc_pic.UpdateStatus( DONE_PEL_ME );
276 // // 5. Set picture complexity
277 // if ( (enc_pic.GetStatus() & DONE_PIC_COMPLEXITY ) == 0 ){
278 // m_pcoder.CalcComplexity( m_enc_pbuffer, pnum, m_predparams.LumaBParams(2) );
279 // enc_pic.UpdateStatus( DONE_PIC_COMPLEXITY );
280 // }
282 //6. Revise the number of references if one ref is a bad predictor
283 // if ( (enc_pic.GetStatus() & DONE_PIC_COMPLEXITY)!=0 &&
284 // pparams.NumRefs()==2){
285 // if (enc_pic.GetPredBias()>0.8)
286 // enc_pic.DropRef(2);
287 // else if(enc_pic.GetPredBias()<0.2)
288 // enc_pic.DropRef(1);
289 // }
294 if ( current_pp->PicSort().IsInter() ){
295 // // 7. Normalise complexity for the current picture
296 // m_pcoder.NormaliseComplexity( m_enc_pbuffer, m_current_display_pnum );
298 bool subgroup_reconfig;
301 subgroup_reconfig = false;
303 //8. Do subpel refinement
304 m_pcoder.SubPixelME( m_enc_pbuffer, m_current_display_pnum );
306 //9. Do mode decision
307 m_pcoder.ModeDecisionME( m_enc_pbuffer, m_current_display_pnum );
309 //10. Work out how many blocks are intra
310 m_pcoder.IntraModeAnalyse( m_enc_pbuffer, m_current_display_pnum );
312 //11. Change the GOP structure to PPP if there are too many intras
313 if ( m_L1_sep>1 && current_pic->GetMEData().IntraBlockRatio()>0.25
314 && (m_current_display_pnum % (m_encparams.L1Sep()*field_factor))==0){
316 subgroup_reconfig = true;
318 m_L1_sep = 1;
319 for (int i = 0; i<field_factor*m_encparams.L1Sep(); ++i){
321 int pnum = m_current_display_pnum-i+(field_factor-1);
323 EncPicture& enc_pic = m_enc_pbuffer.GetPicture(pnum);
324 PictureParams& pparams = enc_pic.GetPparams();
326 SetPicTypeAndRefs( pparams );
327 enc_pic.UpdateStatus( DONE_SET_PTYPE );
329 current_pic->SetStatus( DONE_SET_PTYPE );
331 // Current picture to code has now changed: recalculate
332 m_current_display_pnum = CodedToDisplay( m_current_code_pnum );
333 current_pic = &m_enc_pbuffer.GetPicture(m_current_display_pnum );
334 current_pp = &current_pic->GetPparams();
338 }while(subgroup_reconfig==true);
340 //11. Do cut detection and insert intra pictures
341 if ( current_pic->GetMEData().IntraBlockRatio()>0.3333 ){
342 is_a_cut = true;
343 if ( m_encparams.L1Sep()>1 &&
344 (m_current_display_pnum % (field_factor*m_encparams.L1Sep())) == 0){
345 m_gop_start_num = current_pp->PictureNum();//restart the GOP
348 if ( current_pp->PicSort().IsRef() ) // Set the picture type to intra
349 current_pic->SetPictureSort (PictureSort::IntraRefPictureSort());
350 else
351 current_pic->SetPictureSort (PictureSort::IntraNonRefPictureSort());
353 if ( m_encparams.Verbose() )
354 std::cout<<std::endl<<"Cut detected and I-picture inserted!";
357 else{
358 //12. Do motion compensation if not a cut
359 // MEData& me_data = current_pic->GetMEData();
361 // if (me_data.IntraBlockRatio()>0.1)//FIXME: this is broken with adaptive block sizes
362 // m_predparams.SetBlockSizes(*m_intra_olbp, m_srcparams.CFormat() );
364 m_pcoder.MotionCompensate(m_enc_pbuffer, m_current_display_pnum, SUBTRACT );
365 current_pic->UpdateStatus( DONE_MC );
370 if ( current_pp->PicSort().IsRef()==true )
371 m_enc_pbuffer.SetRetiredPictureNum( m_show_pnum, m_current_display_pnum );
373 // 12. Now code the residual data and motion data
374 if (m_encparams.TargetRate() != 0)
375 UpdateIntraPicCBRModel( *current_pp, is_a_cut );
377 // 13. Write a sequence header if necessary
378 if( (m_encparams.NumL1() > 0 && current_pp->PicSort().IsRef()==true &&
379 current_pp->PicSort().IsIntra()==true && (m_current_display_pnum % m_encparams.L1Sep() == 0)) ||
380 (m_encparams.NumL1() == 0 && (m_current_display_pnum % m_encparams.GOPLength())==0))
382 if (m_encparams.Verbose())
384 std::cout<<std::endl<<std::endl<<"GOP start: writing sequence header before picture ";
385 std::cout<<m_current_display_pnum;
387 SequenceHeaderByteIO *p_seqheader_byteio = new SequenceHeaderByteIO
388 ( m_pic_in->GetSourceParams(),
389 m_encparams);
390 p_seqheader_byteio->Output();
392 m_dirac_byte_stream.AddSequenceHeader(p_seqheader_byteio);
395 // 13. Write the picture header.
396 PictureByteIO* p_picture_byteio = new PictureByteIO(*current_pp, m_current_display_pnum );
397 p_picture_byteio->Output();
399 if ( m_encparams.Verbose() ){
400 if (m_encparams.TargetRate()!=0 )
401 m_ratecontrol->Report();
403 if (m_encparams.FieldCoding())
404 std::cout<<std::endl<<std::endl<<"Compressing field "<<m_current_code_pnum<<", ";
405 else
406 std::cout<<std::endl<<std::endl<<"Compressing frame "<<m_current_code_pnum<<", ";
407 std::cout<<m_current_display_pnum<<" in display order";
409 if (is_a_cut==true || current_pp->PicSort().IsIntra()==false )
410 std::cout<<std::endl<<current_pic->GetMEData().IntraBlockRatio()*100.0<<"% of blocks are intra ";
411 if (is_a_cut==true)
412 std::cout<<std::endl<<"Cut detected and intra picture inserted.";
414 std::cout<<std::endl<<"Picture type is ";
415 if (current_pp->PicSort().IsRef() )
416 std::cout<<"REF";
417 else std::cout<<"NON-REF";
419 std::cout<<" , ";
420 if (current_pp->PicSort().IsIntra())
421 std::cout<<"INTRA";
422 else std::cout<<"INTER";
424 if ( current_pp->PicSort().IsInter() ){
425 std::cout<<std::endl<<"References "
426 << (m_encparams.FieldCoding() ? "field " : "frame ")
427 << current_pp->Refs()[0];
428 if (current_pp->Refs().size() > 1)
429 std::cout<<" and "<< current_pp->Refs()[1];
433 // 14. Code the motion vectors
434 if ( current_pp->PicSort().IsInter() )
435 m_pcoder.CodeMVData(m_enc_pbuffer , m_current_display_pnum, p_picture_byteio);
437 // 15. Do prefiltering on the residue if necessary
438 if (m_encparams.Prefilter() != NO_PF )
439 m_pcoder.Prefilter( m_enc_pbuffer, m_current_display_pnum );
441 // 16. Do the transform on the 3 components
442 m_pcoder.DoDWT( m_enc_pbuffer, m_current_display_pnum , FORWARD);
444 // 17. Select the quantisers
446 // 18. Code the residue
447 m_pcoder.CodeResidue(m_enc_pbuffer , m_current_display_pnum, p_picture_byteio);
449 const PictureSort& psort = current_pp->PicSort();
451 /* All coding is done - so output and reconstruct */
453 m_dirac_byte_stream.AddPicture(p_picture_byteio);
455 // 19. Do the inverse DWT if necessary
456 m_pcoder.DoDWT( m_enc_pbuffer, m_current_display_pnum , BACKWARD);
459 // 20. Motion compensate back if necessary
460 if (psort.IsInter() && !is_a_cut )
461 m_pcoder.MotionCompensate(m_enc_pbuffer, m_current_display_pnum, ADD );
463 // Reset block sizes for next picture
464 m_predparams.SetBlockSizes(*m_basic_olb_params2, m_srcparams.CFormat() );
466 // 21. Clip the data to keep it in range
467 current_pic->Clip();
469 // Use the results of encoding to update the CBR model
470 if (m_encparams.TargetRate() != 0 )
471 UpdateCBRModel(*current_pic, p_picture_byteio);
473 // 22. Measure the encoded picture quality
474 if ( m_encparams.LocalDecode() )
475 m_qmonitor.UpdateModel( *current_pic );
477 // Increment our position
478 m_current_code_pnum++;
480 CleanBuffers();
482 current_pic->SetStatus( ALL_ENC );
486 // Return the latest picture that can be shown
487 if ( m_enc_pbuffer.GetPicture(m_show_pnum).GetStatus() == ALL_ENC ){
488 if ( m_encparams.Verbose() ){
489 std::cout<<std::endl<<"Return " <<
490 (m_encparams.FieldCoding() ? "field " : "frame ") <<
491 m_show_pnum << " in display order";
493 return &m_enc_pbuffer.GetPicture(m_show_pnum );
495 else
496 return NULL;
501 void SequenceCompressor::CleanBuffers()
503 // If we're not at the beginning, clean the buffer
504 if ( m_current_code_pnum != 0 )
505 m_enc_pbuffer.CleanRetired( m_show_pnum, m_current_display_pnum );
508 const EncPicture *SequenceCompressor::GetPictureEncoded()
510 if (m_current_display_pnum >= 0)
511 return &m_enc_pbuffer.GetPicture( m_current_display_pnum );
513 return 0;
516 DiracByteStats SequenceCompressor::EndSequence()
518 DiracByteStats seq_stats;
520 if (m_just_finished)
522 seq_stats=m_dirac_byte_stream.EndSequence();
523 m_just_finished = false;
524 m_all_done = true;
527 return seq_stats;
532 void SequenceCompressor::MakeSequenceReport()
534 if ( m_encparams.LocalDecode() )
535 m_qmonitor.WriteLog();
537 std::cout<<std::endl;
541 void SequenceCompressor::UpdateIntraPicCBRModel( const PictureParams& pparams, const bool is_a_cut ){
542 // For intra pictures we want to update before coding
543 // especially if they're inserted
545 if ( pparams.PicSort().IsIntra() && m_current_display_pnum > 0 &&
546 m_encparams.NumL1() != 0){
547 // Calculate the new QF for encoding the following I picture
548 if ( is_a_cut )
549 m_ratecontrol->SetCutPictureQualFactor();
550 else
551 m_ratecontrol->CalcNextIntraQualFactor();
555 FrameSequenceCompressor::FrameSequenceCompressor(
556 StreamPicInput* pin ,
557 EncoderParams& encp,
558 DiracByteStream& dirac_byte_stream):
559 SequenceCompressor(pin, encp, dirac_byte_stream)
563 void FrameSequenceCompressor::SetPicTypeAndRefs( PictureParams& pparams )
565 // Set the temporal prediction parameters for frame coding
567 const int pnum = pparams.PictureNum();
568 const int rel_pnum = pnum - m_gop_start_num;
569 const int gop_len = m_encparams.GOPLength();
570 const int num_L1 = m_encparams.NumL1();
572 pparams.SetRetiredPictureNum( -1 );
573 pparams.Refs().clear();
575 if ( num_L1>0 ){
577 if ( rel_pnum % gop_len == 0){
578 if (gop_len > 1)
579 pparams.SetPicSort( PictureSort::IntraRefPictureSort());
580 else // I-picture only coding
581 pparams.SetPicSort( PictureSort::IntraNonRefPictureSort());
583 // I picture expires after we've coded the next I picture
584 pparams.SetExpiryTime( 2*m_L1_sep );
586 else if (rel_pnum % m_L1_sep == 0){
587 pparams.SetPicSort( PictureSort::InterRefPictureSort());
589 // Ref the previous I or L1 picture
590 pparams.Refs().push_back( pnum - m_L1_sep );
592 // if we don't have the first L1 picture ...
593 if ( ((rel_pnum-m_L1_sep) % gop_len>0) && m_L1_sep>1)
594 // ... other ref is the prior I/L1 picture but one
595 pparams.Refs().push_back( pnum - 2*m_L1_sep );
597 // Expires after the next L1 or I picture
598 pparams.SetExpiryTime( 2*m_L1_sep );
599 if (rel_pnum % m_encparams.L1Sep() == 0 )
600 pparams.SetExpiryTime(2*m_encparams.L1Sep());
602 else if ((rel_pnum+1) % m_L1_sep == 0){
603 pparams.SetPicSort( PictureSort::InterNonRefPictureSort());
605 // .. and the previous picture
606 pparams.Refs().push_back(pnum-1);
607 // Refs are the next I or L1 picture ...
608 if (m_enc_pbuffer.IsPictureAvail(pnum+1))
609 pparams.Refs().push_back(pnum+1);
611 pparams.SetExpiryTime( 1 );
613 else{
614 pparams.SetPicSort( PictureSort::InterRefPictureSort());
616 // .. and the previous picture
617 pparams.Refs().push_back(pnum-1);
618 // Refs are the next I or L1 picture ...
619 int next_ref = ((pnum/m_L1_sep)+1)*m_L1_sep;
620 if (m_enc_pbuffer.IsPictureAvail(next_ref))
621 pparams.Refs().push_back(next_ref);
623 pparams.SetExpiryTime( 2 );
627 else{
628 pparams.SetPicSort( PictureSort::IntraNonRefPictureSort());
629 pparams.SetExpiryTime( 1 );
634 bool FrameSequenceCompressor::LoadNextFrame()
636 PictureParams pp( m_pparams );
637 pp.SetPictureNum( m_last_picture_read+1 );
639 // Set an initially huge expiry time as we don't know when it will expire yet
640 pp.SetExpiryTime(1<<30);
642 m_enc_pbuffer.PushPicture( pp );
644 m_pic_in->ReadNextPicture( m_enc_pbuffer.GetPicture(m_last_picture_read+1) );
646 // Copy into the original data
647 m_enc_pbuffer.GetPicture(m_last_picture_read+1).SetOrigData();
649 if ( m_encparams.Prefilter()==CWM )
650 CWMFilter(m_enc_pbuffer.GetPicture( m_last_picture_read+1 ) ,
651 m_encparams.PrefilterStrength() );
653 if ( m_pic_in->End() )
655 m_all_done = true;
656 return false;
659 m_last_picture_read++;
661 return true;
664 int FrameSequenceCompressor::CodedToDisplay( const int cnum )
666 int div;
668 if (m_L1_sep>0)
670 // We have L1 and L2 pictures
671 if (cnum==0)
672 return 0;
673 else if ((cnum-1)% m_L1_sep==0)
674 {//we have L1 or subsequent I pictures
675 div=(cnum-1)/m_L1_sep;
676 return cnum+m_L1_sep-1;
678 else//we have L2 pictures
679 return cnum-1;
681 else
682 {//we just have I-pictures, so no re-ordering
684 return cnum;
688 void FrameSequenceCompressor::UpdateCBRModel(EncPicture& my_frame,
689 const PictureByteIO* p_picture_byteio)
691 // Update the quality factor
692 m_ratecontrol->CalcNextQualFactor(my_frame.GetPparams(), p_picture_byteio->GetSize()*8);
697 FieldSequenceCompressor::FieldSequenceCompressor(
698 StreamPicInput* pin ,
699 EncoderParams& encp,
700 DiracByteStream& dirac_byte_stream):
701 SequenceCompressor(pin, encp, dirac_byte_stream)
703 m_delay = 2;
706 bool FieldSequenceCompressor::LoadNextFrame()
708 PictureParams pp( m_pparams );
709 pp.SetExpiryTime( 1<<30 );
711 int pnum = m_last_picture_read+1;
713 for (int j=pnum; j<=pnum+1; ++j){
714 pp.SetPictureNum( j );
715 m_enc_pbuffer.PushPicture( pp );
718 StreamFieldInput* field_input = (StreamFieldInput*) m_pic_in;
719 field_input->ReadNextFrame( m_enc_pbuffer.GetPicture( pnum ), m_enc_pbuffer.GetPicture(pnum+1) );
721 // Copy data across
722 for (int j=pnum; j<=pnum+1; ++j){
723 m_enc_pbuffer.GetPicture( j ).SetOrigData();
725 if ( m_encparams.Prefilter()==CWM )
726 CWMFilter(m_enc_pbuffer.GetPicture( j ), m_encparams.PrefilterStrength() );
730 if ( m_pic_in->End() ){
731 m_all_done = true;
732 return false;
735 m_last_picture_read +=2;
737 return true;
740 void FieldSequenceCompressor::PreMotionEstmationFilter(PicArray& comp)
742 //Special case for first row
743 for (int i = comp.FirstX(); i <= comp.LastX(); ++i)
745 comp[comp.FirstY()][i] = (3*comp[comp.FirstY()][i] +
746 comp[comp.FirstY()+1][i] +2 )>>2;
748 //Middle section
749 for (int j = comp.FirstY()+1; j < comp.LastY(); ++j)
751 for (int i = comp.FirstX(); i <= comp.LastX(); ++i)
753 comp[j][i] = (comp[j-1][i] + 2*comp[j][i] + comp[j+1][i] + 2)>>2;
756 //Special case for last row
757 for (int i = comp.FirstX(); i <= comp.LastX(); ++i)
759 comp[comp.LastY()][i] = (comp[comp.LastY()-1][i] +
760 3*comp[comp.LastY()][i] + 2)>>2;
764 void FieldSequenceCompressor::SetPicTypeAndRefs( PictureParams& pparams )
766 // FIXME: won't work with adaptive GOP properly
767 // Set the temporal prediction parameters for field coding
769 const int pnum = pparams.PictureNum();
770 const int rel_pnum = pparams.PictureNum()-m_gop_start_num;
771 const int gop_len = m_encparams.GOPLength();
772 const int num_L1 = m_encparams.NumL1();
774 pparams.SetRetiredPictureNum( -1 );
775 pparams.Refs().clear();
777 if ( num_L1>0 ){
779 if ( (rel_pnum/2) % gop_len == 0){
780 // Field 1 is Intra Field
781 if (gop_len > 1){
782 pparams.SetPicSort( PictureSort::IntraRefPictureSort());
783 // I picture expires after we've coded the next L1 picture
784 pparams.SetExpiryTime( gop_len * 2);
785 pparams.SetExpiryTime( 2*m_L1_sep );
786 if ( pnum%2){
787 pparams.SetPicSort( PictureSort::InterRefPictureSort());
788 // Ref the previous I field
789 pparams.Refs().push_back( pnum-1 );
792 else{
793 // I-picture only coding
794 pparams.SetPicSort( PictureSort::IntraNonRefPictureSort());
795 pparams.SetExpiryTime( gop_len );
798 else if ((rel_pnum/2) % m_L1_sep == 0){
800 pparams.SetPicSort( PictureSort::InterRefPictureSort());
802 if (pnum%2){
803 // Field 2
804 // Ref the first field of same picture
805 pparams.Refs().push_back( pnum - 1);
806 // Ref the previous field 2 of I or L1 picture
807 pparams.Refs().push_back( pnum - m_L1_sep*2 );
809 else{
810 // Field 1
811 // Ref the field 1 of previous I or L1 picture
812 pparams.Refs().push_back( pnum - m_L1_sep*2 );
813 // Ref the field 2 of previous I or L1 picture
814 pparams.Refs().push_back( pnum - m_L1_sep*2 + 1 );
817 // Expires after the next L1 or I picture
818 pparams.SetExpiryTime( (m_L1_sep+1)*2-1 );
819 if ((rel_pnum/2) % m_encparams.L1Sep() == 0 )
820 pparams.SetExpiryTime((2*m_encparams.L1Sep())+1*2-1);
822 else if ((rel_pnum/2+1) % m_L1_sep == 0){
823 // Bi-directional non-reference fields.
824 if (pnum%2)
825 pparams.SetPicSort( PictureSort::InterNonRefPictureSort());
826 else
827 pparams.SetPicSort( PictureSort::InterRefPictureSort());
829 pparams.Refs().push_back(pnum-1);
830 if (m_enc_pbuffer.IsPictureAvail(pnum+2))
831 pparams.Refs().push_back(pnum+2);
833 pparams.SetExpiryTime( 1 );
835 else{
836 // Bi-directional reference fields.
837 pparams.SetPicSort( PictureSort::InterRefPictureSort());
839 pparams.Refs().push_back(pnum-1);
840 int next_ref = (((pnum/2)/m_L1_sep+1)*m_L1_sep)*2+(pnum%2);
841 if (m_enc_pbuffer.IsPictureAvail(next_ref))
842 pparams.Refs().push_back(next_ref);
843 pparams.SetExpiryTime( 4 );
847 else{
848 pparams.SetPicSort( PictureSort::IntraNonRefPictureSort());
849 pparams.SetExpiryTime( 2 );
853 FieldSequenceCompressor::~FieldSequenceCompressor()
857 int FieldSequenceCompressor::CodedToDisplay( const int pnum )
859 // Frame the field pnum belongs to
860 int fnum = pnum>>1;
861 if (m_L1_sep>0)
863 // We have L1 and L2 frames
864 if (fnum==0)
865 return pnum;
866 else if ((fnum-1)% m_L1_sep==0)
867 {//we have L1 or subsequent I frames
868 return (pnum+(m_L1_sep-1)*2);
870 else//we have L2 frames
871 return (pnum - 2);
873 else
874 {//we just have I-frames, so no re-ordering
875 return (pnum);
879 void FieldSequenceCompressor::UpdateCBRModel(EncPicture& my_picture,
880 const PictureByteIO* p_picture_byteio)
882 if (m_current_display_pnum%2 == 0)
883 m_field1_bytes = p_picture_byteio->GetSize();
884 else
885 m_field2_bytes = p_picture_byteio->GetSize();
887 // Update the quality factor
888 if (my_picture.GetPparams().PictureNum()%2)
889 m_ratecontrol->CalcNextQualFactor(my_picture.GetPparams(), (m_field1_bytes+m_field2_bytes)*8);