1 /*****************************************************************************
2 * Copyright (C) 2013 x265 project
4 * Authors: Steve Borho <steve@borho.org>
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.
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.
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.
20 * This program is also available under a commercial proprietary license.
21 * For more information, contact us at license @ x265.com.
22 *****************************************************************************/
25 #include "primitives.h"
26 #include "threadpool.h"
29 #include "framedata.h"
34 #include "slicetype.h"
35 #include "frameencoder.h"
36 #include "ratecontrol.h"
43 const char g_sliceTypeToChar
[] = {'B', 'P', 'I'};
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), "
59 m_encodedFrameNum
= 0;
62 m_numLumaWPFrames
= 0;
63 m_numChromaWPFrames
= 0;
64 m_numLumaWPBiFrames
= 0;
65 m_numChromaWPBiFrames
= 0;
67 m_frameEncoder
= NULL
;
80 m_numThreadLocalData
= 0;
83 void Encoder::create()
85 if (!primitives
.sad
[0])
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");
92 x265_param
* p
= m_param
;
94 int rows
= (p
->sourceHeight
+ p
->maxCUSize
- 1) >> g_log2Size
[p
->maxCUSize
];
96 // Do not allow WPP if only one row, it is pointless and unstable
98 p
->bEnableWavefront
= 0;
100 int poolThreadCount
= p
->poolNumThreads
? p
->poolNumThreads
: getCpuCount();
102 // Trim the thread pool if --wpp, --pme, and --pmode are disabled
103 if (!p
->bEnableWavefront
&& !p
->bDistributeModeAnalysis
&& !p
->bDistributeMotionEstimation
)
106 if (poolThreadCount
> 1)
108 m_threadPool
= ThreadPool::allocThreadPool(poolThreadCount
);
109 poolThreadCount
= m_threadPool
->getThreadCount();
114 if (!poolThreadCount
)
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");
124 // disable all pool features if the thread pool is disabled or unusable.
125 p
->bEnableWavefront
= p
->bDistributeModeAnalysis
= p
->bDistributeMotionEstimation
= 0;
128 if (!p
->frameNumThreads
)
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
143 p
->frameNumThreads
= 1;
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" : "");
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
);
154 if (!m_scalingList
.init())
156 x265_log(m_param
, X265_LOG_ERROR
, "Unable to allocate scaling list arrays\n");
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
))
165 m_scalingList
.setupQuantMatrices();
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
++)
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
);
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
];
184 m_lookahead
= new Lookahead(m_param
, m_threadPool
);
185 m_dpb
= new DPB(m_param
);
186 m_rateControl
= new RateControl(m_param
);
191 /* Try to open CSV file handle */
194 m_csvfpt
= fopen(m_param
->csvfn
, "r");
197 // file already exists, re-open for append
199 m_csvfpt
= fopen(m_param
->csvfn
, "ab");
203 // new CSV file, write header
204 m_csvfpt
= fopen(m_param
->csvfn
, "wb");
207 if (m_param
->logLevel
>= X265_LOG_DEBUG
)
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");
216 fputs(summaryCSVHeader
, m_csvfpt
);
221 m_aborted
|= parseLambdaFile(m_param
);
224 void Encoder::destroy()
228 ATOMIC_DEC(&m_exportedPic
->m_countRefEncoders
);
229 m_exportedPic
= NULL
;
233 m_rateControl
->terminate(); // unblock all blocked RC calls
237 for (int i
= 0; i
< m_param
->frameNumThreads
; i
++)
239 // Ensure frame encoder is idle before destroying it
240 m_frameEncoder
[i
].getEncodedPicture(m_nalList
);
241 m_frameEncoder
[i
].destroy();
244 delete [] m_frameEncoder
;
247 for (int i
= 0; i
< m_numThreadLocalData
; i
++)
248 m_threadLocalData
[i
].destroy();
250 delete [] m_threadLocalData
;
254 m_lookahead
->destroy();
261 m_rateControl
->destroy();
262 delete m_rateControl
;
264 // thread pool release should always happen last
266 m_threadPool
->release();
268 X265_FREE(m_cuOffsetY
);
269 X265_FREE(m_cuOffsetC
);
270 X265_FREE(m_buOffsetY
);
271 X265_FREE(m_buOffsetC
);
275 free(m_param
->rc
.statFileName
); // alloc'd by strdup
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
++)
288 if (!m_frameEncoder
[i
].init(this, numRows
, numCols
, i
))
290 x265_log(m_param
, X265_LOG_ERROR
, "Unable to initialize frame encoder, aborting\n");
295 if (m_param
->bEmitHRDSEI
)
296 m_rateControl
->initHRD(&m_sps
);
297 if (!m_rateControl
->init(&m_sps
))
300 m_encodeStartTime
= x265_mdate();
303 void Encoder::updateVbvPlan(RateControl
* rc
)
305 for (int i
= 0; i
< m_param
->frameNumThreads
; i
++)
307 FrameEncoder
*encoder
= &m_frameEncoder
[i
];
308 if (encoder
->m_rce
.isActive
&& encoder
->m_rce
.poc
!= rc
->m_curSlice
->m_poc
)
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
);
316 rc
->m_predictedBits
+= bits
;
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.
326 * pic_in input original YUV picture or NULL
327 * pic_out pointer to reconstructed picture struct
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 */
332 int Encoder::encode(const x265_picture
* pic_in
, x265_picture
* pic_out
)
339 ATOMIC_DEC(&m_exportedPic
->m_countRefEncoders
);
340 m_exportedPic
= NULL
;
341 m_dpb
->recycleUnreferenced();
346 if (pic_in
->colorSpace
!= m_param
->internalCsp
)
348 x265_log(m_param
, X265_LOG_ERROR
, "Unsupported color space (%d) on input\n",
352 if (pic_in
->bitDepth
< 8 || pic_in
->bitDepth
> 16)
354 x265_log(m_param
, X265_LOG_ERROR
, "Input bit depth (%d) must be between 8 and 16\n",
360 if (m_dpb
->m_freeList
.empty())
363 if (inFrame
->create(m_param
))
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 */
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
;
377 if (!inFrame
->m_origPicYuv
->createOffsets(m_sps
))
380 x265_log(m_param
, X265_LOG_ERROR
, "memory allocation failure, aborting encode\n");
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
;
397 x265_log(m_param
, X265_LOG_ERROR
, "memory allocation failure, aborting encode\n");
404 inFrame
= m_dpb
->m_freeList
.popBack();
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
;
416 m_firstPts
= inFrame
->m_pts
;
417 if (m_bframeDelay
&& m_pocLast
== m_bframeDelay
)
418 m_bframeDelayTime
= inFrame
->m_pts
- m_firstPts
;
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
)
425 if (m_param
->rc
.cuTree
&& m_param
->rc
.bStatRead
)
427 if (!m_rateControl
->cuTreeReadFor2Pass(inFrame
))
434 m_rateControl
->calcAdaptiveQuantFrame(inFrame
);
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
);
443 m_lookahead
->flush();
445 FrameEncoder
*curEncoder
= &m_frameEncoder
[m_curEncoder
];
446 m_curEncoder
= (m_curEncoder
+ 1) % m_param
->frameNumThreads
;
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
);
456 Slice
*slice
= outFrame
->m_encData
->m_slice
;
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
;
465 pic_out
->pts
= outFrame
->m_pts
;
466 pic_out
->dts
= outFrame
->m_dts
;
468 switch (slice
->m_sliceType
)
471 pic_out
->sliceType
= outFrame
->m_lowres
.bKeyframe
? X265_TYPE_IDR
: X265_TYPE_I
;
474 pic_out
->sliceType
= X265_TYPE_P
;
477 pic_out
->sliceType
= X265_TYPE_B
;
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
));
489 if (m_param
->analysisMode
)
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
;
497 if (slice
->m_sliceType
== P_SLICE
)
499 if (slice
->m_weightPredTable
[0][0][0].bPresentFlag
)
501 if (slice
->m_weightPredTable
[0][0][1].bPresentFlag
||
502 slice
->m_weightPredTable
[0][0][2].bPresentFlag
)
503 m_numChromaWPFrames
++;
505 else if (slice
->m_sliceType
== B_SLICE
)
507 bool bLuma
= false, bChroma
= false;
508 for (int l
= 0; l
< 2; l
++)
510 if (slice
->m_weightPredTable
[l
][0][0].bPresentFlag
)
512 if (slice
->m_weightPredTable
[l
][0][1].bPresentFlag
||
513 slice
->m_weightPredTable
[l
][0][2].bPresentFlag
)
518 m_numLumaWPBiFrames
++;
520 m_numChromaWPBiFrames
++;
525 finishFrameStats(outFrame
, curEncoder
, curEncoder
->m_accessUnitBits
);
526 // Allow this frame to be recycled if no frame encoders are using it for reference
529 ATOMIC_DEC(&outFrame
->m_countRefEncoders
);
530 m_dpb
->recycleUnreferenced();
533 m_exportedPic
= outFrame
;
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();
545 // give this picture a FrameData instance before encoding
546 if (m_dpb
->m_picSymFreeList
)
548 frameEnc
->m_encData
= m_dpb
->m_picSymFreeList
;
549 m_dpb
->m_picSymFreeList
= m_dpb
->m_picSymFreeList
->m_freeListNext
;
550 frameEnc
->reinit(m_sps
);
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
;
565 curEncoder
->m_rce
.encodeOrder
= m_encodedFrameNum
++;
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
;
575 frameEnc
->m_dts
= frameEnc
->m_reorderedPts
;
577 // determine references, setup RPS, etc
578 m_dpb
->prepareEncode(frameEnc
);
580 if (m_param
->rc
.rateControlMode
!= X265_RC_CQP
)
581 m_lookahead
->getEstimatedPictureCost(frameEnc
);
583 // Allow FrameEncoder::compressFrame() to start in the frame encoder thread
584 if (!curEncoder
->startCompressFrame(frameEnc
))
587 else if (m_encodedFrameNum
)
588 m_rateControl
->setFinalFrameCount(m_encodedFrameNum
);
593 void EncStats::addPsnr(double psnrY
, double psnrU
, double psnrV
)
600 void EncStats::addBits(uint64_t bits
)
606 void EncStats::addSsim(double ssim
)
608 m_globalSsim
+= ssim
;
611 void EncStats::addQP(double aveQp
)
616 char* Encoder::statsCSVString(EncStats
& stat
, char* buffer
)
620 sprintf(buffer
, "-, -, -, -, -, -, -, ");
624 double fps
= (double)m_param
->fpsNum
/ m_param
->fpsDenom
;
625 double scale
= fps
/ 1000 / (double)stat
.m_numPics
;
627 int len
= sprintf(buffer
, "%-6u, ", stat
.m_numPics
);
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
)
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
);
639 len
+= sprintf(buffer
+ len
, "-, -, -, ");
641 if (m_param
->bEnableSsim
)
642 sprintf(buffer
+ len
, "%.3lf, ", x265_ssim2dB(stat
.m_globalSsim
/ (double)stat
.m_numPics
));
644 sprintf(buffer
+ len
, "-, ");
648 char* Encoder::statsString(EncStats
& stat
, char* buffer
)
650 double fps
= (double)m_param
->fpsNum
/ m_param
->fpsDenom
;
651 double scale
= fps
/ 1000 / (double)stat
.m_numPics
;
653 int len
= sprintf(buffer
, "%6u, ", stat
.m_numPics
);
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
)
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
);
664 if (m_param
->bEnableSsim
)
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
));
673 void Encoder::printSummary()
675 if (m_param
->logLevel
< X265_LOG_INFO
)
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
)
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
);
693 if (m_param
->bEnableWeightedBiPred
&& m_analyzeB
.m_numPics
)
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
);
700 for (int i
= 0; i
<= m_param
->bframes
; i
++)
701 pWithB
+= m_lookahead
->m_histogram
[i
];
706 for (int i
= 0; i
<= m_param
->bframes
; i
++)
707 p
+= sprintf(buffer
+ p
, "%.1f%% ", 100. * m_lookahead
->m_histogram
[i
] / pWithB
);
709 x265_log(m_param
, X265_LOG_INFO
, "consecutive B-frames: %s\n", buffer
);
711 if (m_param
->bLossless
)
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
;
717 x265_log(m_param
, X265_LOG_INFO
, "lossless compression ratio %.2f::1\n", uncompressed
/ m_analyzeAll
.m_accBits
);
720 if (!m_param
->bLogCuStats
)
723 for (int sliceType
= 2; sliceType
>= 0; sliceType
--)
725 if (sliceType
== P_SLICE
&& !m_analyzeP
.m_numPics
)
727 if (sliceType
== B_SLICE
&& !m_analyzeB
.m_numPics
)
730 StatisticLog finalLog
;
731 for (uint32_t depth
= 0; depth
<= g_maxCUDepth
; depth
++)
733 for (int i
= 0; i
< m_param
->frameNumThreads
; i
++)
735 StatisticLog
& enclog
= m_frameEncoder
[i
].m_sliceTypeLog
[sliceType
];
737 finalLog
.totalCu
+= enclog
.totalCu
;
738 finalLog
.cntIntra
[depth
] += enclog
.cntIntra
[depth
];
739 for (int m
= 0; m
< INTER_MODES
; m
++)
742 finalLog
.cuIntraDistribution
[depth
][m
] += enclog
.cuIntraDistribution
[depth
][m
];
743 finalLog
.cuInterDistribution
[depth
][m
] += enclog
.cuInterDistribution
[depth
][m
];
746 if (depth
== g_maxCUDepth
)
747 finalLog
.cntIntraNxN
+= enclog
.cntIntraNxN
;
748 if (sliceType
!= I_SLICE
)
750 finalLog
.cntTotalCu
[depth
] += enclog
.cntTotalCu
[depth
];
751 finalLog
.cntInter
[depth
] += enclog
.cntInter
[depth
];
752 finalLog
.cntSkipCu
[depth
] += enclog
.cntSkipCu
[depth
];
756 uint64_t cntInter
, cntSkipCu
, cntIntra
= 0, cntIntraNxN
= 0, encCu
= 0;
757 uint64_t cuInterDistribution
[INTER_MODES
], cuIntraDistribution
[INTRA_MODES
];
759 // check for 0/0, if true assign 0 else calculate percentage
760 for (int n
= 0; n
< INTER_MODES
; n
++)
762 if (!finalLog
.cntInter
[depth
])
763 cuInterDistribution
[n
] = 0;
765 cuInterDistribution
[n
] = (finalLog
.cuInterDistribution
[depth
][n
] * 100) / finalLog
.cntInter
[depth
];
769 if (!finalLog
.cntIntra
[depth
])
772 cuIntraDistribution
[n
] = 0;
776 cntIntraNxN
= (finalLog
.cntIntraNxN
* 100) / finalLog
.cntIntra
[depth
];
777 cuIntraDistribution
[n
] = (finalLog
.cuIntraDistribution
[depth
][n
] * 100) / finalLog
.cntIntra
[depth
];
782 if (!finalLog
.totalCu
)
784 else if (sliceType
== I_SLICE
)
786 cntIntra
= (finalLog
.cntIntra
[depth
] * 100) / finalLog
.totalCu
;
787 cntIntraNxN
= (finalLog
.cntIntraNxN
* 100) / finalLog
.totalCu
;
790 encCu
= ((finalLog
.cntIntra
[depth
] + finalLog
.cntInter
[depth
]) * 100) / finalLog
.totalCu
;
792 if (sliceType
== I_SLICE
)
797 else if (!finalLog
.cntTotalCu
[depth
])
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
];
811 int cuSize
= g_maxCUSize
>> depth
;
812 char stats
[256] = { 0 };
814 if (sliceType
!= I_SLICE
)
815 len
+= sprintf(stats
+ len
, " EncCU "X265_LL
"%% Merge "X265_LL
"%%", encCu
, cntSkipCu
);
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]);
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
)
839 if (depth
== g_maxCUDepth
)
840 len
+= sprintf(stats
+ len
, " %dx%d "X265_LL
"%%", cuSize
/ 2, cuSize
/ 2, cntIntraNxN
);
843 len
+= sprintf(stats
+ len
, ")");
844 if (sliceType
== I_SLICE
)
846 if (depth
== g_maxCUDepth
)
847 len
+= sprintf(stats
+ len
, " %dx%d: "X265_LL
"%%", cuSize
/ 2, cuSize
/ 2, cntIntraNxN
);
850 const char slicechars
[] = "BPI";
852 x265_log(m_param
, X265_LOG_INFO
, "%c%-2d:%s\n", slicechars
[sliceType
], cuSize
, stats
);
857 void Encoder::fetchStats(x265_stats
*stats
, size_t statsSizeBytes
)
859 if (statsSizeBytes
>= sizeof(stats
))
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)
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
;
877 stats
->globalSsim
= 0;
878 stats
->globalPsnr
= 0;
880 stats
->elapsedVideoTime
= 0;
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
889 void Encoder::writeLog(int argc
, char **argv
)
893 if (m_param
->logLevel
>= X265_LOG_DEBUG
)
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
);
899 // CLI arguments or other
900 for (int i
= 1; i
< argc
; i
++)
902 if (i
) fputc(' ', m_csvfpt
);
903 fputs(argv
[i
], m_csvfpt
);
906 // current date and time
910 timeinfo
= localtime(&now
);
912 strftime(buffer
, 128, "%c", timeinfo
);
913 fprintf(m_csvfpt
, ", %s, ", buffer
);
916 fetchStats(&stats
, sizeof(stats
));
918 // elapsed time, fps, bitrate
919 fprintf(m_csvfpt
, "%.2f, %.2f, %.2f,",
920 stats
.elapsedEncodeTime
, stats
.encodedPictureCount
/ stats
.elapsedEncodeTime
, stats
.bitrate
);
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
);
927 fprintf(m_csvfpt
, " -, -, -, -,");
928 if (m_param
->bEnableSsim
)
929 fprintf(m_csvfpt
, " %.6f, %6.3f,", stats
.globalSsim
, x265_ssim2dB(stats
.globalSsim
));
931 fprintf(m_csvfpt
, " -, -,");
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
);
941 * Produce an ascii(hex) representation of picture digest.
943 * Returns: a statically allocated null-terminated string. DO NOT FREE.
945 static const char*digestToString(const unsigned char digest
[3][16], int numChar
)
947 const char* hex
= "0123456789abcdef";
948 static char string
[99];
951 for (int yuvIdx
= 0; yuvIdx
< 3; yuvIdx
++)
953 for (int i
= 0; i
< numChar
; i
++)
955 string
[cnt
++] = hex
[digest
[yuvIdx
][i
] >> 4];
956 string
[cnt
++] = hex
[digest
[yuvIdx
][i
] & 0xf];
962 string
[cnt
- 1] = '\0';
966 void Encoder::finishFrameStats(Frame
* curFrame
, FrameEncoder
*curEncoder
, uint64_t bits
)
968 PicYuv
* reconPic
= curFrame
->m_reconPicYuv
;
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
;
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
;
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);
988 FrameData
& curEncData
= *curFrame
->m_encData
;
989 Slice
* slice
= curEncData
.m_slice
;
991 //===== add bits, psnr and ssim =====
992 m_analyzeAll
.addBits(bits
);
993 m_analyzeAll
.addQP(curEncData
.m_avgQpAq
);
995 if (m_param
->bEnablePsnr
)
996 m_analyzeAll
.addPsnr(psnrY
, psnrU
, psnrV
);
999 if (m_param
->bEnableSsim
&& curEncoder
->m_ssimCnt
)
1001 ssim
= curEncoder
->m_ssim
/ curEncoder
->m_ssimCnt
;
1002 m_analyzeAll
.addSsim(ssim
);
1004 if (slice
->isIntra())
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
);
1013 else if (slice
->isInterP())
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
);
1022 else if (slice
->isInterB())
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
);
1032 // if debug log level is enabled, per frame logging is performed
1033 if (m_param
->logLevel
>= X265_LOG_DEBUG
)
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
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
));
1050 if (!slice
->isIntra())
1052 int numLists
= slice
->isInterP() ? 1 : 2;
1053 for (int list
= 0; list
< numLists
; list
++)
1055 p
+= sprintf(buf
+ p
, " [L%d ", list
);
1056 for (int ref
= 0; ref
< slice
->m_numRefIdx
[list
]; ref
++)
1058 int k
= slice
->m_refPOCList
[list
][ref
] - slice
->m_lastIDR
;
1059 p
+= sprintf(buf
+ p
, "%d ", k
);
1062 p
+= sprintf(buf
+ p
, "]");
1066 // per frame CSV logging if the file handle is valid
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
);
1076 fprintf(m_csvfpt
, " -, -, -, -,");
1077 if (m_param
->bEnableSsim
)
1078 fprintf(m_csvfpt
, " %.6f, %6.3f,", ssim
, x265_ssim2dB(ssim
));
1080 fprintf(m_csvfpt
, " -, -,");
1081 fprintf(m_csvfpt
, " %.3lf, %.3lf", curEncoder
->m_frameTime
, curEncoder
->m_elapsedCompressTime
);
1082 if (!slice
->isIntra())
1084 int numLists
= slice
->isInterP() ? 1 : 2;
1085 for (int list
= 0; list
< numLists
; list
++)
1087 fprintf(m_csvfpt
, ", ");
1088 for (int ref
= 0; ref
< slice
->m_numRefIdx
[list
]; ref
++)
1090 int k
= slice
->m_refPOCList
[list
][ref
] - slice
->m_lastIDR
;
1091 fprintf(m_csvfpt
, " %d", k
);
1096 fprintf(m_csvfpt
, ", -");
1099 fprintf(m_csvfpt
, ", -, -");
1100 fprintf(m_csvfpt
, "\n");
1103 if (m_param
->decodedPictureHashSEI
&& m_param
->logLevel
>= X265_LOG_FULL
)
1105 const char* digestStr
= NULL
;
1106 if (m_param
->decodedPictureHashSEI
== 1)
1108 digestStr
= digestToString(curEncoder
->m_seiReconPictureDigest
.m_digest
, 16);
1109 p
+= sprintf(buf
+ p
, " [MD5:%s]", digestStr
);
1111 else if (m_param
->decodedPictureHashSEI
== 2)
1113 digestStr
= digestToString(curEncoder
->m_seiReconPictureDigest
.m_digest
, 2);
1114 p
+= sprintf(buf
+ p
, " [CRC:%s]", digestStr
);
1116 else if (m_param
->decodedPictureHashSEI
== 3)
1118 digestStr
= digestToString(curEncoder
->m_seiReconPictureDigest
.m_digest
, 4);
1119 p
+= sprintf(buf
+ p
, " [Checksum:%s]", digestStr
);
1122 x265_log(m_param
, X265_LOG_DEBUG
, "%s\n", buf
);
1127 #if defined(_MSC_VER)
1128 #pragma warning(disable: 4800) // forcing int to bool
1129 #pragma warning(disable: 4127) // conditional expression is constant
1132 void Encoder::getStreamHeaders(NALList
& list
, Entropy
& sbacCoder
, Bitstream
& bs
)
1134 sbacCoder
.setBitstream(&bs
);
1136 /* headers for start of bitstream */
1138 sbacCoder
.codeVPS(m_vps
);
1139 bs
.writeByteAlignment();
1140 list
.serialize(NAL_UNIT_VPS
, bs
);
1143 sbacCoder
.codeSPS(m_sps
, m_scalingList
, m_vps
.ptl
);
1144 bs
.writeByteAlignment();
1145 list
.serialize(NAL_UNIT_SPS
, bs
);
1148 sbacCoder
.codePPS(m_pps
);
1149 bs
.writeByteAlignment();
1150 list
.serialize(NAL_UNIT_PPS
, bs
);
1152 if (m_param
->bEmitInfoSEI
)
1154 char *opts
= x265_param2string(m_param
);
1157 char *buffer
= X265_MALLOC(char, strlen(opts
) + strlen(x265_version_str
) +
1158 strlen(x265_build_info_str
) + 200);
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
);
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
);
1181 if (m_param
->bEmitHRDSEI
|| !!m_param
->interlaceMode
)
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;
1189 sei
.write(bs
, m_sps
);
1190 bs
.writeByteAlignment();
1191 list
.serialize(NAL_UNIT_PREFIX_SEI
, bs
);
1195 void Encoder::initSPS(SPS
*sps
)
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;
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
;
1212 sps
->log2MinCodingBlockSize
= g_maxLog2CUSize
- g_maxCUDepth
;
1213 sps
->log2DiffMaxMinCodingBlockSize
= g_maxCUDepth
;
1215 sps
->quadtreeTULog2MaxSize
= X265_MIN(g_maxLog2CUSize
, 5);
1216 sps
->quadtreeTULog2MinSize
= 2;
1217 sps
->quadtreeTUMaxDepthInter
= m_param
->tuQTMaxInterDepth
;
1218 sps
->quadtreeTUMaxDepthIntra
= m_param
->tuQTMaxIntraDepth
;
1220 sps
->bUseSAO
= m_param
->bEnableSAO
;
1222 sps
->bUseAMP
= m_param
->bEnableAMP
;
1223 sps
->maxAMPDepth
= m_param
->bEnableAMP
? g_maxCUDepth
: 0;
1225 sps
->maxDecPicBuffering
= m_vps
.maxDecPicBuffering
;
1226 sps
->numReorderPics
= m_vps
.numReorderPics
;
1228 sps
->bUseStrongIntraSmoothing
= m_param
->bEnableStrongIntraSmoothing
;
1229 sps
->bTemporalMVPEnabled
= m_param
->bEnableTemporalMvp
;
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
;
1237 vui
.overscanInfoPresentFlag
= m_param
->vui
.bEnableOverscanInfoPresentFlag
;
1238 vui
.overscanAppropriateFlag
= m_param
->vui
.bEnableOverscanAppropriateFlag
;
1240 vui
.videoSignalTypePresentFlag
= m_param
->vui
.bEnableVideoSignalTypePresentFlag
;
1241 vui
.videoFormat
= m_param
->vui
.videoFormat
;
1242 vui
.videoFullRangeFlag
= m_param
->vui
.bEnableVideoFullRangeFlag
;
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
;
1249 vui
.chromaLocInfoPresentFlag
= m_param
->vui
.bEnableChromaLocInfoPresentFlag
;
1250 vui
.chromaSampleLocTypeTopField
= m_param
->vui
.chromaSampleLocTypeTopField
;
1251 vui
.chromaSampleLocTypeBottomField
= m_param
->vui
.chromaSampleLocTypeBottomField
;
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
;
1259 vui
.frameFieldInfoPresentFlag
= !!m_param
->interlaceMode
;
1260 vui
.fieldSeqFlag
= !!m_param
->interlaceMode
;
1262 vui
.hrdParametersPresentFlag
= m_param
->bEmitHRDSEI
;
1264 vui
.timingInfo
.numUnitsInTick
= m_param
->fpsDenom
;
1265 vui
.timingInfo
.timeScale
= m_param
->fpsNum
;
1268 void Encoder::initPPS(PPS
*pps
)
1270 bool bIsVbv
= m_param
->rc
.vbvBufferSize
> 0 && m_param
->rc
.vbvMaxBitrate
> 0;
1272 if (!m_param
->bLossless
&& (m_param
->rc
.aqMode
|| bIsVbv
))
1274 pps
->bUseDQP
= true;
1275 pps
->maxCuDQPDepth
= 0; /* TODO: make configurable? */
1279 pps
->bUseDQP
= false;
1280 pps
->maxCuDQPDepth
= 0;
1283 pps
->chromaCbQpOffset
= m_param
->cbQpOffset
;
1284 pps
->chromaCrQpOffset
= m_param
->crQpOffset
;
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
;
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;
1301 pps
->bEntropyCodingSyncEnabled
= m_param
->bEnableWavefront
;
1304 void Encoder::configure(x265_param
*p
)
1308 if (p
->keyframeMax
< 0)
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;
1316 else if (p
->keyframeMax
<= 1)
1318 // disable lookahead for all-intra encodes
1319 p
->bFrameAdaptive
= 0;
1322 if (!p
->keyframeMin
)
1324 double fps
= (double)p
->fpsNum
/ p
->fpsDenom
;
1325 p
->keyframeMin
= X265_MIN((int)fps
, p
->keyframeMax
/ 10);
1327 p
->keyframeMin
= X265_MAX(1, X265_MIN(p
->keyframeMin
, p
->keyframeMax
/ 2 + 1));
1329 if (p
->bBPyramid
&& !p
->bframes
)
1332 /* Disable features which are not supported by the current RD level */
1335 if (p
->psyRdoq
> 0) /* impossible */
1336 x265_log(p
, X265_LOG_WARNING
, "--psy-rdoq disabled, requires --rdlevel 4 or higher\n");
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;
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;
1353 if (p
->psyRd
> 0) /* impossible */
1354 x265_log(p
, X265_LOG_WARNING
, "--psy-rd disabled, requires --rdlevel 2 or higher\n");
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;
1362 if (!p
->bEnableRectInter
) /* not useful */
1363 p
->bEnableAMP
= false;
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
)
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
1380 if (p
->rc
.rateControlMode
== X265_RC_CQP
)
1382 p
->rc
.aqMode
= X265_AQ_NONE
;
1385 p
->rc
.aqStrength
= 0;
1388 if (p
->rc
.aqMode
== 0 && p
->rc
.cuTree
)
1390 p
->rc
.aqMode
= X265_AQ_VARIANCE
;
1391 p
->rc
.aqStrength
= 0.0;
1394 if (p
->lookaheadDepth
== 0 && p
->rc
.cuTree
&& !p
->rc
.bStatRead
)
1396 x265_log(p
, X265_LOG_WARNING
, "cuTree disabled, requires lookahead to be enabled\n");
1400 if (p
->rc
.aqStrength
== 0 && p
->rc
.cuTree
== 0)
1401 p
->rc
.aqMode
= X265_AQ_NONE
;
1403 if (p
->rc
.aqMode
== X265_AQ_NONE
&& p
->rc
.cuTree
== 0)
1404 p
->rc
.aqStrength
= 0;
1406 if (p
->internalCsp
!= X265_CSP_I420
)
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");
1412 if (p
->scalingLists
&& p
->internalCsp
== X265_CSP_I444
)
1414 x265_log(p
, X265_LOG_WARNING
, "Scaling lists are not yet supported for 4:4:4 color space\n");
1415 p
->scalingLists
= 0;
1418 if (p
->interlaceMode
)
1419 x265_log(p
, X265_LOG_WARNING
, "Support for interlaced video is experimental\n");
1421 if (p
->rc
.rfConstantMin
> p
->rc
.rfConstant
)
1423 x265_log(m_param
, X265_LOG_WARNING
, "CRF min must be less than CRF\n");
1424 p
->rc
.rfConstantMin
= 0;
1427 m_bframeDelay
= p
->bframes
? (p
->bBPyramid
? 2 : 1) : 0;
1429 p
->bFrameBias
= X265_MIN(X265_MAX(-90, p
->bFrameBias
), 100);
1431 if (p
->logLevel
< X265_LOG_INFO
)
1433 /* don't measure these metrics if they will not be reported */
1437 /* Warn users trying to measure PSNR/SSIM with psy opts on. */
1438 if (p
->bEnablePsnr
|| p
->bEnableSsim
)
1440 const char *s
= NULL
;
1442 if (p
->psyRd
|| p
->psyRdoq
)
1444 s
= p
->bEnablePsnr
? "psnr" : "ssim";
1445 x265_log(p
, X265_LOG_WARNING
, "--%s used with psy on: results will be invalid!\n", s
);
1447 else if (!p
->rc
.aqMode
&& p
->bEnableSsim
)
1449 x265_log(p
, X265_LOG_WARNING
, "--ssim used with AQ off: results will be invalid!\n");
1452 else if (p
->rc
.aqStrength
> 0 && p
->bEnablePsnr
)
1454 x265_log(p
, X265_LOG_WARNING
, "--psnr used with AQ on: results will be invalid!\n");
1458 x265_log(p
, X265_LOG_WARNING
, "--tune %s should be used if attempting to benchmark %s!\n", s
, s
);
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;
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))
1472 uint32_t rem
= p
->sourceWidth
& (minCUSize
- 1);
1473 uint32_t padsize
= minCUSize
- rem
;
1474 p
->sourceWidth
+= padsize
;
1476 /* set the confirmation window offsets */
1477 m_conformanceWindow
.bEnabled
= true;
1478 m_conformanceWindow
.rightOffset
= padsize
;
1481 //======== set pad size if height is not multiple of the minimum CU size =========
1482 if (p
->sourceHeight
& (minCUSize
- 1))
1484 uint32_t rem
= p
->sourceHeight
& (minCUSize
- 1);
1485 uint32_t padsize
= minCUSize
- rem
;
1486 p
->sourceHeight
+= padsize
;
1488 /* set the confirmation window offsets */
1489 m_conformanceWindow
.bEnabled
= true;
1490 m_conformanceWindow
.bottomOffset
= padsize
;