14a2200f8b677609be5cc6643e9b9cea8718b505
[deb_x265.git] / source / encoder / encoder.cpp
1 /*****************************************************************************
2 * Copyright (C) 2013 x265 project
3 *
4 * Authors: Steve Borho <steve@borho.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
19 *
20 * This program is also available under a commercial proprietary license.
21 * For more information, contact us at license @ x265.com.
22 *****************************************************************************/
23
24 #include "common.h"
25 #include "primitives.h"
26 #include "threadpool.h"
27 #include "param.h"
28 #include "frame.h"
29 #include "framedata.h"
30 #include "picyuv.h"
31
32 #include "bitcost.h"
33 #include "encoder.h"
34 #include "slicetype.h"
35 #include "frameencoder.h"
36 #include "ratecontrol.h"
37 #include "dpb.h"
38 #include "nal.h"
39
40 #include "x265.h"
41
42 namespace x265 {
43 const char g_sliceTypeToChar[] = {'B', 'P', 'I'};
44 }
45
46 static const char *summaryCSVHeader =
47 "Command, Date/Time, Elapsed Time, FPS, Bitrate, "
48 "Y PSNR, U PSNR, V PSNR, Global PSNR, SSIM, SSIM (dB), "
49 "I count, I ave-QP, I kpbs, I-PSNR Y, I-PSNR U, I-PSNR V, I-SSIM (dB), "
50 "P count, P ave-QP, P kpbs, P-PSNR Y, P-PSNR U, P-PSNR V, P-SSIM (dB), "
51 "B count, B ave-QP, B kpbs, B-PSNR Y, B-PSNR U, B-PSNR V, B-SSIM (dB), "
52 "Version\n";
53
54 const char* defaultAnalysisFileName = "x265_analysis.dat";
55
56 using namespace x265;
57
58 Encoder::Encoder()
59 {
60 m_aborted = false;
61 m_encodedFrameNum = 0;
62 m_pocLast = -1;
63 m_curEncoder = 0;
64 m_numLumaWPFrames = 0;
65 m_numChromaWPFrames = 0;
66 m_numLumaWPBiFrames = 0;
67 m_numChromaWPBiFrames = 0;
68 m_lookahead = NULL;
69 m_frameEncoder = NULL;
70 m_rateControl = NULL;
71 m_dpb = NULL;
72 m_exportedPic = NULL;
73 m_numDelayedPic = 0;
74 m_outputCount = 0;
75 m_csvfpt = NULL;
76 m_param = NULL;
77 m_cuOffsetY = NULL;
78 m_cuOffsetC = NULL;
79 m_buOffsetY = NULL;
80 m_buOffsetC = NULL;
81 m_threadPool = 0;
82 m_numThreadLocalData = 0;
83 m_analysisFile = NULL;
84 }
85
86 void Encoder::create()
87 {
88 if (!primitives.sad[0])
89 {
90 // this should be an impossible condition when using our public API, and indicates a serious bug.
91 x265_log(m_param, X265_LOG_ERROR, "Primitives must be initialized before encoder is created\n");
92 abort();
93 }
94
95 x265_param* p = m_param;
96
97 int rows = (p->sourceHeight + p->maxCUSize - 1) >> g_log2Size[p->maxCUSize];
98
99 // Do not allow WPP if only one row, it is pointless and unstable
100 if (rows == 1)
101 p->bEnableWavefront = 0;
102
103 int poolThreadCount = p->poolNumThreads ? p->poolNumThreads : getCpuCount();
104
105 // Trim the thread pool if --wpp, --pme, and --pmode are disabled
106 if (!p->bEnableWavefront && !p->bDistributeModeAnalysis && !p->bDistributeMotionEstimation)
107 poolThreadCount = 0;
108
109 if (poolThreadCount > 1)
110 {
111 m_threadPool = ThreadPool::allocThreadPool(poolThreadCount);
112 poolThreadCount = m_threadPool->getThreadCount();
113 }
114 else
115 poolThreadCount = 0;
116
117 if (!poolThreadCount)
118 {
119 // issue warnings if any of these features were requested
120 if (p->bEnableWavefront)
121 x265_log(p, X265_LOG_WARNING, "No thread pool allocated, --wpp disabled\n");
122 if (p->bDistributeMotionEstimation)
123 x265_log(p, X265_LOG_WARNING, "No thread pool allocated, --pme disabled\n");
124 if (p->bDistributeModeAnalysis)
125 x265_log(p, X265_LOG_WARNING, "No thread pool allocated, --pmode disabled\n");
126
127 // disable all pool features if the thread pool is disabled or unusable.
128 p->bEnableWavefront = p->bDistributeModeAnalysis = p->bDistributeMotionEstimation = 0;
129 }
130
131 if (!p->frameNumThreads)
132 {
133 // auto-detect frame threads
134 int cpuCount = getCpuCount();
135 if (!p->bEnableWavefront)
136 p->frameNumThreads = X265_MIN(cpuCount, (rows + 1) / 2);
137 else if (cpuCount >= 32)
138 p->frameNumThreads = 6; // dual-socket 10-core IvyBridge or higher
139 else if (cpuCount >= 16)
140 p->frameNumThreads = 5; // 8 HT cores, or dual socket
141 else if (cpuCount >= 8)
142 p->frameNumThreads = 3; // 4 HT cores
143 else if (cpuCount >= 4)
144 p->frameNumThreads = 2; // Dual or Quad core
145 else
146 p->frameNumThreads = 1;
147 }
148
149 x265_log(p, X265_LOG_INFO, "WPP streams / frame threads / pool : %d / %d / %d%s%s\n",
150 p->bEnableWavefront ? rows : 0, p->frameNumThreads, poolThreadCount,
151 p->bDistributeMotionEstimation ? " / pme" : "", p->bDistributeModeAnalysis ? " / pmode" : "");
152
153 m_frameEncoder = new FrameEncoder[m_param->frameNumThreads];
154 for (int i = 0; i < m_param->frameNumThreads; i++)
155 m_frameEncoder[i].setThreadPool(m_threadPool);
156
157 if (!m_scalingList.init())
158 {
159 x265_log(m_param, X265_LOG_ERROR, "Unable to allocate scaling list arrays\n");
160 m_aborted = true;
161 }
162 else if (!m_param->scalingLists || !strcmp(m_param->scalingLists, "off"))
163 m_scalingList.m_bEnabled = false;
164 else if (!strcmp(m_param->scalingLists, "default"))
165 m_scalingList.setDefaultScalingList();
166 else if (m_scalingList.parseScalingList(m_param->scalingLists))
167 m_aborted = true;
168 m_scalingList.setupQuantMatrices();
169
170 /* Allocate thread local data, one for each thread pool worker and
171 * if --no-wpp, one for each frame encoder */
172 m_numThreadLocalData = poolThreadCount;
173 if (!m_param->bEnableWavefront)
174 m_numThreadLocalData += m_param->frameNumThreads;
175 m_threadLocalData = new ThreadLocalData[m_numThreadLocalData];
176 for (int i = 0; i < m_numThreadLocalData; i++)
177 {
178 m_threadLocalData[i].analysis.setThreadPool(m_threadPool);
179 m_threadLocalData[i].analysis.initSearch(*m_param, m_scalingList);
180 m_threadLocalData[i].analysis.create(m_threadLocalData);
181 }
182
183 if (!m_param->bEnableWavefront)
184 for (int i = 0; i < m_param->frameNumThreads; i++)
185 m_frameEncoder[i].m_tld = &m_threadLocalData[poolThreadCount + i];
186
187 m_lookahead = new Lookahead(m_param, m_threadPool);
188 m_dpb = new DPB(m_param);
189 m_rateControl = new RateControl(m_param);
190
191 initSPS(&m_sps);
192 initPPS(&m_pps);
193
194 /* Try to open CSV file handle */
195 if (m_param->csvfn)
196 {
197 m_csvfpt = fopen(m_param->csvfn, "r");
198 if (m_csvfpt)
199 {
200 /* file already exists, re-open for append */
201 fclose(m_csvfpt);
202 m_csvfpt = fopen(m_param->csvfn, "ab");
203 }
204 else
205 {
206 /* new CSV file, write header */
207 m_csvfpt = fopen(m_param->csvfn, "wb");
208 if (m_csvfpt)
209 {
210 if (m_param->logLevel >= X265_LOG_DEBUG)
211 {
212 fprintf(m_csvfpt, "Encode Order, Type, POC, QP, Bits, ");
213 if (m_param->rc.rateControlMode == X265_RC_CRF)
214 fprintf(m_csvfpt, "RateFactor, ");
215 fprintf(m_csvfpt, "Y PSNR, U PSNR, V PSNR, YUV PSNR, SSIM, SSIM (dB), "
216 "Encoding time, Elapsed time, List 0, List 1\n");
217 }
218 else
219 fputs(summaryCSVHeader, m_csvfpt);
220 }
221 }
222 }
223
224 if (m_frameEncoder)
225 {
226 int numRows = (m_param->sourceHeight + g_maxCUSize - 1) / g_maxCUSize;
227 int numCols = (m_param->sourceWidth + g_maxCUSize - 1) / g_maxCUSize;
228 for (int i = 0; i < m_param->frameNumThreads; i++)
229 {
230 if (!m_frameEncoder[i].init(this, numRows, numCols, i))
231 {
232 x265_log(m_param, X265_LOG_ERROR, "Unable to initialize frame encoder, aborting\n");
233 m_aborted = true;
234 }
235 }
236 }
237
238 if (m_param->bEmitHRDSEI)
239 m_rateControl->initHRD(&m_sps);
240 if (!m_rateControl->init(&m_sps))
241 m_aborted = true;
242
243 m_lookahead->init();
244
245 if (m_param->analysisMode)
246 {
247 const char* name = m_param->analysisFileName;
248 if (!name)
249 name = defaultAnalysisFileName;
250 const char* mode = m_param->analysisMode == X265_ANALYSIS_LOAD ? "rb" : "wb";
251 m_analysisFile = fopen(name, mode);
252 if (!m_analysisFile)
253 {
254 x265_log(NULL, X265_LOG_ERROR, "Analysis load/save: failed to open file %s\n", name);
255 m_aborted = true;
256 }
257 }
258
259 m_aborted |= parseLambdaFile(m_param);
260
261 m_encodeStartTime = x265_mdate();
262 }
263
264 void Encoder::destroy()
265 {
266 if (m_exportedPic)
267 {
268 ATOMIC_DEC(&m_exportedPic->m_countRefEncoders);
269 m_exportedPic = NULL;
270 }
271
272 if (m_rateControl)
273 m_rateControl->terminate(); // unblock all blocked RC calls
274
275 if (m_frameEncoder)
276 {
277 for (int i = 0; i < m_param->frameNumThreads; i++)
278 {
279 // Ensure frame encoder is idle before destroying it
280 m_frameEncoder[i].getEncodedPicture(m_nalList);
281 m_frameEncoder[i].destroy();
282 }
283
284 delete [] m_frameEncoder;
285 }
286
287 for (int i = 0; i < m_numThreadLocalData; i++)
288 m_threadLocalData[i].destroy();
289
290 delete [] m_threadLocalData;
291
292 if (m_lookahead)
293 {
294 m_lookahead->destroy();
295 delete m_lookahead;
296 }
297
298 delete m_dpb;
299 if (m_rateControl)
300 {
301 m_rateControl->destroy();
302 delete m_rateControl;
303 }
304 // thread pool release should always happen last
305 if (m_threadPool)
306 m_threadPool->release();
307
308 X265_FREE(m_cuOffsetY);
309 X265_FREE(m_cuOffsetC);
310 X265_FREE(m_buOffsetY);
311 X265_FREE(m_buOffsetC);
312
313 if (m_analysisFile)
314 fclose(m_analysisFile);
315 free(m_param->analysisFileName);
316 free(m_param->csvfn);
317 if (m_csvfpt)
318 fclose(m_csvfpt);
319 free(m_param->rc.statFileName); // alloc'd by strdup
320
321 X265_FREE(m_param);
322 }
323
324 void Encoder::updateVbvPlan(RateControl* rc)
325 {
326 for (int i = 0; i < m_param->frameNumThreads; i++)
327 {
328 FrameEncoder *encoder = &m_frameEncoder[i];
329 if (encoder->m_rce.isActive && encoder->m_rce.poc != rc->m_curSlice->m_poc)
330 {
331 int64_t bits = (int64_t) X265_MAX(encoder->m_rce.frameSizeEstimated, encoder->m_rce.frameSizePlanned);
332 rc->m_bufferFill -= bits;
333 rc->m_bufferFill = X265_MAX(rc->m_bufferFill, 0);
334 rc->m_bufferFill += encoder->m_rce.bufferRate;
335 rc->m_bufferFill = X265_MIN(rc->m_bufferFill, rc->m_bufferSize);
336 if (rc->m_2pass)
337 rc->m_predictedBits += bits;
338 }
339 }
340 }
341
342 /**
343 * Feed one new input frame into the encoder, get one frame out. If pic_in is
344 * NULL, a flush condition is implied and pic_in must be NULL for all subsequent
345 * calls for this encoder instance.
346 *
347 * pic_in input original YUV picture or NULL
348 * pic_out pointer to reconstructed picture struct
349 *
350 * returns 0 if no frames are currently available for output
351 * 1 if frame was output, m_nalList contains access unit
352 * negative on malloc error or abort */
353 int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)
354 {
355 if (m_aborted)
356 return -1;
357
358 if (m_exportedPic)
359 {
360 ATOMIC_DEC(&m_exportedPic->m_countRefEncoders);
361 m_exportedPic = NULL;
362 m_dpb->recycleUnreferenced();
363 }
364
365 if (pic_in)
366 {
367 if (pic_in->colorSpace != m_param->internalCsp)
368 {
369 x265_log(m_param, X265_LOG_ERROR, "Unsupported color space (%d) on input\n",
370 pic_in->colorSpace);
371 return -1;
372 }
373 if (pic_in->bitDepth < 8 || pic_in->bitDepth > 16)
374 {
375 x265_log(m_param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n",
376 pic_in->bitDepth);
377 return -1;
378 }
379
380 Frame *inFrame;
381 if (m_dpb->m_freeList.empty())
382 {
383 inFrame = new Frame;
384 if (inFrame->create(m_param))
385 {
386 /* the first PicYuv created is asked to generate the CU and block unit offset
387 * arrays which are then shared with all subsequent PicYuv (orig and recon)
388 * allocated by this top level encoder */
389 if (m_cuOffsetY)
390 {
391 inFrame->m_fencPic->m_cuOffsetC = m_cuOffsetC;
392 inFrame->m_fencPic->m_cuOffsetY = m_cuOffsetY;
393 inFrame->m_fencPic->m_buOffsetC = m_buOffsetC;
394 inFrame->m_fencPic->m_buOffsetY = m_buOffsetY;
395 }
396 else
397 {
398 if (!inFrame->m_fencPic->createOffsets(m_sps))
399 {
400 m_aborted = true;
401 x265_log(m_param, X265_LOG_ERROR, "memory allocation failure, aborting encode\n");
402 inFrame->destroy();
403 delete inFrame;
404 return -1;
405 }
406 else
407 {
408 m_cuOffsetC = inFrame->m_fencPic->m_cuOffsetC;
409 m_cuOffsetY = inFrame->m_fencPic->m_cuOffsetY;
410 m_buOffsetC = inFrame->m_fencPic->m_buOffsetC;
411 m_buOffsetY = inFrame->m_fencPic->m_buOffsetY;
412 }
413 }
414 }
415 else
416 {
417 m_aborted = true;
418 x265_log(m_param, X265_LOG_ERROR, "memory allocation failure, aborting encode\n");
419 inFrame->destroy();
420 delete inFrame;
421 return -1;
422 }
423 }
424 else
425 inFrame = m_dpb->m_freeList.popBack();
426
427 /* Copy input picture into a Frame and PicYuv, send to lookahead */
428 inFrame->m_poc = ++m_pocLast;
429 inFrame->m_fencPic->copyFromPicture(*pic_in, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset);
430
431 inFrame->m_userData = pic_in->userData;
432 inFrame->m_pts = pic_in->pts;
433 inFrame->m_forceqp = pic_in->forceqp;
434
435 if (m_pocLast == 0)
436 m_firstPts = inFrame->m_pts;
437 if (m_bframeDelay && m_pocLast == m_bframeDelay)
438 m_bframeDelayTime = inFrame->m_pts - m_firstPts;
439
440 /* Encoder holds a reference count until stats collection is finished */
441 ATOMIC_INC(&inFrame->m_countRefEncoders);
442 bool bEnableWP = m_param->bEnableWeightedPred || m_param->bEnableWeightedBiPred;
443 if (m_param->rc.aqMode || bEnableWP)
444 {
445 if (m_param->rc.cuTree && m_param->rc.bStatRead)
446 {
447 if (!m_rateControl->cuTreeReadFor2Pass(inFrame))
448 {
449 m_aborted = 1;
450 return -1;
451 }
452 }
453 else
454 m_rateControl->calcAdaptiveQuantFrame(inFrame);
455 }
456
457 /* Use the frame types from the first pass, if available */
458 int sliceType = (m_param->rc.bStatRead) ? m_rateControl->rateControlSliceType(inFrame->m_poc) : pic_in->sliceType;
459
460 /* In analysisSave mode, x265_analysis_data is allocated in pic_in and inFrame points to this */
461 /* Load analysis data before lookahead->addPicture, since sliceType has been decided */
462 if (m_param->analysisMode == X265_ANALYSIS_LOAD)
463 {
464 x265_picture* inputPic = const_cast<x265_picture*>(pic_in);
465 /* readAnalysisFile reads analysis data for the frame and allocates memory based on slicetype */
466 readAnalysisFile(&inputPic->analysisData, inFrame->m_poc);
467 inFrame->m_analysisData.poc = inFrame->m_poc;
468 inFrame->m_analysisData.sliceType = inputPic->analysisData.sliceType;
469 inFrame->m_analysisData.numCUsInFrame = inputPic->analysisData.numCUsInFrame;
470 inFrame->m_analysisData.numPartitions = inputPic->analysisData.numPartitions;
471 inFrame->m_analysisData.interData = inputPic->analysisData.interData;
472 inFrame->m_analysisData.intraData = inputPic->analysisData.intraData;
473 sliceType = inputPic->analysisData.sliceType;
474 }
475
476 m_lookahead->addPicture(inFrame, sliceType);
477 m_numDelayedPic++;
478 }
479 else
480 m_lookahead->flush();
481
482 FrameEncoder *curEncoder = &m_frameEncoder[m_curEncoder];
483 m_curEncoder = (m_curEncoder + 1) % m_param->frameNumThreads;
484 int ret = 0;
485
486 // getEncodedPicture() should block until the FrameEncoder has completed
487 // encoding the frame. This is how back-pressure through the API is
488 // accomplished when the encoder is full.
489 Frame *outFrame = curEncoder->getEncodedPicture(m_nalList);
490
491 if (outFrame)
492 {
493 Slice *slice = outFrame->m_encData->m_slice;
494
495 /* Free up pic_in->analysisData since it has already been used */
496 if (m_param->analysisMode == X265_ANALYSIS_LOAD)
497 freeAnalysis(&outFrame->m_analysisData);
498
499 if (pic_out)
500 {
501 PicYuv *recpic = outFrame->m_reconPic;
502 pic_out->poc = slice->m_poc;
503 pic_out->bitDepth = X265_DEPTH;
504 pic_out->userData = outFrame->m_userData;
505 pic_out->colorSpace = m_param->internalCsp;
506
507 pic_out->pts = outFrame->m_pts;
508 pic_out->dts = outFrame->m_dts;
509
510 switch (slice->m_sliceType)
511 {
512 case I_SLICE:
513 pic_out->sliceType = outFrame->m_lowres.bKeyframe ? X265_TYPE_IDR : X265_TYPE_I;
514 break;
515 case P_SLICE:
516 pic_out->sliceType = X265_TYPE_P;
517 break;
518 case B_SLICE:
519 pic_out->sliceType = X265_TYPE_B;
520 break;
521 }
522
523 pic_out->planes[0] = recpic->m_picOrg[0];
524 pic_out->stride[0] = (int)(recpic->m_stride * sizeof(pixel));
525 pic_out->planes[1] = recpic->m_picOrg[1];
526 pic_out->stride[1] = (int)(recpic->m_strideC * sizeof(pixel));
527 pic_out->planes[2] = recpic->m_picOrg[2];
528 pic_out->stride[2] = (int)(recpic->m_strideC * sizeof(pixel));
529
530 /* Dump analysis data from pic_out to file in save mode and free */
531 if (m_param->analysisMode == X265_ANALYSIS_SAVE)
532 {
533 pic_out->analysisData.poc = pic_out->poc;
534 pic_out->analysisData.sliceType = pic_out->sliceType;
535 pic_out->analysisData.numCUsInFrame = outFrame->m_analysisData.numCUsInFrame;
536 pic_out->analysisData.numPartitions = outFrame->m_analysisData.numPartitions;
537 pic_out->analysisData.interData = outFrame->m_analysisData.interData;
538 pic_out->analysisData.intraData = outFrame->m_analysisData.intraData;
539 writeAnalysisFile(&pic_out->analysisData);
540 freeAnalysis(&pic_out->analysisData);
541 }
542 }
543 if (slice->m_sliceType == P_SLICE)
544 {
545 if (slice->m_weightPredTable[0][0][0].bPresentFlag)
546 m_numLumaWPFrames++;
547 if (slice->m_weightPredTable[0][0][1].bPresentFlag ||
548 slice->m_weightPredTable[0][0][2].bPresentFlag)
549 m_numChromaWPFrames++;
550 }
551 else if (slice->m_sliceType == B_SLICE)
552 {
553 bool bLuma = false, bChroma = false;
554 for (int l = 0; l < 2; l++)
555 {
556 if (slice->m_weightPredTable[l][0][0].bPresentFlag)
557 bLuma = true;
558 if (slice->m_weightPredTable[l][0][1].bPresentFlag ||
559 slice->m_weightPredTable[l][0][2].bPresentFlag)
560 bChroma = true;
561 }
562
563 if (bLuma)
564 m_numLumaWPBiFrames++;
565 if (bChroma)
566 m_numChromaWPBiFrames++;
567 }
568 if (m_aborted)
569 return -1;
570 finishFrameStats(outFrame, curEncoder, curEncoder->m_accessUnitBits);
571
572 // Allow this frame to be recycled if no frame encoders are using it for reference
573 if (!pic_out)
574 {
575 ATOMIC_DEC(&outFrame->m_countRefEncoders);
576 m_dpb->recycleUnreferenced();
577 }
578 else
579 m_exportedPic = outFrame;
580
581 m_numDelayedPic--;
582
583 ret = 1;
584 }
585
586 // pop a single frame from decided list, then provide to frame encoder
587 // curEncoder is guaranteed to be idle at this point
588 Frame* frameEnc = m_lookahead->getDecidedPicture();
589 if (frameEnc)
590 {
591 // give this picture a FrameData instance before encoding
592 if (m_dpb->m_picSymFreeList)
593 {
594 frameEnc->m_encData = m_dpb->m_picSymFreeList;
595 m_dpb->m_picSymFreeList = m_dpb->m_picSymFreeList->m_freeListNext;
596 frameEnc->reinit(m_sps);
597 }
598 else
599 {
600 frameEnc->allocEncodeData(m_param, m_sps);
601 Slice* slice = frameEnc->m_encData->m_slice;
602 slice->m_sps = &m_sps;
603 slice->m_pps = &m_pps;
604 slice->m_maxNumMergeCand = m_param->maxNumMergeCand;
605 slice->m_endCUAddr = slice->realEndAddress(m_sps.numCUsInFrame * NUM_CU_PARTITIONS);
606 frameEnc->m_reconPic->m_cuOffsetC = m_cuOffsetC;
607 frameEnc->m_reconPic->m_cuOffsetY = m_cuOffsetY;
608 frameEnc->m_reconPic->m_buOffsetC = m_buOffsetC;
609 frameEnc->m_reconPic->m_buOffsetY = m_buOffsetY;
610 }
611 curEncoder->m_rce.encodeOrder = m_encodedFrameNum++;
612 if (m_bframeDelay)
613 {
614 int64_t *prevReorderedPts = m_prevReorderedPts;
615 frameEnc->m_dts = m_encodedFrameNum > m_bframeDelay
616 ? prevReorderedPts[(m_encodedFrameNum - m_bframeDelay) % m_bframeDelay]
617 : frameEnc->m_reorderedPts - m_bframeDelayTime;
618 prevReorderedPts[m_encodedFrameNum % m_bframeDelay] = frameEnc->m_reorderedPts;
619 }
620 else
621 frameEnc->m_dts = frameEnc->m_reorderedPts;
622 /* Allocate analysis data before encode in save mode. This is allocated in frameEnc*/
623 if (m_param->analysisMode == X265_ANALYSIS_SAVE)
624 {
625 x265_analysis_data* analysis = &frameEnc->m_analysisData;
626 analysis->poc = frameEnc->m_poc;
627 analysis->sliceType = frameEnc->m_lowres.sliceType;
628 uint32_t widthInCU = (m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize;
629 uint32_t heightInCU = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;
630
631 uint32_t numCUsInFrame = widthInCU * heightInCU;
632 analysis->numCUsInFrame = numCUsInFrame;
633 analysis->numPartitions = NUM_CU_PARTITIONS;
634 allocAnalysis(analysis);
635 }
636
637 // determine references, setup RPS, etc
638 m_dpb->prepareEncode(frameEnc);
639
640 if (m_param->rc.rateControlMode != X265_RC_CQP)
641 m_lookahead->getEstimatedPictureCost(frameEnc);
642
643 // Allow FrameEncoder::compressFrame() to start in the frame encoder thread
644 if (!curEncoder->startCompressFrame(frameEnc))
645 m_aborted = true;
646 }
647 else if (m_encodedFrameNum)
648 m_rateControl->setFinalFrameCount(m_encodedFrameNum);
649
650 return ret;
651 }
652
653 void EncStats::addPsnr(double psnrY, double psnrU, double psnrV)
654 {
655 m_psnrSumY += psnrY;
656 m_psnrSumU += psnrU;
657 m_psnrSumV += psnrV;
658 }
659
660 void EncStats::addBits(uint64_t bits)
661 {
662 m_accBits += bits;
663 m_numPics++;
664 }
665
666 void EncStats::addSsim(double ssim)
667 {
668 m_globalSsim += ssim;
669 }
670
671 void EncStats::addQP(double aveQp)
672 {
673 m_totalQp += aveQp;
674 }
675
676 char* Encoder::statsCSVString(EncStats& stat, char* buffer)
677 {
678 if (!stat.m_numPics)
679 {
680 sprintf(buffer, "-, -, -, -, -, -, -, ");
681 return buffer;
682 }
683
684 double fps = (double)m_param->fpsNum / m_param->fpsDenom;
685 double scale = fps / 1000 / (double)stat.m_numPics;
686
687 int len = sprintf(buffer, "%-6u, ", stat.m_numPics);
688
689 len += sprintf(buffer + len, "%2.2lf, ", stat.m_totalQp / (double)stat.m_numPics);
690 len += sprintf(buffer + len, "%-8.2lf, ", stat.m_accBits * scale);
691 if (m_param->bEnablePsnr)
692 {
693 len += sprintf(buffer + len, "%.3lf, %.3lf, %.3lf, ",
694 stat.m_psnrSumY / (double)stat.m_numPics,
695 stat.m_psnrSumU / (double)stat.m_numPics,
696 stat.m_psnrSumV / (double)stat.m_numPics);
697 }
698 else
699 len += sprintf(buffer + len, "-, -, -, ");
700
701 if (m_param->bEnableSsim)
702 sprintf(buffer + len, "%.3lf, ", x265_ssim2dB(stat.m_globalSsim / (double)stat.m_numPics));
703 else
704 sprintf(buffer + len, "-, ");
705 return buffer;
706 }
707
708 char* Encoder::statsString(EncStats& stat, char* buffer)
709 {
710 double fps = (double)m_param->fpsNum / m_param->fpsDenom;
711 double scale = fps / 1000 / (double)stat.m_numPics;
712
713 int len = sprintf(buffer, "%6u, ", stat.m_numPics);
714
715 len += sprintf(buffer + len, "Avg QP:%2.2lf", stat.m_totalQp / (double)stat.m_numPics);
716 len += sprintf(buffer + len, " kb/s: %-8.2lf", stat.m_accBits * scale);
717 if (m_param->bEnablePsnr)
718 {
719 len += sprintf(buffer + len, " PSNR Mean: Y:%.3lf U:%.3lf V:%.3lf",
720 stat.m_psnrSumY / (double)stat.m_numPics,
721 stat.m_psnrSumU / (double)stat.m_numPics,
722 stat.m_psnrSumV / (double)stat.m_numPics);
723 }
724 if (m_param->bEnableSsim)
725 {
726 sprintf(buffer + len, " SSIM Mean: %.6lf (%.3lfdB)",
727 stat.m_globalSsim / (double)stat.m_numPics,
728 x265_ssim2dB(stat.m_globalSsim / (double)stat.m_numPics));
729 }
730 return buffer;
731 }
732
733 void Encoder::printSummary()
734 {
735 if (m_param->logLevel < X265_LOG_INFO)
736 return;
737
738 char buffer[200];
739 if (m_analyzeI.m_numPics)
740 x265_log(m_param, X265_LOG_INFO, "frame I: %s\n", statsString(m_analyzeI, buffer));
741 if (m_analyzeP.m_numPics)
742 x265_log(m_param, X265_LOG_INFO, "frame P: %s\n", statsString(m_analyzeP, buffer));
743 if (m_analyzeB.m_numPics)
744 x265_log(m_param, X265_LOG_INFO, "frame B: %s\n", statsString(m_analyzeB, buffer));
745 if (m_analyzeAll.m_numPics)
746 x265_log(m_param, X265_LOG_INFO, "global : %s\n", statsString(m_analyzeAll, buffer));
747 if (m_param->bEnableWeightedPred && m_analyzeP.m_numPics)
748 {
749 x265_log(m_param, X265_LOG_INFO, "Weighted P-Frames: Y:%.1f%% UV:%.1f%%\n",
750 (float)100.0 * m_numLumaWPFrames / m_analyzeP.m_numPics,
751 (float)100.0 * m_numChromaWPFrames / m_analyzeP.m_numPics);
752 }
753 if (m_param->bEnableWeightedBiPred && m_analyzeB.m_numPics)
754 {
755 x265_log(m_param, X265_LOG_INFO, "Weighted B-Frames: Y:%.1f%% UV:%.1f%%\n",
756 (float)100.0 * m_numLumaWPBiFrames / m_analyzeB.m_numPics,
757 (float)100.0 * m_numChromaWPBiFrames / m_analyzeB.m_numPics);
758 }
759 int pWithB = 0;
760 for (int i = 0; i <= m_param->bframes; i++)
761 pWithB += m_lookahead->m_histogram[i];
762
763 if (pWithB)
764 {
765 int p = 0;
766 for (int i = 0; i <= m_param->bframes; i++)
767 p += sprintf(buffer + p, "%.1f%% ", 100. * m_lookahead->m_histogram[i] / pWithB);
768
769 x265_log(m_param, X265_LOG_INFO, "consecutive B-frames: %s\n", buffer);
770 }
771 if (m_param->bLossless)
772 {
773 float frameSize = (float)(m_param->sourceWidth - m_sps.conformanceWindow.rightOffset) *
774 (m_param->sourceHeight - m_sps.conformanceWindow.bottomOffset);
775 float uncompressed = frameSize * X265_DEPTH * m_analyzeAll.m_numPics;
776
777 x265_log(m_param, X265_LOG_INFO, "lossless compression ratio %.2f::1\n", uncompressed / m_analyzeAll.m_accBits);
778 }
779
780 if (!m_param->bLogCuStats)
781 return;
782
783 for (int sliceType = 2; sliceType >= 0; sliceType--)
784 {
785 if (sliceType == P_SLICE && !m_analyzeP.m_numPics)
786 continue;
787 if (sliceType == B_SLICE && !m_analyzeB.m_numPics)
788 continue;
789
790 StatisticLog finalLog;
791 for (uint32_t depth = 0; depth <= g_maxCUDepth; depth++)
792 {
793 for (int i = 0; i < m_param->frameNumThreads; i++)
794 {
795 StatisticLog& enclog = m_frameEncoder[i].m_sliceTypeLog[sliceType];
796 if (!depth)
797 finalLog.totalCu += enclog.totalCu;
798 finalLog.cntIntra[depth] += enclog.cntIntra[depth];
799 for (int m = 0; m < INTER_MODES; m++)
800 {
801 if (m < INTRA_MODES)
802 finalLog.cuIntraDistribution[depth][m] += enclog.cuIntraDistribution[depth][m];
803 finalLog.cuInterDistribution[depth][m] += enclog.cuInterDistribution[depth][m];
804 }
805
806 if (depth == g_maxCUDepth)
807 finalLog.cntIntraNxN += enclog.cntIntraNxN;
808 if (sliceType != I_SLICE)
809 {
810 finalLog.cntTotalCu[depth] += enclog.cntTotalCu[depth];
811 finalLog.cntInter[depth] += enclog.cntInter[depth];
812 finalLog.cntSkipCu[depth] += enclog.cntSkipCu[depth];
813 }
814 }
815
816 uint64_t cntInter, cntSkipCu, cntIntra = 0, cntIntraNxN = 0, encCu = 0;
817 uint64_t cuInterDistribution[INTER_MODES], cuIntraDistribution[INTRA_MODES];
818
819 // check for 0/0, if true assign 0 else calculate percentage
820 for (int n = 0; n < INTER_MODES; n++)
821 {
822 if (!finalLog.cntInter[depth])
823 cuInterDistribution[n] = 0;
824 else
825 cuInterDistribution[n] = (finalLog.cuInterDistribution[depth][n] * 100) / finalLog.cntInter[depth];
826
827 if (n < INTRA_MODES)
828 {
829 if (!finalLog.cntIntra[depth])
830 {
831 cntIntraNxN = 0;
832 cuIntraDistribution[n] = 0;
833 }
834 else
835 {
836 cntIntraNxN = (finalLog.cntIntraNxN * 100) / finalLog.cntIntra[depth];
837 cuIntraDistribution[n] = (finalLog.cuIntraDistribution[depth][n] * 100) / finalLog.cntIntra[depth];
838 }
839 }
840 }
841
842 if (!finalLog.totalCu)
843 encCu = 0;
844 else if (sliceType == I_SLICE)
845 {
846 cntIntra = (finalLog.cntIntra[depth] * 100) / finalLog.totalCu;
847 cntIntraNxN = (finalLog.cntIntraNxN * 100) / finalLog.totalCu;
848 }
849 else
850 encCu = ((finalLog.cntIntra[depth] + finalLog.cntInter[depth]) * 100) / finalLog.totalCu;
851
852 if (sliceType == I_SLICE)
853 {
854 cntInter = 0;
855 cntSkipCu = 0;
856 }
857 else if (!finalLog.cntTotalCu[depth])
858 {
859 cntInter = 0;
860 cntIntra = 0;
861 cntSkipCu = 0;
862 }
863 else
864 {
865 cntInter = (finalLog.cntInter[depth] * 100) / finalLog.cntTotalCu[depth];
866 cntIntra = (finalLog.cntIntra[depth] * 100) / finalLog.cntTotalCu[depth];
867 cntSkipCu = (finalLog.cntSkipCu[depth] * 100) / finalLog.cntTotalCu[depth];
868 }
869
870 // print statistics
871 int cuSize = g_maxCUSize >> depth;
872 char stats[256] = { 0 };
873 int len = 0;
874 if (sliceType != I_SLICE)
875 len += sprintf(stats + len, " EncCU "X265_LL "%% Merge "X265_LL "%%", encCu, cntSkipCu);
876
877 if (cntInter)
878 {
879 len += sprintf(stats + len, " Inter "X265_LL "%%", cntInter);
880 if (m_param->bEnableAMP)
881 len += sprintf(stats + len, "(%dx%d "X265_LL "%% %dx%d "X265_LL "%% %dx%d "X265_LL "%% AMP "X265_LL "%%)",
882 cuSize, cuSize, cuInterDistribution[0],
883 cuSize / 2, cuSize, cuInterDistribution[2],
884 cuSize, cuSize / 2, cuInterDistribution[1],
885 cuInterDistribution[3]);
886 else if (m_param->bEnableRectInter)
887 len += sprintf(stats + len, "(%dx%d "X265_LL "%% %dx%d "X265_LL "%% %dx%d "X265_LL "%%)",
888 cuSize, cuSize, cuInterDistribution[0],
889 cuSize / 2, cuSize, cuInterDistribution[2],
890 cuSize, cuSize / 2, cuInterDistribution[1]);
891 }
892 if (cntIntra)
893 {
894 len += sprintf(stats + len, " Intra "X265_LL "%%(DC "X265_LL "%% P "X265_LL "%% Ang "X265_LL "%%",
895 cntIntra, cuIntraDistribution[0],
896 cuIntraDistribution[1], cuIntraDistribution[2]);
897 if (sliceType != I_SLICE)
898 {
899 if (depth == g_maxCUDepth)
900 len += sprintf(stats + len, " %dx%d "X265_LL "%%", cuSize / 2, cuSize / 2, cntIntraNxN);
901 }
902
903 len += sprintf(stats + len, ")");
904 if (sliceType == I_SLICE)
905 {
906 if (depth == g_maxCUDepth)
907 len += sprintf(stats + len, " %dx%d: "X265_LL "%%", cuSize / 2, cuSize / 2, cntIntraNxN);
908 }
909 }
910 const char slicechars[] = "BPI";
911 if (stats[0])
912 x265_log(m_param, X265_LOG_INFO, "%c%-2d:%s\n", slicechars[sliceType], cuSize, stats);
913 }
914 }
915 }
916
917 void Encoder::fetchStats(x265_stats *stats, size_t statsSizeBytes)
918 {
919 if (statsSizeBytes >= sizeof(stats))
920 {
921 stats->globalPsnrY = m_analyzeAll.m_psnrSumY;
922 stats->globalPsnrU = m_analyzeAll.m_psnrSumU;
923 stats->globalPsnrV = m_analyzeAll.m_psnrSumV;
924 stats->encodedPictureCount = m_analyzeAll.m_numPics;
925 stats->totalWPFrames = m_numLumaWPFrames;
926 stats->accBits = m_analyzeAll.m_accBits;
927 stats->elapsedEncodeTime = (double)(x265_mdate() - m_encodeStartTime) / 1000000;
928 if (stats->encodedPictureCount > 0)
929 {
930 stats->globalSsim = m_analyzeAll.m_globalSsim / stats->encodedPictureCount;
931 stats->globalPsnr = (stats->globalPsnrY * 6 + stats->globalPsnrU + stats->globalPsnrV) / (8 * stats->encodedPictureCount);
932 stats->elapsedVideoTime = (double)stats->encodedPictureCount * m_param->fpsDenom / m_param->fpsNum;
933 stats->bitrate = (0.001f * stats->accBits) / stats->elapsedVideoTime;
934 }
935 else
936 {
937 stats->globalSsim = 0;
938 stats->globalPsnr = 0;
939 stats->bitrate = 0;
940 stats->elapsedVideoTime = 0;
941 }
942 }
943
944 /* If new statistics are added to x265_stats, we must check here whether the
945 * structure provided by the user is the new structure or an older one (for
946 * future safety) */
947 }
948
949 void Encoder::writeLog(int argc, char **argv)
950 {
951 if (m_csvfpt)
952 {
953 if (m_param->logLevel >= X265_LOG_DEBUG)
954 {
955 // adding summary to a per-frame csv log file needs a summary header
956 fprintf(m_csvfpt, "\nSummary\n");
957 fputs(summaryCSVHeader, m_csvfpt);
958 }
959 // CLI arguments or other
960 for (int i = 1; i < argc; i++)
961 {
962 if (i) fputc(' ', m_csvfpt);
963 fputs(argv[i], m_csvfpt);
964 }
965
966 // current date and time
967 time_t now;
968 struct tm* timeinfo;
969 time(&now);
970 timeinfo = localtime(&now);
971 char buffer[200];
972 strftime(buffer, 128, "%c", timeinfo);
973 fprintf(m_csvfpt, ", %s, ", buffer);
974
975 x265_stats stats;
976 fetchStats(&stats, sizeof(stats));
977
978 // elapsed time, fps, bitrate
979 fprintf(m_csvfpt, "%.2f, %.2f, %.2f,",
980 stats.elapsedEncodeTime, stats.encodedPictureCount / stats.elapsedEncodeTime, stats.bitrate);
981
982 if (m_param->bEnablePsnr)
983 fprintf(m_csvfpt, " %.3lf, %.3lf, %.3lf, %.3lf,",
984 stats.globalPsnrY / stats.encodedPictureCount, stats.globalPsnrU / stats.encodedPictureCount,
985 stats.globalPsnrV / stats.encodedPictureCount, stats.globalPsnr);
986 else
987 fprintf(m_csvfpt, " -, -, -, -,");
988 if (m_param->bEnableSsim)
989 fprintf(m_csvfpt, " %.6f, %6.3f,", stats.globalSsim, x265_ssim2dB(stats.globalSsim));
990 else
991 fprintf(m_csvfpt, " -, -,");
992
993 fputs(statsCSVString(m_analyzeI, buffer), m_csvfpt);
994 fputs(statsCSVString(m_analyzeP, buffer), m_csvfpt);
995 fputs(statsCSVString(m_analyzeB, buffer), m_csvfpt);
996 fprintf(m_csvfpt, " %s\n", x265_version_str);
997 }
998 }
999
1000 /**
1001 * Produce an ascii(hex) representation of picture digest.
1002 *
1003 * Returns: a statically allocated null-terminated string. DO NOT FREE.
1004 */
1005 static const char*digestToString(const unsigned char digest[3][16], int numChar)
1006 {
1007 const char* hex = "0123456789abcdef";
1008 static char string[99];
1009 int cnt = 0;
1010
1011 for (int yuvIdx = 0; yuvIdx < 3; yuvIdx++)
1012 {
1013 for (int i = 0; i < numChar; i++)
1014 {
1015 string[cnt++] = hex[digest[yuvIdx][i] >> 4];
1016 string[cnt++] = hex[digest[yuvIdx][i] & 0xf];
1017 }
1018
1019 string[cnt++] = ',';
1020 }
1021
1022 string[cnt - 1] = '\0';
1023 return string;
1024 }
1025
1026 void Encoder::finishFrameStats(Frame* curFrame, FrameEncoder *curEncoder, uint64_t bits)
1027 {
1028 PicYuv* reconPic = curFrame->m_reconPic;
1029
1030 //===== calculate PSNR =====
1031 int width = reconPic->m_picWidth - m_sps.conformanceWindow.rightOffset;
1032 int height = reconPic->m_picHeight - m_sps.conformanceWindow.bottomOffset;
1033 int size = width * height;
1034
1035 int maxvalY = 255 << (X265_DEPTH - 8);
1036 int maxvalC = 255 << (X265_DEPTH - 8);
1037 double refValueY = (double)maxvalY * maxvalY * size;
1038 double refValueC = (double)maxvalC * maxvalC * size / 4.0;
1039 uint64_t ssdY, ssdU, ssdV;
1040
1041 ssdY = curEncoder->m_SSDY;
1042 ssdU = curEncoder->m_SSDU;
1043 ssdV = curEncoder->m_SSDV;
1044 double psnrY = (ssdY ? 10.0 * log10(refValueY / (double)ssdY) : 99.99);
1045 double psnrU = (ssdU ? 10.0 * log10(refValueC / (double)ssdU) : 99.99);
1046 double psnrV = (ssdV ? 10.0 * log10(refValueC / (double)ssdV) : 99.99);
1047
1048 FrameData& curEncData = *curFrame->m_encData;
1049 Slice* slice = curEncData.m_slice;
1050
1051 //===== add bits, psnr and ssim =====
1052 m_analyzeAll.addBits(bits);
1053 m_analyzeAll.addQP(curEncData.m_avgQpAq);
1054
1055 if (m_param->bEnablePsnr)
1056 m_analyzeAll.addPsnr(psnrY, psnrU, psnrV);
1057
1058 double ssim = 0.0;
1059 if (m_param->bEnableSsim && curEncoder->m_ssimCnt)
1060 {
1061 ssim = curEncoder->m_ssim / curEncoder->m_ssimCnt;
1062 m_analyzeAll.addSsim(ssim);
1063 }
1064 if (slice->isIntra())
1065 {
1066 m_analyzeI.addBits(bits);
1067 m_analyzeI.addQP(curEncData.m_avgQpAq);
1068 if (m_param->bEnablePsnr)
1069 m_analyzeI.addPsnr(psnrY, psnrU, psnrV);
1070 if (m_param->bEnableSsim)
1071 m_analyzeI.addSsim(ssim);
1072 }
1073 else if (slice->isInterP())
1074 {
1075 m_analyzeP.addBits(bits);
1076 m_analyzeP.addQP(curEncData.m_avgQpAq);
1077 if (m_param->bEnablePsnr)
1078 m_analyzeP.addPsnr(psnrY, psnrU, psnrV);
1079 if (m_param->bEnableSsim)
1080 m_analyzeP.addSsim(ssim);
1081 }
1082 else if (slice->isInterB())
1083 {
1084 m_analyzeB.addBits(bits);
1085 m_analyzeB.addQP(curEncData.m_avgQpAq);
1086 if (m_param->bEnablePsnr)
1087 m_analyzeB.addPsnr(psnrY, psnrU, psnrV);
1088 if (m_param->bEnableSsim)
1089 m_analyzeB.addSsim(ssim);
1090 }
1091
1092 // if debug log level is enabled, per frame logging is performed
1093 if (m_param->logLevel >= X265_LOG_DEBUG)
1094 {
1095 char c = (slice->isIntra() ? 'I' : slice->isInterP() ? 'P' : 'B');
1096 int poc = slice->m_poc;
1097 if (!IS_REFERENCED(curFrame))
1098 c += 32; // lower case if unreferenced
1099
1100 char buf[1024];
1101 int p;
1102 p = sprintf(buf, "POC:%d %c QP %2.2lf(%d) %10d bits", poc, c, curEncData.m_avgQpAq, slice->m_sliceQp, (int)bits);
1103 if (m_param->rc.rateControlMode == X265_RC_CRF)
1104 p += sprintf(buf + p, " RF:%.3lf", curEncData.m_rateFactor);
1105 if (m_param->bEnablePsnr)
1106 p += sprintf(buf + p, " [Y:%6.2lf U:%6.2lf V:%6.2lf]", psnrY, psnrU, psnrV);
1107 if (m_param->bEnableSsim)
1108 p += sprintf(buf + p, " [SSIM: %.3lfdB]", x265_ssim2dB(ssim));
1109
1110 if (!slice->isIntra())
1111 {
1112 int numLists = slice->isInterP() ? 1 : 2;
1113 for (int list = 0; list < numLists; list++)
1114 {
1115 p += sprintf(buf + p, " [L%d ", list);
1116 for (int ref = 0; ref < slice->m_numRefIdx[list]; ref++)
1117 {
1118 int k = slice->m_refPOCList[list][ref] - slice->m_lastIDR;
1119 p += sprintf(buf + p, "%d ", k);
1120 }
1121
1122 p += sprintf(buf + p, "]");
1123 }
1124 }
1125
1126 // per frame CSV logging if the file handle is valid
1127 if (m_csvfpt)
1128 {
1129 fprintf(m_csvfpt, "%d, %c-SLICE, %4d, %2.2lf, %10d,", m_outputCount++, c, poc, curEncData.m_avgQpAq, (int)bits);
1130 if (m_param->rc.rateControlMode == X265_RC_CRF)
1131 fprintf(m_csvfpt, "%.3lf,", curEncData.m_rateFactor);
1132 double psnr = (psnrY * 6 + psnrU + psnrV) / 8;
1133 if (m_param->bEnablePsnr)
1134 fprintf(m_csvfpt, "%.3lf, %.3lf, %.3lf, %.3lf,", psnrY, psnrU, psnrV, psnr);
1135 else
1136 fprintf(m_csvfpt, " -, -, -, -,");
1137 if (m_param->bEnableSsim)
1138 fprintf(m_csvfpt, " %.6f, %6.3f,", ssim, x265_ssim2dB(ssim));
1139 else
1140 fprintf(m_csvfpt, " -, -,");
1141 fprintf(m_csvfpt, " %.3lf, %.3lf", curEncoder->m_frameTime, curEncoder->m_elapsedCompressTime);
1142 if (!slice->isIntra())
1143 {
1144 int numLists = slice->isInterP() ? 1 : 2;
1145 for (int list = 0; list < numLists; list++)
1146 {
1147 fprintf(m_csvfpt, ", ");
1148 for (int ref = 0; ref < slice->m_numRefIdx[list]; ref++)
1149 {
1150 int k = slice->m_refPOCList[list][ref] - slice->m_lastIDR;
1151 fprintf(m_csvfpt, " %d", k);
1152 }
1153 }
1154
1155 if (numLists == 1)
1156 fprintf(m_csvfpt, ", -");
1157 }
1158 else
1159 fprintf(m_csvfpt, ", -, -");
1160 fprintf(m_csvfpt, "\n");
1161 }
1162
1163 if (m_param->decodedPictureHashSEI && m_param->logLevel >= X265_LOG_FULL)
1164 {
1165 const char* digestStr = NULL;
1166 if (m_param->decodedPictureHashSEI == 1)
1167 {
1168 digestStr = digestToString(curEncoder->m_seiReconPictureDigest.m_digest, 16);
1169 p += sprintf(buf + p, " [MD5:%s]", digestStr);
1170 }
1171 else if (m_param->decodedPictureHashSEI == 2)
1172 {
1173 digestStr = digestToString(curEncoder->m_seiReconPictureDigest.m_digest, 2);
1174 p += sprintf(buf + p, " [CRC:%s]", digestStr);
1175 }
1176 else if (m_param->decodedPictureHashSEI == 3)
1177 {
1178 digestStr = digestToString(curEncoder->m_seiReconPictureDigest.m_digest, 4);
1179 p += sprintf(buf + p, " [Checksum:%s]", digestStr);
1180 }
1181 }
1182 x265_log(m_param, X265_LOG_DEBUG, "%s\n", buf);
1183 fflush(stderr);
1184 }
1185 }
1186
1187 #if defined(_MSC_VER)
1188 #pragma warning(disable: 4800) // forcing int to bool
1189 #pragma warning(disable: 4127) // conditional expression is constant
1190 #endif
1191
1192 void Encoder::getStreamHeaders(NALList& list, Entropy& sbacCoder, Bitstream& bs)
1193 {
1194 sbacCoder.setBitstream(&bs);
1195
1196 /* headers for start of bitstream */
1197 bs.resetBits();
1198 sbacCoder.codeVPS(m_vps);
1199 bs.writeByteAlignment();
1200 list.serialize(NAL_UNIT_VPS, bs);
1201
1202 bs.resetBits();
1203 sbacCoder.codeSPS(m_sps, m_scalingList, m_vps.ptl);
1204 bs.writeByteAlignment();
1205 list.serialize(NAL_UNIT_SPS, bs);
1206
1207 bs.resetBits();
1208 sbacCoder.codePPS(m_pps);
1209 bs.writeByteAlignment();
1210 list.serialize(NAL_UNIT_PPS, bs);
1211
1212 if (m_param->bEmitInfoSEI)
1213 {
1214 char *opts = x265_param2string(m_param);
1215 if (opts)
1216 {
1217 char *buffer = X265_MALLOC(char, strlen(opts) + strlen(x265_version_str) +
1218 strlen(x265_build_info_str) + 200);
1219 if (buffer)
1220 {
1221 sprintf(buffer, "x265 (build %d) - %s:%s - H.265/HEVC codec - "
1222 "Copyright 2013-2014 (c) Multicoreware Inc - "
1223 "http://x265.org - options: %s",
1224 X265_BUILD, x265_version_str, x265_build_info_str, opts);
1225
1226 bs.resetBits();
1227 SEIuserDataUnregistered idsei;
1228 idsei.m_userData = (uint8_t*)buffer;
1229 idsei.m_userDataLength = (uint32_t)strlen(buffer);
1230 idsei.write(bs, m_sps);
1231 bs.writeByteAlignment();
1232 list.serialize(NAL_UNIT_PREFIX_SEI, bs);
1233
1234 X265_FREE(buffer);
1235 }
1236
1237 X265_FREE(opts);
1238 }
1239 }
1240
1241 if (m_param->bEmitHRDSEI || !!m_param->interlaceMode)
1242 {
1243 /* Picture Timing and Buffering Period SEI require the SPS to be "activated" */
1244 SEIActiveParameterSets sei;
1245 sei.m_selfContainedCvsFlag = true;
1246 sei.m_noParamSetUpdateFlag = true;
1247
1248 bs.resetBits();
1249 sei.write(bs, m_sps);
1250 bs.writeByteAlignment();
1251 list.serialize(NAL_UNIT_PREFIX_SEI, bs);
1252 }
1253 }
1254
1255 void Encoder::initSPS(SPS *sps)
1256 {
1257 m_vps.ptl.progressiveSourceFlag = !m_param->interlaceMode;
1258 m_vps.ptl.interlacedSourceFlag = !!m_param->interlaceMode;
1259 m_vps.ptl.nonPackedConstraintFlag = false;
1260 m_vps.ptl.frameOnlyConstraintFlag = false;
1261
1262 sps->conformanceWindow = m_conformanceWindow;
1263 sps->chromaFormatIdc = m_param->internalCsp;
1264 sps->picWidthInLumaSamples = m_param->sourceWidth;
1265 sps->picHeightInLumaSamples = m_param->sourceHeight;
1266 sps->numCuInWidth = (m_param->sourceWidth + g_maxCUSize - 1) / g_maxCUSize;
1267 sps->numCuInHeight = (m_param->sourceHeight + g_maxCUSize - 1) / g_maxCUSize;
1268 sps->numCUsInFrame = sps->numCuInWidth * sps->numCuInHeight;
1269 sps->numPartitions = NUM_CU_PARTITIONS;
1270 sps->numPartInCUSize = 1 << g_maxFullDepth;
1271
1272 sps->log2MinCodingBlockSize = g_maxLog2CUSize - g_maxCUDepth;
1273 sps->log2DiffMaxMinCodingBlockSize = g_maxCUDepth;
1274
1275 sps->quadtreeTULog2MaxSize = X265_MIN(g_maxLog2CUSize, 5);
1276 sps->quadtreeTULog2MinSize = 2;
1277 sps->quadtreeTUMaxDepthInter = m_param->tuQTMaxInterDepth;
1278 sps->quadtreeTUMaxDepthIntra = m_param->tuQTMaxIntraDepth;
1279
1280 sps->bUseSAO = m_param->bEnableSAO;
1281
1282 sps->bUseAMP = m_param->bEnableAMP;
1283 sps->maxAMPDepth = m_param->bEnableAMP ? g_maxCUDepth : 0;
1284
1285 sps->maxDecPicBuffering = m_vps.maxDecPicBuffering;
1286 sps->numReorderPics = m_vps.numReorderPics;
1287
1288 sps->bUseStrongIntraSmoothing = m_param->bEnableStrongIntraSmoothing;
1289 sps->bTemporalMVPEnabled = m_param->bEnableTemporalMvp;
1290
1291 VUI& vui = sps->vuiParameters;
1292 vui.aspectRatioInfoPresentFlag = !!m_param->vui.aspectRatioIdc;
1293 vui.aspectRatioIdc = m_param->vui.aspectRatioIdc;
1294 vui.sarWidth = m_param->vui.sarWidth;
1295 vui.sarHeight = m_param->vui.sarHeight;
1296
1297 vui.overscanInfoPresentFlag = m_param->vui.bEnableOverscanInfoPresentFlag;
1298 vui.overscanAppropriateFlag = m_param->vui.bEnableOverscanAppropriateFlag;
1299
1300 vui.videoSignalTypePresentFlag = m_param->vui.bEnableVideoSignalTypePresentFlag;
1301 vui.videoFormat = m_param->vui.videoFormat;
1302 vui.videoFullRangeFlag = m_param->vui.bEnableVideoFullRangeFlag;
1303
1304 vui.colourDescriptionPresentFlag = m_param->vui.bEnableColorDescriptionPresentFlag;
1305 vui.colourPrimaries = m_param->vui.colorPrimaries;
1306 vui.transferCharacteristics = m_param->vui.transferCharacteristics;
1307 vui.matrixCoefficients = m_param->vui.matrixCoeffs;
1308
1309 vui.chromaLocInfoPresentFlag = m_param->vui.bEnableChromaLocInfoPresentFlag;
1310 vui.chromaSampleLocTypeTopField = m_param->vui.chromaSampleLocTypeTopField;
1311 vui.chromaSampleLocTypeBottomField = m_param->vui.chromaSampleLocTypeBottomField;
1312
1313 vui.defaultDisplayWindow.bEnabled = m_param->vui.bEnableDefaultDisplayWindowFlag;
1314 vui.defaultDisplayWindow.rightOffset = m_param->vui.defDispWinRightOffset;
1315 vui.defaultDisplayWindow.topOffset = m_param->vui.defDispWinTopOffset;
1316 vui.defaultDisplayWindow.bottomOffset = m_param->vui.defDispWinBottomOffset;
1317 vui.defaultDisplayWindow.leftOffset = m_param->vui.defDispWinLeftOffset;
1318
1319 vui.frameFieldInfoPresentFlag = !!m_param->interlaceMode;
1320 vui.fieldSeqFlag = !!m_param->interlaceMode;
1321
1322 vui.hrdParametersPresentFlag = m_param->bEmitHRDSEI;
1323
1324 vui.timingInfo.numUnitsInTick = m_param->fpsDenom;
1325 vui.timingInfo.timeScale = m_param->fpsNum;
1326 }
1327
1328 void Encoder::initPPS(PPS *pps)
1329 {
1330 bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0;
1331
1332 if (!m_param->bLossless && (m_param->rc.aqMode || bIsVbv))
1333 {
1334 pps->bUseDQP = true;
1335 pps->maxCuDQPDepth = 0; /* TODO: make configurable? */
1336 }
1337 else
1338 {
1339 pps->bUseDQP = false;
1340 pps->maxCuDQPDepth = 0;
1341 }
1342
1343 pps->chromaQpOffset[0] = m_param->cbQpOffset;
1344 pps->chromaQpOffset[1] = m_param->crQpOffset;
1345
1346 pps->bConstrainedIntraPred = m_param->bEnableConstrainedIntra;
1347 pps->bUseWeightPred = m_param->bEnableWeightedPred;
1348 pps->bUseWeightedBiPred = m_param->bEnableWeightedBiPred;
1349 pps->bTransquantBypassEnabled = m_param->bCULossless || m_param->bLossless;
1350 pps->bTransformSkipEnabled = m_param->bEnableTransformSkip;
1351 pps->bSignHideEnabled = m_param->bEnableSignHiding;
1352
1353 pps->bDeblockingFilterControlPresent = !m_param->bEnableLoopFilter || m_param->deblockingFilterBetaOffset || m_param->deblockingFilterTCOffset;
1354 pps->bPicDisableDeblockingFilter = !m_param->bEnableLoopFilter;
1355 pps->deblockingFilterBetaOffsetDiv2 = m_param->deblockingFilterBetaOffset;
1356 pps->deblockingFilterTcOffsetDiv2 = m_param->deblockingFilterTCOffset;
1357
1358 pps->bEntropyCodingSyncEnabled = m_param->bEnableWavefront;
1359 }
1360
1361 void Encoder::configure(x265_param *p)
1362 {
1363 this->m_param = p;
1364
1365 if (p->keyframeMax < 0)
1366 {
1367 /* A negative max GOP size indicates the user wants only one I frame at
1368 * the start of the stream. Set an infinite GOP distance and disable
1369 * adaptive I frame placement */
1370 p->keyframeMax = INT_MAX;
1371 p->scenecutThreshold = 0;
1372 }
1373 else if (p->keyframeMax <= 1)
1374 {
1375 // disable lookahead for all-intra encodes
1376 p->bFrameAdaptive = 0;
1377 p->bframes = 0;
1378 }
1379 if (!p->keyframeMin)
1380 {
1381 double fps = (double)p->fpsNum / p->fpsDenom;
1382 p->keyframeMin = X265_MIN((int)fps, p->keyframeMax / 10);
1383 }
1384 p->keyframeMin = X265_MAX(1, X265_MIN(p->keyframeMin, p->keyframeMax / 2 + 1));
1385
1386 if (p->bBPyramid && !p->bframes)
1387 p->bBPyramid = 0;
1388
1389 /* Disable features which are not supported by the current RD level */
1390 if (p->rdLevel < 5)
1391 {
1392 if (p->bEnableCbfFastMode) /* impossible */
1393 x265_log(p, X265_LOG_WARNING, "--fast-cbf disabled, requires --rdlevel 5 or higher\n");
1394 p->bEnableCbfFastMode = 0;
1395 }
1396 if (p->rdLevel < 4)
1397 {
1398 if (p->psyRdoq > 0) /* impossible */
1399 x265_log(p, X265_LOG_WARNING, "--psy-rdoq disabled, requires --rdlevel 4 or higher\n");
1400 p->psyRdoq = 0;
1401 }
1402 if (p->rdLevel < 3)
1403 {
1404 if (p->bCULossless) /* impossible */
1405 x265_log(p, X265_LOG_WARNING, "--cu-lossless disabled, requires --rdlevel 3 or higher\n");
1406 if (p->bEnableTransformSkip) /* impossible */
1407 x265_log(p, X265_LOG_WARNING, "--tskip disabled, requires --rdlevel 3 or higher\n");
1408 p->bCULossless = p->bEnableTransformSkip = 0;
1409 }
1410 if (p->rdLevel < 2)
1411 {
1412 if (p->bDistributeModeAnalysis) /* not useful */
1413 x265_log(p, X265_LOG_WARNING, "--pmode disabled, requires --rdlevel 2 or higher\n");
1414 p->bDistributeModeAnalysis = 0;
1415
1416 if (p->psyRd > 0) /* impossible */
1417 x265_log(p, X265_LOG_WARNING, "--psy-rd disabled, requires --rdlevel 2 or higher\n");
1418 p->psyRd = 0;
1419
1420 if (p->bEnableRectInter) /* broken, not very useful */
1421 x265_log(p, X265_LOG_WARNING, "--rect disabled, requires --rdlevel 2 or higher\n");
1422 p->bEnableRectInter = 0;
1423 }
1424
1425 if (!p->bEnableRectInter) /* not useful */
1426 p->bEnableAMP = false;
1427
1428 /* In 444, chroma gets twice as much resolution, so halve quality when psy-rd is enabled */
1429 if (p->internalCsp == X265_CSP_I444 && p->psyRd)
1430 {
1431 p->cbQpOffset += 6;
1432 p->crQpOffset += 6;
1433 }
1434
1435 if (p->bLossless)
1436 {
1437 p->rc.rateControlMode = X265_RC_CQP;
1438 p->rc.qp = 4; // An oddity, QP=4 is more lossless than QP=0 and gives better lambdas
1439 p->bEnableSsim = 0;
1440 p->bEnablePsnr = 0;
1441 }
1442
1443 if (p->rc.rateControlMode == X265_RC_CQP)
1444 {
1445 p->rc.aqMode = X265_AQ_NONE;
1446 p->rc.bitrate = 0;
1447 p->rc.cuTree = 0;
1448 p->rc.aqStrength = 0;
1449 }
1450
1451 if (p->rc.aqMode == 0 && p->rc.cuTree)
1452 {
1453 p->rc.aqMode = X265_AQ_VARIANCE;
1454 p->rc.aqStrength = 0.0;
1455 }
1456
1457 if (p->lookaheadDepth == 0 && p->rc.cuTree && !p->rc.bStatRead)
1458 {
1459 x265_log(p, X265_LOG_WARNING, "cuTree disabled, requires lookahead to be enabled\n");
1460 p->rc.cuTree = 0;
1461 }
1462
1463 if (p->rc.aqStrength == 0 && p->rc.cuTree == 0)
1464 p->rc.aqMode = X265_AQ_NONE;
1465
1466 if (p->rc.aqMode == X265_AQ_NONE && p->rc.cuTree == 0)
1467 p->rc.aqStrength = 0;
1468
1469 if (p->internalCsp != X265_CSP_I420)
1470 {
1471 x265_log(p, X265_LOG_WARNING, "!! HEVC Range Extension specifications are not finalized !!\n");
1472 x265_log(p, X265_LOG_WARNING, "!! This output bitstream may not be compliant with the final spec !!\n");
1473 }
1474
1475 if (p->scalingLists && p->internalCsp == X265_CSP_I444)
1476 {
1477 x265_log(p, X265_LOG_WARNING, "Scaling lists are not yet supported for 4:4:4 color space\n");
1478 p->scalingLists = 0;
1479 }
1480
1481 if (p->interlaceMode)
1482 x265_log(p, X265_LOG_WARNING, "Support for interlaced video is experimental\n");
1483
1484 if (p->rc.rfConstantMin > p->rc.rfConstant)
1485 {
1486 x265_log(m_param, X265_LOG_WARNING, "CRF min must be less than CRF\n");
1487 p->rc.rfConstantMin = 0;
1488 }
1489
1490 m_bframeDelay = p->bframes ? (p->bBPyramid ? 2 : 1) : 0;
1491
1492 p->bFrameBias = X265_MIN(X265_MAX(-90, p->bFrameBias), 100);
1493
1494 if (p->logLevel < X265_LOG_INFO)
1495 {
1496 /* don't measure these metrics if they will not be reported */
1497 p->bEnablePsnr = 0;
1498 p->bEnableSsim = 0;
1499 }
1500 /* Warn users trying to measure PSNR/SSIM with psy opts on. */
1501 if (p->bEnablePsnr || p->bEnableSsim)
1502 {
1503 const char *s = NULL;
1504
1505 if (p->psyRd || p->psyRdoq)
1506 {
1507 s = p->bEnablePsnr ? "psnr" : "ssim";
1508 x265_log(p, X265_LOG_WARNING, "--%s used with psy on: results will be invalid!\n", s);
1509 }
1510 else if (!p->rc.aqMode && p->bEnableSsim)
1511 {
1512 x265_log(p, X265_LOG_WARNING, "--ssim used with AQ off: results will be invalid!\n");
1513 s = "ssim";
1514 }
1515 else if (p->rc.aqStrength > 0 && p->bEnablePsnr)
1516 {
1517 x265_log(p, X265_LOG_WARNING, "--psnr used with AQ on: results will be invalid!\n");
1518 s = "psnr";
1519 }
1520 if (s)
1521 x265_log(p, X265_LOG_WARNING, "--tune %s should be used if attempting to benchmark %s!\n", s, s);
1522 }
1523
1524 /* initialize the conformance window */
1525 m_conformanceWindow.bEnabled = false;
1526 m_conformanceWindow.rightOffset = 0;
1527 m_conformanceWindow.topOffset = 0;
1528 m_conformanceWindow.bottomOffset = 0;
1529 m_conformanceWindow.leftOffset = 0;
1530
1531 /* set pad size if width is not multiple of the minimum CU size */
1532 if (p->sourceWidth & (MIN_CU_SIZE - 1))
1533 {
1534 uint32_t rem = p->sourceWidth & (MIN_CU_SIZE - 1);
1535 uint32_t padsize = MIN_CU_SIZE - rem;
1536 p->sourceWidth += padsize;
1537
1538 m_conformanceWindow.bEnabled = true;
1539 m_conformanceWindow.rightOffset = padsize;
1540 }
1541
1542 /* set pad size if height is not multiple of the minimum CU size */
1543 if (p->sourceHeight & (MIN_CU_SIZE - 1))
1544 {
1545 uint32_t rem = p->sourceHeight & (MIN_CU_SIZE - 1);
1546 uint32_t padsize = MIN_CU_SIZE - rem;
1547 p->sourceHeight += padsize;
1548
1549 m_conformanceWindow.bEnabled = true;
1550 m_conformanceWindow.bottomOffset = padsize;
1551 }
1552 if (p->bDistributeModeAnalysis && p->analysisMode)
1553 {
1554 p->analysisMode = X265_ANALYSIS_OFF;
1555 x265_log(p, X265_LOG_WARNING, "Analysis save and load mode not supported for distributed mode analysis\n");
1556 }
1557 }
1558
1559 void Encoder::allocAnalysis(x265_analysis_data* analysis)
1560 {
1561 if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I)
1562 {
1563 analysis_intra_data *intraData = (analysis_intra_data*)analysis->intraData;
1564 CHECKED_MALLOC_ZERO(intraData, analysis_intra_data, 1);
1565 CHECKED_MALLOC(intraData->depth, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
1566 CHECKED_MALLOC(intraData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
1567 CHECKED_MALLOC(intraData->partSizes, char, analysis->numPartitions * analysis->numCUsInFrame);
1568 analysis->intraData = intraData;
1569 }
1570 else
1571 {
1572 analysis_inter_data *interData = (analysis_inter_data*)analysis->interData;
1573 CHECKED_MALLOC(interData, analysis_inter_data, analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * 2);
1574 analysis->interData = interData;
1575 }
1576 return;
1577
1578 fail:
1579 freeAnalysis(analysis);
1580 m_aborted = true;
1581 }
1582
1583 void Encoder::freeAnalysis(x265_analysis_data* analysis)
1584 {
1585 if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I)
1586 {
1587 X265_FREE(((analysis_intra_data*)analysis->intraData)->depth);
1588 X265_FREE(((analysis_intra_data*)analysis->intraData)->modes);
1589 X265_FREE(((analysis_intra_data*)analysis->intraData)->partSizes);
1590 X265_FREE(analysis->intraData);
1591 }
1592 else
1593 X265_FREE(analysis->interData);
1594 }
1595
1596 void Encoder::readAnalysisFile(x265_analysis_data* analysis, int curPoc)
1597 {
1598
1599 #define X265_FREAD(val, size, readSize, fileOffset)\
1600 if (fread(val, size, readSize, fileOffset) != readSize)\
1601 {\
1602 x265_log(NULL, X265_LOG_ERROR, "Error reading analysis data\n");\
1603 freeAnalysis(analysis);\
1604 m_aborted = true;\
1605 return;\
1606 }\
1607
1608 static uint64_t consumedBytes = 0;
1609 static uint64_t totalConsumedBytes = 0;
1610 fseeko(m_analysisFile, totalConsumedBytes, SEEK_SET);
1611
1612 int poc; uint32_t frameRecordSize;
1613 X265_FREAD(&frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
1614 X265_FREAD(&poc, sizeof(int), 1, m_analysisFile);
1615
1616 uint64_t currentOffset = totalConsumedBytes;
1617
1618 /* Seeking to the right frame Record */
1619 while (poc != curPoc && !feof(m_analysisFile))
1620 {
1621 currentOffset += frameRecordSize;
1622 fseeko(m_analysisFile, currentOffset, SEEK_SET);
1623 X265_FREAD(&frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
1624 X265_FREAD(&poc, sizeof(int), 1, m_analysisFile);
1625 }
1626
1627 if (poc != curPoc || feof(m_analysisFile))
1628 {
1629 x265_log(NULL, X265_LOG_WARNING, "Error reading analysis data: Cannot find POC %d\n", curPoc);
1630 freeAnalysis(analysis);
1631 return;
1632 }
1633
1634 /* Now arrived at the right frame, read the record */
1635 analysis->poc = poc;
1636 analysis->frameRecordSize = frameRecordSize;
1637 X265_FREAD(&analysis->sliceType, sizeof(int), 1, m_analysisFile);
1638 X265_FREAD(&analysis->numCUsInFrame, sizeof(int), 1, m_analysisFile);
1639 X265_FREAD(&analysis->numPartitions, sizeof(int), 1, m_analysisFile);
1640
1641 /* Memory is allocated for inter and intra analysis data based on the slicetype */
1642 allocAnalysis(analysis);
1643
1644 if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I)
1645 {
1646 X265_FREAD(((analysis_intra_data *)analysis->intraData)->depth, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile);
1647 X265_FREAD(((analysis_intra_data *)analysis->intraData)->modes, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile);
1648 X265_FREAD(((analysis_intra_data *)analysis->intraData)->partSizes, sizeof(char), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile);
1649 analysis->sliceType = X265_TYPE_I;
1650 consumedBytes += frameRecordSize;
1651 }
1652 else if (analysis->sliceType == X265_TYPE_P)
1653 {
1654 X265_FREAD(analysis->interData, sizeof(analysis_inter_data), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU, m_analysisFile);
1655 consumedBytes += frameRecordSize;
1656 totalConsumedBytes = consumedBytes;
1657 }
1658 else
1659 {
1660 X265_FREAD(analysis->interData, sizeof(analysis_inter_data), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * 2, m_analysisFile);
1661 consumedBytes += frameRecordSize;
1662 }
1663 #undef X265_FREAD
1664 }
1665
1666 void Encoder::writeAnalysisFile(x265_analysis_data* analysis)
1667 {
1668
1669 #define X265_FWRITE(val, size, writeSize, fileOffset)\
1670 if (fwrite(val, size, writeSize, fileOffset) < writeSize)\
1671 {\
1672 x265_log(NULL, X265_LOG_ERROR, "Error writing analysis data\n");\
1673 freeAnalysis(analysis);\
1674 m_aborted = true;\
1675 return;\
1676 }\
1677
1678 /* calculate frameRecordSize */
1679 analysis->frameRecordSize = sizeof(analysis->frameRecordSize) + sizeof(analysis->poc) + sizeof(analysis->sliceType) +
1680 sizeof(analysis->numCUsInFrame) + sizeof(analysis->numPartitions);
1681 if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I)
1682 analysis->frameRecordSize += sizeof(uint8_t) * analysis->numCUsInFrame * analysis->numPartitions * 3;
1683 else if (analysis->sliceType == X265_TYPE_P)
1684 analysis->frameRecordSize += sizeof(analysis_inter_data) * analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU;
1685 else
1686 analysis->frameRecordSize += sizeof(analysis_inter_data) * analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * 2;
1687
1688 X265_FWRITE(&analysis->frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
1689 X265_FWRITE(&analysis->poc, sizeof(int), 1, m_analysisFile);
1690 X265_FWRITE(&analysis->sliceType, sizeof(int), 1, m_analysisFile);
1691 X265_FWRITE(&analysis->numCUsInFrame, sizeof(int), 1, m_analysisFile);
1692 X265_FWRITE(&analysis->numPartitions, sizeof(int), 1, m_analysisFile);
1693
1694 if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I)
1695 {
1696 X265_FWRITE(((analysis_intra_data*)analysis->intraData)->depth, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile);
1697 X265_FWRITE(((analysis_intra_data*)analysis->intraData)->modes, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile);
1698 X265_FWRITE(((analysis_intra_data*)analysis->intraData)->partSizes, sizeof(char), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile);
1699 }
1700 else if (analysis->sliceType == X265_TYPE_P)
1701 {
1702 X265_FWRITE(analysis->interData, sizeof(analysis_inter_data), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU, m_analysisFile);
1703 }
1704 else
1705 {
1706 X265_FWRITE(analysis->interData, sizeof(analysis_inter_data), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * 2, m_analysisFile);
1707 }
1708 #undef X265_FWRITE
1709 }