From 1378c8e67112c6cfe6414ae6b51e2862cb4c2baf Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 29 Mar 2022 13:55:52 +0200 Subject: [PATCH] Fixed #7753: Step calculation in YUV decoder (#7758) * Fixed #7753: Step calculation in YUV decoder * Fixed rectangle_is_empty * Added rectangle intersection check in YUV decoder * Skip intersecting rectangles in YUV decoder * Refactored YUV work object handling * Allocate / free in yuv_context_new and yuv_context_free * WINPR_ASSERT all function arguments * Pass yuv_context_reset result from h264_context_reset * Reset PTP_WORK buffer to NULL after use --- channels/video/client/video_main.c | 3 +- include/freerdp/codec/yuv.h | 2 +- libfreerdp/codec/h264.c | 4 +- libfreerdp/codec/region.c | 4 +- libfreerdp/codec/yuv.c | 341 ++++++++++++++++++++--------- 5 files changed, 249 insertions(+), 105 deletions(-) diff --git a/channels/video/client/video_main.c b/channels/video/client/video_main.c index ed69c06a4..422b3538a 100644 --- a/channels/video/client/video_main.c +++ b/channels/video/client/video_main.c @@ -219,7 +219,8 @@ static PresentationContext* PresentationContext_new(VideoClientContext* video, B WLog_ERR(TAG, "unable to create a h264 context"); goto fail; } - h264_context_reset(ret->h264, width, height); + if (!h264_context_reset(ret->h264, width, height)) + goto fail; ret->currentSample = Stream_New(NULL, 4096); if (!ret->currentSample) diff --git a/include/freerdp/codec/yuv.h b/include/freerdp/codec/yuv.h index be5ba81ab..adf056f6f 100644 --- a/include/freerdp/codec/yuv.h +++ b/include/freerdp/codec/yuv.h @@ -52,7 +52,7 @@ extern "C" BYTE* pYUVChromaData[3], const RECTANGLE_16* regionRects, UINT32 numRegionRects); - FREERDP_API void yuv_context_reset(YUV_CONTEXT* context, UINT32 width, UINT32 height); + FREERDP_API BOOL yuv_context_reset(YUV_CONTEXT* context, UINT32 width, UINT32 height); FREERDP_API YUV_CONTEXT* yuv_context_new(BOOL encoder, UINT32 ThreadingFlags); FREERDP_API void yuv_context_free(YUV_CONTEXT* context); diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index 1fc26fd78..fa9df2dba 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -643,9 +643,7 @@ BOOL h264_context_reset(H264_CONTEXT* h264, UINT32 width, UINT32 height) h264->width = width; h264->height = height; - yuv_context_reset(h264->yuv, width, height); - - return TRUE; + return yuv_context_reset(h264->yuv, width, height); } H264_CONTEXT* h264_context_new(BOOL Compressor) diff --git a/libfreerdp/codec/region.c b/libfreerdp/codec/region.c index 861a7ba5a..96b64aeb3 100644 --- a/libfreerdp/codec/region.c +++ b/libfreerdp/codec/region.c @@ -140,10 +140,10 @@ static RECTANGLE_16* region16_extents_noconst(REGION16* region) BOOL rectangle_is_empty(const RECTANGLE_16* rect) { - /* A rectangle with width = 0 or height = 0 should be regarded + /* A rectangle with width <= 0 or height <= 0 should be regarded * as empty. */ - return ((rect->left == rect->right) || (rect->top == rect->bottom)) ? TRUE : FALSE; + return ((rect->left >= rect->right) || (rect->top >= rect->bottom)) ? TRUE : FALSE; } BOOL region16_is_empty(const REGION16* region) diff --git a/libfreerdp/codec/yuv.c b/libfreerdp/codec/yuv.c index 28debca98..ada7fcbee 100644 --- a/libfreerdp/codec/yuv.c +++ b/libfreerdp/codec/yuv.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,16 +8,7 @@ #define TAG FREERDP_TAG("codec") -struct S_YUV_CONTEXT -{ - UINT32 width, height; - BOOL useThreads; - UINT32 nthreads; - UINT32 heightStep; - - PTP_POOL threadPool; - TP_CALLBACK_ENVIRON ThreadPoolEnv; -}; +#define TILE_SIZE 64 typedef struct { @@ -55,6 +47,24 @@ typedef struct UINT32 iStride[3]; } YUV_ENCODE_WORK_PARAM; +struct S_YUV_CONTEXT +{ + UINT32 width, height; + BOOL useThreads; + BOOL encoder; + UINT32 nthreads; + UINT32 heightStep; + + PTP_POOL threadPool; + TP_CALLBACK_ENVIRON ThreadPoolEnv; + + UINT32 work_object_count; + PTP_WORK* work_objects; + YUV_ENCODE_WORK_PARAM* work_enc_params; + YUV_PROCESS_WORK_PARAM* work_dec_params; + YUV_COMBINE_WORK_PARAM* work_combined_params; +}; + static INLINE BOOL avc420_yuv_to_rgb(const BYTE* pYUVData[3], const UINT32 iStride[3], const RECTANGLE_16* rect, UINT32 nDstStep, BYTE* pDstData, DWORD DstFormat) @@ -62,6 +72,12 @@ static INLINE BOOL avc420_yuv_to_rgb(const BYTE* pYUVData[3], const UINT32 iStri primitives_t* prims = primitives_get(); prim_size_t roi; const BYTE* pYUVPoint[3]; + + WINPR_ASSERT(pYUVData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(rect); + WINPR_ASSERT(pDstData); + const INT32 width = rect->right - rect->left; const INT32 height = rect->bottom - rect->top; BYTE* pDstPoint = pDstData + rect->top * nDstStep + rect->left * GetBytesPerPixel(DstFormat); @@ -87,6 +103,12 @@ static INLINE BOOL avc444_yuv_to_rgb(const BYTE* pYUVData[3], const UINT32 iStri primitives_t* prims = primitives_get(); prim_size_t roi; const BYTE* pYUVPoint[3]; + + WINPR_ASSERT(pYUVData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(rect); + WINPR_ASSERT(pDstData); + const INT32 width = rect->right - rect->left; const INT32 height = rect->bottom - rect->top; BYTE* pDstPoint = pDstData + rect->top * nDstStep + rect->left * GetBytesPerPixel(DstFormat); @@ -111,6 +133,7 @@ static void CALLBACK yuv420_process_work_callback(PTP_CALLBACK_INSTANCE instance YUV_PROCESS_WORK_PARAM* param = (YUV_PROCESS_WORK_PARAM*)context; WINPR_UNUSED(instance); WINPR_UNUSED(work); + WINPR_ASSERT(param); if (!avc420_yuv_to_rgb(param->pYUVData, param->iStride, ¶m->rect, param->nDstStep, param->dest, param->DstFormat)) @@ -123,17 +146,55 @@ static void CALLBACK yuv444_process_work_callback(PTP_CALLBACK_INSTANCE instance YUV_PROCESS_WORK_PARAM* param = (YUV_PROCESS_WORK_PARAM*)context; WINPR_UNUSED(instance); WINPR_UNUSED(work); + WINPR_ASSERT(param); if (!avc444_yuv_to_rgb(param->pYUVData, param->iStride, ¶m->rect, param->nDstStep, param->dest, param->DstFormat)) WLog_WARN(TAG, "avc444_yuv_to_rgb failed"); } -void yuv_context_reset(YUV_CONTEXT* context, UINT32 width, UINT32 height) +BOOL yuv_context_reset(YUV_CONTEXT* context, UINT32 width, UINT32 height) { + WINPR_ASSERT(context); + context->width = width; context->height = height; context->heightStep = (height / context->nthreads); + + if (context->useThreads) + { + const UINT32 count = + (width + TILE_SIZE - 1) / TILE_SIZE * (height + TILE_SIZE - 1) / TILE_SIZE * 4; + + context->work_object_count = 0; + if (context->encoder) + { + free(context->work_enc_params); + context->work_enc_params = calloc(count, sizeof(YUV_ENCODE_WORK_PARAM)); + if (!context->work_enc_params) + return FALSE; + } + else + { + free(context->work_dec_params); + context->work_dec_params = calloc(count, sizeof(YUV_PROCESS_WORK_PARAM)); + if (!context->work_dec_params) + return FALSE; + + free(context->work_combined_params); + context->work_combined_params = calloc(count, sizeof(YUV_COMBINE_WORK_PARAM)); + if (!context->work_combined_params) + return FALSE; + } + + free(context->work_objects); + context->work_objects = calloc(count, sizeof(PTP_WORK)); + if (!context->work_objects) + return FALSE; + + context->work_object_count = count; + } + return TRUE; } YUV_CONTEXT* yuv_context_new(BOOL encoder, UINT32 ThreadingFlags) @@ -146,6 +207,7 @@ YUV_CONTEXT* yuv_context_new(BOOL encoder, UINT32 ThreadingFlags) /** do it here to avoid a race condition between threads */ primitives_get(); + ret->encoder = encoder; ret->nthreads = 1; if (!(ThreadingFlags & THREADING_FLAGS_DISABLE_THREADS)) { @@ -181,6 +243,9 @@ void yuv_context_free(YUV_CONTEXT* context) if (context->threadPool) CloseThreadpool(context->threadPool); DestroyThreadpoolEnvironment(&context->ThreadPoolEnv); + free(context->work_objects); + free(context->work_enc_params); + free(context->work_dec_params); } free(context); } @@ -193,6 +258,12 @@ static INLINE YUV_PROCESS_WORK_PARAM pool_decode_param(const RECTANGLE_16* rect, { YUV_PROCESS_WORK_PARAM current = { 0 }; + WINPR_ASSERT(rect); + WINPR_ASSERT(context); + WINPR_ASSERT(pYUVData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(dest); + current.context = context; current.DstFormat = DstFormat; current.pYUVData[0] = pYUVData[0]; @@ -207,32 +278,6 @@ static INLINE YUV_PROCESS_WORK_PARAM pool_decode_param(const RECTANGLE_16* rect, return current; } -static BOOL allocate_objects(PTP_WORK** work, void** params, size_t size, UINT32 count) -{ - if (count == 0) - return FALSE; - - count *= 2; - { - PTP_WORK* tmp; - PTP_WORK* cur = *work; - tmp = realloc(cur, sizeof(PTP_WORK*) * count); - if (!tmp) - return FALSE; - *work = tmp; - memset(tmp, 0, sizeof(PTP_WORK*) * count); - } - { - void* cur = *params; - void* tmp = realloc(cur, size * count); - if (!tmp) - return FALSE; - memset(tmp, 0, size * count); - *params = tmp; - } - return TRUE; -} - static BOOL submit_object(PTP_WORK* work_object, PTP_WORK_CALLBACK cb, const void* param, YUV_CONTEXT* context) { @@ -247,36 +292,68 @@ static BOOL submit_object(PTP_WORK* work_object, PTP_WORK_CALLBACK cb, const voi return TRUE; } -static void free_objects(PTP_WORK* work_objects, void* params, UINT32 waitCount) +static void free_objects(PTP_WORK* work_objects, UINT32 waitCount) { - if (work_objects) - { UINT32 i; - for (i = 0; i < waitCount; i++) + + WINPR_ASSERT(work_objects || (waitCount == 0)); + + for (i = 0; i < waitCount; i++) { - if (!work_objects[i]) - continue; - WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE); - CloseThreadpoolWork(work_objects[i]); + PTP_WORK cur = work_objects[i]; + work_objects[i] = NULL; + + if (!cur) + continue; + + WaitForThreadpoolWorkCallbacks(cur, FALSE); + CloseThreadpoolWork(cur); + } +} + +static BOOL intersects(UINT32 pos, const RECTANGLE_16* regionRects, UINT32 numRegionRects) +{ + UINT32 x; + + WINPR_ASSERT(regionRects || (numRegionRects == 0)); + + for (x = pos + 1; x < numRegionRects; x++) + { + const RECTANGLE_16* what = ®ionRects[pos]; + const RECTANGLE_16* rect = ®ionRects[x]; + + if (rectangles_intersects(what, rect)) + { + WLog_WARN(TAG, "YUV decoder: intersecting rectangles, aborting"); + return TRUE; } } - free(work_objects); - free(params); + return FALSE; } static BOOL pool_decode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* pYUVData[3], const UINT32 iStride[3], UINT32 yuvHeight, UINT32 DstFormat, BYTE* dest, UINT32 nDstStep, const RECTANGLE_16* regionRects, UINT32 numRegionRects) { - UINT32 steps; BOOL rc = FALSE; UINT32 x, y; - PTP_WORK* work_objects = NULL; - YUV_PROCESS_WORK_PARAM* params = NULL; - UINT32 waitCount = 0, nobjects; + UINT32 waitCount = 0; primitives_t* prims = primitives_get(); + WINPR_ASSERT(context); + WINPR_ASSERT(cb); + WINPR_ASSERT(pYUVData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(dest); + WINPR_ASSERT(regionRects || (numRegionRects == 0)); + + if (context->encoder) + { + WLog_ERR(TAG, "YUV context set up for encoding, can not decode with it, aborting"); + return FALSE; + } + if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU)) { for (y = 0; y < numRegionRects; y++) @@ -290,48 +367,57 @@ static BOOL pool_decode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* } /* case where we use threads */ - steps = MAX((context->nthreads + numRegionRects / 2 + 1) / numRegionRects, 1); - nobjects = numRegionRects * steps; - - if (!allocate_objects(&work_objects, (void**)¶ms, sizeof(YUV_PROCESS_WORK_PARAM), nobjects)) - goto fail; - for (x = 0; x < numRegionRects; x++) { const RECTANGLE_16* rect = ®ionRects[x]; - const UINT32 height = rect->bottom - rect->top; + RECTANGLE_16 r = *rect; - const UINT32 heightStep = MAX((height + steps / 2 + 1) / steps, 1); - for (y = 0; y < steps; y++) + if (intersects(x, regionRects, numRegionRects)) + continue; + + while (r.left < r.right) { - YUV_PROCESS_WORK_PARAM* cur = ¶ms[waitCount]; - RECTANGLE_16 r = *rect; - r.top += y * heightStep; + RECTANGLE_16 y = r; + y.right = MIN(r.right, r.left + TILE_SIZE); - /* If we have an odd bounding rectangle we might end up with < steps - * workers. Check we do not exceed the bounding rectangle. */ - r.bottom = r.top + heightStep; - if (r.bottom > rect->bottom) - r.bottom = rect->bottom; - if (r.top >= rect->bottom) - continue; - if (r.bottom > yuvHeight) - r.bottom = yuvHeight; - *cur = pool_decode_param(&r, context, pYUVData, iStride, DstFormat, dest, nDstStep); - if (!submit_object(&work_objects[waitCount], cb, cur, context)) - goto fail; - waitCount++; + while (y.top < y.bottom) + { + RECTANGLE_16 z = y; + YUV_PROCESS_WORK_PARAM* cur; + + if (context->work_object_count <= waitCount) + { + WLog_ERR(TAG, "YUV decoder: invalid number of tiles, only support %" PRIu32, + context->work_object_count); + goto fail; + } + + cur = &context->work_dec_params[waitCount]; + z.bottom = MIN(z.bottom, z.top + TILE_SIZE); + if (rectangle_is_empty(&z)) + continue; + *cur = pool_decode_param(&z, context, pYUVData, iStride, DstFormat, dest, nDstStep); + if (!submit_object(&context->work_objects[waitCount], cb, cur, context)) + goto fail; + waitCount++; + y.top += TILE_SIZE; + } + + r.left += TILE_SIZE; } } rc = TRUE; fail: - free_objects(work_objects, params, nobjects); + free_objects(context->work_objects, waitCount); return rc; } static INLINE BOOL check_rect(const YUV_CONTEXT* yuv, const RECTANGLE_16* rect, UINT32 nDstWidth, UINT32 nDstHeight) { + WINPR_ASSERT(yuv); + WINPR_ASSERT(rect); + /* Check, if the output rectangle is valid in decoded h264 frame. */ if ((rect->right > yuv->width) || (rect->left > yuv->width)) return FALSE; @@ -354,8 +440,14 @@ static void CALLBACK yuv444_combine_work_callback(PTP_CALLBACK_INSTANCE instance { YUV_COMBINE_WORK_PARAM* param = (YUV_COMBINE_WORK_PARAM*)context; primitives_t* prims = primitives_get(); + + WINPR_ASSERT(param); YUV_CONTEXT* yuv = param->context; + WINPR_ASSERT(yuv); + const RECTANGLE_16* rect = ¶m->rect; + WINPR_ASSERT(rect); + const UINT32 alignedWidth = yuv->width + ((yuv->width % 16 != 0) ? 16 - yuv->width % 16 : 0); const UINT32 alignedHeight = yuv->height + ((yuv->height % 16 != 0) ? 16 - yuv->height % 16 : 0); @@ -377,6 +469,14 @@ static INLINE YUV_COMBINE_WORK_PARAM pool_decode_rect_param( const UINT32 iStride[3], UINT32 yuvHeight, BYTE* pYUVDstData[3], const UINT32 iDstStride[3]) { YUV_COMBINE_WORK_PARAM current = { 0 }; + + WINPR_ASSERT(rect); + WINPR_ASSERT(context); + WINPR_ASSERT(pYUVData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(pYUVDstData); + WINPR_ASSERT(iDstStride); + current.context = context; current.pYUVData[0] = pYUVData[0]; current.pYUVData[1] = pYUVData[1]; @@ -402,12 +502,17 @@ static BOOL pool_decode_rect(YUV_CONTEXT* context, BYTE type, const BYTE* pYUVDa { BOOL rc = FALSE; UINT32 y; - PTP_WORK* work_objects = NULL; - YUV_COMBINE_WORK_PARAM* params = NULL; UINT32 waitCount = 0; PTP_WORK_CALLBACK cb = yuv444_combine_work_callback; primitives_t* prims = primitives_get(); + WINPR_ASSERT(context); + WINPR_ASSERT(pYUVData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(pYUVDstData); + WINPR_ASSERT(iDstStride); + WINPR_ASSERT(regionRects || (numRegionRects == 0)); + if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU)) { for (y = 0; y < numRegionRects; y++) @@ -421,23 +526,27 @@ static BOOL pool_decode_rect(YUV_CONTEXT* context, BYTE type, const BYTE* pYUVDa } /* case where we use threads */ - if (!allocate_objects(&work_objects, (void**)¶ms, sizeof(YUV_COMBINE_WORK_PARAM), - numRegionRects)) - goto fail; - for (waitCount = 0; waitCount < numRegionRects; waitCount++) { - YUV_COMBINE_WORK_PARAM* current = ¶ms[waitCount]; + YUV_COMBINE_WORK_PARAM* current; + + if (context->work_object_count <= waitCount) + { + WLog_ERR(TAG, "YUV rect decoder: invalid number of tiles, only support %" PRIu32, + context->work_object_count); + goto fail; + } + current = &context->work_combined_params[waitCount]; *current = pool_decode_rect_param(®ionRects[waitCount], context, type, pYUVData, iStride, yuvHeight, pYUVDstData, iDstStride); - if (!submit_object(&work_objects[waitCount], cb, current, context)) + if (!submit_object(&context->work_objects[waitCount], cb, current, context)) goto fail; } rc = TRUE; fail: - free_objects(work_objects, params, waitCount); + free_objects(context->work_objects, waitCount); return rc; } @@ -448,6 +557,19 @@ BOOL yuv444_context_decode(YUV_CONTEXT* context, BYTE type, const BYTE* pYUVData { const BYTE* pYUVCDstData[3]; + WINPR_ASSERT(context); + WINPR_ASSERT(pYUVData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(pYUVDstData); + WINPR_ASSERT(iDstStride); + WINPR_ASSERT(dest); + WINPR_ASSERT(regionRects || (numRegionRects == 0)); + + if (context->encoder) + { + WLog_ERR(TAG, "YUV context set up for encoding, can not decode with it, aborting"); + return FALSE; + } if (!pool_decode_rect(context, type, pYUVData, iStride, yuvHeight, pYUVDstData, iDstStride, regionRects, numRegionRects)) return FALSE; @@ -478,6 +600,7 @@ static void CALLBACK yuv420_encode_work_callback(PTP_CALLBACK_INSTANCE instance, WINPR_UNUSED(instance); WINPR_UNUSED(work); + WINPR_ASSERT(param); roi.width = param->rect.right - param->rect.left; roi.height = param->rect.bottom - param->rect.top; @@ -508,6 +631,7 @@ static void CALLBACK yuv444v1_encode_work_callback(PTP_CALLBACK_INSTANCE instanc WINPR_UNUSED(instance); WINPR_UNUSED(work); + WINPR_ASSERT(param); roi.width = param->rect.right - param->rect.left; roi.height = param->rect.bottom - param->rect.top; @@ -544,6 +668,7 @@ static void CALLBACK yuv444v2_encode_work_callback(PTP_CALLBACK_INSTANCE instanc WINPR_UNUSED(instance); WINPR_UNUSED(work); + WINPR_ASSERT(param); roi.width = param->rect.right - param->rect.left; roi.height = param->rect.bottom - param->rect.top; @@ -576,6 +701,12 @@ static INLINE YUV_ENCODE_WORK_PARAM pool_encode_fill(const RECTANGLE_16* rect, Y { YUV_ENCODE_WORK_PARAM current = { 0 }; + WINPR_ASSERT(rect); + WINPR_ASSERT(context); + WINPR_ASSERT(pSrcData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(pYUVLumaData); + current.context = context; current.pSrcData = pSrcData; current.SrcFormat = SrcFormat; @@ -605,11 +736,22 @@ static BOOL pool_encode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* { BOOL rc = FALSE; primitives_t* prims = primitives_get(); - UINT32 x, y, nobjects; - PTP_WORK* work_objects = NULL; - YUV_ENCODE_WORK_PARAM* params = NULL; + UINT32 x, y; UINT32 waitCount = 0; + WINPR_ASSERT(context); + WINPR_ASSERT(cb); + WINPR_ASSERT(pSrcData); + WINPR_ASSERT(iStride); + WINPR_ASSERT(regionRects || (numRegionRects == 0)); + + if (!context->encoder) + { + + WLog_ERR(TAG, "YUV context set up for decoding, can not encode with it, aborting"); + return FALSE; + } + if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU)) { for (x = 0; x < numRegionRects; x++) @@ -623,21 +765,15 @@ static BOOL pool_encode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* } /* case where we use threads */ - nobjects = (context->height + context->heightStep - 1) / context->heightStep; for (x = 0; x < numRegionRects; x++) { const RECTANGLE_16* rect = ®ionRects[x]; const UINT32 height = rect->bottom - rect->top; const UINT32 steps = (height + context->heightStep / 2) / context->heightStep; - if (waitCount + steps >= nobjects) - nobjects *= 2; waitCount += steps; } - if (!allocate_objects(&work_objects, (void**)¶ms, sizeof(YUV_ENCODE_WORK_PARAM), nobjects)) - goto fail; - for (x = 0; x < numRegionRects; x++) { const RECTANGLE_16* rect = ®ionRects[x]; @@ -647,11 +783,20 @@ static BOOL pool_encode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* for (y = 0; y < steps; y++) { RECTANGLE_16 r = *rect; - YUV_ENCODE_WORK_PARAM* current = ¶ms[waitCount]; + YUV_ENCODE_WORK_PARAM* current; + + if (context->work_object_count <= waitCount) + { + WLog_ERR(TAG, "YUV encoder: invalid number of tiles, only support %" PRIu32, + context->work_object_count); + goto fail; + } + + current = &context->work_enc_params[waitCount]; r.top += y * context->heightStep; *current = pool_encode_fill(&r, context, pSrcData, nSrcStep, SrcFormat, iStride, pYUVLumaData, pYUVChromaData); - if (!submit_object(&work_objects[waitCount], cb, current, context)) + if (!submit_object(&context->work_objects[waitCount], cb, current, context)) goto fail; waitCount++; } @@ -659,7 +804,7 @@ static BOOL pool_encode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* rc = TRUE; fail: - free_objects(work_objects, params, waitCount); + free_objects(context->work_objects, waitCount); return rc; }