我一直在尝试从 HEVC 参考解码器中创建一个 DLL 并集成到我的应用程序中,但我遇到了无法解决的链接错误我尝试添加项目依赖项/引用。我附上了下面的代码片段。我不断收到以下链接错误。
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
我想要做的是让解码器实例作为我的 CHEVC 类中的成员变量
TAppDecTop m_RefDecoder;
上面这行是导致 line 的问题,unresolved external symbol "bool g_md5_mismatch" 错误也是由于这行,
在 LibraryAPI.h 中
#ifndef _LIBRARY_API_H_
#define _LIBRARY_API_H_
namespace NSF
{
class CAPI
{
public:
virtual ~CAPI() { }
};
}
#endif // _LIBRARY_API_H_
在 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;
};
}
在 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
在 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);
}
在 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
在 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;
}