• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <fstream>
2 #include <gtest/gtest.h>
3 #include "codec_def.h"
4 #include "codec_app_def.h"
5 #include "utils/BufferedData.h"
6 #include "BaseThreadDecoderTest.h"
7 
readBit(uint8_t * pBufPtr,int32_t & curBit)8 static int32_t readBit (uint8_t* pBufPtr, int32_t& curBit) {
9   int nIndex = curBit / 8;
10   int nOffset = curBit % 8 + 1;
11 
12   curBit++;
13   return (pBufPtr[nIndex] >> (8 - nOffset)) & 0x01;
14 }
15 
readBits(uint8_t * pBufPtr,int32_t & n,int32_t & curBit)16 static int32_t readBits (uint8_t* pBufPtr, int32_t& n, int32_t& curBit) {
17   int r = 0;
18   int i;
19   for (i = 0; i < n; i++) {
20     r |= (readBit (pBufPtr, curBit) << (n - i - 1));
21   }
22   return r;
23 }
24 
bsGetUe(uint8_t * pBufPtr,int32_t & curBit)25 static int32_t bsGetUe (uint8_t* pBufPtr, int32_t& curBit) {
26   int r = 0;
27   int i = 0;
28   while ((readBit (pBufPtr, curBit) == 0) && (i < 32)) {
29     i++;
30   }
31   r = readBits (pBufPtr, i, curBit);
32   r += (1 << i) - 1;
33   return r;
34 }
35 
readFirstMbInSlice(uint8_t * pSliceNalPtr)36 static int32_t readFirstMbInSlice (uint8_t* pSliceNalPtr) {
37   int32_t curBit = 0;
38   int32_t firstMBInSlice = bsGetUe (pSliceNalPtr + 1, curBit);
39   return firstMBInSlice;
40 }
41 
ReadFrame(uint8_t * pBuf,const int32_t & iFileSize,const int32_t & bufPos)42 static int32_t ReadFrame (uint8_t* pBuf, const int32_t& iFileSize, const int32_t& bufPos) {
43   int32_t bytes_available = iFileSize - bufPos;
44   if (bytes_available < 4) {
45     return bytes_available;
46   }
47   uint8_t* ptr = pBuf + bufPos;
48   int32_t read_bytes = 0;
49   int32_t sps_count = 0;
50   int32_t pps_count = 0;
51   int32_t non_idr_pict_count = 0;
52   int32_t idr_pict_count = 0;
53   int32_t nal_deliminator = 0;
54   while (read_bytes < bytes_available - 4) {
55     bool has4ByteStartCode = ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 1;
56     bool has3ByteStartCode = false;
57     if (!has4ByteStartCode) {
58       has3ByteStartCode = ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 1;
59     }
60     if (has4ByteStartCode || has3ByteStartCode) {
61       int32_t byteOffset = has4ByteStartCode ? 4 : 3;
62       uint8_t nal_unit_type = has4ByteStartCode ? (ptr[4] & 0x1F) : (ptr[3] & 0x1F);
63       if (nal_unit_type == 1) {
64         int32_t firstMBInSlice = readFirstMbInSlice (ptr + byteOffset);
65         if (++non_idr_pict_count >= 1 && idr_pict_count >= 1 && firstMBInSlice == 0) {
66           return read_bytes;
67         }
68         if (non_idr_pict_count >= 2 && firstMBInSlice == 0) {
69           return read_bytes;
70         }
71       } else if (nal_unit_type == 5) {
72         int32_t firstMBInSlice = readFirstMbInSlice (ptr + byteOffset);
73         if (++idr_pict_count >= 1 && non_idr_pict_count >= 1 && firstMBInSlice == 0) {
74           return read_bytes;
75         }
76         if (idr_pict_count >= 2 && firstMBInSlice == 0) {
77           return read_bytes;
78         }
79       } else if (nal_unit_type == 7) {
80         if ((++sps_count >= 1) && (non_idr_pict_count >= 1 || idr_pict_count >= 1)) {
81           return read_bytes;
82         }
83         if (sps_count == 2) return read_bytes;
84       } else if (nal_unit_type == 8) {
85         if (++pps_count >= 1 && (non_idr_pict_count >= 1 || idr_pict_count >= 1)) return read_bytes;
86       } else if (nal_unit_type == 9) {
87         if (++nal_deliminator == 2) {
88           return read_bytes;
89         }
90       }
91       if (read_bytes >= bytes_available - 4) {
92         return bytes_available;
93       }
94       read_bytes += 4;
95       ptr += 4;
96     } else {
97       ++ptr;
98       ++read_bytes;
99     }
100   }
101   return bytes_available;
102 }
103 
Write2File(FILE * pFp,unsigned char * pData[3],int iStride[2],int iWidth,int iHeight)104 static void Write2File (FILE* pFp, unsigned char* pData[3], int iStride[2], int iWidth, int iHeight) {
105   int   i;
106   unsigned char*  pPtr = NULL;
107 
108   pPtr = pData[0];
109   for (i = 0; i < iHeight; i++) {
110     fwrite (pPtr, 1, iWidth, pFp);
111     pPtr += iStride[0];
112   }
113 
114   iHeight = iHeight / 2;
115   iWidth = iWidth / 2;
116   pPtr = pData[1];
117   for (i = 0; i < iHeight; i++) {
118     fwrite (pPtr, 1, iWidth, pFp);
119     pPtr += iStride[1];
120   }
121 
122   pPtr = pData[2];
123   for (i = 0; i < iHeight; i++) {
124     fwrite (pPtr, 1, iWidth, pFp);
125     pPtr += iStride[1];
126   }
127 }
128 
Process(SBufferInfo * pInfo,FILE * pFp)129 static void Process (SBufferInfo* pInfo, FILE* pFp) {
130   if (pFp && pInfo->pDst[0] && pInfo->pDst[1] && pInfo->pDst[2] && pInfo) {
131     int iStride[2];
132     int iWidth = pInfo->UsrData.sSystemBuffer.iWidth;
133     int iHeight = pInfo->UsrData.sSystemBuffer.iHeight;
134     iStride[0] = pInfo->UsrData.sSystemBuffer.iStride[0];
135     iStride[1] = pInfo->UsrData.sSystemBuffer.iStride[1];
136 
137     Write2File (pFp, (unsigned char**)pInfo->pDst, iStride, iWidth, iHeight);
138   }
139 }
140 
BaseThreadDecoderTest()141 BaseThreadDecoderTest::BaseThreadDecoderTest()
142   : decoder_ (NULL), uiTimeStamp (0), pYuvFile (NULL), bEnableYuvDumpTest (false), decodeStatus_ (OpenFile) {
143 }
144 
SetUp()145 int32_t BaseThreadDecoderTest::SetUp() {
146   long rv = WelsCreateDecoder (&decoder_);
147   EXPECT_EQ (0, rv);
148   EXPECT_TRUE (decoder_ != NULL);
149   if (decoder_ == NULL) {
150     return rv;
151   }
152 
153   SDecodingParam decParam;
154   memset (&decParam, 0, sizeof (SDecodingParam));
155   decParam.uiTargetDqLayer = UCHAR_MAX;
156   decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY;
157   decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
158   int iThreadCount = (rand() % 2) + 2;
159   decoder_->SetOption (DECODER_OPTION_NUM_OF_THREADS, &iThreadCount);
160 
161   rv = decoder_->Initialize (&decParam);
162   EXPECT_EQ (0, rv);
163   return (int32_t)rv;
164 }
165 
TearDown()166 void BaseThreadDecoderTest::TearDown() {
167   if (decoder_ != NULL) {
168     decoder_->Uninitialize();
169     WelsDestroyDecoder (decoder_);
170   }
171 }
172 
173 
DecodeFrame(const uint8_t * src,size_t sliceSize,Callback * cbk)174 void BaseThreadDecoderTest::DecodeFrame (const uint8_t* src, size_t sliceSize, Callback* cbk) {
175   SBufferInfo bufInfo;
176   memset (pData, 0, sizeof (pData));
177   memset (&bufInfo, 0, sizeof (SBufferInfo));
178   bufInfo.uiInBsTimeStamp = ++uiTimeStamp;
179 
180   DECODING_STATE rv = decoder_->DecodeFrameNoDelay (src, (int) sliceSize, pData, &bufInfo);
181   ASSERT_TRUE (rv == dsErrorFree);
182   sBufInfo = bufInfo;
183   if (sBufInfo.iBufferStatus == 1 && cbk != NULL) {
184     if (bEnableYuvDumpTest) {
185       Process (&sBufInfo, pYuvFile);
186     }
187     const Frame frame = {
188       {
189         // y plane
190         sBufInfo.pDst[0],
191         bufInfo.UsrData.sSystemBuffer.iWidth,
192         bufInfo.UsrData.sSystemBuffer.iHeight,
193         bufInfo.UsrData.sSystemBuffer.iStride[0]
194       },
195       {
196         // u plane
197         sBufInfo.pDst[1],
198         sBufInfo.UsrData.sSystemBuffer.iWidth / 2,
199         sBufInfo.UsrData.sSystemBuffer.iHeight / 2,
200         sBufInfo.UsrData.sSystemBuffer.iStride[1]
201       },
202       {
203         // v plane
204         sBufInfo.pDst[2],
205         sBufInfo.UsrData.sSystemBuffer.iWidth / 2,
206         sBufInfo.UsrData.sSystemBuffer.iHeight / 2,
207         sBufInfo.UsrData.sSystemBuffer.iStride[1]
208       },
209     };
210     cbk->onDecodeFrame (frame);
211   }
212 }
FlushFrame(Callback * cbk)213 void BaseThreadDecoderTest::FlushFrame (Callback* cbk) {
214   SBufferInfo bufInfo;
215   memset (pData, 0, sizeof (pData));
216   memset (&bufInfo, 0, sizeof (SBufferInfo));
217 
218   DECODING_STATE rv = decoder_->FlushFrame (pData, &bufInfo);
219   ASSERT_TRUE (rv == dsErrorFree);
220   sBufInfo = bufInfo;
221   if (sBufInfo.iBufferStatus == 1 && cbk != NULL) {
222     if (bEnableYuvDumpTest) {
223       Process (&sBufInfo, pYuvFile);
224     }
225     const Frame frame = {
226       {
227         // y plane
228         sBufInfo.pDst[0],
229         sBufInfo.UsrData.sSystemBuffer.iWidth,
230         sBufInfo.UsrData.sSystemBuffer.iHeight,
231         sBufInfo.UsrData.sSystemBuffer.iStride[0]
232       },
233       {
234         // u plane
235         sBufInfo.pDst[1],
236         sBufInfo.UsrData.sSystemBuffer.iWidth / 2,
237         sBufInfo.UsrData.sSystemBuffer.iHeight / 2,
238         sBufInfo.UsrData.sSystemBuffer.iStride[1]
239       },
240       {
241         // v plane
242         sBufInfo.pDst[2],
243         sBufInfo.UsrData.sSystemBuffer.iWidth / 2,
244         sBufInfo.UsrData.sSystemBuffer.iHeight / 2,
245         sBufInfo.UsrData.sSystemBuffer.iStride[1]
246       },
247     };
248     cbk->onDecodeFrame (frame);
249   }
250 }
ThreadDecodeFile(const char * fileName,Callback * cbk)251 bool BaseThreadDecoderTest::ThreadDecodeFile (const char* fileName, Callback* cbk) {
252   std::ifstream file (fileName, std::ios::in | std::ios::binary);
253   if (!file.is_open())
254     return false;
255 
256   BufferedData buf;
257   char b;
258   for (;;) {
259     file.read (&b, 1);
260     if (file.gcount() != 1) { // end of file
261       break;
262     }
263     if (!buf.PushBack (b)) {
264       std::cout << "unable to allocate memory" << std::endl;
265       return false;
266     }
267   }
268 
269   std::string outFileName = std::string (fileName);
270   size_t pos = outFileName.find_last_of (".");
271   if (bEnableYuvDumpTest) {
272     outFileName = outFileName.substr (0, pos) + std::string (".yuv");
273     pYuvFile = fopen (outFileName.c_str(), "wb");
274   }
275 
276   uiTimeStamp = 0;
277   memset (&sBufInfo, 0, sizeof (SBufferInfo));
278   int32_t bufPos = 0;
279   int32_t bytesConsumed = 0;
280   int32_t fileSize = (int32_t)buf.Length();
281   while (bytesConsumed < fileSize) {
282     int32_t frameSize = ReadFrame (buf.data(), fileSize, bufPos);
283     if (::testing::Test::HasFatalFailure()) {
284       return false;
285     }
286     uint8_t* frame_ptr = buf.data() + bufPos;
287     DecodeFrame (frame_ptr, frameSize, cbk);
288     if (::testing::Test::HasFatalFailure()) {
289       return false;
290     }
291     bufPos += frameSize;
292     bytesConsumed += frameSize;
293   }
294 
295   int32_t iEndOfStreamFlag = 1;
296   decoder_->SetOption (DECODER_OPTION_END_OF_STREAM, &iEndOfStreamFlag);
297 
298   // Flush out last frames in decoder buffer
299   int32_t num_of_frames_in_buffer = 0;
300   decoder_->GetOption (DECODER_OPTION_NUM_OF_FRAMES_REMAINING_IN_BUFFER, &num_of_frames_in_buffer);
301   for (int32_t i = 0; i < num_of_frames_in_buffer; ++i) {
302     FlushFrame (cbk);
303   }
304   if (bEnableYuvDumpTest) {
305     fclose (pYuvFile);
306   }
307   return true;
308 }
309 
Open(const char * fileName)310 bool BaseThreadDecoderTest::Open (const char* fileName) {
311   if (decodeStatus_ == OpenFile) {
312     file_.open (fileName, std::ios_base::out | std::ios_base::binary);
313     if (file_.is_open()) {
314       decodeStatus_ = Decoding;
315       return true;
316     }
317   }
318   return false;
319 }
320