source: SHVCSoftware/branches/SHM-6-dev/source/App/TAppDecoder/TAppDecTop.cpp @ 1426

Last change on this file since 1426 was 809, checked in by seregin, 11 years ago

fix last AU pictures output, patch was provided by Ramasubramonian, Adarsh Krishnan <aramasub@…>

  • Property svn:eol-style set to native
File size: 55.7 KB
Line 
1/* The copyright in this software is being made available under the BSD
2 * License, included below. This software may be subject to other third party
3 * and contributor rights, including patent rights, and no such rights are
4 * granted under this license.
5 *
6 * Copyright (c) 2010-2014, ITU/ISO/IEC
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 *  * Redistributions of source code must retain the above copyright notice,
13 *    this list of conditions and the following disclaimer.
14 *  * Redistributions in binary form must reproduce the above copyright notice,
15 *    this list of conditions and the following disclaimer in the documentation
16 *    and/or other materials provided with the distribution.
17 *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
18 *    be used to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/** \file     TAppDecTop.cpp
35    \brief    Decoder application class
36*/
37
38#include <list>
39#include <vector>
40#include <stdio.h>
41#include <fcntl.h>
42#include <assert.h>
43#include <iostream>
44#include "TAppDecTop.h"
45#include "TLibDecoder/AnnexBread.h"
46#include "TLibDecoder/NALread.h"
47//! \ingroup TAppDecoder
48//! \{
49
50// ====================================================================================================================
51// Constructor / destructor / initialization / destroy
52// ====================================================================================================================
53
54#if SVC_EXTENSION
55TAppDecTop::TAppDecTop()
56{
57  for(UInt layer=0; layer < MAX_LAYERS; layer++)
58  {
59    m_aiPOCLastDisplay[layer]  = -MAX_INT;
60    m_apcTDecTop[layer] = &m_acTDecTop[layer];
61  }
62}
63#else
64TAppDecTop::TAppDecTop()
65: m_iPOCLastDisplay(-MAX_INT)
66{
67}
68#endif
69
70Void TAppDecTop::create()
71{
72}
73
74Void TAppDecTop::destroy()
75{
76  if (m_pchBitstreamFile)
77  {
78    free (m_pchBitstreamFile);
79    m_pchBitstreamFile = NULL;
80  }
81#if SVC_EXTENSION
82  for( Int i = 0; i <= m_tgtLayerId; i++ )
83  {
84    if( m_pchReconFile[i] )
85    {
86      free ( m_pchReconFile[i] );
87      m_pchReconFile[i] = NULL;
88    }
89  }
90#if AVC_BASE
91  if( m_pchBLReconFile )
92  {
93    free ( m_pchBLReconFile );
94    m_pchBLReconFile = NULL;
95  }
96#endif
97#else
98  if (m_pchReconFile)
99  {
100    free (m_pchReconFile);
101    m_pchReconFile = NULL;
102  }
103#endif
104#if AVC_SYNTAX || SYNTAX_OUTPUT
105  if( m_pchBLSyntaxFile )
106  {
107    free ( m_pchBLSyntaxFile );
108    m_pchBLSyntaxFile = NULL;
109  }
110#endif
111}
112
113// ====================================================================================================================
114// Public member functions
115// ====================================================================================================================
116
117/**
118 - create internal class
119 - initialize internal class
120 - until the end of the bitstream, call decoding function in TDecTop class
121 - delete allocated buffers
122 - destroy internal class
123 .
124 */
125#if SVC_EXTENSION
126Void TAppDecTop::decode()
127{
128  Int                poc;
129  TComList<TComPic*>* pcListPic = NULL;
130
131  ifstream bitstreamFile(m_pchBitstreamFile, ifstream::in | ifstream::binary);
132  if (!bitstreamFile)
133  {
134    fprintf(stderr, "\nfailed to open bitstream file `%s' for reading\n", m_pchBitstreamFile);
135    exit(EXIT_FAILURE);
136  }
137
138  InputByteStream bytestream(bitstreamFile);
139
140  // create & initialize internal classes
141  xCreateDecLib();
142  xInitDecLib  ();
143
144  // main decoder loop
145  Bool openedReconFile[MAX_LAYERS]; // reconstruction file not yet opened. (must be performed after SPS is seen)
146  Bool loopFiltered[MAX_LAYERS];
147  memset( loopFiltered, false, sizeof( loopFiltered ) );
148
149  for(UInt layer=0; layer<=m_tgtLayerId; layer++)
150  {
151    openedReconFile[layer] = false;
152    m_aiPOCLastDisplay[layer] += m_iSkipFrame;      // set the last displayed POC correctly for skip forward.
153  }
154
155  UInt curLayerId = 0;     // current layer to be reconstructed
156
157#if AVC_BASE
158  TComPic pcBLPic;
159  fstream streamYUV;
160  if( m_pchBLReconFile )
161  {
162    streamYUV.open( m_pchBLReconFile, fstream::in | fstream::binary );
163  }
164  TComList<TComPic*> *cListPic = m_acTDecTop[0].getListPic();
165#if AVC_SYNTAX || !REPN_FORMAT_IN_VPS
166  m_acTDecTop[0].setBLsize( m_iBLSourceWidth, m_iBLSourceHeight );
167#endif
168  m_acTDecTop[0].setBLReconFile( &streamYUV );
169  pcBLPic.setLayerId( 0 );
170  cListPic->pushBack( &pcBLPic );
171#if AVC_SYNTAX
172  fstream streamSyntaxFile;
173  if( m_pchBLSyntaxFile )
174  {
175    streamSyntaxFile.open( m_pchBLSyntaxFile, fstream::in | fstream::binary );
176  }
177  m_acTDecTop[0].setBLSyntaxFile( &streamSyntaxFile );
178#endif
179#endif
180
181  while (!!bitstreamFile)
182  {
183    /* location serves to work around a design fault in the decoder, whereby
184     * the process of reading a new slice that is the first slice of a new frame
185     * requires the TDecTop::decode() method to be called again with the same
186     * nal unit. */
187    streampos location = bitstreamFile.tellg();
188    AnnexBStats stats = AnnexBStats();
189
190    vector<uint8_t> nalUnit;
191    InputNALUnit nalu;
192    byteStreamNALUnit(bytestream, nalUnit, stats);
193    // call actual decoding function
194    Bool bNewPicture = false;
195    Bool bNewPOC = false;
196    if (nalUnit.empty())
197    {
198      /* this can happen if the following occur:
199       *  - empty input file
200       *  - two back-to-back start_code_prefixes
201       *  - start_code_prefix immediately followed by EOF
202       */
203      fprintf(stderr, "Warning: Attempt to decode an empty NAL unit\n");
204    }
205    else
206    {
207      read(nalu, nalUnit);
208      if( (m_iMaxTemporalLayer >= 0 && nalu.m_temporalId > m_iMaxTemporalLayer) || !isNaluWithinTargetDecLayerIdSet(&nalu)  ||
209        (nalu.m_layerId > m_tgtLayerId) )
210      {
211        bNewPicture = false;
212      }
213      else
214      {
215        bNewPicture = m_acTDecTop[nalu.m_layerId].decode(nalu, m_iSkipFrame, m_aiPOCLastDisplay[nalu.m_layerId], curLayerId, bNewPOC);
216#if POC_RESET_IDC_DECODER
217        if ( (bNewPicture && m_acTDecTop[nalu.m_layerId].getParseIdc() == 3) || (m_acTDecTop[nalu.m_layerId].getParseIdc() == 0) )
218#else
219        if (bNewPicture)
220#endif
221        {
222          bitstreamFile.clear();
223          /* location points to the current nalunit payload[1] due to the
224           * need for the annexB parser to read three extra bytes.
225           * [1] except for the first NAL unit in the file
226           *     (but bNewPicture doesn't happen then) */
227          bitstreamFile.seekg(location-streamoff(3));
228          bytestream.reset();
229        }
230#if POC_RESET_IDC_DECODER
231        else if(m_acTDecTop[nalu.m_layerId].getParseIdc() == 1) 
232        {
233          bitstreamFile.clear();
234          // This is before third parse of the NAL unit, and
235          // location points to correct beginning of the NALU
236          bitstreamFile.seekg(location);
237          bytestream.reset();
238        }
239#endif
240      }
241    }
242
243#if POC_RESET_IDC_DECODER
244    if ((bNewPicture && m_acTDecTop[nalu.m_layerId].getParseIdc() == 3) || (m_acTDecTop[nalu.m_layerId].getParseIdc() == 0) || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS)
245#else
246    if (bNewPicture || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS)
247#endif
248    {
249#if O0194_DIFFERENT_BITDEPTH_EL_BL
250      //Bug fix: The bit depth was not set correctly for each layer when doing DBF
251      g_bitDepthY = g_bitDepthYLayer[curLayerId];
252      g_bitDepthC = g_bitDepthCLayer[curLayerId];
253#endif
254      if (!loopFiltered[curLayerId] || bitstreamFile)
255      {
256        m_acTDecTop[curLayerId].executeLoopFilters(poc, pcListPic);
257      }
258      loopFiltered[curLayerId] = (nalu.m_nalUnitType == NAL_UNIT_EOS);
259#if EARLY_REF_PIC_MARKING
260      m_acTDecTop[curLayerId].earlyPicMarking(m_iMaxTemporalLayer, m_targetDecLayerIdSet);
261#endif
262    }
263
264#if POC_RESET_IDC_DECODER
265    if( bNewPicture && m_acTDecTop[nalu.m_layerId].getParseIdc() == 0 )
266    {
267      outputAllPictures( nalu.m_layerId, true );
268    }
269#endif
270
271    if( pcListPic )
272    {
273      if ( m_pchReconFile[curLayerId] && !openedReconFile[curLayerId] )
274      {
275        if (!m_outputBitDepthY) { m_outputBitDepthY = g_bitDepthY; }
276        if (!m_outputBitDepthC) { m_outputBitDepthC = g_bitDepthC; }
277
278        m_acTVideoIOYuvReconFile[curLayerId].open( m_pchReconFile[curLayerId], true, m_outputBitDepthY, m_outputBitDepthC, g_bitDepthY, g_bitDepthC ); // write mode
279
280        openedReconFile[curLayerId] = true;
281      }
282#if ALIGNED_BUMPING
283      Bool outputPicturesFlag = true; 
284#if NO_OUTPUT_OF_PRIOR_PICS
285      if( m_acTDecTop[nalu.m_layerId].getNoOutputPriorPicsFlag() )
286      {
287        outputPicturesFlag = false;
288      }
289#endif
290
291      if (nalu.m_nalUnitType == NAL_UNIT_EOS) // End of sequence
292      {
293        flushAllPictures( nalu.m_layerId, outputPicturesFlag );       
294      }
295
296#if POC_RESET_IDC_DECODER
297      if( bNewPicture && m_acTDecTop[nalu.m_layerId].getParseIdc() != 0 )
298      // New picture, slice header parsed but picture not decoded
299#else
300      if( bNewPicture ) // New picture, slice header parsed but picture not decoded
301#endif
302      {
303#if NO_OUTPUT_OF_PRIOR_PICS
304        if( 
305#else
306        if ( bNewPOC &&
307#endif
308           (   nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL
309            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_N_LP
310            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_N_LP
311            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_RADL
312            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_LP ) )
313        {
314          flushAllPictures( nalu.m_layerId, outputPicturesFlag );
315        }
316        else
317        {
318          this->checkOutputBeforeDecoding( nalu.m_layerId );
319        }
320      }
321
322      /* The following code has to be executed when the last DU of the picture is decoded
323         TODO: Need code to identify end of decoding a picture
324      {
325        this->checkOutputAfterDecoding( );
326      } */
327#else
328      if ( bNewPicture && bNewPOC &&
329           (   nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL
330            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_N_LP
331            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_N_LP
332            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_RADL
333            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_LP ) )
334      {
335        xFlushOutput( pcListPic, curLayerId );
336      }
337      if (nalu.m_nalUnitType == NAL_UNIT_EOS)
338      {
339        xFlushOutput( pcListPic, curLayerId );       
340      }
341      // write reconstruction to file
342      if(bNewPicture)
343      {
344        xWriteOutput( pcListPic, curLayerId, nalu.m_temporalId );
345      }
346#endif
347    }
348  }
349#if ALIGNED_BUMPING
350   flushAllPictures( true );   
351#else
352  for(UInt layer = 0; layer <= m_tgtLayerId; layer++)
353  {
354    xFlushOutput( m_acTDecTop[layer].getListPic(), layer );
355  }
356#endif
357  // delete buffers
358#if AVC_BASE
359  UInt layerIdmin = m_acTDecTop[0].getBLReconFile()->is_open() ? 1 : 0;
360
361  if( streamYUV.is_open() )
362  {
363    streamYUV.close();
364  }
365#if AVC_SYNTAX
366  if( streamSyntaxFile.is_open() )
367  {
368    streamSyntaxFile.close();
369  }
370#endif
371  pcBLPic.destroy();
372
373  for(UInt layer = layerIdmin; layer <= m_tgtLayerId; layer++)
374#else
375  for(UInt layer = 0; layer <= m_tgtLayerId; layer++)
376#endif
377  {
378    m_acTDecTop[layer].deletePicBuffer();
379  }
380
381  // destroy internal classes
382  xDestroyDecLib();
383}
384#else
385Void TAppDecTop::decode()
386{
387  Int                 poc;
388  TComList<TComPic*>* pcListPic = NULL;
389
390  ifstream bitstreamFile(m_pchBitstreamFile, ifstream::in | ifstream::binary);
391  if (!bitstreamFile)
392  {
393    fprintf(stderr, "\nfailed to open bitstream file `%s' for reading\n", m_pchBitstreamFile);
394    exit(EXIT_FAILURE);
395  }
396
397  InputByteStream bytestream(bitstreamFile);
398
399  // create & initialize internal classes
400  xCreateDecLib();
401  xInitDecLib  ();
402  m_iPOCLastDisplay += m_iSkipFrame;      // set the last displayed POC correctly for skip forward.
403
404  // main decoder loop
405  Bool openedReconFile = false; // reconstruction file not yet opened. (must be performed after SPS is seen)
406  Bool loopFiltered = false;
407
408#if SYNTAX_OUTPUT
409  if( !m_pchBLSyntaxFile )
410  {
411    printf( "Wrong base layer syntax file\n" );
412    exit(EXIT_FAILURE);
413  }
414  fstream streamSyntaxFile( m_pchBLSyntaxFile, fstream::out | fstream::binary );
415  if( !streamSyntaxFile.good() )
416  {
417    printf( "Base layer syntax input reading error\n" );
418    exit(EXIT_FAILURE);
419  }
420  m_cTDecTop.setBLSyntaxFile( &streamSyntaxFile );
421
422  for( Int i = m_iBLFrames * m_iBLSourceWidth * m_iBLSourceHeight * SYNTAX_BYTES / 16; i >= 0; i-- )
423  {
424    streamSyntaxFile.put( 0 );
425  }
426  streamSyntaxFile.seekp( 0 );
427#endif
428
429  while (!!bitstreamFile)
430  {
431    /* location serves to work around a design fault in the decoder, whereby
432     * the process of reading a new slice that is the first slice of a new frame
433     * requires the TDecTop::decode() method to be called again with the same
434     * nal unit. */
435    streampos location = bitstreamFile.tellg();
436    AnnexBStats stats = AnnexBStats();
437
438    vector<uint8_t> nalUnit;
439    InputNALUnit nalu;
440    byteStreamNALUnit(bytestream, nalUnit, stats);
441
442    // call actual decoding function
443    Bool bNewPicture = false;
444    if (nalUnit.empty())
445    {
446      /* this can happen if the following occur:
447       *  - empty input file
448       *  - two back-to-back start_code_prefixes
449       *  - start_code_prefix immediately followed by EOF
450       */
451      fprintf(stderr, "Warning: Attempt to decode an empty NAL unit\n");
452    }
453    else
454    {
455      read(nalu, nalUnit);
456      if( (m_iMaxTemporalLayer >= 0 && nalu.m_temporalId > m_iMaxTemporalLayer) || !isNaluWithinTargetDecLayerIdSet(&nalu)  )
457      {
458          bNewPicture = false;
459        }
460      else
461      {
462        bNewPicture = m_cTDecTop.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay);
463        if (bNewPicture)
464        {
465          bitstreamFile.clear();
466          /* location points to the current nalunit payload[1] due to the
467           * need for the annexB parser to read three extra bytes.
468           * [1] except for the first NAL unit in the file
469           *     (but bNewPicture doesn't happen then) */
470          bitstreamFile.seekg(location-streamoff(3));
471          bytestream.reset();
472        }
473      }
474    }
475    if (bNewPicture || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS)
476    {
477      if (!loopFiltered || bitstreamFile)
478      {
479        m_cTDecTop.executeLoopFilters(poc, pcListPic);
480      }
481      loopFiltered = (nalu.m_nalUnitType == NAL_UNIT_EOS);
482    }
483#if !FIX_WRITING_OUTPUT
484#if SETTING_NO_OUT_PIC_PRIOR
485    if (bNewPicture && m_cTDecTop.getNoOutputPriorPicsFlag())
486    {
487      m_cTDecTop.checkNoOutputPriorPics( pcListPic );
488    }
489#endif
490#endif
491
492    if( pcListPic )
493    {
494      if ( m_pchReconFile && !openedReconFile )
495      {
496        if (!m_outputBitDepthY) { m_outputBitDepthY = g_bitDepthY; }
497        if (!m_outputBitDepthC) { m_outputBitDepthC = g_bitDepthC; }
498
499        m_cTVideoIOYuvReconFile.open( m_pchReconFile, true, m_outputBitDepthY, m_outputBitDepthC, g_bitDepthY, g_bitDepthC ); // write mode
500        openedReconFile = true;
501      }
502#if FIX_WRITING_OUTPUT
503      // write reconstruction to file
504      if( bNewPicture )
505      {
506        xWriteOutput( pcListPic, nalu.m_temporalId );
507      }
508#if SETTING_NO_OUT_PIC_PRIOR
509      if ( (bNewPicture || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_CRA) && m_cTDecTop.getNoOutputPriorPicsFlag() )
510      {
511        m_cTDecTop.checkNoOutputPriorPics( pcListPic );
512        m_cTDecTop.setNoOutputPriorPicsFlag (false);
513      }
514#endif
515#endif
516      if ( bNewPicture &&
517           (   nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_W_RADL
518            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR_N_LP
519            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_N_LP
520            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_RADL
521            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA_W_LP ) )
522      {
523        xFlushOutput( pcListPic );
524      }
525      if (nalu.m_nalUnitType == NAL_UNIT_EOS)
526      {
527#if FIX_OUTPUT_EOS
528        xWriteOutput( pcListPic, nalu.m_temporalId );
529#else
530        xFlushOutput( pcListPic );       
531#endif
532      }
533      // write reconstruction to file -- for additional bumping as defined in C.5.2.3
534#if FIX_WRITING_OUTPUT
535      if(!bNewPicture && nalu.m_nalUnitType >= NAL_UNIT_CODED_SLICE_TRAIL_N && nalu.m_nalUnitType <= NAL_UNIT_RESERVED_VCL31)
536#else
537      if(bNewPicture)
538#endif
539      {
540        xWriteOutput( pcListPic, nalu.m_temporalId );
541      }
542    }
543  }
544
545#if SYNTAX_OUTPUT
546  if( streamSyntaxFile.is_open() )
547  {
548    streamSyntaxFile.close();
549  }
550#endif
551
552  xFlushOutput( pcListPic );
553  // delete buffers
554  m_cTDecTop.deletePicBuffer();
555
556  // destroy internal classes
557  xDestroyDecLib();
558}
559#endif
560
561// ====================================================================================================================
562// Protected member functions
563// ====================================================================================================================
564
565Void TAppDecTop::xCreateDecLib()
566{
567#if SVC_EXTENSION
568  // initialize global variables
569  initROM();
570
571  for(UInt layer = 0; layer <= m_tgtLayerId; layer++)
572  {
573    // set layer ID
574    m_acTDecTop[layer].setLayerId                      ( layer );
575
576    // create decoder class
577    m_acTDecTop[layer].create();
578
579    m_acTDecTop[layer].setLayerDec(m_apcTDecTop);
580  }
581#else
582  // create decoder class
583  m_cTDecTop.create();
584#endif
585}
586
587Void TAppDecTop::xDestroyDecLib()
588{
589#if SVC_EXTENSION
590  // destroy ROM
591  destroyROM();
592
593  for(UInt layer = 0; layer <= m_tgtLayerId; layer++)
594  {
595    if ( m_pchReconFile[layer] )
596    {
597      m_acTVideoIOYuvReconFile[layer].close();
598    }
599
600    // destroy decoder class
601    m_acTDecTop[layer].destroy();
602  }
603#else
604  if ( m_pchReconFile )
605  {
606    m_cTVideoIOYuvReconFile. close();
607  }
608
609  // destroy decoder class
610  m_cTDecTop.destroy();
611#endif
612}
613
614Void TAppDecTop::xInitDecLib()
615{
616  // initialize decoder class
617#if SVC_EXTENSION
618  for(UInt layer = 0; layer <= m_tgtLayerId; layer++)
619  {
620    m_acTDecTop[layer].init();
621    m_acTDecTop[layer].setDecodedPictureHashSEIEnabled(m_decodedPictureHashSEIEnabled);
622    m_acTDecTop[layer].setNumLayer( m_tgtLayerId + 1 );
623#if OUTPUT_LAYER_SET_INDEX
624    m_acTDecTop[layer].setCommonDecoderParams( this->getCommonDecoderParams() );
625#endif
626  }
627
628#else
629  m_cTDecTop.init();
630  m_cTDecTop.setDecodedPictureHashSEIEnabled(m_decodedPictureHashSEIEnabled);
631#endif
632}
633
634/** \param pcListPic list of pictures to be written to file
635    \todo            DYN_REF_FREE should be revised
636 */
637#if SVC_EXTENSION
638Void TAppDecTop::xWriteOutput( TComList<TComPic*>* pcListPic, UInt layerId, UInt tId )
639#else
640Void TAppDecTop::xWriteOutput( TComList<TComPic*>* pcListPic, UInt tId )
641#endif
642{
643  if (pcListPic->empty())
644  {
645    return;
646  }
647
648  TComList<TComPic*>::iterator iterPic   = pcListPic->begin();
649  Int numPicsNotYetDisplayed = 0;
650  Int dpbFullness = 0;
651#if SVC_EXTENSION
652TComSPS* activeSPS = m_acTDecTop[layerId].getActiveSPS();
653#else
654  TComSPS* activeSPS = m_cTDecTop.getActiveSPS();
655#endif
656  UInt numReorderPicsHighestTid;
657  UInt maxDecPicBufferingHighestTid;
658  UInt maxNrSublayers = activeSPS->getMaxTLayers();
659
660  if(m_iMaxTemporalLayer == -1 || m_iMaxTemporalLayer >= maxNrSublayers)
661  {
662    numReorderPicsHighestTid = activeSPS->getNumReorderPics(maxNrSublayers-1);
663    maxDecPicBufferingHighestTid =  activeSPS->getMaxDecPicBuffering(maxNrSublayers-1); 
664  }
665  else
666  {
667    numReorderPicsHighestTid = activeSPS->getNumReorderPics(m_iMaxTemporalLayer);
668    maxDecPicBufferingHighestTid = activeSPS->getMaxDecPicBuffering(m_iMaxTemporalLayer); 
669  }
670
671  while (iterPic != pcListPic->end())
672  {
673    TComPic* pcPic = *(iterPic);
674#if SVC_EXTENSION
675    if(pcPic->getOutputMark() && pcPic->getPOC() > m_aiPOCLastDisplay[layerId])
676#else
677    if(pcPic->getOutputMark() && pcPic->getPOC() > m_iPOCLastDisplay)
678#endif
679    {
680      numPicsNotYetDisplayed++;
681      dpbFullness++;
682    }
683    else if(pcPic->getSlice( 0 )->isReferenced())
684    {
685      dpbFullness++;
686    }
687    iterPic++;
688  }
689  iterPic   = pcListPic->begin();
690  if (numPicsNotYetDisplayed>2)
691  {
692    iterPic++;
693  }
694
695  TComPic* pcPic = *(iterPic);
696  if (numPicsNotYetDisplayed>2 && pcPic->isField()) //Field Decoding
697  {
698    TComList<TComPic*>::iterator endPic   = pcListPic->end();
699    endPic--;
700    iterPic   = pcListPic->begin();
701    while (iterPic != endPic)
702    {
703      TComPic* pcPicTop = *(iterPic);
704      iterPic++;
705      TComPic* pcPicBottom = *(iterPic);
706
707#if SVC_EXTENSION
708      if( pcPicTop->getOutputMark() && pcPicBottom->getOutputMark() &&
709        (numPicsNotYetDisplayed >  numReorderPicsHighestTid || dpbFullness > maxDecPicBufferingHighestTid) &&
710        (!(pcPicTop->getPOC()%2) && pcPicBottom->getPOC() == pcPicTop->getPOC()+1) &&       
711        (pcPicTop->getPOC() == m_aiPOCLastDisplay[layerId]+1 || m_aiPOCLastDisplay[layerId]<0) )
712#else
713      if ( pcPicTop->getOutputMark() && pcPicBottom->getOutputMark() &&
714          (numPicsNotYetDisplayed >  numReorderPicsHighestTid || dpbFullness > maxDecPicBufferingHighestTid) &&
715          (!(pcPicTop->getPOC()%2) && pcPicBottom->getPOC() == pcPicTop->getPOC()+1) &&
716          (pcPicTop->getPOC() == m_iPOCLastDisplay+1 || m_iPOCLastDisplay < 0))
717#endif
718      {
719        // write to file
720        numPicsNotYetDisplayed = numPicsNotYetDisplayed-2;
721#if SVC_EXTENSION
722        if ( m_pchReconFile[layerId] )
723        {
724          const Window &conf = pcPicTop->getConformanceWindow();
725          const Window &defDisp = m_respectDefDispWindow ? pcPicTop->getDefDisplayWindow() : Window();
726          const Bool isTff = pcPicTop->isTopField();
727          TComPicYuv* pPicCYuvRecTop = pcPicTop->getPicYuvRec();
728          TComPicYuv* pPicCYuvRecBot = pcPicBottom->getPicYuvRec();
729#if Q0074_SEI_COLOR_MAPPING
730          if( m_acTDecTop[layerId].m_ColorMapping->getColorMappingFlag() )
731          {
732            pPicCYuvRecTop = m_acTDecTop[layerId].m_ColorMapping->getColorMapping( pPicCYuvRecTop, 0, layerId );
733            pPicCYuvRecBot = m_acTDecTop[layerId].m_ColorMapping->getColorMapping( pPicCYuvRecBot, 1, layerId );
734          }
735#endif
736#if REPN_FORMAT_IN_VPS
737          UInt chromaFormatIdc = pcPic->getSlice(0)->getChromaFormatIdc();
738          Int xScal =  TComSPS::getWinUnitX( chromaFormatIdc ), yScal = TComSPS::getWinUnitY( chromaFormatIdc );
739
740          m_acTVideoIOYuvReconFile[layerId].write( pPicCYuvRecTop, pPicCYuvRecBot,
741            conf.getWindowLeftOffset()  * xScal + defDisp.getWindowLeftOffset(),
742            conf.getWindowRightOffset() * xScal + defDisp.getWindowRightOffset(),
743            conf.getWindowTopOffset()   * yScal + defDisp.getWindowTopOffset(),
744            conf.getWindowBottomOffset()* yScal + defDisp.getWindowBottomOffset(), isTff );
745#else
746          m_acTVideoIOYuvReconFile[layerId].write( pPicCYuvRecTop, pPicCYuvRecBot,
747            conf.getWindowLeftOffset()   + defDisp.getWindowLeftOffset(),
748            conf.getWindowRightOffset()  + defDisp.getWindowRightOffset(),
749            conf.getWindowTopOffset()    + defDisp.getWindowTopOffset(),
750            conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset(), isTff );
751#endif
752        }
753
754        // update POC of display order
755        m_aiPOCLastDisplay[layerId] = pcPicBottom->getPOC();
756#else
757        if ( m_pchReconFile )
758        {
759          const Window &conf = pcPicTop->getConformanceWindow();
760          const Window &defDisp = m_respectDefDispWindow ? pcPicTop->getDefDisplayWindow() : Window();
761          const Bool isTff = pcPicTop->isTopField();
762          TComPicYuv* pPicCYuvRecTop = pcPicTop->getPicYuvRec();
763          TComPicYuv* pPicCYuvRecBot = pcPicBottom->getPicYuvRec();
764#if Q0074_SEI_COLOR_MAPPING
765          if ( m_cTDecTop.m_ColorMapping->getColorMappingFlag() )
766          {
767            pPicCYuvRecTop = m_cTDecTop.m_ColorMapping->getColorMapping( pPicCYuvRecTop, 0 );
768            pPicCYuvRecBot = m_cTDecTop.m_ColorMapping->getColorMapping( pPicCYuvRecBot, 1 );
769          }
770#endif
771          m_cTVideoIOYuvReconFile.write( pPicCYuvRecTop, pPicCYuvRecBot,
772            conf.getWindowLeftOffset() + defDisp.getWindowLeftOffset(),
773            conf.getWindowRightOffset() + defDisp.getWindowRightOffset(),
774            conf.getWindowTopOffset() + defDisp.getWindowTopOffset(),
775            conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset(), isTff );
776        }
777
778        // update POC of display order
779        m_iPOCLastDisplay = pcPicBottom->getPOC();
780#endif
781
782        // erase non-referenced picture in the reference picture list after display
783        if ( !pcPicTop->getSlice(0)->isReferenced() && pcPicTop->getReconMark() == true )
784        {
785#if !DYN_REF_FREE
786          pcPicTop->setReconMark(false);
787
788          // mark it should be extended later
789          pcPicTop->getPicYuvRec()->setBorderExtension( false );
790
791#else
792          pcPicTop->destroy();
793          pcListPic->erase( iterPic );
794          iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
795          continue;
796#endif
797        }
798        if ( !pcPicBottom->getSlice(0)->isReferenced() && pcPicBottom->getReconMark() == true )
799        {
800#if !DYN_REF_FREE
801          pcPicBottom->setReconMark(false);
802
803          // mark it should be extended later
804          pcPicBottom->getPicYuvRec()->setBorderExtension( false );
805
806#else
807          pcPicBottom->destroy();
808          pcListPic->erase( iterPic );
809          iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
810          continue;
811#endif
812        }
813        pcPicTop->setOutputMark(false);
814        pcPicBottom->setOutputMark(false);
815      }
816    }
817  }
818  else if (!pcPic->isField()) //Frame Decoding
819  {
820    iterPic = pcListPic->begin();
821    while (iterPic != pcListPic->end())
822    {
823      pcPic = *(iterPic);
824
825#if SVC_EXTENSION
826      if( pcPic->getOutputMark() && pcPic->getPOC() > m_aiPOCLastDisplay[layerId] &&
827        (numPicsNotYetDisplayed >  numReorderPicsHighestTid || dpbFullness > maxDecPicBufferingHighestTid) )
828#else
829      if(pcPic->getOutputMark() && pcPic->getPOC() > m_iPOCLastDisplay &&
830        (numPicsNotYetDisplayed >  numReorderPicsHighestTid || dpbFullness > maxDecPicBufferingHighestTid))
831#endif
832      {
833        // write to file
834        numPicsNotYetDisplayed--;
835        if(pcPic->getSlice(0)->isReferenced() == false)
836        {
837          dpbFullness--;
838        }
839#if SVC_EXTENSION
840        if( m_pchReconFile[layerId] )
841        {
842          const Window &conf = pcPic->getConformanceWindow();
843          const Window &defDisp = m_respectDefDispWindow ? pcPic->getDefDisplayWindow() : Window();
844          TComPicYuv* pPicCYuvRec = pcPic->getPicYuvRec();
845#if Q0074_SEI_COLOR_MAPPING
846          if ( m_acTDecTop[layerId].m_ColorMapping->getColorMappingFlag() )
847          {
848            pPicCYuvRec = m_acTDecTop[layerId].m_ColorMapping->getColorMapping( pPicCYuvRec, 0, layerId );
849          }
850#endif
851
852#if REPN_FORMAT_IN_VPS
853          UInt chromaFormatIdc = pcPic->getSlice(0)->getChromaFormatIdc();
854          Int xScal =  TComSPS::getWinUnitX( chromaFormatIdc ), yScal = TComSPS::getWinUnitY( chromaFormatIdc );
855
856          m_acTVideoIOYuvReconFile[layerId].write( pPicCYuvRec,
857            conf.getWindowLeftOffset()  * xScal + defDisp.getWindowLeftOffset(),
858            conf.getWindowRightOffset() * xScal + defDisp.getWindowRightOffset(),
859            conf.getWindowTopOffset()   * yScal + defDisp.getWindowTopOffset(),
860            conf.getWindowBottomOffset()* yScal + defDisp.getWindowBottomOffset() );
861#else
862          m_acTVideoIOYuvReconFile[layerId].write( pPicCYuvRec,
863            conf.getWindowLeftOffset()   + defDisp.getWindowLeftOffset(),
864            conf.getWindowRightOffset()  + defDisp.getWindowRightOffset(),
865            conf.getWindowTopOffset()    + defDisp.getWindowTopOffset(),
866            conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset() );
867#endif
868        }
869
870        // update POC of display order
871        m_aiPOCLastDisplay[layerId] = pcPic->getPOC();
872#else
873        if ( m_pchReconFile )
874        {
875#if SYNTAX_OUTPUT
876          TComPicYuv* pPicCYuvRec = pcPic->getPicYuvRec();
877#if Q0074_SEI_COLOR_MAPPING
878          if( m_acTDecTop[layerIdx].m_ColorMapping->getColorMappingFlag() )
879          {
880            pPicCYuvRec = m_acTDecTop[layerIdx].m_ColorMapping->getColorMapping( pPicCYuvRec, 0, layerIdx );
881          }
882#endif
883          const Window &conf = pcPic->getConformanceWindow();
884          const Window &defDisp = m_respectDefDispWindow ? pcPic->getDefDisplayWindow() : Window();
885          m_cTVideoIOYuvReconFile.write( pPicCYuvRec,
886            conf.getWindowLeftOffset() + defDisp.getWindowLeftOffset(),
887            conf.getWindowRightOffset() + defDisp.getWindowRightOffset(),
888            conf.getWindowTopOffset() + defDisp.getWindowTopOffset(),
889            conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset() );
890#endif
891        }
892
893        // update POC of display order
894        m_iPOCLastDisplay = pcPic->getPOC();
895#endif
896
897        // erase non-referenced picture in the reference picture list after display
898        if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
899        {
900#if !DYN_REF_FREE
901          pcPic->setReconMark(false);
902
903          // mark it should be extended later
904          pcPic->getPicYuvRec()->setBorderExtension( false );
905
906#else
907          pcPic->destroy();
908          pcListPic->erase( iterPic );
909          iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
910          continue;
911#endif
912        }
913        pcPic->setOutputMark(false);
914      }
915
916      iterPic++;
917    }
918  }
919}
920
921/** \param pcListPic list of pictures to be written to file
922    \todo            DYN_REF_FREE should be revised
923 */
924#if SVC_EXTENSION
925Void TAppDecTop::xFlushOutput( TComList<TComPic*>* pcListPic, UInt layerId )
926#else
927Void TAppDecTop::xFlushOutput( TComList<TComPic*>* pcListPic )
928#endif
929{
930  if(!pcListPic || pcListPic->empty())
931  {
932    return;
933  }
934  TComList<TComPic*>::iterator iterPic   = pcListPic->begin();
935
936  iterPic   = pcListPic->begin();
937  TComPic* pcPic = *(iterPic);
938
939  if (pcPic->isField()) //Field Decoding
940  {
941    TComList<TComPic*>::iterator endPic   = pcListPic->end();
942    endPic--;
943    TComPic *pcPicTop, *pcPicBottom = NULL;
944    while (iterPic != endPic)
945    {
946      pcPicTop = *(iterPic);
947      iterPic++;
948      pcPicBottom = *(iterPic);
949
950      if ( pcPicTop->getOutputMark() && pcPicBottom->getOutputMark() && !(pcPicTop->getPOC()%2) && (pcPicBottom->getPOC() == pcPicTop->getPOC()+1) )
951      {
952        // write to file
953#if SVC_EXTENSION
954        if ( m_pchReconFile[layerId] )
955        {
956          const Window &conf = pcPicTop->getConformanceWindow();
957          const Window &defDisp = m_respectDefDispWindow ? pcPicTop->getDefDisplayWindow() : Window();
958          const Bool isTff = pcPicTop->isTopField();
959          TComPicYuv* pPicCYuvRecTop = pcPicTop->getPicYuvRec();
960          TComPicYuv* pPicCYuvRecBot = pcPicBottom->getPicYuvRec();
961#if Q0074_SEI_COLOR_MAPPING
962          if( m_acTDecTop[layerId].m_ColorMapping->getColorMappingFlag() )
963          {
964            pPicCYuvRecTop = m_acTDecTop[layerId].m_ColorMapping->getColorMapping( pPicCYuvRecTop, 0, layerId );
965            pPicCYuvRecBot = m_acTDecTop[layerId].m_ColorMapping->getColorMapping( pPicCYuvRecBot, 1, layerId );
966          }
967#endif
968#if REPN_FORMAT_IN_VPS
969          UInt chromaFormatIdc = pcPic->getSlice(0)->getChromaFormatIdc();
970          Int xScal =  TComSPS::getWinUnitX( chromaFormatIdc ), yScal = TComSPS::getWinUnitY( chromaFormatIdc );
971
972          m_acTVideoIOYuvReconFile[layerId].write( pPicCYuvRecTop, pPicCYuvRecBot,
973            conf.getWindowLeftOffset()  *xScal + defDisp.getWindowLeftOffset(),
974            conf.getWindowRightOffset() *xScal + defDisp.getWindowRightOffset(),
975            conf.getWindowTopOffset()   *yScal + defDisp.getWindowTopOffset(),
976            conf.getWindowBottomOffset()*yScal + defDisp.getWindowBottomOffset(), isTff );
977#else
978          m_acTVideoIOYuvReconFile[layerId].write( pPicCYuvRecTop, pPicCYuvRecBot,
979            conf.getWindowLeftOffset()   + defDisp.getWindowLeftOffset(),
980            conf.getWindowRightOffset()  + defDisp.getWindowRightOffset(),
981            conf.getWindowTopOffset()    + defDisp.getWindowTopOffset(),
982            conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset(), isTff );
983#endif
984        }
985
986        // update POC of display order
987        m_aiPOCLastDisplay[layerId] = pcPicBottom->getPOC();
988#else
989        if ( m_pchReconFile )
990        {
991          const Window &conf = pcPicTop->getConformanceWindow();
992          const Window &defDisp = m_respectDefDispWindow ? pcPicTop->getDefDisplayWindow() : Window();
993          const Bool isTff = pcPicTop->isTopField();
994          TComPicYuv* pPicCYuvRecTop = pcPicTop->getPicYuvRec();
995          TComPicYuv* pPicCYuvRecBot = pcPicBottom->getPicYuvRec();
996#if Q0074_SEI_COLOR_MAPPING
997          if( m_cTDecTop.m_ColorMapping->getColorMappingFlag() )
998          {
999            pPicCYuvRecTop = m_cTDecTop.m_ColorMapping->getColorMapping( pPicCYuvRecTop, 0 );
1000            pPicCYuvRecBot = m_cTDecTop.m_ColorMapping->getColorMapping( pPicCYuvRecBot, 1 );
1001          }
1002#endif
1003          m_cTVideoIOYuvReconFile.write( pPicCYuvRecTop, pPicCYuvRecBot,
1004            conf.getWindowLeftOffset() + defDisp.getWindowLeftOffset(),
1005            conf.getWindowRightOffset() + defDisp.getWindowRightOffset(),
1006            conf.getWindowTopOffset() + defDisp.getWindowTopOffset(),
1007            conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset(), isTff );
1008        }
1009
1010        // update POC of display order
1011        m_iPOCLastDisplay = pcPicBottom->getPOC();
1012#endif
1013
1014        // erase non-referenced picture in the reference picture list after display
1015        if ( !pcPicTop->getSlice(0)->isReferenced() && pcPicTop->getReconMark() == true )
1016        {
1017#if !DYN_REF_FREE
1018          pcPicTop->setReconMark(false);
1019
1020          // mark it should be extended later
1021          pcPicTop->getPicYuvRec()->setBorderExtension( false );
1022
1023#else
1024          pcPicTop->destroy();
1025          pcListPic->erase( iterPic );
1026          iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
1027          continue;
1028#endif
1029        }
1030        if ( !pcPicBottom->getSlice(0)->isReferenced() && pcPicBottom->getReconMark() == true )
1031        {
1032#if !DYN_REF_FREE
1033          pcPicBottom->setReconMark(false);
1034
1035          // mark it should be extended later
1036          pcPicBottom->getPicYuvRec()->setBorderExtension( false );
1037
1038#else
1039          pcPicBottom->destroy();
1040          pcListPic->erase( iterPic );
1041          iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
1042          continue;
1043#endif
1044        }
1045        pcPicTop->setOutputMark(false);
1046        pcPicBottom->setOutputMark(false);
1047
1048#if !DYN_REF_FREE
1049        if(pcPicTop)
1050        {
1051          pcPicTop->destroy();
1052          delete pcPicTop;
1053          pcPicTop = NULL;
1054        }
1055#endif
1056      }
1057    }
1058    if(pcPicBottom)
1059    {
1060      pcPicBottom->destroy();
1061      delete pcPicBottom;
1062      pcPicBottom = NULL;
1063    }
1064  }
1065  else //Frame decoding
1066  {
1067    while (iterPic != pcListPic->end())
1068    {
1069      pcPic = *(iterPic);
1070
1071      if ( pcPic->getOutputMark() )
1072      {
1073        // write to file
1074#if SVC_EXTENSION
1075        if ( m_pchReconFile[layerId] )
1076        {
1077          const Window &conf = pcPic->getConformanceWindow();
1078          const Window &defDisp = m_respectDefDispWindow ? pcPic->getDefDisplayWindow() : Window();
1079          TComPicYuv* pPicCYuvRec = pcPic->getPicYuvRec();
1080#if Q0074_SEI_COLOR_MAPPING
1081          if( m_acTDecTop[layerId].m_ColorMapping->getColorMappingFlag() )
1082          {
1083            pPicCYuvRec = m_acTDecTop[layerId].m_ColorMapping->getColorMapping( pPicCYuvRec, 0, layerId );
1084          }
1085#endif
1086#if REPN_FORMAT_IN_VPS
1087          UInt chromaFormatIdc = pcPic->getSlice(0)->getChromaFormatIdc();
1088          Int xScal =  TComSPS::getWinUnitX( chromaFormatIdc ), yScal = TComSPS::getWinUnitY( chromaFormatIdc );
1089
1090          m_acTVideoIOYuvReconFile[layerId].write( pPicCYuvRec,
1091            conf.getWindowLeftOffset()  *xScal + defDisp.getWindowLeftOffset(),
1092            conf.getWindowRightOffset() *xScal + defDisp.getWindowRightOffset(),
1093            conf.getWindowTopOffset()   *yScal + defDisp.getWindowTopOffset(),
1094            conf.getWindowBottomOffset()*yScal + defDisp.getWindowBottomOffset() );
1095#else
1096          m_acTVideoIOYuvReconFile[layerId].write( pPicCYuvRec,
1097            conf.getWindowLeftOffset()   + defDisp.getWindowLeftOffset(),
1098            conf.getWindowRightOffset()  + defDisp.getWindowRightOffset(),
1099            conf.getWindowTopOffset()    + defDisp.getWindowTopOffset(),
1100            conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset() );
1101#endif
1102        }
1103
1104        // update POC of display order
1105        m_aiPOCLastDisplay[layerId] = pcPic->getPOC();
1106#else
1107        if ( m_pchReconFile )
1108        {
1109          const Window &conf = pcPic->getConformanceWindow();
1110          const Window &defDisp = m_respectDefDispWindow ? pcPic->getDefDisplayWindow() : Window();
1111          TComPicYuv* pPicCYuvRec = pcPic->getPicYuvRec();
1112#if Q0074_SEI_COLOR_MAPPING
1113          if( m_cTDecTop.m_ColorMapping->getColorMappingFlag() )
1114          {
1115            pPicCYuvRec = m_cTDecTop.m_ColorMapping->getColorMapping( pPicCYuvRec );
1116          }
1117#endif
1118          m_cTVideoIOYuvReconFile.write( pPicCYuvRec,
1119            conf.getWindowLeftOffset() + defDisp.getWindowLeftOffset(),
1120            conf.getWindowRightOffset() + defDisp.getWindowRightOffset(),
1121            conf.getWindowTopOffset() + defDisp.getWindowTopOffset(),
1122            conf.getWindowBottomOffset() + defDisp.getWindowBottomOffset() );
1123        }
1124
1125        // update POC of display order
1126        m_iPOCLastDisplay = pcPic->getPOC();
1127#endif
1128
1129        // erase non-referenced picture in the reference picture list after display
1130        if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
1131        {
1132#if !DYN_REF_FREE
1133          pcPic->setReconMark(false);
1134
1135          // mark it should be extended later
1136          pcPic->getPicYuvRec()->setBorderExtension( false );
1137
1138#else
1139          pcPic->destroy();
1140          pcListPic->erase( iterPic );
1141          iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
1142          continue;
1143#endif
1144        }
1145        pcPic->setOutputMark(false);
1146      }
1147#if !SVC_EXTENSION
1148#if !DYN_REF_FREE
1149      if(pcPic)
1150      {
1151        pcPic->destroy();
1152        delete pcPic;
1153        pcPic = NULL;
1154      }
1155#endif
1156#endif
1157      iterPic++;
1158    }
1159  }
1160#if SVC_EXTENSION
1161  m_aiPOCLastDisplay[layerId] = -MAX_INT;
1162#else
1163  pcListPic->clear();
1164  m_iPOCLastDisplay = -MAX_INT;
1165#endif
1166}
1167
1168/** \param nalu Input nalu to check whether its LayerId is within targetDecLayerIdSet
1169 */
1170Bool TAppDecTop::isNaluWithinTargetDecLayerIdSet( InputNALUnit* nalu )
1171{
1172  if ( m_targetDecLayerIdSet.size() == 0 ) // By default, the set is empty, meaning all LayerIds are allowed
1173  {
1174    return true;
1175  }
1176  for (std::vector<Int>::iterator it = m_targetDecLayerIdSet.begin(); it != m_targetDecLayerIdSet.end(); it++)
1177  {
1178    if ( nalu->m_reservedZero6Bits == (*it) )
1179    {
1180      return true;
1181    }
1182  }
1183  return false;
1184}
1185#if ALIGNED_BUMPING
1186// Function outputs a picture, and marks it as not needed for output.
1187Void TAppDecTop::xOutputAndMarkPic( TComPic *pic, const Char *reconFile, const Int layerIdx, Int &pocLastDisplay, DpbStatus &dpbStatus )
1188{
1189  if ( reconFile )
1190  {
1191    const Window &conf = pic->getConformanceWindow();
1192    const Window &defDisp = m_respectDefDispWindow ? pic->getDefDisplayWindow() : Window();
1193    Int xScal =  1, yScal = 1;
1194#if REPN_FORMAT_IN_VPS
1195    UInt chromaFormatIdc = pic->getSlice(0)->getChromaFormatIdc();
1196    xScal = TComSPS::getWinUnitX( chromaFormatIdc );
1197    yScal = TComSPS::getWinUnitY( chromaFormatIdc );
1198#endif
1199    TComPicYuv* pPicCYuvRec = pic->getPicYuvRec();
1200#if Q0074_SEI_COLOR_MAPPING
1201    pPicCYuvRec = m_acTDecTop[layerIdx].m_ColorMapping->getColorMapping( pPicCYuvRec, 0, layerIdx );
1202#endif
1203    m_acTVideoIOYuvReconFile[layerIdx].write( pPicCYuvRec,
1204      conf.getWindowLeftOffset()  * xScal + defDisp.getWindowLeftOffset(),
1205      conf.getWindowRightOffset() * xScal + defDisp.getWindowRightOffset(),
1206      conf.getWindowTopOffset()   * yScal + defDisp.getWindowTopOffset(),
1207      conf.getWindowBottomOffset()* yScal + defDisp.getWindowBottomOffset() );
1208  }
1209  // update POC of display order
1210  pocLastDisplay = pic->getPOC();
1211
1212  // Mark as not needed for output
1213  pic->setOutputMark(false);
1214
1215  // "erase" non-referenced picture in the reference picture list after display
1216  if ( !pic->getSlice(0)->isReferenced() && pic->getReconMark() == true )
1217  {
1218    pic->setReconMark(false);
1219
1220    // mark it should be extended later
1221    pic->getPicYuvRec()->setBorderExtension( false );
1222
1223    dpbStatus.m_numPicsInLayer[layerIdx]--;
1224  }
1225}
1226
1227Void TAppDecTop::flushAllPictures(Int layerId, Bool outputPictures)
1228{
1229  // First "empty" all pictures that are not used for reference and not needed for output
1230  emptyUnusedPicturesNotNeededForOutput();
1231
1232  if( outputPictures )  // All pictures in the DPB in that layer are to be output; this means other pictures would also be output
1233  {
1234    std::vector<Int>  listOfPocs;
1235    std::vector<Int>  listOfPocsInEachLayer[MAX_LAYERS];
1236    std::vector<Int>  listOfPocsPositionInEachLayer[MAX_LAYERS];
1237    DpbStatus dpbStatus;
1238
1239    // Find the status of the DPB
1240    xFindDPBStatus(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus);
1241
1242    if( listOfPocs.size() )
1243    {
1244      while( listOfPocsInEachLayer[layerId].size() )    // As long as there picture in the layer to be output
1245      {
1246        bumpingProcess( listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus );
1247      }
1248    }
1249  }
1250
1251  // Now remove all pictures from the layer DPB?
1252  markAllPicturesAsErased(layerId);
1253}
1254Void TAppDecTop::flushAllPictures(Bool outputPictures)
1255{
1256  // First "empty" all pictures that are not used for reference and not needed for output
1257  emptyUnusedPicturesNotNeededForOutput();
1258
1259  if( outputPictures )  // All pictures in the DPB are to be output
1260  {
1261    std::vector<Int>  listOfPocs;
1262    std::vector<Int>  listOfPocsInEachLayer[MAX_LAYERS];
1263    std::vector<Int>  listOfPocsPositionInEachLayer[MAX_LAYERS];
1264    DpbStatus dpbStatus;
1265
1266    // Find the status of the DPB
1267#if POC_RESET_IDC_DECODER
1268    xFindDPBStatus(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus, false);
1269#else
1270    xFindDPBStatus(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus);
1271#endif
1272
1273    while( dpbStatus.m_numAUsNotDisplayed )
1274    {
1275      bumpingProcess( listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus );
1276    }
1277  }
1278
1279  // Now remove all pictures from the DPB?
1280  markAllPicturesAsErased();
1281}
1282
1283Void TAppDecTop::markAllPicturesAsErased()
1284{
1285  for(Int i = 0; i < MAX_LAYERS; i++)
1286  {
1287    m_acTDecTop[i].getListPic()->clear();
1288  }
1289}
1290
1291Void TAppDecTop::markAllPicturesAsErased(Int layerIdx)
1292{
1293  m_acTDecTop[layerIdx].getListPic()->clear();
1294}
1295
1296Void TAppDecTop::checkOutputBeforeDecoding(Int layerIdx)
1297{
1298   
1299  std::vector<Int>  listOfPocs;
1300  std::vector<Int>  listOfPocsInEachLayer[MAX_LAYERS];
1301  std::vector<Int>  listOfPocsPositionInEachLayer[MAX_LAYERS];
1302  DpbStatus dpbStatus;
1303
1304  // First "empty" all pictures that are not used for reference and not needed for output
1305  emptyUnusedPicturesNotNeededForOutput();
1306
1307  // Find the status of the DPB
1308  xFindDPBStatus(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus);
1309
1310  // If not picture to be output, return
1311  if( listOfPocs.size() == 0 )
1312  {
1313    return;
1314  }
1315
1316  // Find DPB-information from the VPS
1317  DpbStatus maxDpbLimit;
1318#if RESOLUTION_BASED_DPB
1319  Int targetLsIdx, subDpbIdx;
1320  TComVPS *vps = findDpbParametersFromVps(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, maxDpbLimit);
1321
1322  if( getCommonDecoderParams()->getTargetOutputLayerSetIdx() == 0 )
1323  {
1324    targetLsIdx = 0;
1325    subDpbIdx   = 0; 
1326  }
1327  else
1328  {
1329    targetLsIdx = vps->getOutputLayerSetIdx( getCommonDecoderParams()->getTargetOutputLayerSetIdx() );
1330    subDpbIdx   = vps->getSubDpbAssigned( targetLsIdx, layerIdx );
1331  }
1332#else
1333  Int subDpbIdx = getCommonDecoderParams()->getTargetOutputLayerSetIdx() == 0 ? 0 : layerIdx;
1334  findDpbParametersFromVps(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, maxDpbLimit);
1335#endif
1336  // Assume that listOfPocs is sorted in increasing order - if not have to sort it.
1337  while( ifInvokeBumpingBeforeDecoding(dpbStatus, maxDpbLimit, layerIdx, subDpbIdx) )
1338  {
1339    bumpingProcess( listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus );
1340  } 
1341}
1342
1343Void TAppDecTop::checkOutputAfterDecoding()
1344{   
1345  std::vector<Int>  listOfPocs;
1346  std::vector<Int>  listOfPocsInEachLayer[MAX_LAYERS];
1347  std::vector<Int>  listOfPocsPositionInEachLayer[MAX_LAYERS];
1348  DpbStatus dpbStatus;
1349
1350  // First "empty" all pictures that are not used for reference and not needed for output
1351  emptyUnusedPicturesNotNeededForOutput();
1352
1353  // Find the status of the DPB
1354  xFindDPBStatus(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus);
1355
1356  // If not picture to be output, return
1357  if( listOfPocs.size() == 0 )
1358  {
1359    return;
1360  }
1361
1362  // Find DPB-information from the VPS
1363  DpbStatus maxDpbLimit;
1364  findDpbParametersFromVps(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, maxDpbLimit);
1365
1366  // Assume that listOfPocs is sorted in increasing order - if not have to sort it.
1367  while( ifInvokeBumpingAfterDecoding(dpbStatus, maxDpbLimit) )
1368  {
1369    bumpingProcess( listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus );
1370  } 
1371}
1372
1373Void TAppDecTop::bumpingProcess(std::vector<Int> &listOfPocs, std::vector<Int> *listOfPocsInEachLayer, std::vector<Int> *listOfPocsPositionInEachLayer, DpbStatus &dpbStatus)
1374{
1375  // Choose the smallest POC value
1376  Int pocValue = *(listOfPocs.begin());
1377  std::vector<int>::iterator it;
1378  TComList<TComPic*>::iterator iterPic;
1379  for( Int layerIdx = 0; layerIdx < dpbStatus.m_numLayers; layerIdx++)
1380  {
1381    // Check if picture with pocValue is present.
1382    it = find( listOfPocsInEachLayer[layerIdx].begin(), listOfPocsInEachLayer[layerIdx].end(), pocValue );
1383    if( it != listOfPocsInEachLayer[layerIdx].end() )  // picture found.
1384    {
1385      Int picPosition = std::distance( listOfPocsInEachLayer[layerIdx].begin(), it );
1386      Int j;
1387      for(j = 0, iterPic = m_acTDecTop[layerIdx].getListPic()->begin(); j < listOfPocsPositionInEachLayer[layerIdx][picPosition]; j++) // Picture to be output
1388      {
1389        iterPic++;
1390      }
1391      TComPic *pic = *iterPic;
1392
1393      xOutputAndMarkPic( pic, m_pchReconFile[layerIdx], layerIdx, m_aiPOCLastDisplay[layerIdx], dpbStatus );
1394
1395      listOfPocsInEachLayer[layerIdx].erase( it );
1396      listOfPocsPositionInEachLayer[layerIdx].erase( listOfPocsPositionInEachLayer[layerIdx].begin() + picPosition );
1397    }
1398  }
1399  // Update sub-DPB status
1400  for( Int subDpbIdx = 0; subDpbIdx < dpbStatus.m_numSubDpbs; subDpbIdx++)
1401  {
1402    dpbStatus.m_numPicsInSubDpb[subDpbIdx]--;
1403  }
1404  dpbStatus.m_numAUsNotDisplayed--;   
1405
1406  // Remove the picture from the listOfPocs
1407  listOfPocs.erase( listOfPocs.begin() );
1408}
1409
1410TComVPS *TAppDecTop::findDpbParametersFromVps(std::vector<Int> const &listOfPocs, std::vector<Int> const *listOfPocsInEachLayer, std::vector<Int> const *listOfPocsPositionInEachLayer, DpbStatus &maxDpbLimit)
1411{
1412  Int targetOutputLsIdx = getCommonDecoderParams()->getTargetOutputLayerSetIdx();
1413  TComVPS *vps = NULL;
1414
1415  if( targetOutputLsIdx == 0 )   // Only base layer is output
1416  {
1417    TComSPS *sps = NULL;
1418    assert( listOfPocsInEachLayer[0].size() != 0 );
1419    TComList<TComPic*>::iterator iterPic;
1420    Int j;
1421    for(j = 0, iterPic = m_acTDecTop[0].getListPic()->begin(); j < listOfPocsPositionInEachLayer[0][0]; j++) // Picture to be output
1422    {
1423      iterPic++;
1424    }
1425    TComPic *pic = *iterPic;
1426    sps = pic->getSlice(0)->getSPS();   assert( sps->getLayerId() == 0 );
1427    vps = pic->getSlice(0)->getVPS();
1428    Int highestTId = sps->getMaxTLayers() - 1;
1429
1430    maxDpbLimit.m_numAUsNotDisplayed = sps->getNumReorderPics( highestTId ); // m_numAUsNotDisplayed is only variable name - stores reorderpics
1431    maxDpbLimit.m_maxLatencyIncrease = sps->getMaxLatencyIncrease( highestTId ) > 0;
1432    if( maxDpbLimit.m_maxLatencyIncrease )
1433    {
1434      maxDpbLimit.m_maxLatencyPictures = sps->getMaxLatencyIncrease( highestTId ) + sps->getNumReorderPics( highestTId ) - 1;
1435    }
1436    maxDpbLimit.m_numPicsInLayer[0] = sps->getMaxDecPicBuffering( highestTId );
1437    maxDpbLimit.m_numPicsInSubDpb[0] = sps->getMaxDecPicBuffering( highestTId );
1438  }
1439  else
1440  {
1441    // -------------------------------------
1442    // Find the VPS used for the pictures
1443    // -------------------------------------
1444    for(Int i = 0; i < MAX_LAYERS; i++)
1445    {
1446      if( m_acTDecTop[i].getListPic()->empty() )
1447      {
1448        assert( listOfPocsInEachLayer[i].size() == 0 );
1449        continue;
1450      }
1451      std::vector<Int>::const_iterator it;
1452      it = find( listOfPocsInEachLayer[i].begin(), listOfPocsInEachLayer[i].end(), listOfPocs[0] );
1453      TComList<TComPic*>::iterator iterPic;
1454      if( it != listOfPocsInEachLayer[i].end() )
1455      {
1456        Int picPosition = std::distance( listOfPocsInEachLayer[i].begin(), it );
1457        Int j;
1458        for(j = 0, iterPic = m_acTDecTop[i].getListPic()->begin(); j < listOfPocsPositionInEachLayer[i][picPosition]; j++) // Picture to be output
1459        {
1460          iterPic++;
1461        }
1462        TComPic *pic = *iterPic;
1463        vps = pic->getSlice(0)->getVPS();
1464        break;
1465      }
1466    }
1467
1468    Int targetLsIdx       = vps->getOutputLayerSetIdx( getCommonDecoderParams()->getTargetOutputLayerSetIdx() );
1469    Int highestTId = vps->getMaxTLayers() - 1;
1470
1471    maxDpbLimit.m_numAUsNotDisplayed = vps->getMaxVpsNumReorderPics( targetOutputLsIdx, highestTId ); // m_numAUsNotDisplayed is only variable name - stores reorderpics
1472    maxDpbLimit.m_maxLatencyIncrease  = vps->getMaxVpsLatencyIncreasePlus1(targetOutputLsIdx, highestTId ) > 0;
1473    if( maxDpbLimit.m_maxLatencyIncrease )
1474    {
1475      maxDpbLimit.m_maxLatencyPictures = vps->getMaxVpsNumReorderPics( targetOutputLsIdx, highestTId ) + vps->getMaxVpsLatencyIncreasePlus1(targetOutputLsIdx, highestTId ) - 1;
1476    }
1477    for(Int i = 0; i < vps->getNumLayersInIdList( targetLsIdx ); i++)
1478    {
1479#if RESOUTION_BASED_DPB
1480      maxDpbLimit.m_numPicsInLayer[i] = vps->getMaxVpsLayerDecPicBuffMinus1( targetOutputLsIdx, i, highestTId ) + 1;
1481      maxDpbLimit.m_numPicsInSubDpb[vps->getSubDpbAssigned( targetLsIdx, i )] = vps->getMaxVpsDecPicBufferingMinus1( targetOutputLsIdx, vps->getSubDpbAssigned( targetLsIdx, i ), highestTId) + 1;
1482#else
1483      maxDpbLimit.m_numPicsInSubDpb[i] = vps->getMaxVpsDecPicBufferingMinus1( targetOutputLsIdx, i, highestTId) + 1;
1484#endif
1485    }
1486    // -------------------------------------
1487  }
1488  return vps;
1489}
1490Void TAppDecTop::emptyUnusedPicturesNotNeededForOutput()
1491{
1492  for(Int layerIdx = 0; layerIdx < MAX_LAYERS; layerIdx++)
1493  {
1494    TComList <TComPic*> *pcListPic = m_acTDecTop[layerIdx].getListPic();
1495    TComList<TComPic*>::iterator iterPic = pcListPic->begin();
1496    while ( iterPic != pcListPic->end() )
1497    {
1498      TComPic *pic = *iterPic;
1499      if( !pic->getSlice(0)->isReferenced() && !pic->getOutputMark() )
1500      {
1501        // Emtpy the picture buffer
1502        pic->setReconMark( false );
1503      }
1504      iterPic++;
1505    }
1506  }
1507}
1508
1509Bool TAppDecTop::ifInvokeBumpingBeforeDecoding( const DpbStatus &dpbStatus, const DpbStatus &dpbLimit, const Int layerIdx, const Int subDpbIdx )
1510{
1511  Bool retVal = false;
1512  // Number of reorder picutres
1513  retVal |= ( dpbStatus.m_numAUsNotDisplayed > dpbLimit.m_numAUsNotDisplayed );
1514
1515  // Number of pictures in each sub-DPB
1516  retVal |= ( dpbStatus.m_numPicsInSubDpb[subDpbIdx] >= dpbLimit.m_numPicsInSubDpb[subDpbIdx] );
1517 
1518#if RESOLUTION_BASED_DPB
1519  // Number of pictures in each layer
1520  retVal |= ( dpbStatus.m_numPicsInLayer[layerIdx] >= dpbLimit.m_numPicsInLayer[layerIdx]);
1521#endif
1522
1523  return retVal;
1524}
1525
1526Bool TAppDecTop::ifInvokeBumpingAfterDecoding( const DpbStatus &dpbStatus, const DpbStatus &dpbLimit )
1527{
1528  Bool retVal = false;
1529
1530  // Number of reorder picutres
1531  retVal |= ( dpbStatus.m_numAUsNotDisplayed > dpbLimit.m_numAUsNotDisplayed );
1532
1533  return retVal;
1534}
1535
1536Void TAppDecTop::xFindDPBStatus( std::vector<Int> &listOfPocs
1537                            , std::vector<Int> *listOfPocsInEachLayer
1538                            , std::vector<Int> *listOfPocsPositionInEachLayer
1539                            , DpbStatus &dpbStatus
1540#if POC_RESET_IDC_DECODER
1541                            , Bool notOutputCurrAu
1542#endif
1543                            )
1544{
1545  TComVPS *vps = NULL;
1546  dpbStatus.init();
1547  for( Int i = 0; i < MAX_LAYERS; i++ )
1548  {
1549    if( m_acTDecTop[i].getListPic()->empty() )
1550    {
1551      continue;
1552    }
1553   
1554    // To check # AUs that have at least one picture not output,
1555    // For each layer, populate listOfPOcs if not already present
1556    TComList<TComPic*>::iterator iterPic = m_acTDecTop[i].getListPic()->begin();
1557    Int picPositionInList = 0;
1558    while (iterPic != m_acTDecTop[i].getListPic()->end())
1559    {
1560      TComPic* pic = *(iterPic);
1561      if( pic->getReconMark() )
1562      {
1563        if( vps == NULL )
1564        {
1565          vps = pic->getSlice(0)->getVPS();
1566        }
1567#if POC_RESET_IDC_DECODER
1568        if( !(pic->isCurrAu() && notOutputCurrAu ) )
1569        {
1570#endif
1571          std::vector<Int>::iterator it;
1572          if( pic->getOutputMark() ) // && pic->getPOC() > m_aiPOCLastDisplay[i])
1573          {
1574            it = find( listOfPocs.begin(), listOfPocs.end(), pic->getPOC() ); // Check if already included
1575            if( it == listOfPocs.end() )  // New POC value - i.e. new AU - add to the list
1576            {
1577              listOfPocs.push_back( pic->getPOC() );
1578            }
1579            listOfPocsInEachLayer         [i].push_back( pic->getPOC()    );    // POC to be output in each layer
1580            listOfPocsPositionInEachLayer [i].push_back( picPositionInList  );  // For ease of access
1581          }
1582          if( pic->getSlice(0)->isReferenced() || pic->getOutputMark() )
1583          {
1584            dpbStatus.m_numPicsInLayer[i]++;  // Count pictures that are "used for reference" or "needed for output"
1585          }
1586#if POC_RESET_IDC_DECODER
1587        }
1588#endif
1589      }
1590      iterPic++;
1591      picPositionInList++;
1592    }
1593  }
1594
1595  assert( vps != NULL );    // No picture in any DPB?
1596  std::sort( listOfPocs.begin(), listOfPocs.end() );    // Sort in increasing order of POC
1597  Int targetLsIdx = vps->getOutputLayerSetIdx( getCommonDecoderParams()->getTargetOutputLayerSetIdx() );
1598  // Update status
1599  dpbStatus.m_numAUsNotDisplayed = listOfPocs.size();   // Number of AUs not displayed
1600  dpbStatus.m_numLayers = vps->getNumLayersInIdList( targetLsIdx );
1601  dpbStatus.m_numSubDpbs = vps->getNumSubDpbs( vps->getOutputLayerSetIdx(
1602                                                      this->getCommonDecoderParams()->getTargetOutputLayerSetIdx() ) );
1603
1604  for(Int i = 0; i < dpbStatus.m_numLayers; i++)
1605  {
1606    dpbStatus.m_numPicsNotDisplayedInLayer[i] = listOfPocsInEachLayer[i].size();
1607#if RESOLUTION_BASED_DPB
1608    dpbStatus.m_numPicsInSubDpb[vps->getSubDpbAssigned(targetLsIdx,i)] += dpbStatus.m_numPicsInLayer[i];
1609#else
1610    dpbStatus.m_numPicsInSubDpb[i] += dpbStatus.m_numPicsInLayer[i];
1611#endif
1612  }
1613  assert( dpbStatus.m_numAUsNotDisplayed != -1 );
1614} 
1615
1616#if POC_RESET_IDC_DECODER
1617Void TAppDecTop::outputAllPictures(Int layerId, Bool notOutputCurrPic)
1618{
1619  { // All pictures in the DPB in that layer are to be output; this means other pictures would also be output
1620    std::vector<Int>  listOfPocs;
1621    std::vector<Int>  listOfPocsInEachLayer[MAX_LAYERS];
1622    std::vector<Int>  listOfPocsPositionInEachLayer[MAX_LAYERS];
1623    DpbStatus dpbStatus;
1624
1625    // Find the status of the DPB
1626    xFindDPBStatus(listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus, notOutputCurrPic);
1627
1628    if( listOfPocs.size() )
1629    {
1630      while( listOfPocsInEachLayer[layerId].size() )    // As long as there picture in the layer to be output
1631      {
1632        bumpingProcess( listOfPocs, listOfPocsInEachLayer, listOfPocsPositionInEachLayer, dpbStatus );
1633      }
1634    }
1635  }
1636}
1637#endif
1638#endif
1639//! \}
Note: See TracBrowser for help on using the repository browser.