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