1 /* ***** BEGIN LICENSE BLOCK *****
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
20 * Portions created by the Initial Developer are Copyright (C) 2004.
21 * All Rights Reserved.
23 * Contributor(s): Thomas Davies (Original Author),
25 * Anuradha Suraparaju,
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
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
,
49 DiracByteStream
& dirac_byte_stream
):
51 m_just_finished(true),
52 m_srcparams(pin
->GetSourceParams()),
54 m_predparams(encp
.GetPicPredParams()),
55 m_L1_sep(encp
.L1Sep()),
56 m_pparams(m_srcparams
.CFormat(),
59 m_encparams
.LumaDepth(),
60 m_encparams
.ChromaDepth() ),
62 m_current_display_pnum(-1),
63 m_current_code_pnum(0),
64 m_show_pnum(-1),m_last_picture_read(-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()
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() );
157 if (m_encparams
.NumL1() > 0)
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()))))
170 * Encode the remaining picture in the frame buffer. We check if
171 * the reference pictures are available and modify the picture sort
174 if (current_code_fnum
<= last_frame_read
)
176 m_current_display_pnum
= m_current_code_pnum
;
182 if (m_last_picture_read
>= m_current_display_pnum
)
188 if (m_last_picture_read
>= m_current_display_pnum
+ queue_size
)
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 );
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
= ¤t_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 );
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);
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;
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
= ¤t_pic
->GetPparams();
338 }while(subgroup_reconfig
==true);
340 //11. Do cut detection and insert intra pictures
341 if ( current_pic
->GetMEData().IntraBlockRatio()>0.3333 ){
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());
351 current_pic
->SetPictureSort (PictureSort::IntraNonRefPictureSort());
353 if ( m_encparams
.Verbose() )
354 std::cout
<<std::endl
<<"Cut detected and I-picture inserted!";
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(),
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
<<", ";
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 ";
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() )
417 else std::cout
<<"NON-REF";
420 if (current_pp
->PicSort().IsIntra())
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
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
++;
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
);
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
);
516 DiracByteStats
SequenceCompressor::EndSequence()
518 DiracByteStats seq_stats
;
522 seq_stats
=m_dirac_byte_stream
.EndSequence();
523 m_just_finished
= false;
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
549 m_ratecontrol
->SetCutPictureQualFactor();
551 m_ratecontrol
->CalcNextIntraQualFactor();
555 FrameSequenceCompressor::FrameSequenceCompressor(
556 StreamPicInput
* pin
,
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();
577 if ( rel_pnum
% gop_len
== 0){
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 );
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 );
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() )
659 m_last_picture_read
++;
664 int FrameSequenceCompressor::CodedToDisplay( const int cnum
)
670 // We have L1 and L2 pictures
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
682 {//we just have I-pictures, so no re-ordering
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
,
700 DiracByteStream
& dirac_byte_stream
):
701 SequenceCompressor(pin
, encp
, dirac_byte_stream
)
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) );
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() ){
735 m_last_picture_read
+=2;
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;
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();
779 if ( (rel_pnum
/2) % gop_len
== 0){
780 // Field 1 is Intra Field
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
);
787 pparams
.SetPicSort( PictureSort::InterRefPictureSort());
788 // Ref the previous I field
789 pparams
.Refs().push_back( pnum
-1 );
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());
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 );
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.
825 pparams
.SetPicSort( PictureSort::InterNonRefPictureSort());
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 );
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 );
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
863 // We have L1 and L2 frames
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
874 {//we just have I-frames, so no re-ordering
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();
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);