/work/vvenc/source/Lib/vvenc/vvencimpl.cpp
Line | Count | Source |
1 | | /* ----------------------------------------------------------------------------- |
2 | | The copyright in this software is being made available under the Clear BSD |
3 | | License, included below. No patent rights, trademark rights and/or |
4 | | other Intellectual Property Rights other than the copyrights concerning |
5 | | the Software are granted under this license. |
6 | | |
7 | | The Clear BSD License |
8 | | |
9 | | Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors. |
10 | | All rights reserved. |
11 | | |
12 | | Redistribution and use in source and binary forms, with or without modification, |
13 | | are permitted (subject to the limitations in the disclaimer below) provided that |
14 | | the following conditions are met: |
15 | | |
16 | | * Redistributions of source code must retain the above copyright notice, |
17 | | this list of conditions and the following disclaimer. |
18 | | |
19 | | * Redistributions in binary form must reproduce the above copyright |
20 | | notice, this list of conditions and the following disclaimer in the |
21 | | documentation and/or other materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the copyright holder nor the names of its |
24 | | contributors may be used to endorse or promote products derived from this |
25 | | software without specific prior written permission. |
26 | | |
27 | | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY |
28 | | THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
29 | | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
31 | | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
32 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
33 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
34 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
35 | | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
36 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
37 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
38 | | POSSIBILITY OF SUCH DAMAGE. |
39 | | |
40 | | |
41 | | ------------------------------------------------------------------------------------------- */ |
42 | | |
43 | | /** |
44 | | \ingroup vvenc |
45 | | \file vvencimpl.cpp |
46 | | \brief This file contains the internal interface of the vvenc SDK. |
47 | | */ |
48 | | |
49 | | #include "vvencimpl.h" |
50 | | |
51 | | #include <iostream> |
52 | | #include <stdio.h> |
53 | | #include <algorithm> |
54 | | |
55 | | #include "vvenc/version.h" |
56 | | #include "CommonLib/CommonDef.h" |
57 | | #include "CommonLib/Nal.h" |
58 | | #include "CommonLib/Picture.h" |
59 | | #include "EncoderLib/EncGOP.h" |
60 | | #include "EncoderLib/EncLib.h" |
61 | | |
62 | | #if ENABLE_SIMD_TRAFO |
63 | | #include "CommonLib/TrQuant_EMT.h" |
64 | | #endif // ENABLE_SIMD_TRAFO |
65 | | |
66 | | #if defined( __linux__ ) |
67 | | #include <malloc.h> |
68 | | #endif |
69 | | |
70 | | #if defined( TARGET_SIMD_X86 ) |
71 | | #include "CommonLib/x86/CommonDefX86.h" |
72 | | #endif // defined( TARGET_SIMD_X86 ) |
73 | | #if defined( TARGET_SIMD_ARM ) |
74 | | #include "CommonLib/arm/CommonDefARM.h" |
75 | | #endif // defined( TARGET_SIMD_ARM ) |
76 | | |
77 | | #if _DEBUG |
78 | | #define HANDLE_EXCEPTION 0 |
79 | | #else |
80 | | #define HANDLE_EXCEPTION 1 |
81 | | #endif |
82 | | |
83 | | |
84 | | namespace vvenc { |
85 | | |
86 | | #define ROTPARAMS(x, message) if(x) { rcErrorString = message; return VVENC_ERR_PARAMETER;} |
87 | | |
88 | | // ==================================================================================================================== |
89 | | |
90 | | static_assert( sizeof(Pel) == sizeof(*(vvencYUVPlane::ptr)), "internal bits per pel differ from interface definition" ); |
91 | | |
92 | | // ==================================================================================================================== |
93 | | |
94 | | VVEncImpl::VVEncImpl() |
95 | 1.19k | { |
96 | 1.19k | setSIMDExtension( nullptr ); // ensure SIMD-detection is finished |
97 | 1.19k | m_cEncoderInfo = createEncoderInfoStr(); |
98 | 1.19k | } |
99 | | |
100 | | VVEncImpl::~VVEncImpl() |
101 | 1.19k | { |
102 | | |
103 | 1.19k | } |
104 | | |
105 | | int VVEncImpl::getConfig( vvenc_config& config ) const |
106 | 0 | { |
107 | 0 | if( !m_bInitialized ){ return VVENC_ERR_INITIALIZE; } |
108 | | |
109 | 0 | config = m_cVVEncCfg; |
110 | 0 | return VVENC_OK; |
111 | 0 | } |
112 | | |
113 | | int VVEncImpl::reconfig( const vvenc_config& ) |
114 | 0 | { |
115 | 0 | if( !m_bInitialized ){ return VVENC_ERR_INITIALIZE; } |
116 | 0 | return VVENC_ERR_NOT_SUPPORTED; |
117 | 0 | } |
118 | | |
119 | | int VVEncImpl::checkConfig( const vvenc_config& config ) |
120 | 0 | { |
121 | 0 | vvenc_config configCpy = config; |
122 | 0 | if ( vvenc_init_config_parameter(&configCpy) ) |
123 | 0 | { |
124 | 0 | return VVENC_ERR_INITIALIZE; |
125 | 0 | } |
126 | | |
127 | 0 | return VVENC_OK; |
128 | 0 | } |
129 | | |
130 | | int VVEncImpl::init( vvenc_config* config ) |
131 | 1.19k | { |
132 | 1.19k | if( m_bInitialized ){ return VVENC_ERR_INITIALIZE; } |
133 | | |
134 | 1.19k | if (nullptr == config) |
135 | 0 | { |
136 | 0 | msg.log( VVENC_ERROR, "vvenc_config is null\n" ); |
137 | 0 | return VVENC_ERR_PARAMETER; |
138 | 0 | } |
139 | | |
140 | 1.19k | m_cVVEncCfgExt = *config; |
141 | 1.19k | m_cVVEncCfg = *config; |
142 | | |
143 | 1.19k | if ( vvenc_init_config_parameter(&m_cVVEncCfg) ) // init auto/dependent options |
144 | 0 | { |
145 | 0 | return VVENC_ERR_INITIALIZE; |
146 | 0 | } |
147 | | |
148 | 1.19k | if( config->m_msgFnc ) |
149 | 0 | { |
150 | 0 | msg.setCallback( config->m_msgCtx, config->m_msgFnc ); |
151 | 0 | } |
152 | | |
153 | 1.19k | #if !IFP_RC_DETERMINISTIC |
154 | 1.19k | if( m_cVVEncCfg.m_RCTargetBitrate != 0 && m_cVVEncCfg.m_ifp ) |
155 | 0 | { |
156 | 0 | msg.log( VVENC_WARNING, "Using RC with IFP. Results are non-deterministic!\n" ); |
157 | 0 | } |
158 | 1.19k | #endif |
159 | | |
160 | | // initialize the encoder |
161 | 1.19k | m_pEncLib = new EncLib ( msg ); |
162 | | |
163 | | #if HANDLE_EXCEPTION |
164 | | try |
165 | | #endif |
166 | 1.19k | { |
167 | 1.19k | m_pEncLib->initEncoderLib( m_cVVEncCfg ); |
168 | 1.19k | } |
169 | | #if HANDLE_EXCEPTION |
170 | | catch( std::exception& e ) |
171 | | { |
172 | | msg.log( VVENC_ERROR, "\n%s\n", e.what() ); |
173 | | m_cErrorString = e.what(); |
174 | | return VVENC_ERR_UNSPECIFIED; |
175 | | } |
176 | | #endif |
177 | | |
178 | 1.19k | m_bInitialized = true; |
179 | 1.19k | m_eState = INTERNAL_STATE_INITIALIZED; |
180 | 1.19k | return VVENC_OK; |
181 | 1.19k | } |
182 | | |
183 | | int VVEncImpl::initPass( int pass, const char* statsFName ) |
184 | 0 | { |
185 | 0 | if( !m_bInitialized ){ return VVENC_ERR_INITIALIZE; } |
186 | 0 | if( pass > 1 ) |
187 | 0 | { |
188 | 0 | std::stringstream css; |
189 | 0 | css << "initPass(" << pass << ") no support for pass " << pass << ". use 0 (first pass) and 1 (second pass)"; |
190 | 0 | m_cErrorString = css.str(); |
191 | 0 | return VVENC_ERR_NOT_SUPPORTED; |
192 | 0 | } |
193 | | |
194 | 0 | if ( m_pEncLib ) |
195 | 0 | { |
196 | | #if HANDLE_EXCEPTION |
197 | | try |
198 | | #endif |
199 | 0 | { |
200 | 0 | m_pEncLib->initPass( pass, statsFName ); |
201 | 0 | } |
202 | | #if HANDLE_EXCEPTION |
203 | | catch( std::exception& e ) |
204 | | { |
205 | | msg.log( VVENC_ERROR, "\n%s\n", e.what() ); |
206 | | m_cErrorString = e.what(); |
207 | | return VVENC_ERR_UNSPECIFIED; |
208 | | } |
209 | | #endif |
210 | 0 | } |
211 | |
|
212 | 0 | m_eState = INTERNAL_STATE_INITIALIZED; |
213 | 0 | return VVENC_OK; |
214 | 0 | } |
215 | | |
216 | | int VVEncImpl::uninit() |
217 | 1.19k | { |
218 | 1.19k | if( !m_bInitialized ){ return VVENC_ERR_INITIALIZE; } |
219 | | |
220 | 1.19k | if ( m_pEncLib ) |
221 | 1.19k | { |
222 | | #if HANDLE_EXCEPTION |
223 | | try |
224 | | #endif |
225 | 1.19k | { |
226 | 1.19k | m_pEncLib->uninitEncoderLib(); |
227 | 1.19k | delete m_pEncLib; |
228 | 1.19k | m_pEncLib = nullptr; |
229 | 1.19k | } |
230 | | #if HANDLE_EXCEPTION |
231 | | catch( std::exception& e ) |
232 | | { |
233 | | msg.log( VVENC_ERROR, "\n%s\n", e.what() ); |
234 | | m_cErrorString = e.what(); |
235 | | return VVENC_ERR_UNSPECIFIED; |
236 | | } |
237 | | #endif |
238 | 1.19k | } |
239 | | |
240 | 1.19k | #if defined( __linux__ ) && defined( __GLIBC__ ) |
241 | 1.19k | malloc_trim(0); // free unused heap memory |
242 | 1.19k | #endif |
243 | | |
244 | 1.19k | m_bInitialized = false; |
245 | 1.19k | m_eState = INTERNAL_STATE_UNINITIALIZED; |
246 | 1.19k | return VVENC_OK; |
247 | 1.19k | } |
248 | | |
249 | | bool VVEncImpl::isInitialized() const |
250 | 0 | { |
251 | 0 | return m_bInitialized; |
252 | 0 | } |
253 | | |
254 | | int VVEncImpl::setRecYUVBufferCallback( void * ctx, vvencRecYUVBufferCallback callback ) |
255 | 0 | { |
256 | 0 | if( !m_bInitialized || !m_pEncLib ){ return VVENC_ERR_INITIALIZE; } |
257 | | |
258 | 0 | m_pEncLib->setRecYUVBufferCallback( ctx, callback ); |
259 | 0 | return VVENC_OK; |
260 | 0 | } |
261 | | |
262 | | int VVEncImpl::encode( vvencYUVBuffer* pcYUVBuffer, vvencAccessUnit* pcAccessUnit, bool* pbEncodeDone ) |
263 | 2.39k | { |
264 | 2.39k | if( !m_bInitialized ) { return VVENC_ERR_INITIALIZE; } |
265 | 2.39k | if( m_eState == INTERNAL_STATE_FINALIZED ) { m_cErrorString = "encoder already flushed, please reinit."; return VVENC_ERR_RESTART_REQUIRED; } |
266 | | |
267 | 2.39k | if( !pcAccessUnit ) |
268 | 0 | { |
269 | 0 | m_cErrorString = "vvencAccessUnit is null. AU memory must be allocated before encode call."; |
270 | 0 | return VVENC_NOT_ENOUGH_MEM; |
271 | 0 | } |
272 | 2.39k | if( pcAccessUnit->payloadSize <= 0 ) |
273 | 0 | { |
274 | 0 | m_cErrorString = "vvencAccessUnit has no payload size. AU payload must have a sufficient size to store encoded data."; |
275 | 0 | return VVENC_NOT_ENOUGH_MEM; |
276 | 0 | } |
277 | | |
278 | 2.39k | int iRet= VVENC_OK; |
279 | | |
280 | 2.39k | bool bFlush = false; |
281 | 2.39k | if( pcYUVBuffer ) |
282 | 1.19k | { |
283 | 1.19k | if( m_eState == INTERNAL_STATE_FLUSHING ) { m_cErrorString = "encoder already received flush indication, please reinit."; return VVENC_ERR_RESTART_REQUIRED; } |
284 | | |
285 | 1.19k | if( pcYUVBuffer->planes[0].ptr == nullptr ) |
286 | 0 | { |
287 | 0 | m_cErrorString = "InputPicture: invalid input buffers"; |
288 | 0 | return VVENC_ERR_UNSPECIFIED; |
289 | 0 | } |
290 | | |
291 | 1.19k | if( m_cVVEncCfg.m_internChromaFormat != VVENC_CHROMA_400 ) |
292 | 1.19k | { |
293 | 1.19k | if( pcYUVBuffer->planes[1].ptr == nullptr || |
294 | 1.19k | pcYUVBuffer->planes[2].ptr == nullptr ) |
295 | 0 | { |
296 | 0 | m_cErrorString = "InputPicture: invalid input buffers for chroma"; |
297 | 0 | return VVENC_ERR_UNSPECIFIED; |
298 | 0 | } |
299 | 1.19k | } |
300 | | |
301 | 1.19k | if( pcYUVBuffer->planes[0].width != m_cVVEncCfg.m_SourceWidth ) |
302 | 0 | { |
303 | 0 | m_cErrorString = "InputPicture: unsupported width"; |
304 | 0 | return VVENC_ERR_UNSPECIFIED; |
305 | 0 | } |
306 | | |
307 | 1.19k | if( pcYUVBuffer->planes[0].height != m_cVVEncCfg.m_SourceHeight ) |
308 | 0 | { |
309 | 0 | m_cErrorString = "InputPicture: unsupported height"; |
310 | 0 | return VVENC_ERR_UNSPECIFIED; |
311 | 0 | } |
312 | | |
313 | 1.19k | if( pcYUVBuffer->planes[0].width > pcYUVBuffer->planes[0].stride ) |
314 | 0 | { |
315 | 0 | m_cErrorString = "InputPicture: unsupported width stride combination"; |
316 | 0 | return VVENC_ERR_UNSPECIFIED; |
317 | 0 | } |
318 | | |
319 | 1.19k | if( m_cVVEncCfg.m_internChromaFormat != VVENC_CHROMA_400 ) |
320 | 1.19k | { |
321 | 1.19k | if( m_cVVEncCfg.m_internChromaFormat == VVENC_CHROMA_444 ) |
322 | 0 | { |
323 | 0 | if( pcYUVBuffer->planes[1].stride && pcYUVBuffer->planes[0].width > pcYUVBuffer->planes[1].stride ) |
324 | 0 | { |
325 | 0 | m_cErrorString = "InputPicture: unsupported width cstride combination for 2nd plane"; |
326 | 0 | return VVENC_ERR_UNSPECIFIED; |
327 | 0 | } |
328 | | |
329 | 0 | if( pcYUVBuffer->planes[2].stride && pcYUVBuffer->planes[0].width > pcYUVBuffer->planes[2].stride ) |
330 | 0 | { |
331 | 0 | m_cErrorString = "InputPicture: unsupported width cstride combination for 3rd plane"; |
332 | 0 | return VVENC_ERR_UNSPECIFIED; |
333 | 0 | } |
334 | 0 | } |
335 | 1.19k | else |
336 | 1.19k | { |
337 | 1.19k | if( pcYUVBuffer->planes[1].stride && pcYUVBuffer->planes[0].width/2 > pcYUVBuffer->planes[1].stride ) |
338 | 0 | { |
339 | 0 | m_cErrorString = "InputPicture: unsupported width cstride combination for 2nd plane"; |
340 | 0 | return VVENC_ERR_UNSPECIFIED; |
341 | 0 | } |
342 | | |
343 | 1.19k | if( pcYUVBuffer->planes[2].stride && pcYUVBuffer->planes[0].width/2 > pcYUVBuffer->planes[2].stride ) |
344 | 0 | { |
345 | 0 | m_cErrorString = "InputPicture: unsupported width cstride combination for 3rd plane"; |
346 | 0 | return VVENC_ERR_UNSPECIFIED; |
347 | 0 | } |
348 | 1.19k | } |
349 | 1.19k | } |
350 | | |
351 | 1.19k | if ( ! xConvertVerifyYUVBuffer( pcYUVBuffer ) ) |
352 | 0 | { |
353 | 0 | m_cErrorString = "InputPicture: Source image contains values outside the specified bit range"; |
354 | 0 | return VVENC_ERR_UNSPECIFIED; |
355 | 0 | } |
356 | | |
357 | 1.19k | if( m_eState == INTERNAL_STATE_INITIALIZED ){ m_eState = INTERNAL_STATE_ENCODING; } |
358 | 1.19k | } |
359 | 1.19k | else |
360 | 1.19k | { |
361 | 1.19k | if( m_eState == INTERNAL_STATE_ENCODING ){ m_eState = INTERNAL_STATE_FLUSHING; } |
362 | 1.19k | bFlush = true; |
363 | 1.19k | } |
364 | | |
365 | | // reset AU data |
366 | 2.39k | if( pcAccessUnit ) |
367 | 2.39k | { |
368 | 2.39k | vvenc_accessUnit_reset(pcAccessUnit); |
369 | 2.39k | } |
370 | 2.39k | *pbEncodeDone = false; |
371 | | |
372 | 2.39k | AccessUnitList cAu; |
373 | | #if HANDLE_EXCEPTION |
374 | | try |
375 | | #endif |
376 | 2.39k | { |
377 | 2.39k | m_pEncLib->encodePicture( bFlush, pcYUVBuffer, cAu, *pbEncodeDone ); |
378 | 2.39k | } |
379 | | #if HANDLE_EXCEPTION |
380 | | catch( std::exception& e ) |
381 | | { |
382 | | msg.log( VVENC_ERROR, "\n%s\n", e.what() ); |
383 | | m_cErrorString = e.what(); |
384 | | return VVENC_ERR_UNSPECIFIED; |
385 | | } |
386 | | #endif |
387 | | |
388 | 2.39k | if( *pbEncodeDone ) |
389 | 1.19k | { |
390 | 1.19k | if( m_eState == INTERNAL_STATE_FLUSHING ) |
391 | 1.19k | { |
392 | 1.19k | m_eState = INTERNAL_STATE_FINALIZED; |
393 | 1.19k | } |
394 | 0 | else if( m_eState == INTERNAL_STATE_INITIALIZED ) |
395 | 0 | { |
396 | 0 | m_eState = INTERNAL_STATE_INITIALIZED; // keep initialized state, when flushing without having encoded anything, we still can start to encode |
397 | 0 | } |
398 | 0 | else |
399 | 0 | { |
400 | 0 | *pbEncodeDone = false; |
401 | 0 | } |
402 | 1.19k | } |
403 | 1.19k | else |
404 | 1.19k | { |
405 | 1.19k | if( bFlush && m_cVVEncCfg.m_RCNumPasses == 2 && m_pEncLib->getCurPass() == 0 ) |
406 | 0 | { |
407 | | // process all remaining pictures of first pass on first flush packet |
408 | 0 | while ( ! *pbEncodeDone ) |
409 | 0 | { |
410 | | #if HANDLE_EXCEPTION |
411 | | try |
412 | | #endif |
413 | 0 | { |
414 | 0 | m_pEncLib->encodePicture( bFlush, pcYUVBuffer, cAu, *pbEncodeDone ); |
415 | 0 | } |
416 | | #if HANDLE_EXCEPTION |
417 | | catch( std::exception& e ) |
418 | | { |
419 | | msg.log( VVENC_ERROR, "\n%s\n", e.what() ); |
420 | | m_cErrorString = e.what(); |
421 | | return VVENC_ERR_UNSPECIFIED; |
422 | | } |
423 | | #endif |
424 | 0 | } |
425 | 0 | m_eState = INTERNAL_STATE_FINALIZED; |
426 | 0 | } |
427 | 1.19k | } |
428 | | |
429 | | /* copy output AU */ |
430 | 2.39k | if ( !cAu.empty() ) |
431 | 1.19k | { |
432 | 1.19k | int sizeAu = xGetAccessUnitsSize( cAu ); |
433 | 1.19k | if( pcAccessUnit->payloadSize < sizeAu ) |
434 | 0 | { |
435 | 0 | std::stringstream css; |
436 | 0 | css << "vvencAccessUnit payload size is too small to store data. (payload size: " << pcAccessUnit->payloadSize << ", needed " << sizeAu << ")"; |
437 | 0 | m_cErrorString =css.str(); |
438 | 0 | return VVENC_NOT_ENOUGH_MEM; |
439 | 0 | } |
440 | | |
441 | 1.19k | iRet = xCopyAu( *pcAccessUnit, cAu ); |
442 | 1.19k | } |
443 | | |
444 | 2.39k | #if defined( __linux__ ) && defined( __GLIBC__ ) |
445 | 2.39k | malloc_trim(0); // free unused heap memory |
446 | 2.39k | #endif |
447 | | |
448 | 2.39k | return iRet; |
449 | 2.39k | } |
450 | | |
451 | | int VVEncImpl::getParameterSets( vvencAccessUnit *pcAccessUnit ) |
452 | 0 | { |
453 | 0 | if( !m_bInitialized ) { return VVENC_ERR_INITIALIZE; } |
454 | 0 | if( m_eState == INTERNAL_STATE_FINALIZED ) { m_cErrorString = "encoder already flushed, please reinit."; return VVENC_ERR_RESTART_REQUIRED; } |
455 | | |
456 | 0 | if( !pcAccessUnit ) |
457 | 0 | { |
458 | 0 | m_cErrorString = "vvencAccessUnit is null. AU memory must be allocated before encode call."; |
459 | 0 | return VVENC_NOT_ENOUGH_MEM; |
460 | 0 | } |
461 | 0 | if( pcAccessUnit->payloadSize <= 0 ) |
462 | 0 | { |
463 | 0 | m_cErrorString = "vvencAccessUnit has no payload size. AU payload must have a sufficient size to store encoded data."; |
464 | 0 | return VVENC_NOT_ENOUGH_MEM; |
465 | 0 | } |
466 | | |
467 | 0 | int iRet= VVENC_OK; |
468 | | |
469 | | // reset AU data |
470 | 0 | vvenc_accessUnit_reset(pcAccessUnit); |
471 | |
|
472 | 0 | AccessUnitList cAu; |
473 | | #if HANDLE_EXCEPTION |
474 | | try |
475 | | #endif |
476 | 0 | { |
477 | 0 | m_pEncLib->getParameterSets( cAu ); |
478 | 0 | } |
479 | | #if HANDLE_EXCEPTION |
480 | | catch( std::exception& e ) |
481 | | { |
482 | | msg.log( VVENC_ERROR, "\n%s\n", e.what() ); |
483 | | m_cErrorString = e.what(); |
484 | | return VVENC_ERR_UNSPECIFIED; |
485 | | } |
486 | | #endif |
487 | | |
488 | | /* copy output AU */ |
489 | 0 | if ( !cAu.empty() ) |
490 | 0 | { |
491 | 0 | int sizeAu = xGetAccessUnitsSize( cAu ); |
492 | 0 | if( pcAccessUnit->payloadSize < sizeAu ) |
493 | 0 | { |
494 | 0 | std::stringstream css; |
495 | 0 | css << "vvencAccessUnit payload size is too small to store data. (payload size: " << pcAccessUnit->payloadSize << ", needed " << sizeAu << ")"; |
496 | 0 | m_cErrorString =css.str(); |
497 | 0 | return VVENC_NOT_ENOUGH_MEM; |
498 | 0 | } |
499 | | |
500 | 0 | iRet = xCopyAu( *pcAccessUnit, cAu ); |
501 | 0 | } |
502 | | |
503 | 0 | return iRet; |
504 | 0 | } |
505 | | |
506 | | |
507 | | |
508 | | const char* VVEncImpl::getVersionNumber() |
509 | 0 | { |
510 | 0 | return VVENC_VERSION; |
511 | 0 | } |
512 | | |
513 | | const char* VVEncImpl::getEncoderInfo() const |
514 | 0 | { |
515 | 0 | return m_cEncoderInfo.c_str(); |
516 | 0 | } |
517 | | |
518 | | const char* VVEncImpl::getLastError() const |
519 | 0 | { |
520 | 0 | return m_cErrorString.c_str(); |
521 | 0 | } |
522 | | |
523 | | const char* VVEncImpl::getErrorMsg( int nRet ) |
524 | 0 | { |
525 | 0 | switch( nRet ) |
526 | 0 | { |
527 | 0 | case VVENC_OK : return vvencErrorMsg[0]; break; |
528 | 0 | case VVENC_ERR_UNSPECIFIED: return vvencErrorMsg[1]; break; |
529 | 0 | case VVENC_ERR_INITIALIZE: return vvencErrorMsg[2]; break; |
530 | 0 | case VVENC_ERR_ALLOCATE: return vvencErrorMsg[3]; break; |
531 | 0 | case VVENC_NOT_ENOUGH_MEM: return vvencErrorMsg[4]; break; |
532 | 0 | case VVENC_ERR_PARAMETER: return vvencErrorMsg[5]; break; |
533 | 0 | case VVENC_ERR_NOT_SUPPORTED: return vvencErrorMsg[6]; break; |
534 | 0 | case VVENC_ERR_RESTART_REQUIRED: return vvencErrorMsg[7]; break; |
535 | 0 | case VVENC_ERR_CPU: return vvencErrorMsg[8]; break; |
536 | 0 | default: return vvencErrorMsg[9]; break; |
537 | 0 | } |
538 | 0 | return vvencErrorMsg[9]; |
539 | 0 | } |
540 | | |
541 | | int VVEncImpl::setAndRetErrorMsg( int iRet ) |
542 | 0 | { |
543 | 0 | if( m_cErrorString.empty() ) |
544 | 0 | { |
545 | 0 | m_cErrorString = getErrorMsg(iRet); |
546 | 0 | } |
547 | |
|
548 | 0 | return iRet; |
549 | 0 | } |
550 | | |
551 | | int VVEncImpl::getNumLeadFrames() const |
552 | 0 | { |
553 | 0 | return m_cVVEncCfg.m_leadFrames; |
554 | 0 | } |
555 | | |
556 | | int VVEncImpl::getNumTrailFrames() const |
557 | 0 | { |
558 | 0 | return m_cVVEncCfg.m_trailFrames; |
559 | 0 | } |
560 | | |
561 | | int VVEncImpl::printSummary() const |
562 | 0 | { |
563 | 0 | if( !m_bInitialized ){ return -1; } |
564 | 0 | if( nullptr == m_pEncLib ) { return -1; } |
565 | | |
566 | 0 | m_pEncLib->printSummary(); |
567 | 0 | return 0; |
568 | 0 | } |
569 | | |
570 | | bool VVEncImpl::xConvertVerifyYUVBuffer( vvencYUVBuffer* pcYUVBuffer ) |
571 | 1.19k | { |
572 | 1.19k | if( pcYUVBuffer == nullptr ){ return false; } |
573 | | |
574 | 1.19k | bool conv8bit = false; |
575 | 1.19k | if ( m_cVVEncCfg.m_inputBitDepth[0] == 10 && m_cVVEncCfg.m_internalBitDepth[0] == 8 && |
576 | 0 | m_cVVEncCfg.m_inputBitDepth[0] == m_cVVEncCfg.m_MSBExtendedBitDepth[0] ) |
577 | 0 | { |
578 | 0 | conv8bit = true; |
579 | 0 | } |
580 | | |
581 | 1.19k | const int numComp = (m_cVVEncCfg.m_internChromaFormat==VVENC_CHROMA_400) ? 1 : 3; |
582 | 1.19k | const int16_t mask = ~( ( 1 << m_cVVEncCfg.m_internalBitDepth[0] ) - 1 ); |
583 | 1.19k | int dstSum = 0; |
584 | 4.79k | for( int comp = 0; comp < numComp; comp++ ) |
585 | 3.59k | { |
586 | 3.59k | vvencYUVPlane& plane = pcYUVBuffer->planes[ comp ]; |
587 | 3.59k | int16_t* dst = plane.ptr; |
588 | | |
589 | 3.59k | if ( conv8bit ) |
590 | 0 | { |
591 | 0 | for( int y = 0; y < plane.height; y++, dst += plane.stride ) |
592 | 0 | { |
593 | 0 | for( int x = 0; x < plane.width; x++ ) |
594 | 0 | { |
595 | 0 | dst[ x ] = (Pel)std::min<Pel>( 255, ( dst[x] + 2 ) >> 2 ); |
596 | 0 | dstSum |= dst[ x ] & mask; |
597 | 0 | } |
598 | 0 | } |
599 | 0 | } |
600 | 3.59k | else |
601 | 3.59k | { |
602 | 376k | for( int y = 0; y < plane.height; y++, dst += plane.stride ) |
603 | 373k | { |
604 | 44.9M | for( int x = 0; x < plane.width; x++ ) |
605 | 44.5M | { |
606 | 44.5M | dstSum |= dst[ x ] & mask; |
607 | 44.5M | } |
608 | 373k | } |
609 | 3.59k | } |
610 | 3.59k | } |
611 | 1.19k | return (dstSum != 0) ? false : true; |
612 | 1.19k | } |
613 | | |
614 | | int VVEncImpl::xGetAccessUnitsSize( const vvenc::AccessUnitList& rcAuList ) |
615 | 1.19k | { |
616 | 1.19k | uint32_t sizeSum = 0; |
617 | 1.19k | if ( ! rcAuList.empty() ) |
618 | 1.19k | { |
619 | 4.79k | for (vvenc::AccessUnitList::const_iterator it = rcAuList.begin(); it != rcAuList.end(); it++) |
620 | 3.59k | { |
621 | 3.59k | const vvenc::NALUnitEBSP& nalu = **it; |
622 | 3.59k | if (it == rcAuList.begin() || |
623 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_DCI || |
624 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_SPS || |
625 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_VPS || |
626 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_PPS || |
627 | 1.19k | nalu.m_nalUnitType == VVENC_NAL_UNIT_PREFIX_APS || |
628 | 1.19k | nalu.m_nalUnitType == VVENC_NAL_UNIT_SUFFIX_APS ) |
629 | 2.39k | { |
630 | 2.39k | sizeSum += 4; |
631 | 2.39k | } |
632 | 1.19k | else |
633 | 1.19k | { |
634 | 1.19k | sizeSum += 3; |
635 | 1.19k | } |
636 | 3.59k | sizeSum += uint32_t(nalu.m_nalUnitData.str().size()); |
637 | 3.59k | } |
638 | 1.19k | } |
639 | | |
640 | 1.19k | return sizeSum; |
641 | 1.19k | } |
642 | | |
643 | | |
644 | | int VVEncImpl::xCopyAu( vvencAccessUnit& rcAccessUnit, const vvenc::AccessUnitList& rcAuList ) |
645 | 1.19k | { |
646 | 1.19k | rcAccessUnit.rap = false; |
647 | | |
648 | 1.19k | std::vector<uint32_t> annexBsizes; |
649 | | |
650 | | /* copy output AU */ |
651 | 1.19k | if ( ! rcAuList.empty() ) |
652 | 1.19k | { |
653 | 1.19k | uint32_t sizeSum = 0; |
654 | 4.79k | for (vvenc::AccessUnitList::const_iterator it = rcAuList.begin(); it != rcAuList.end(); it++) |
655 | 3.59k | { |
656 | 3.59k | const vvenc::NALUnitEBSP& nalu = **it; |
657 | 3.59k | uint32_t size = 0; /* size of annexB unit in bytes */ |
658 | | |
659 | 3.59k | if (it == rcAuList.begin() || |
660 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_DCI || |
661 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_SPS || |
662 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_VPS || |
663 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_PPS || |
664 | 1.19k | nalu.m_nalUnitType == VVENC_NAL_UNIT_PREFIX_APS || |
665 | 1.19k | nalu.m_nalUnitType == VVENC_NAL_UNIT_SUFFIX_APS ) |
666 | 2.39k | { |
667 | 2.39k | size += 4; |
668 | 2.39k | } |
669 | 1.19k | else |
670 | 1.19k | { |
671 | 1.19k | size += 3; |
672 | 1.19k | } |
673 | 3.59k | size += uint32_t(nalu.m_nalUnitData.str().size()); |
674 | 3.59k | sizeSum += size; |
675 | 3.59k | annexBsizes.push_back( size ); |
676 | | |
677 | 3.59k | switch( nalu.m_nalUnitType ) |
678 | 3.59k | { |
679 | 0 | case VVENC_NAL_UNIT_CODED_SLICE_TRAIL: |
680 | 0 | case VVENC_NAL_UNIT_CODED_SLICE_STSA: |
681 | 1.19k | case VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL: |
682 | 1.19k | case VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP: |
683 | 1.19k | case VVENC_NAL_UNIT_CODED_SLICE_CRA: |
684 | 1.19k | case VVENC_NAL_UNIT_CODED_SLICE_GDR: |
685 | 1.19k | case VVENC_NAL_UNIT_CODED_SLICE_RADL: |
686 | 1.19k | case VVENC_NAL_UNIT_CODED_SLICE_RASL: |
687 | 1.19k | case VVENC_NAL_UNIT_DCI: |
688 | 1.19k | case VVENC_NAL_UNIT_VPS: |
689 | 2.39k | case VVENC_NAL_UNIT_SPS: |
690 | 3.59k | case VVENC_NAL_UNIT_PPS: |
691 | 3.59k | case VVENC_NAL_UNIT_PREFIX_APS: |
692 | 3.59k | case VVENC_NAL_UNIT_SUFFIX_APS: |
693 | 3.59k | rcAccessUnit.essentialBytes += size; |
694 | 3.59k | break; |
695 | 0 | default: |
696 | 0 | break; |
697 | 3.59k | } |
698 | 3.59k | } |
699 | | |
700 | 1.19k | if( rcAccessUnit.payloadSize < (int)sizeSum ) |
701 | 0 | { |
702 | 0 | return -1; |
703 | 0 | } |
704 | | |
705 | 1.19k | uint32_t iUsedSize = 0; |
706 | 4.79k | for (vvenc::AccessUnitList::const_iterator it = rcAuList.begin(); it != rcAuList.end(); it++) |
707 | 3.59k | { |
708 | 3.59k | const vvenc::NALUnitEBSP& nalu = **it; |
709 | 3.59k | static const uint8_t start_code_prefix[] = {0,0,0,1}; |
710 | 3.59k | if (it == rcAuList.begin() || |
711 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_DCI || |
712 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_SPS || |
713 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_VPS || |
714 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_PPS || |
715 | 1.19k | nalu.m_nalUnitType == VVENC_NAL_UNIT_PREFIX_APS || |
716 | 1.19k | nalu.m_nalUnitType == VVENC_NAL_UNIT_SUFFIX_APS ) |
717 | 2.39k | { |
718 | | /* From AVC, When any of the following conditions are fulfilled, the |
719 | | * zero_byte syntax element shall be present: |
720 | | * - the nal_unit_type within the nal_unit() is equal to 7 (sequence |
721 | | * parameter set) or 8 (picture parameter set), |
722 | | * - the byte stream NAL unit syntax structure contains the first NAL |
723 | | * unit of an access unit in decoding order, as specified by subclause |
724 | | * 7.4.1.2.3. |
725 | | */ |
726 | 2.39k | ::memcpy( rcAccessUnit.payload + iUsedSize, reinterpret_cast<const char*>(start_code_prefix), 4 ); |
727 | 2.39k | iUsedSize += 4; |
728 | 2.39k | } |
729 | 1.19k | else |
730 | 1.19k | { |
731 | 1.19k | ::memcpy( rcAccessUnit.payload + iUsedSize, reinterpret_cast<const char*>(start_code_prefix+1), 3 ); |
732 | 1.19k | iUsedSize += 3; |
733 | 1.19k | } |
734 | 3.59k | uint32_t nalDataSize = uint32_t(nalu.m_nalUnitData.str().size()) ; |
735 | 3.59k | ::memcpy( rcAccessUnit.payload + iUsedSize, nalu.m_nalUnitData.str().c_str() , nalDataSize ); |
736 | 3.59k | iUsedSize += nalDataSize; |
737 | | |
738 | 3.59k | if( nalu.m_nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_IDR_W_RADL || |
739 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_IDR_N_LP || |
740 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_CRA || |
741 | 2.39k | nalu.m_nalUnitType == VVENC_NAL_UNIT_CODED_SLICE_GDR ) |
742 | 1.19k | { |
743 | 1.19k | rcAccessUnit.rap = true; |
744 | 1.19k | } |
745 | | //rcAccessUnit.nalUnitTypeVec.push_back( nalu.m_nalUnitType ); |
746 | 3.59k | } |
747 | | |
748 | 1.19k | rcAccessUnit.payloadUsedSize = iUsedSize; |
749 | 1.19k | if( iUsedSize != sizeSum ) |
750 | 0 | { |
751 | 0 | return VVENC_NOT_ENOUGH_MEM; |
752 | 0 | } |
753 | | |
754 | | //rcAccessUnit.annexBsizeVec = annexBsizes; |
755 | 1.19k | rcAccessUnit.ctsValid = rcAuList.ctsValid; |
756 | 1.19k | rcAccessUnit.dtsValid = rcAuList.dtsValid; |
757 | 1.19k | rcAccessUnit.cts = rcAuList.cts; |
758 | 1.19k | rcAccessUnit.dts = rcAuList.dts; |
759 | 1.19k | rcAccessUnit.sliceType = (vvencSliceType)rcAuList.sliceType; |
760 | 1.19k | rcAccessUnit.refPic = rcAuList.refPic; |
761 | 1.19k | rcAccessUnit.temporalLayer = rcAuList.temporalLayer; |
762 | 1.19k | rcAccessUnit.poc = rcAuList.poc; |
763 | 1.19k | rcAccessUnit.status = rcAuList.status; |
764 | | #if VVENC_USE_UNSTABLE_API |
765 | | rcAccessUnit.userData = rcAuList.userData; |
766 | | #endif |
767 | | |
768 | 1.19k | if ( !rcAuList.InfoString.empty() ) |
769 | 1.19k | { |
770 | 1.19k | if( rcAuList.InfoString.size() >= VVENC_MAX_STRING_LEN ) |
771 | 0 | { |
772 | 0 | rcAuList.InfoString.copy( rcAccessUnit.infoString , VVENC_MAX_STRING_LEN-1 ); |
773 | 0 | rcAccessUnit.infoString[VVENC_MAX_STRING_LEN-1] = '\0'; |
774 | 0 | } |
775 | 1.19k | else |
776 | 1.19k | { |
777 | 1.19k | rcAuList.InfoString.copy( rcAccessUnit.infoString , rcAuList.InfoString.size()+1 ); |
778 | 1.19k | rcAccessUnit.infoString[rcAuList.InfoString.size()] = '\0'; |
779 | 1.19k | } |
780 | 1.19k | } |
781 | 0 | else |
782 | 0 | { |
783 | 0 | rcAccessUnit.infoString[0] = '\0'; |
784 | 0 | } |
785 | 1.19k | } |
786 | | |
787 | 1.19k | return 0; |
788 | 1.19k | } |
789 | | |
790 | | |
791 | | ///< set message output function for encoder lib. if not set, no messages will be printed. |
792 | | void VVEncImpl::registerMsgCbf( void * ctx, vvencLoggingCallback msgFnc ) |
793 | 0 | { |
794 | | // DEPRECATED |
795 | 0 | g_msgFnc = msgFnc; |
796 | 0 | g_msgFncCtx = ctx; |
797 | 0 | } |
798 | | |
799 | | ///< tries to set given simd extensions used. if not supported by cpu, highest possible extension level will be set and returned. |
800 | | const char* VVEncImpl::setSIMDExtension( const char* simdId ) |
801 | 1.19k | { |
802 | 1.19k | const std::string simdReqStr( simdId ? simdId : "" ); |
803 | | #if ENABLE_SIMD_OPT && ( defined( TARGET_SIMD_X86 ) || defined( TARGET_SIMD_ARM ) ) |
804 | | # if HANDLE_EXCEPTION |
805 | | try |
806 | | # endif // HANDLE_EXCEPTION |
807 | | { |
808 | | # if defined( TARGET_SIMD_ARM ) |
809 | | ARM_VEXT arm_ext = string_to_arm_vext( simdReqStr ); |
810 | | # if defined( TARGET_SIMD_X86 ) |
811 | | // Translate any non-scalar Arm SIMD request to enable SIMDe. |
812 | | X86_VEXT x86_ext = arm_ext == arm_simd::UNDEFINED ? x86_simd::UNDEFINED |
813 | | : arm_ext == arm_simd::SCALAR ? x86_simd::SCALAR |
814 | | : SIMD_EVERYWHERE_EXTENSION_LEVEL; |
815 | | # endif // TARGET_SIMD_X86 |
816 | | try |
817 | | { |
818 | | # if defined( TARGET_SIMD_X86 ) |
819 | | read_x86_extension_flags( x86_ext ); |
820 | | # endif // TARGET_SIMD_X86 |
821 | | read_arm_extension_flags( arm_ext ); |
822 | | } |
823 | | catch( Exception& ) |
824 | | { |
825 | | // Not using the actual message from the exception here, because we need to insert the SIMD-level name instead of |
826 | | // the enum. |
827 | | THROW( "requested SIMD level (" << simdReqStr << ") not supported by current CPU (max " |
828 | | << read_arm_extension_name() << ")." ); |
829 | | } |
830 | | # else // defined( TARGET_SIMD_X86 ) |
831 | | X86_VEXT request_ext = string_to_x86_vext( simdReqStr ); |
832 | | try |
833 | | { |
834 | | read_x86_extension_flags( request_ext ); |
835 | | } |
836 | | catch( Exception& ) |
837 | | { |
838 | | // Not using the actual message from the exception here, because we need to insert the SIMD-level name instead of |
839 | | // the enum. |
840 | | THROW( "requested SIMD level (" << simdReqStr << ") not supported by current CPU (max " |
841 | | << read_x86_extension_name() << ")." ); |
842 | | } |
843 | | # endif // defined( TARGET_SIMD_X86 ) |
844 | | |
845 | | # if ENABLE_SIMD_OPT_BUFFER |
846 | | g_pelBufOP.initPelBufOps(); |
847 | | # endif // ENABLE_SIMD_OPT_BUFFER |
848 | | |
849 | | # if ENABLE_SIMD_TRAFO |
850 | | g_tCoeffOps.initTCoeffOps(); |
851 | | # endif // ENABLE_SIMD_TRAFO |
852 | | |
853 | | # if defined( TARGET_SIMD_ARM ) |
854 | | return read_arm_extension_name().c_str(); |
855 | | # else // !TARGET_SIMD_ARM |
856 | | return read_x86_extension_name().c_str(); |
857 | | # endif // !TARGET_SIMD_ARM |
858 | | } |
859 | | # if HANDLE_EXCEPTION |
860 | | catch( Exception& e ) |
861 | | { |
862 | | MsgLog msg; |
863 | | msg.log( VVENC_ERROR, "\n%s\n", e.what() ); |
864 | | return nullptr; |
865 | | } |
866 | | # endif // HANDLE_EXCEPTION |
867 | | #else // !( ENABLE_SIMD_OPT && ( defined( TARGET_SIMD_X86 ) || defined( TARGET_SIMD_ARM ) ) ) |
868 | 1.19k | if( !simdReqStr.empty() && simdReqStr != "SCALAR" ) |
869 | 0 | { |
870 | 0 | MsgLog msg; |
871 | 0 | msg.log( VVENC_ERROR, "\nVVenC built without SIMD support\n" ); |
872 | 0 | return nullptr; |
873 | 0 | } |
874 | 1.19k | return "SCALAR"; |
875 | 1.19k | #endif // !( ENABLE_SIMD_OPT && ( defined( TARGET_SIMD_X86 ) || defined( TARGET_SIMD_ARM ) ) ) |
876 | 1.19k | } |
877 | | |
878 | | ///< creates compile info string containing OS, Compiler and Bit-depth (e.g. 32 or 64 bit). |
879 | | std::string VVEncImpl::getCompileInfoString() |
880 | 1.19k | { |
881 | 1.19k | std::string info; |
882 | 1.19k | char convBuf[ 256 ]; |
883 | 1.19k | snprintf( convBuf, sizeof( convBuf ), NVM_ONOS ); info += convBuf; |
884 | 1.19k | snprintf( convBuf, sizeof( convBuf ), NVM_COMPILEDBY); info += convBuf; |
885 | 1.19k | snprintf( convBuf, sizeof( convBuf ), NVM_BITS ); info += convBuf; |
886 | 1.19k | return info; |
887 | 1.19k | } |
888 | | |
889 | | std::string VVEncImpl::createEncoderInfoStr() |
890 | 1.19k | { |
891 | 1.19k | std::stringstream cssCap; |
892 | | #if defined( TARGET_SIMD_ARM ) && ENABLE_SIMD_OPT |
893 | | setSIMDExtension( nullptr ); // Ensure SIMD-detection is finished |
894 | | cssCap << getCompileInfoString() << "[SIMD=" << read_arm_extension_name() << "]"; |
895 | | #elif defined( TARGET_SIMD_X86 ) && ENABLE_SIMD_OPT |
896 | | setSIMDExtension( nullptr ); // Ensure SIMD-detection is finished |
897 | | cssCap << getCompileInfoString() << "[SIMD=" << read_x86_extension_name() <<"]"; |
898 | | #else // !TARGET_SIMD_X86 && !TARGET_SIMD_ARM |
899 | 1.19k | cssCap << getCompileInfoString() << "[SIMD=SCALAR]"; |
900 | 1.19k | #endif |
901 | | |
902 | 1.19k | std::string cInfoStr; |
903 | 1.19k | cInfoStr = "VVenC, the Fraunhofer H.266/VVC Encoder, version " VVENC_VERSION; |
904 | 1.19k | cInfoStr += " "; |
905 | 1.19k | cInfoStr += cssCap.str(); |
906 | | |
907 | 1.19k | return cInfoStr; |
908 | 1.19k | } |
909 | | |
910 | | ///< decode bitstream is deprecated and will be removed |
911 | | int VVEncImpl::decodeBitstream( const char* FileName, const char* trcFile, const char* trcRule) |
912 | 0 | { |
913 | 0 | MsgLog msg; |
914 | 0 | msg.log( VVENC_ERROR, "vvenc_decode_bitstream is deprecated and not working anymore." ); |
915 | 0 | return VVENC_ERR_NOT_SUPPORTED; |
916 | 0 | } |
917 | | |
918 | | |
919 | | } // namespace |