Ticket #620: TAppDecTop_MemoryLeakFixed.cpp

File TAppDecTop_MemoryLeakFixed.cpp, 11.0 KB (added by ywhe, 10 years ago)

to fix the memory leak in TAppDecTop::xFlushOutput()

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-2012, 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
44#include "TAppDecTop.h"
45#include "TLibDecoder/AnnexBread.h"
46#include "TLibDecoder/NALread.h"
47
48//! \ingroup TAppDecoder
49//! \{
50
51// ====================================================================================================================
52// Constructor / destructor / initialization / destroy
53// ====================================================================================================================
54
55TAppDecTop::TAppDecTop()
56{
57  ::memset (m_abDecFlag, 0, sizeof (m_abDecFlag));
58  m_iPOCLastDisplay  = -MAX_INT;
59}
60
61Void TAppDecTop::create()
62{
63}
64
65Void TAppDecTop::destroy()
66{
67}
68
69// ====================================================================================================================
70// Public member functions
71// ====================================================================================================================
72
73/**
74 - create internal class
75 - initialize internal class
76 - until the end of the bitstream, call decoding function in TDecTop class
77 - delete allocated buffers
78 - destroy internal class
79 .
80 */
81Void TAppDecTop::decode()
82{
83  UInt                uiPOC;
84  TComList<TComPic*>* pcListPic = NULL;
85
86  ifstream bitstreamFile(m_pchBitstreamFile, ifstream::in | ifstream::binary);
87  if (!bitstreamFile)
88  {
89    fprintf(stderr, "\nfailed to open bitstream file `%s' for reading\n", m_pchBitstreamFile);
90    exit(EXIT_FAILURE);
91  }
92
93  InputByteStream bytestream(bitstreamFile);
94
95  // create & initialize internal classes
96  xCreateDecLib();
97  xInitDecLib  ();
98  m_iPOCLastDisplay += m_iSkipFrame;      // set the last displayed POC correctly for skip forward.
99
100  // main decoder loop
101  bool recon_opened = false; // reconstruction file not yet opened. (must be performed after SPS is seen)
102
103  while (!!bitstreamFile)
104  {
105    /* location serves to work around a design fault in the decoder, whereby
106     * the process of reading a new slice that is the first slice of a new frame
107     * requires the TDecTop::decode() method to be called again with the same
108     * nal unit. */
109    streampos location = bitstreamFile.tellg();
110    AnnexBStats stats = AnnexBStats();
111    bool bPreviousPictureDecoded = false;
112
113    vector<uint8_t> nalUnit;
114    InputNALUnit nalu;
115    byteStreamNALUnit(bytestream, nalUnit, stats);
116
117    // call actual decoding function
118    bool bNewPicture = false;
119    if (nalUnit.empty())
120    {
121      /* this can happen if the following occur:
122       *  - empty input file
123       *  - two back-to-back start_code_prefixes
124       *  - start_code_prefix immediately followed by EOF
125       */
126      fprintf(stderr, "Warning: Attempt to decode an empty NAL unit\n");
127    }
128    else
129    {
130      read(nalu, nalUnit);
131#if TEMPORAL_ID_RESTRICTION
132      if(nalu.m_nalUnitType == NAL_UNIT_SPS)
133      {
134        assert(nalu.m_temporalId == 0);
135      }
136#endif
137      if(m_iMaxTemporalLayer >= 0 && nalu.m_temporalId > m_iMaxTemporalLayer)
138      {
139        if(bPreviousPictureDecoded)
140        {
141          bNewPicture = true;
142          bPreviousPictureDecoded = false;
143        }
144        else
145        {
146          bNewPicture = false;
147        }
148      }
149      else
150      {
151        bNewPicture = m_cTDecTop.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay);
152        if (bNewPicture)
153        {
154          bitstreamFile.clear();
155          /* location points to the current nalunit payload[1] due to the
156           * need for the annexB parser to read three extra bytes.
157           * [1] except for the first NAL unit in the file
158           *     (but bNewPicture doesn't happen then) */
159          bitstreamFile.seekg(location-streamoff(3));
160          bytestream.reset();
161        }
162        bPreviousPictureDecoded = true; 
163      }
164    }
165    if (bNewPicture || !bitstreamFile)
166    {
167      m_cTDecTop.executeDeblockAndAlf(uiPOC, pcListPic, m_iSkipFrame, m_iPOCLastDisplay);
168    }
169
170    if( pcListPic )
171    {
172      if ( m_pchReconFile && !recon_opened )
173      {
174        if ( m_outputBitDepth == 0 )
175        {
176          m_outputBitDepth = g_uiBitDepth + g_uiBitIncrement;
177        }
178
179        m_cTVideoIOYuvReconFile.open( m_pchReconFile, true, m_outputBitDepth, g_uiBitDepth + g_uiBitIncrement ); // write mode
180        recon_opened = true;
181      }
182#if CRA_BLA_TFD_MODIFICATIONS
183      if ( bNewPicture && 
184           (   nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR
185            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLANT
186            || nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_BLA ) )
187#else
188      if (bNewPicture && (nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR))
189#endif
190      {
191        xFlushOutput( pcListPic );
192      }
193      // write reconstruction to file
194      if(bNewPicture)
195      {
196        xWriteOutput( pcListPic, nalu.m_temporalId );
197      }
198    }
199  }
200 
201  xFlushOutput( pcListPic );
202  // delete buffers
203  m_cTDecTop.deletePicBuffer();
204 
205  // destroy internal classes
206  xDestroyDecLib();
207}
208
209// ====================================================================================================================
210// Protected member functions
211// ====================================================================================================================
212
213Void TAppDecTop::xCreateDecLib()
214{
215  // create decoder class
216  m_cTDecTop.create();
217}
218
219Void TAppDecTop::xDestroyDecLib()
220{
221  if ( m_pchReconFile )
222  {
223    m_cTVideoIOYuvReconFile. close();
224  }
225 
226  // destroy decoder class
227  m_cTDecTop.destroy();
228}
229
230Void TAppDecTop::xInitDecLib()
231{
232  // initialize decoder class
233  m_cTDecTop.init();
234  m_cTDecTop.setPictureDigestEnabled(m_pictureDigestEnabled);
235}
236
237/** \param pcListPic list of pictures to be written to file
238    \todo            DYN_REF_FREE should be revised
239 */
240Void TAppDecTop::xWriteOutput( TComList<TComPic*>* pcListPic, UInt tId )
241{
242  TComList<TComPic*>::iterator iterPic   = pcListPic->begin();
243  Int not_displayed = 0;
244
245  while (iterPic != pcListPic->end())
246  {
247    TComPic* pcPic = *(iterPic);
248    if(pcPic->getOutputMark() && pcPic->getPOC() > m_iPOCLastDisplay)
249    {
250       not_displayed++;
251    }
252    iterPic++;
253  }
254  iterPic   = pcListPic->begin();
255 
256  while (iterPic != pcListPic->end())
257  {
258    TComPic* pcPic = *(iterPic);
259    TComSPS *sps = pcPic->getSlice(0)->getSPS();
260   
261    if ( pcPic->getOutputMark() && (not_displayed >  pcPic->getSlice(0)->getSPS()->getNumReorderPics(tId) && pcPic->getPOC() > m_iPOCLastDisplay))
262    {
263      // write to file
264       not_displayed--;
265      if ( m_pchReconFile )
266      {
267        m_cTVideoIOYuvReconFile.write( pcPic->getPicYuvRec(), sps->getPicCropLeftOffset(), sps->getPicCropRightOffset(), sps->getPicCropTopOffset(), sps->getPicCropBottomOffset() );
268      }
269     
270      // update POC of display order
271      m_iPOCLastDisplay = pcPic->getPOC();
272     
273      // erase non-referenced picture in the reference picture list after display
274      if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
275      {
276#if !DYN_REF_FREE
277        pcPic->setReconMark(false);
278       
279        // mark it should be extended later
280        pcPic->getPicYuvRec()->setBorderExtension( false );
281       
282#else
283        pcPic->destroy();
284        pcListPic->erase( iterPic );
285        iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
286        continue;
287#endif
288      }
289      pcPic->setOutputMark(false);
290    }
291   
292    iterPic++;
293  }
294}
295
296/** \param pcListPic list of pictures to be written to file
297    \todo            DYN_REF_FREE should be revised
298 */
299Void TAppDecTop::xFlushOutput( TComList<TComPic*>* pcListPic )
300{
301  if(!pcListPic)
302  {
303    return;
304  } 
305  TComList<TComPic*>::iterator iterPic   = pcListPic->begin();
306
307  iterPic   = pcListPic->begin();
308 
309  while (iterPic != pcListPic->end())
310  {
311    TComPic* pcPic = *(iterPic);
312    TComSPS *sps = pcPic->getSlice(0)->getSPS();
313
314    if ( pcPic->getOutputMark() )
315    {
316      // write to file
317      if ( m_pchReconFile )
318      {
319        m_cTVideoIOYuvReconFile.write( pcPic->getPicYuvRec(), sps->getPicCropLeftOffset(), sps->getPicCropRightOffset(), sps->getPicCropTopOffset(), sps->getPicCropBottomOffset() );
320      }
321     
322      // update POC of display order
323      m_iPOCLastDisplay = pcPic->getPOC();
324     
325      // erase non-referenced picture in the reference picture list after display
326      if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
327      {
328#if !DYN_REF_FREE
329        pcPic->setReconMark(false);
330       
331        // mark it should be extended later
332        pcPic->getPicYuvRec()->setBorderExtension( false );
333       
334#else
335        pcPic->destroy();
336        pcListPic->erase( iterPic );
337        iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
338        continue;
339#endif
340      }
341      pcPic->setOutputMark(false);
342    }
343#if !DYN_REF_FREE
344    //memory leak fix;
345    if(pcPic)
346    {
347      pcPic->destroy();
348      delete pcPic;
349      pcPic = NULL;
350    }
351#endif   
352    iterPic++;
353  }
354  pcListPic->clear();
355  m_iPOCLastDisplay = -MAX_INT;
356}
357
358//! \}