0

I have been trying to create a DLL out of the HEVC reference decoder and integrate into my application and I'm stuck with a linking error which I'm not able to solve I have tried adding project dependencies/references. I have attached the code snippet below. I keep getting the following linking error.

HEVCDecoderDXVA.lib(HEVCRefDecImp.obj) : error LNK2019: unresolved external symbol "public: __thiscall TAppDecTop::TAppDecTop(void)" (??0TAppDecTop@@QAE@XZ) referenced in function "public: __thiscall CHEVC::CHEVC(void)" (??0CHEVC@@QAE@XZ)
TLibDecoder.lib(TDecGop.obj) : error LNK2001: unresolved external symbol "bool g_md5_mismatch" (?g_md5_mismatch@@3_NA)
C:\HEVCDecoder3\build\Debug\HEVCDecoderDLL.dll : fatal error LNK1120: 2 unresolved externals

What I'm trying to do is to have decoder instance as a member variable in my CHEVC class

TAppDecTop m_RefDecoder;

The above line is the problem causing line , The unresolved external symbol "bool g_md5_mismatch" error is also due to this line,

In LibraryAPI.h

#ifndef _LIBRARY_API_H_
#define _LIBRARY_API_H_

namespace NSF
{

    class CAPI
    {
    public:
        virtual ~CAPI() { }
    };

}

#endif // _LIBRARY_API_H_

In AppDecInf.h

#ifndef REF_DEC_INF_H
#define REF_DEC_INF_H


#include "LibraryAPI.h"

namespace NAppDecoderAPI
{

    class AppDecInf : public NSF::CAPI
    {
    public:
        virtual ~AppDecInf()
        {

        }

        virtual int InitRefDecoder(char *fileName)=0;
        virtual int TerminateRefDecoder()=0;
        virtual int DecodeFrame()=0;

    };

}

In HEVCRefDecImp.h

#ifndef HEVC_REF_DEC_INF_H
#define HEVC_REF_DEC_INF_H


#include "AppDecInf.h"
#include "TAppDecTop.h"


class CHEVC : public  NAppDecoderAPI::AppDecInf 
{
public:
    CHEVC();
    virtual ~CHEVC();

    int InitRefDecoder(char *fileName);
    int TerminateRefDecoder();
    int DecodeFrame();

private:
    bool temp;
    TAppDecTop m_RefDecoder;
};

#endif  //HEVC_REF_DEC_INF_H

In HEVCRefDecImp.cpp

#include"HEVCRefDecImp.h"


CHEVC::CHEVC()
{
    temp = false;
}

CHEVC::~CHEVC()
{

}

int CHEVC::InitRefDecoder(char* fileName)
{
    m_RefDecoder.create();
    return(0);

}

int CHEVC::DecodeFrame()
{
    m_RefDecoder.decode();
    return(0);

}

int CHEVC::TerminateRefDecoder()
{
    m_RefDecoder.destroy();
    return(0);
}

In TAppDecTop.h

#ifndef __TAPPDECTOP__
#define __TAPPDECTOP__

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "TLibVideoIO/TVideoIOYuv.h"
#include "TLibCommon/TComList.h"
#include "TLibCommon/TComPicYuv.h"
#include "TLibDecoder/TDecTop.h"
#include "TAppDecCfg.h"

//! \ingroup TAppDecoder
//! \{

// ====================================================================================================================
// Class definition
// ====================================================================================================================

/// decoder application class
class TAppDecTop : public TAppDecCfg
{
private:
  // class interface
  TDecTop                         m_cTDecTop;                     ///< decoder class
  TVideoIOYuv                     m_cTVideoIOYuvReconFile;        ///< reconstruction YUV class

  // for output control
  Bool                            m_abDecFlag[ MAX_GOP ];         ///< decoded flag in one GOP
  Int                             m_iPOCLastDisplay;              ///< last POC in display order

public:
  TAppDecTop();
  virtual ~TAppDecTop() {}

  Void  create            (); ///< create internal members
  Void  destroy           (); ///< destroy internal members
  Void  decode            (); ///< main decoding function

protected:
  Void  xCreateDecLib     (); ///< create internal classes
  Void  xDestroyDecLib    (); ///< destroy internal classes
  Void  xInitDecLib       (); ///< initialize decoder class

  Void  xWriteOutput      ( TComList<TComPic*>* pcListPic , UInt tId); ///< write YUV to file
  Void  xFlushOutput      ( TComList<TComPic*>* pcListPic ); ///< flush all remaining decoded pictures to file
};

//! \}

#endif

In TAppDecTop.cpp

#include <list>
#include <vector>
#include <stdio.h>
#include <fcntl.h>
#include <assert.h>

#include "TAppDecTop.h"
#include "TLibDecoder/AnnexBread.h"
#include "TLibDecoder/NALread.h"

//! \ingroup TAppDecoder
//! \{

// ====================================================================================================================
// Constructor / destructor / initialization / destroy
// ====================================================================================================================

TAppDecTop::TAppDecTop()
{
  ::memset (m_abDecFlag, 0, sizeof (m_abDecFlag));
  m_iPOCLastDisplay  = -MAX_INT;
}

Void TAppDecTop::create()
{
}

Void TAppDecTop::destroy()
{
}

// ====================================================================================================================
// Public member functions
// ====================================================================================================================

/**
 - create internal class
 - initialize internal class
 - until the end of the bitstream, call decoding function in TDecTop class
 - delete allocated buffers
 - destroy internal class
 .
 */
Void TAppDecTop::decode()
{
  UInt                uiPOC;
  TComList<TComPic*>* pcListPic = NULL;

  ifstream bitstreamFile(m_pchBitstreamFile, ifstream::in | ifstream::binary);
  if (!bitstreamFile)
  {
    fprintf(stderr, "\nfailed to open bitstream file `%s' for reading\n", m_pchBitstreamFile);
    exit(EXIT_FAILURE);
  }

  InputByteStream bytestream(bitstreamFile);

  // create & initialize internal classes
  xCreateDecLib();
  xInitDecLib  ();
  m_iPOCLastDisplay += m_iSkipFrame;      // set the last displayed POC correctly for skip forward.

  // main decoder loop
  bool recon_opened = false; // reconstruction file not yet opened. (must be performed after SPS is seen)

  while (!!bitstreamFile)
  {
    /* location serves to work around a design fault in the decoder, whereby
     * the process of reading a new slice that is the first slice of a new frame
     * requires the TDecTop::decode() method to be called again with the same
     * nal unit. */
    streampos location = bitstreamFile.tellg();
    AnnexBStats stats = AnnexBStats();
    bool bPreviousPictureDecoded = false;

    vector<uint8_t> nalUnit;
    InputNALUnit nalu;
    byteStreamNALUnit(bytestream, nalUnit, stats);

    // call actual decoding function
    bool bNewPicture = false;
    if (nalUnit.empty())
    {
      /* this can happen if the following occur:
       *  - empty input file
       *  - two back-to-back start_code_prefixes
       *  - start_code_prefix immediately followed by EOF
       */
      fprintf(stderr, "Warning: Attempt to decode an empty NAL unit\n");
    }
    else
    {
      read(nalu, nalUnit);
      if(m_iMaxTemporalLayer >= 0 && nalu.m_temporalId > m_iMaxTemporalLayer)
      {
        if(bPreviousPictureDecoded)
        {
          bNewPicture = true;
          bPreviousPictureDecoded = false;
        }
        else
        {
          bNewPicture = false;
        }
      }
      else
      {
        bNewPicture = m_cTDecTop.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay);
        if (bNewPicture)
        {
          bitstreamFile.clear();
          /* location points to the current nalunit payload[1] due to the
           * need for the annexB parser to read three extra bytes.
           * [1] except for the first NAL unit in the file
           *     (but bNewPicture doesn't happen then) */
          bitstreamFile.seekg(location-streamoff(3));
          bytestream.reset();
        }
        bPreviousPictureDecoded = true; 
      }
    }
    if (bNewPicture || !bitstreamFile)
    {
      m_cTDecTop.executeDeblockAndAlf(uiPOC, pcListPic, m_iSkipFrame, m_iPOCLastDisplay);
    }

    if( pcListPic )
    {
      if ( m_pchReconFile && !recon_opened )
      {
        if ( m_outputBitDepth == 0 )
        {
          m_outputBitDepth = g_uiBitDepth + g_uiBitIncrement;
        }

        m_cTVideoIOYuvReconFile.open( m_pchReconFile, true, m_outputBitDepth, g_uiBitDepth + g_uiBitIncrement ); // write mode
        recon_opened = true;
      }
      if (bNewPicture && (nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR))
      {
        xFlushOutput( pcListPic );
      }
      // write reconstruction to file
      if(bNewPicture)
      {
        xWriteOutput( pcListPic, nalu.m_temporalId );
      }
    }
  }

  xFlushOutput( pcListPic );
  // delete buffers
  m_cTDecTop.deletePicBuffer();

  // destroy internal classes
  xDestroyDecLib();
}

// ====================================================================================================================
// Protected member functions
// ====================================================================================================================

Void TAppDecTop::xCreateDecLib()
{
  // create decoder class
  m_cTDecTop.create();
}

Void TAppDecTop::xDestroyDecLib()
{
  if ( m_pchReconFile )
  {
    m_cTVideoIOYuvReconFile. close();
  }

  // destroy decoder class
  m_cTDecTop.destroy();
}

Void TAppDecTop::xInitDecLib()
{
  // initialize decoder class
  m_cTDecTop.init();
  m_cTDecTop.setPictureDigestEnabled(m_pictureDigestEnabled);
}

/** \param pcListPic list of pictures to be written to file
    \todo            DYN_REF_FREE should be revised
 */
Void TAppDecTop::xWriteOutput( TComList<TComPic*>* pcListPic, UInt tId )
{
  TComList<TComPic*>::iterator iterPic   = pcListPic->begin();
  Int not_displayed = 0;

  while (iterPic != pcListPic->end())
  {
    TComPic* pcPic = *(iterPic);
    if(pcPic->getOutputMark() && pcPic->getPOC() > m_iPOCLastDisplay)
    {
       not_displayed++;
    }
    iterPic++;
  }
  iterPic   = pcListPic->begin();

  while (iterPic != pcListPic->end())
  {
    TComPic* pcPic = *(iterPic);
    TComSPS *sps = pcPic->getSlice(0)->getSPS();

    if ( pcPic->getOutputMark() && (not_displayed >  pcPic->getSlice(0)->getSPS()->getNumReorderPics(tId) && pcPic->getPOC() > m_iPOCLastDisplay))
    {
      // write to file
       not_displayed--;
      if ( m_pchReconFile )
      {
        m_cTVideoIOYuvReconFile.write( pcPic->getPicYuvRec(), sps->getPicCropLeftOffset(), sps->getPicCropRightOffset(), sps->getPicCropTopOffset(), sps->getPicCropBottomOffset() );
      }

      // update POC of display order
      m_iPOCLastDisplay = pcPic->getPOC();

      // erase non-referenced picture in the reference picture list after display
      if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
      {
#if !DYN_REF_FREE
        pcPic->setReconMark(false);

        // mark it should be extended later
        pcPic->getPicYuvRec()->setBorderExtension( false );

#else
        pcPic->destroy();
        pcListPic->erase( iterPic );
        iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
        continue;
#endif
      }
      pcPic->setOutputMark(false);
    }

    iterPic++;
  }
}

/** \param pcListPic list of pictures to be written to file
    \todo            DYN_REF_FREE should be revised
 */
Void TAppDecTop::xFlushOutput( TComList<TComPic*>* pcListPic )
{
  if(!pcListPic)
  {
    return;
  } 
  TComList<TComPic*>::iterator iterPic   = pcListPic->begin();

  iterPic   = pcListPic->begin();

  while (iterPic != pcListPic->end())
  {
    TComPic* pcPic = *(iterPic);
    TComSPS *sps = pcPic->getSlice(0)->getSPS();

    if ( pcPic->getOutputMark() )
    {
      // write to file
      if ( m_pchReconFile )
      {
        m_cTVideoIOYuvReconFile.write( pcPic->getPicYuvRec(), sps->getPicCropLeftOffset(), sps->getPicCropRightOffset(), sps->getPicCropTopOffset(), sps->getPicCropBottomOffset() );
      }

      // update POC of display order
      m_iPOCLastDisplay = pcPic->getPOC();

      // erase non-referenced picture in the reference picture list after display
      if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
      {
#if !DYN_REF_FREE
        pcPic->setReconMark(false);

        // mark it should be extended later
        pcPic->getPicYuvRec()->setBorderExtension( false );

#else
        pcPic->destroy();
        pcListPic->erase( iterPic );
        iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
        continue;
#endif
      }
      pcPic->setOutputMark(false);
    }

    iterPic++;
  }
  pcListPic->clear();
  m_iPOCLastDisplay = -MAX_INT;
}
user1529619
  • 57
  • 1
  • 1
  • 5
  • 1
    You do not show the CHEVCRefDecInterface, with constructor CHEVCRefDecInterface(void) where the error appears. It needs TAppDecTop, is that really what you intended? – Johan Lundberg Jul 16 '12 at 18:26
  • Sorry..I had made a mistake while typing the question, I have corrected it. I understand that it is not seeing the implementation of TAppDecTop::TAppDecTop(), but I have included the header file and also added the dependencies – user1529619 Jul 16 '12 at 18:43
  • 1
    is this the only error or warning you get? apparently you do not include the compilation result of TAppDecTop.cpp. Does it work if you put the implementation in the header file instead? – Johan Lundberg Jul 16 '12 at 18:52

0 Answers0