/work/libde265/libde265/image.cc
Line | Count | Source |
1 | | /* |
2 | | * H.265 video codec. |
3 | | * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de> |
4 | | * |
5 | | * This file is part of libde265. |
6 | | * |
7 | | * libde265 is free software: you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation, either version 3 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * libde265 is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with libde265. If not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include "image.h" |
22 | | #include "decctx.h" |
23 | | |
24 | | #include <atomic> |
25 | | |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | #include <assert.h> |
29 | | |
30 | | #include <limits> |
31 | | |
32 | | |
33 | | #ifdef HAVE_MALLOC_H |
34 | | #include <malloc.h> |
35 | | #endif |
36 | | |
37 | | #ifdef HAVE_SSE4_1 |
38 | | // SSE code processes 128bit per iteration and thus might read more data |
39 | | // than is later actually used. |
40 | | // NOTE: custom image allocators have to provide this padding too. When increasing |
41 | | // it, update the de265_image_allocation documentation in de265.h accordingly. |
42 | 0 | #define MEMORY_PADDING 16 |
43 | | #else |
44 | | #define MEMORY_PADDING 0 |
45 | | #endif |
46 | | |
47 | 0 | #define STANDARD_ALIGNMENT 16 |
48 | | |
49 | | #if defined(__MINGW32__) |
50 | | #define ALLOC_ALIGNED(alignment, size) __mingw_aligned_malloc((size), (alignment)) |
51 | | #define FREE_ALIGNED(mem) __mingw_aligned_free((mem)) |
52 | | #elif defined(_MSC_VER) |
53 | | #define ALLOC_ALIGNED(alignment, size) _aligned_malloc((size), (alignment)) |
54 | | #define FREE_ALIGNED(mem) _aligned_free((mem)) |
55 | | #elif defined(HAVE_POSIX_MEMALIGN) |
56 | 0 | static inline void *ALLOC_ALIGNED(size_t alignment, size_t size) { |
57 | 0 | void *mem = nullptr; |
58 | 0 | if (posix_memalign(&mem, alignment, size) != 0) { |
59 | 0 | return nullptr; |
60 | 0 | } |
61 | 0 | return mem; |
62 | 0 | }; |
63 | 0 | #define FREE_ALIGNED(mem) free((mem)) |
64 | | #else |
65 | | #define ALLOC_ALIGNED(alignment, size) memalign((alignment), (size)) |
66 | | #define FREE_ALIGNED(mem) free((mem)) |
67 | | #endif |
68 | | |
69 | 0 | #define ALLOC_ALIGNED_16(size) ALLOC_ALIGNED(16, size) |
70 | | |
71 | | LIBDE265_API void* de265_alloc_image_plane(struct de265_image* img, int cIdx, |
72 | | void* inputdata, int inputstride, void *userdata) |
73 | 0 | { |
74 | 0 | int alignment = STANDARD_ALIGNMENT; |
75 | 0 | uint32_t stride = (img->get_width(cIdx) + alignment-1) / alignment * alignment; |
76 | 0 | uint32_t height = img->get_height(cIdx); |
77 | | |
78 | | // size computed in size_t: stride*height can exceed UINT32_MAX for large planes |
79 | 0 | uint8_t* p = static_cast<uint8_t*>(ALLOC_ALIGNED_16(static_cast<size_t>(stride) * height + MEMORY_PADDING)); |
80 | |
|
81 | 0 | if (p==nullptr) { return nullptr; } |
82 | | |
83 | 0 | img->set_image_plane(cIdx, p, stride, userdata); |
84 | | |
85 | | // copy input data if provided |
86 | |
|
87 | 0 | if (inputdata != nullptr) { |
88 | 0 | if (inputstride == static_cast<int>(stride)) { |
89 | 0 | memcpy(p, inputdata, static_cast<size_t>(stride) * height); |
90 | 0 | } |
91 | 0 | else { |
92 | 0 | for (uint32_t y=0;y<height;y++) { |
93 | 0 | memcpy(p + static_cast<size_t>(y) * stride, |
94 | 0 | static_cast<char*>(inputdata) + static_cast<size_t>(inputstride) * y, |
95 | 0 | inputstride); |
96 | 0 | } |
97 | 0 | } |
98 | 0 | } |
99 | |
|
100 | 0 | return p; |
101 | 0 | } |
102 | | |
103 | | |
104 | | LIBDE265_API void de265_free_image_plane(struct de265_image* img, int cIdx) |
105 | 0 | { |
106 | 0 | uint8_t* p = img->get_image_plane(cIdx); |
107 | 0 | assert(p); |
108 | 0 | FREE_ALIGNED(p); |
109 | 0 | } |
110 | | |
111 | | |
112 | | static int de265_image_get_buffer(de265_decoder_context* ctx, |
113 | | de265_image_spec* spec, de265_image* img, void* userdata) |
114 | 0 | { |
115 | 0 | const uint32_t rawChromaWidth = spec->width / img->SubWidthC; |
116 | 0 | const uint32_t rawChromaHeight = spec->height / img->SubHeightC; |
117 | |
|
118 | 0 | uint32_t luma_stride = (spec->width + spec->alignment-1) / spec->alignment * spec->alignment; |
119 | 0 | uint32_t chroma_stride = (rawChromaWidth + spec->alignment-1) / spec->alignment * spec->alignment; |
120 | |
|
121 | 0 | assert(img->BitDepth_Y >= 8 && img->BitDepth_Y <= 16); |
122 | 0 | assert(img->BitDepth_C >= 8 && img->BitDepth_C <= 16); |
123 | | |
124 | 0 | uint32_t luma_bpl = luma_stride * ((img->BitDepth_Y+7)/8); |
125 | 0 | uint32_t chroma_bpl = chroma_stride * ((img->BitDepth_C+7)/8); |
126 | |
|
127 | 0 | uint32_t luma_height = spec->height; |
128 | 0 | uint32_t chroma_height = rawChromaHeight; |
129 | |
|
130 | 0 | bool alloc_failed = false; |
131 | | |
132 | | // Compute the plane sizes in size_t. Each operand fits in uint32_t, but the |
133 | | // height * bytes-per-line product can exceed UINT32_MAX for large frames, so |
134 | | // the multiplication must be done in 64 bits. Computing it in 32 bits wraps |
135 | | // the allocation size to a small value while fill_image() later writes the |
136 | | // real (size_t) size -> heap buffer overflow (GHSA-vv8h-932h-7r86). |
137 | 0 | uint8_t* p[3] = { nullptr,nullptr,nullptr }; |
138 | 0 | p[0] = static_cast<uint8_t*>(ALLOC_ALIGNED_16(static_cast<size_t>(luma_height) * luma_bpl + MEMORY_PADDING)); |
139 | 0 | if (p[0]==nullptr) { alloc_failed=true; } |
140 | |
|
141 | 0 | if (img->get_chroma_format() != de265_chroma_mono) { |
142 | 0 | p[1] = static_cast<uint8_t*>(ALLOC_ALIGNED_16(static_cast<size_t>(chroma_height) * chroma_bpl + MEMORY_PADDING)); |
143 | 0 | p[2] = static_cast<uint8_t*>(ALLOC_ALIGNED_16(static_cast<size_t>(chroma_height) * chroma_bpl + MEMORY_PADDING)); |
144 | |
|
145 | 0 | if (p[1]==nullptr || p[2]==nullptr) { alloc_failed=true; } |
146 | 0 | } |
147 | 0 | else { |
148 | 0 | p[1] = nullptr; |
149 | 0 | p[2] = nullptr; |
150 | 0 | chroma_stride = 0; |
151 | 0 | } |
152 | |
|
153 | 0 | if (alloc_failed) { |
154 | 0 | for (int i=0;i<3;i++) |
155 | 0 | if (p[i]) { |
156 | 0 | FREE_ALIGNED(p[i]); |
157 | 0 | } |
158 | |
|
159 | 0 | return 0; |
160 | 0 | } |
161 | | |
162 | 0 | img->set_image_plane(0, p[0], luma_stride, nullptr); |
163 | 0 | img->set_image_plane(1, p[1], chroma_stride, nullptr); |
164 | 0 | img->set_image_plane(2, p[2], chroma_stride, nullptr); |
165 | |
|
166 | 0 | img->fill_image(0,0,0); |
167 | |
|
168 | 0 | return 1; |
169 | 0 | } |
170 | | |
171 | | static void de265_image_release_buffer(de265_decoder_context* ctx, |
172 | | de265_image* img, void* userdata) |
173 | 0 | { |
174 | 0 | for (int i=0;i<3;i++) { |
175 | 0 | uint8_t* p = img->get_image_plane(i); |
176 | 0 | if (p) { |
177 | 0 | FREE_ALIGNED(p); |
178 | 0 | } |
179 | 0 | } |
180 | 0 | } |
181 | | |
182 | | |
183 | | de265_image_allocation de265_image::default_image_allocation = { |
184 | | de265_image_get_buffer, |
185 | | de265_image_release_buffer |
186 | | }; |
187 | | |
188 | | |
189 | | void de265_image::set_image_plane(int cIdx, uint8_t* mem, ptrdiff_t stride, void *userdata) |
190 | 0 | { |
191 | 0 | pixels[cIdx] = mem; |
192 | 0 | plane_user_data[cIdx] = userdata; |
193 | |
|
194 | 0 | if (cIdx==0) { this->stride = stride; } |
195 | 0 | else { this->chroma_stride = stride; } |
196 | 0 | } |
197 | | |
198 | | |
199 | 0 | de265_image::de265_image() = default; |
200 | | |
201 | | |
202 | | de265_error de265_image::alloc_image(int w,int h, enum de265_chroma c, |
203 | | std::shared_ptr<const seq_parameter_set> sps, bool allocMetadata, |
204 | | decoder_context* dctx, |
205 | | //encoder_context* ectx, |
206 | | de265_PTS pts, void* user_data, |
207 | | bool useCustomAllocFunc) |
208 | 0 | { |
209 | | //if (allocMetadata) { assert(sps); } |
210 | 0 | if (allocMetadata) { assert(sps); } |
211 | | |
212 | 0 | if (sps) { this->sps = sps; } |
213 | |
|
214 | 0 | release(); /* TODO: review code for efficient allocation when arrays are already |
215 | | allocated to the requested size. Without the release, the old image-data |
216 | | will not be freed. */ |
217 | |
|
218 | 0 | static std::atomic<uint32_t> s_next_image_ID(0); |
219 | 0 | ID = s_next_image_ID++; |
220 | 0 | removed_at_picture_id = std::numeric_limits<uint32_t>::max(); |
221 | |
|
222 | 0 | decctx = dctx; |
223 | | //encctx = ectx; |
224 | | |
225 | | // --- allocate image buffer --- |
226 | |
|
227 | 0 | chroma_format= c; |
228 | |
|
229 | 0 | width = w; |
230 | 0 | height = h; |
231 | 0 | chroma_width = w; |
232 | 0 | chroma_height= h; |
233 | |
|
234 | 0 | this->user_data = user_data; |
235 | 0 | this->pts = pts; |
236 | |
|
237 | 0 | de265_image_spec spec; |
238 | |
|
239 | 0 | uint8_t WinUnitX, WinUnitY; |
240 | |
|
241 | 0 | switch (chroma_format) { |
242 | 0 | case de265_chroma_mono: WinUnitX=1; WinUnitY=1; break; |
243 | 0 | case de265_chroma_420: WinUnitX=2; WinUnitY=2; break; |
244 | 0 | case de265_chroma_422: WinUnitX=2; WinUnitY=1; break; |
245 | 0 | case de265_chroma_444: WinUnitX=1; WinUnitY=1; break; |
246 | 0 | default: |
247 | 0 | assert(0); |
248 | 0 | WinUnitX = WinUnitY = 0; |
249 | 0 | } |
250 | | |
251 | 0 | switch (chroma_format) { |
252 | 0 | case de265_chroma_420: |
253 | 0 | spec.format = de265_image_format_YUV420P8; |
254 | 0 | chroma_width = (chroma_width +1)/2; |
255 | 0 | chroma_height = (chroma_height+1)/2; |
256 | 0 | SubWidthC = 2; |
257 | 0 | SubHeightC = 2; |
258 | 0 | break; |
259 | | |
260 | 0 | case de265_chroma_422: |
261 | 0 | spec.format = de265_image_format_YUV422P8; |
262 | 0 | chroma_width = (chroma_width+1)/2; |
263 | 0 | SubWidthC = 2; |
264 | 0 | SubHeightC = 1; |
265 | 0 | break; |
266 | | |
267 | 0 | case de265_chroma_444: |
268 | 0 | spec.format = de265_image_format_YUV444P8; |
269 | 0 | SubWidthC = 1; |
270 | 0 | SubHeightC = 1; |
271 | 0 | break; |
272 | | |
273 | 0 | case de265_chroma_mono: |
274 | 0 | spec.format = de265_image_format_mono8; |
275 | 0 | chroma_width = 0; |
276 | 0 | chroma_height= 0; |
277 | 0 | SubWidthC = 1; |
278 | 0 | SubHeightC = 1; |
279 | 0 | break; |
280 | | |
281 | 0 | default: |
282 | 0 | assert(false); |
283 | 0 | break; |
284 | 0 | } |
285 | | |
286 | 0 | if (chroma_format != de265_chroma_mono && sps) { |
287 | 0 | assert(sps->SubWidthC == SubWidthC); |
288 | 0 | assert(sps->SubHeightC == SubHeightC); |
289 | 0 | } |
290 | | |
291 | 0 | spec.width = w; |
292 | 0 | spec.height = h; |
293 | 0 | spec.alignment = STANDARD_ALIGNMENT; |
294 | | |
295 | | |
296 | | // conformance window cropping |
297 | |
|
298 | 0 | int left = sps ? sps->conf_win_left_offset : 0; |
299 | 0 | int right = sps ? sps->conf_win_right_offset : 0; |
300 | 0 | int top = sps ? sps->conf_win_top_offset : 0; |
301 | 0 | int bottom = sps ? sps->conf_win_bottom_offset : 0; |
302 | |
|
303 | 0 | if ((left+right)*WinUnitX >= width) { |
304 | 0 | return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE; |
305 | 0 | } |
306 | | |
307 | 0 | if ((top+bottom)*WinUnitY >= height) { |
308 | 0 | return DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE; |
309 | 0 | } |
310 | | |
311 | 0 | width_confwin = width - (left+right)*WinUnitX; |
312 | 0 | height_confwin= height- (top+bottom)*WinUnitY; |
313 | 0 | chroma_width_confwin = chroma_width -left-right; |
314 | 0 | chroma_height_confwin= chroma_height-top-bottom; |
315 | |
|
316 | 0 | spec.crop_left = left *WinUnitX; |
317 | 0 | spec.crop_right = right*WinUnitX; |
318 | 0 | spec.crop_top = top *WinUnitY; |
319 | 0 | spec.crop_bottom= bottom*WinUnitY; |
320 | |
|
321 | 0 | spec.visible_width = width_confwin; |
322 | 0 | spec.visible_height= height_confwin; |
323 | | |
324 | |
|
325 | 0 | BitDepth_Y = (sps==nullptr) ? 8 : sps->BitDepth_Y; |
326 | 0 | BitDepth_C = (sps==nullptr) ? 8 : sps->BitDepth_C; |
327 | |
|
328 | 0 | bpp_shift[0] = (BitDepth_Y <= 8) ? 0 : 1; |
329 | 0 | bpp_shift[1] = (BitDepth_C <= 8) ? 0 : 1; |
330 | 0 | bpp_shift[2] = bpp_shift[1]; |
331 | | |
332 | | |
333 | | // allocate memory and set conformance window pointers |
334 | |
|
335 | 0 | void* alloc_userdata = nullptr; |
336 | 0 | if (decctx) alloc_userdata = decctx->param_image_allocation_userdata; |
337 | | // if (encctx) alloc_userdata = encctx->param_image_allocation_userdata; // actually not needed |
338 | | |
339 | | /* |
340 | | if (encctx && useCustomAllocFunc) { |
341 | | encoder_image_release_func = encctx->release_func; |
342 | | |
343 | | // if we do not provide a release function, use our own |
344 | | |
345 | | if (encoder_image_release_func == nullptr) { |
346 | | image_allocation_functions = de265_image::default_image_allocation; |
347 | | } |
348 | | else { |
349 | | image_allocation_functions.get_buffer = nullptr; |
350 | | image_allocation_functions.release_buffer = nullptr; |
351 | | } |
352 | | } |
353 | 0 | else*/ if (decctx && useCustomAllocFunc) { |
354 | 0 | image_allocation_functions = decctx->param_image_allocation_functions; |
355 | 0 | } |
356 | 0 | else { |
357 | 0 | image_allocation_functions = de265_image::default_image_allocation; |
358 | 0 | } |
359 | |
|
360 | 0 | bool mem_alloc_success = true; |
361 | |
|
362 | 0 | if (image_allocation_functions.get_buffer != nullptr) { |
363 | 0 | mem_alloc_success = image_allocation_functions.get_buffer(decctx, &spec, this, |
364 | 0 | alloc_userdata); |
365 | | |
366 | | // check for memory shortage |
367 | |
|
368 | 0 | if (!mem_alloc_success) |
369 | 0 | { |
370 | 0 | return DE265_ERROR_OUT_OF_MEMORY; |
371 | 0 | } |
372 | | |
373 | | // The strides count samples, not bytes. The accessor scales the whole offset |
374 | | // to bytes for images with more than 8 bits. |
375 | | |
376 | 0 | pixels_confwin[0] = static_cast<uint8_t*>(get_image_plane_at_pos_any_depth(0, left*WinUnitX, top*WinUnitY)); |
377 | |
|
378 | 0 | if (chroma_format != de265_chroma_mono) { |
379 | 0 | pixels_confwin[1] = static_cast<uint8_t*>(get_image_plane_at_pos_any_depth(1, left, top)); |
380 | 0 | pixels_confwin[2] = static_cast<uint8_t*>(get_image_plane_at_pos_any_depth(2, left, top)); |
381 | 0 | } |
382 | 0 | else { |
383 | 0 | pixels_confwin[1] = nullptr; |
384 | 0 | pixels_confwin[2] = nullptr; |
385 | 0 | } |
386 | 0 | } |
387 | | |
388 | | //alloc_functions = *allocfunc; |
389 | | //alloc_userdata = userdata; |
390 | | |
391 | | // --- allocate decoding info arrays --- |
392 | | |
393 | 0 | if (allocMetadata) { |
394 | | // intra pred mode |
395 | |
|
396 | 0 | mem_alloc_success &= intraPredMode.alloc(sps->PicWidthInMinPUs, sps->PicHeightInMinPUs, |
397 | 0 | sps->Log2MinPUSize); |
398 | |
|
399 | 0 | mem_alloc_success &= intraPredModeC.alloc(sps->PicWidthInMinPUs, sps->PicHeightInMinPUs, |
400 | 0 | sps->Log2MinPUSize); |
401 | | |
402 | | // cb info |
403 | |
|
404 | 0 | mem_alloc_success &= cb_info.alloc(sps->PicWidthInMinCbsY, sps->PicHeightInMinCbsY, |
405 | 0 | sps->Log2MinCbSizeY); |
406 | | |
407 | | // pb info |
408 | |
|
409 | 0 | int puWidth = sps->PicWidthInMinCbsY << (sps->Log2MinCbSizeY -2); |
410 | 0 | int puHeight = sps->PicHeightInMinCbsY << (sps->Log2MinCbSizeY -2); |
411 | |
|
412 | 0 | mem_alloc_success &= pb_info.alloc(puWidth,puHeight, 2); |
413 | | |
414 | | |
415 | | // tu info |
416 | |
|
417 | 0 | mem_alloc_success &= tu_info.alloc(sps->PicWidthInTbsY, sps->PicHeightInTbsY, |
418 | 0 | sps->Log2MinTrafoSize); |
419 | | |
420 | | // deblk info |
421 | |
|
422 | 0 | int deblk_w = (sps->pic_width_in_luma_samples +3)/4; |
423 | 0 | int deblk_h = (sps->pic_height_in_luma_samples+3)/4; |
424 | |
|
425 | 0 | mem_alloc_success &= deblk_info.alloc(deblk_w, deblk_h, 2); |
426 | | |
427 | | // CTB info |
428 | |
|
429 | 0 | if (ctb_info.width_in_units != sps->PicWidthInCtbsY || |
430 | 0 | ctb_info.height_in_units != sps->PicHeightInCtbsY || |
431 | 0 | ctb_info.log2unitSize != sps->Log2CtbSizeY) |
432 | 0 | { |
433 | 0 | delete[] ctb_progress; |
434 | |
|
435 | 0 | mem_alloc_success &= ctb_info.alloc(sps->PicWidthInCtbsY, sps->PicHeightInCtbsY, |
436 | 0 | sps->Log2CtbSizeY); |
437 | |
|
438 | 0 | ctb_progress = new de265_progress_lock[ ctb_info.data_size ]; |
439 | 0 | } |
440 | | |
441 | | |
442 | | // check for memory shortage |
443 | |
|
444 | 0 | if (!mem_alloc_success) |
445 | 0 | { |
446 | 0 | return DE265_ERROR_OUT_OF_MEMORY; |
447 | 0 | } |
448 | 0 | } |
449 | | |
450 | 0 | return DE265_OK; |
451 | 0 | } |
452 | | |
453 | | |
454 | | de265_image::~de265_image() |
455 | 0 | { |
456 | 0 | release(); |
457 | | |
458 | | // free progress locks |
459 | |
|
460 | 0 | if (ctb_progress) { |
461 | 0 | delete[] ctb_progress; |
462 | 0 | } |
463 | 0 | } |
464 | | |
465 | | |
466 | | void de265_image::release() |
467 | 0 | { |
468 | | // free image memory |
469 | |
|
470 | 0 | if (pixels[0]) |
471 | 0 | { |
472 | | /* |
473 | | if (encoder_image_release_func != nullptr) { |
474 | | encoder_image_release_func(encctx, this, |
475 | | encctx->param_image_allocation_userdata); |
476 | | } |
477 | 0 | else*/ { |
478 | 0 | image_allocation_functions.release_buffer(decctx, this, |
479 | 0 | decctx ? |
480 | 0 | decctx->param_image_allocation_userdata : |
481 | 0 | nullptr); |
482 | 0 | } |
483 | |
|
484 | 0 | for (int i=0;i<3;i++) |
485 | 0 | { |
486 | 0 | pixels[i] = nullptr; |
487 | 0 | pixels_confwin[i] = nullptr; |
488 | 0 | } |
489 | 0 | } |
490 | | |
491 | | // free slices |
492 | |
|
493 | 0 | for (size_t i=0;i<slices.size();i++) { |
494 | 0 | delete slices[i]; |
495 | 0 | } |
496 | 0 | slices.clear(); |
497 | 0 | } |
498 | | |
499 | | |
500 | | void de265_image::fill_plane(int channel, int value) |
501 | 0 | { |
502 | 0 | int bytes_per_pixel = get_bytes_per_pixel(channel); |
503 | 0 | assert(value >= 0); // needed for the shift operation in the check below |
504 | | |
505 | | // Each plane is allocated with MEMORY_PADDING trailing bytes for safe SSE overread; the |
506 | | // memsets below cover that padding too so it never contains uninitialized heap data. |
507 | 0 | const size_t plane_bytes = |
508 | 0 | (channel == 0 ? static_cast<size_t>(stride) * height |
509 | 0 | : static_cast<size_t>(chroma_stride) * chroma_height) |
510 | 0 | * bytes_per_pixel; |
511 | |
|
512 | 0 | if (bytes_per_pixel == 1) { |
513 | 0 | memset(pixels[channel], value, plane_bytes + MEMORY_PADDING); |
514 | 0 | } |
515 | 0 | else if ((value >> 8) == (value & 0xFF)) { |
516 | 0 | assert(bytes_per_pixel == 2); |
517 | | |
518 | | // if we fill the same byte value to all bytes, we can still use memset() |
519 | 0 | memset(pixels[channel], value & 0xFF, plane_bytes + MEMORY_PADDING); |
520 | 0 | } |
521 | 0 | else { |
522 | 0 | assert(bytes_per_pixel == 2); |
523 | 0 | uint16_t v = value; |
524 | | |
525 | | // Fill whole rows including the stride padding. This covers every byte of the |
526 | | // plane, so no part of it is left with whatever the image allocator handed us. |
527 | |
|
528 | 0 | const ptrdiff_t row_width = (channel==0 ? stride : chroma_stride); |
529 | 0 | const int nRows = (channel==0 ? height : chroma_height); |
530 | | |
531 | | // copy value into first row |
532 | 0 | for (ptrdiff_t x = 0; x < row_width; x++) { |
533 | 0 | *reinterpret_cast<uint16_t*>(&pixels[channel][2 * x]) = v; |
534 | 0 | } |
535 | | |
536 | | // copy first row into remaining rows |
537 | 0 | for (int y = 1; y < nRows; y++) { |
538 | 0 | memcpy(pixels[channel] + y * row_width * 2, pixels[channel], row_width * 2); |
539 | 0 | } |
540 | |
|
541 | 0 | #if MEMORY_PADDING > 0 |
542 | 0 | memset(pixels[channel] + plane_bytes, 0, MEMORY_PADDING); |
543 | 0 | #endif |
544 | 0 | } |
545 | 0 | } |
546 | | |
547 | | |
548 | | void de265_image::fill_image(int y,int cb,int cr) |
549 | 0 | { |
550 | 0 | if (pixels[0]) { |
551 | 0 | fill_plane(0, y); |
552 | 0 | } |
553 | |
|
554 | 0 | if (pixels[1]) { |
555 | 0 | fill_plane(1, cb); |
556 | 0 | } |
557 | |
|
558 | 0 | if (pixels[2]) { |
559 | 0 | fill_plane(2, cr); |
560 | 0 | } |
561 | 0 | } |
562 | | |
563 | | |
564 | | de265_error de265_image::copy_image(const de265_image* src) |
565 | 0 | { |
566 | | /* TODO: actually, since we allocate the image only for internal purpose, we |
567 | | do not have to call the external allocation routines for this. However, then |
568 | | we have to track for each image how to release it again. |
569 | | Another option would be to safe the copied data not in an de265_image at all. |
570 | | */ |
571 | |
|
572 | 0 | de265_error err = alloc_image(src->width, src->height, src->chroma_format, src->sps, false, |
573 | 0 | src->decctx, /*src->encctx,*/ src->pts, src->user_data, false); |
574 | 0 | if (err != DE265_OK) { |
575 | 0 | return err; |
576 | 0 | } |
577 | | |
578 | 0 | copy_lines_from(src, 0, src->height); |
579 | |
|
580 | 0 | return err; |
581 | 0 | } |
582 | | |
583 | | |
584 | | // end = last line + 1 |
585 | | void de265_image::copy_lines_from(const de265_image* src, int first, int end) |
586 | 0 | { |
587 | 0 | if (end > src->height) end=src->height; |
588 | |
|
589 | 0 | assert(first % 2 == 0); |
590 | 0 | assert(end % 2 == 0); |
591 | | |
592 | 0 | int luma_bpp = (sps->BitDepth_Y+7)/8; |
593 | 0 | int chroma_bpp = (sps->BitDepth_C+7)/8; |
594 | |
|
595 | 0 | if (src->stride == stride) { |
596 | 0 | memcpy(pixels[0] + first*stride * luma_bpp, |
597 | 0 | src->pixels[0] + first*src->stride * luma_bpp, |
598 | 0 | (end-first)*stride * luma_bpp); |
599 | 0 | } |
600 | 0 | else { |
601 | 0 | for (int yp=first;yp<end;yp++) { |
602 | 0 | memcpy(pixels[0]+yp*stride * luma_bpp, |
603 | 0 | src->pixels[0]+yp*src->stride * luma_bpp, |
604 | 0 | src->width * luma_bpp); |
605 | 0 | } |
606 | 0 | } |
607 | |
|
608 | 0 | int first_chroma = first / src->SubHeightC; |
609 | 0 | int end_chroma = end / src->SubHeightC; |
610 | |
|
611 | 0 | if (src->chroma_format != de265_chroma_mono) { |
612 | 0 | if (src->chroma_stride == chroma_stride) { |
613 | 0 | memcpy(pixels[1] + first_chroma*chroma_stride * chroma_bpp, |
614 | 0 | src->pixels[1] + first_chroma*chroma_stride * chroma_bpp, |
615 | 0 | (end_chroma-first_chroma) * chroma_stride * chroma_bpp); |
616 | 0 | memcpy(pixels[2] + first_chroma*chroma_stride * chroma_bpp, |
617 | 0 | src->pixels[2] + first_chroma*chroma_stride * chroma_bpp, |
618 | 0 | (end_chroma-first_chroma) * chroma_stride * chroma_bpp); |
619 | 0 | } |
620 | 0 | else { |
621 | 0 | for (int y=first_chroma;y<end_chroma;y++) { |
622 | 0 | memcpy(pixels[1]+y*chroma_stride * chroma_bpp, |
623 | 0 | src->pixels[1]+y*src->chroma_stride * chroma_bpp, |
624 | 0 | src->chroma_width * chroma_bpp); |
625 | 0 | memcpy(pixels[2]+y*chroma_stride * chroma_bpp, |
626 | 0 | src->pixels[2]+y*src->chroma_stride * chroma_bpp, |
627 | 0 | src->chroma_width * chroma_bpp); |
628 | 0 | } |
629 | 0 | } |
630 | 0 | } |
631 | 0 | } |
632 | | |
633 | | |
634 | | void de265_image::exchange_pixel_data_with(de265_image& b) |
635 | 0 | { |
636 | 0 | for (int i=0;i<3;i++) { |
637 | 0 | std::swap(pixels[i], b.pixels[i]); |
638 | 0 | std::swap(pixels_confwin[i], b.pixels_confwin[i]); |
639 | 0 | std::swap(plane_user_data[i], b.plane_user_data[i]); |
640 | 0 | } |
641 | |
|
642 | 0 | std::swap(stride, b.stride); |
643 | 0 | std::swap(chroma_stride, b.chroma_stride); |
644 | 0 | std::swap(image_allocation_functions, b.image_allocation_functions); |
645 | 0 | } |
646 | | |
647 | | |
648 | | void de265_image::thread_start(int nThreads) |
649 | 0 | { |
650 | 0 | std::unique_lock<std::mutex> lock(mutex); |
651 | | |
652 | | //printf("nThreads before: %d %d\n",nThreadsQueued, nThreadsTotal); |
653 | |
|
654 | 0 | nThreadsQueued += nThreads; |
655 | 0 | nThreadsTotal += nThreads; |
656 | | |
657 | | //printf("nThreads after: %d %d\n",nThreadsQueued, nThreadsTotal); |
658 | 0 | } |
659 | | |
660 | | void de265_image::thread_run(const thread_task* task) |
661 | 0 | { |
662 | 0 | std::unique_lock<std::mutex> lock(mutex); |
663 | | |
664 | | //printf("run thread %s\n", task->name().c_str()); |
665 | |
|
666 | 0 | nThreadsQueued--; |
667 | 0 | nThreadsRunning++; |
668 | 0 | } |
669 | | |
670 | | void de265_image::thread_blocks() |
671 | 0 | { |
672 | 0 | std::unique_lock<std::mutex> lock(mutex); |
673 | |
|
674 | 0 | nThreadsRunning--; |
675 | 0 | nThreadsBlocked++; |
676 | 0 | } |
677 | | |
678 | | void de265_image::thread_unblocks() |
679 | 0 | { |
680 | 0 | std::unique_lock<std::mutex> lock(mutex); |
681 | |
|
682 | 0 | nThreadsBlocked--; |
683 | 0 | nThreadsRunning++; |
684 | 0 | } |
685 | | |
686 | | void de265_image::thread_finishes(const thread_task* task) |
687 | 0 | { |
688 | | //printf("finish thread %s\n", task->name().c_str()); |
689 | |
|
690 | 0 | std::unique_lock<std::mutex> lock(mutex); |
691 | |
|
692 | 0 | nThreadsRunning--; |
693 | 0 | nThreadsFinished++; |
694 | 0 | assert(nThreadsRunning >= 0); |
695 | | |
696 | 0 | if (nThreadsFinished==nThreadsTotal) { |
697 | 0 | finished_cond.notify_all(); |
698 | 0 | } |
699 | 0 | } |
700 | | |
701 | | void de265_image::wait_for_progress(thread_task* task, int ctbx,int ctby, int progress) |
702 | 0 | { |
703 | 0 | const int ctbW = sps->PicWidthInCtbsY; |
704 | |
|
705 | 0 | wait_for_progress(task, ctbx + ctbW*ctby, progress); |
706 | 0 | } |
707 | | |
708 | | void de265_image::wait_for_progress(thread_task* task, int ctbAddrRS, int progress) |
709 | 0 | { |
710 | 0 | if (task==nullptr) { return; } |
711 | | |
712 | 0 | de265_progress_lock* progresslock = &ctb_progress[ctbAddrRS]; |
713 | 0 | if (progresslock->get_progress() < progress) { |
714 | 0 | thread_blocks(); |
715 | |
|
716 | 0 | assert(task!=nullptr); |
717 | 0 | task->state = thread_task::Blocked; |
718 | | |
719 | | /* TODO: check whether we are the first blocked task in the list. |
720 | | If we are, we have to conceal input errors. |
721 | | Simplest concealment: do not block. |
722 | | */ |
723 | |
|
724 | 0 | progresslock->wait_for_progress(progress); |
725 | 0 | task->state = thread_task::Running; |
726 | 0 | thread_unblocks(); |
727 | 0 | } |
728 | 0 | } |
729 | | |
730 | | |
731 | | void de265_image::wait_for_completion() |
732 | 0 | { |
733 | 0 | std::unique_lock<std::mutex> lock(mutex); |
734 | |
|
735 | 0 | while (nThreadsFinished!=nThreadsTotal) { |
736 | 0 | finished_cond.wait(lock); |
737 | 0 | } |
738 | 0 | } |
739 | | |
740 | | bool de265_image::debug_is_completed() const |
741 | 0 | { |
742 | 0 | return nThreadsFinished==nThreadsTotal; |
743 | 0 | } |
744 | | |
745 | | |
746 | | |
747 | | void de265_image::clear_metadata() |
748 | 0 | { |
749 | | // TODO: maybe we could avoid the memset by ensuring that all data is written to |
750 | | // during decoding (especially log2CbSize), but it is unlikely to be faster than the memset. |
751 | |
|
752 | 0 | cb_info.clear(); |
753 | 0 | intraPredMode.clear(); |
754 | | //tu_info.clear(); // done on the fly |
755 | 0 | ctb_info.clear(); |
756 | 0 | deblk_info.clear(); |
757 | | |
758 | | // --- reset CTB progresses --- |
759 | |
|
760 | 0 | for (int i=0;i<ctb_info.data_size;i++) { |
761 | 0 | ctb_progress[i].reset(CTB_PROGRESS_NONE); |
762 | 0 | } |
763 | 0 | } |
764 | | |
765 | | |
766 | | void de265_image::set_mv_info(int x,int y, int nPbW,int nPbH, const PBMotion& mv) |
767 | 0 | { |
768 | 0 | int log2PuSize = 2; |
769 | |
|
770 | 0 | int xPu = x >> log2PuSize; |
771 | 0 | int yPu = y >> log2PuSize; |
772 | 0 | int wPu = nPbW >> log2PuSize; |
773 | 0 | int hPu = nPbH >> log2PuSize; |
774 | |
|
775 | 0 | int stride = pb_info.width_in_units; |
776 | |
|
777 | 0 | for (int pby=0;pby<hPu;pby++) |
778 | 0 | for (int pbx=0;pbx<wPu;pbx++) |
779 | 0 | { |
780 | 0 | pb_info[ xPu+pbx + (yPu+pby)*stride ] = mv; |
781 | 0 | } |
782 | 0 | } |
783 | | |
784 | | |
785 | | bool de265_image::available_zscan(int xCurr,int yCurr, int xN,int yN) const |
786 | 0 | { |
787 | 0 | if (xN<0 || yN<0) return false; |
788 | 0 | if (xN>=sps->pic_width_in_luma_samples || |
789 | 0 | yN>=sps->pic_height_in_luma_samples) return false; |
790 | | |
791 | 0 | int minBlockAddrN = pps->scan->MinTbAddrZS[ (xN>>sps->Log2MinTrafoSize) + |
792 | 0 | (yN>>sps->Log2MinTrafoSize) * sps->PicWidthInTbsY ]; |
793 | 0 | int minBlockAddrCurr = pps->scan->MinTbAddrZS[ (xCurr>>sps->Log2MinTrafoSize) + |
794 | 0 | (yCurr>>sps->Log2MinTrafoSize) * sps->PicWidthInTbsY ]; |
795 | |
|
796 | 0 | if (minBlockAddrN > minBlockAddrCurr) return false; |
797 | | |
798 | 0 | int xCurrCtb = xCurr >> sps->Log2CtbSizeY; |
799 | 0 | int yCurrCtb = yCurr >> sps->Log2CtbSizeY; |
800 | 0 | int xNCtb = xN >> sps->Log2CtbSizeY; |
801 | 0 | int yNCtb = yN >> sps->Log2CtbSizeY; |
802 | |
|
803 | 0 | if (get_SliceAddrRS(xCurrCtb,yCurrCtb) != |
804 | 0 | get_SliceAddrRS(xNCtb, yNCtb)) { |
805 | 0 | return false; |
806 | 0 | } |
807 | | |
808 | 0 | if (pps->scan->TileIdRS[xCurrCtb + yCurrCtb*sps->PicWidthInCtbsY] != |
809 | 0 | pps->scan->TileIdRS[xNCtb + yNCtb *sps->PicWidthInCtbsY]) { |
810 | 0 | return false; |
811 | 0 | } |
812 | | |
813 | 0 | return true; |
814 | 0 | } |
815 | | |
816 | | |
817 | | bool de265_image::available_pred_blk(int xC,int yC, int nCbS, int xP, int yP, |
818 | | int nPbW, int nPbH, int partIdx, int xN,int yN) const |
819 | 0 | { |
820 | 0 | logtrace(LogMotion,"C:%d;%d P:%d;%d N:%d;%d size=%d;%d\n",xC,yC,xP,yP,xN,yN,nPbW,nPbH); |
821 | |
|
822 | 0 | int sameCb = (xC <= xN && xN < xC+nCbS && |
823 | 0 | yC <= yN && yN < yC+nCbS); |
824 | |
|
825 | 0 | bool availableN; |
826 | |
|
827 | 0 | if (!sameCb) { |
828 | 0 | availableN = available_zscan(xP,yP,xN,yN); |
829 | 0 | } |
830 | 0 | else { |
831 | 0 | availableN = !(nPbW<<1 == nCbS && nPbH<<1 == nCbS && // NxN |
832 | 0 | partIdx==1 && |
833 | 0 | yN >= yC+nPbH && xN < xC+nPbW); // xN/yN inside partIdx 2 |
834 | 0 | } |
835 | |
|
836 | 0 | if (availableN && get_pred_mode(xN,yN) == MODE_INTRA) { |
837 | 0 | availableN = false; |
838 | 0 | } |
839 | |
|
840 | 0 | return availableN; |
841 | 0 | } |