@@ -87,11 +87,15 @@ static AVFrame* select_best_frame(AVFrame* frames[], int size) |
87 | 87 | } |
88 | 88 |
|
89 | 89 | // Calculate size and allocate buffer |
90 | | -static void alloc_buffer(struct Buffer* dst) |
| 90 | +static int alloc_buffer(struct Buffer* dst) |
91 | 91 | { |
92 | 92 | dst->size |
93 | 93 | = av_image_get_buffer_size(AV_PIX_FMT_RGBA, dst->width, dst->height, 1); |
94 | 94 | dst->data = malloc(dst->size); |
| 95 | + if (!dst->data) { |
| 96 | + return AVERROR(ENOMEM); |
| 97 | + } |
| 98 | + return 0; |
95 | 99 | } |
96 | 100 |
|
97 | 101 | // Use point subsampling to scale image up to target size and convert to RGBA |
@@ -125,6 +129,9 @@ static void downscale(struct Buffer* dst, const struct Buffer const* src) |
125 | 129 | // First sum all pixels into a multidimensional array |
126 | 130 | const size_t size = dst->height * dst->width * sizeof(struct Pixel); |
127 | 131 | struct Pixel(*img)[dst->width] = malloc(size); |
| 132 | + if (!img) { |
| 133 | + return; // Handle allocation failure |
| 134 | + } |
128 | 135 | memset(img, 0, size); |
129 | 136 |
|
130 | 137 | int i = 0; |
@@ -161,6 +168,9 @@ static void downscale(struct Buffer* dst, const struct Buffer const* src) |
161 | 168 | i += 4; |
162 | 169 | } |
163 | 170 | } |
| 171 | + |
| 172 | + // Free the temporary buffer |
| 173 | + free(img); |
164 | 174 | } |
165 | 175 |
|
166 | 176 | // Decrease intensity of pixels with alpha |
@@ -357,7 +367,10 @@ static int encode_frame( |
357 | 367 | // scale_dims() does not work, if image size is exactly that of the target |
358 | 368 | // thumbnail size. Perhaps a peculiarity of sws_scale(). |
359 | 369 | if (img->width < box.width && img->height < box.height) { |
360 | | - alloc_buffer(img); |
| 370 | + err = alloc_buffer(img); |
| 371 | + if (err) { |
| 372 | + return err; |
| 373 | + } |
361 | 374 | err = resample(img, frame); |
362 | 375 | if (err) { |
363 | 376 | return err; |
@@ -375,15 +388,22 @@ static int encode_frame( |
375 | 388 | // around the thumbnail size and much bigger ones. |
376 | 389 | struct Buffer enlarged |
377 | 390 | = { .width = img->width * 4, .height = img->height * 4 }; |
378 | | - alloc_buffer(&enlarged); |
| 391 | + err = alloc_buffer(&enlarged); |
| 392 | + if (err) { |
| 393 | + return err; |
| 394 | + } |
379 | 395 | err = resample(&enlarged, frame); |
380 | 396 | if (err) { |
381 | 397 | free(enlarged.data); |
382 | 398 | return err; |
383 | 399 | } |
384 | | - alloc_buffer(img); |
| 400 | + err = alloc_buffer(img); |
| 401 | + if (err) { |
| 402 | + free(enlarged.data); |
| 403 | + return err; |
| 404 | + } |
385 | 405 | downscale(img, &enlarged); |
386 | | - free(enlarged.data); |
| 406 | + // Don't free enlarged.data here - let Go handle all memory management |
387 | 407 | adjust_orientation(img, orientation); |
388 | 408 | return err; |
389 | 409 | } |
@@ -477,29 +497,42 @@ int generate_thumbnail(struct Buffer* img, AVFormatContext* avfc, |
477 | 497 | int i = 0; |
478 | 498 | AVFrame* frames[MAX_FRAMES] = { NULL }; |
479 | 499 | AVFrame* next = NULL; |
| 500 | + |
| 501 | + // Initialize the output buffer to ensure clean state |
| 502 | + img->data = NULL; |
| 503 | + img->size = 0; |
| 504 | + img->width = 0; |
| 505 | + img->height = 0; |
480 | 506 |
|
481 | 507 | // Read up to 10 frames |
482 | 508 | while (1) { |
483 | 509 | next = av_frame_alloc(); |
| 510 | + if (!next) { |
| 511 | + err = AVERROR(ENOMEM); |
| 512 | + goto cleanup; |
| 513 | + } |
| 514 | + |
484 | 515 | err = read_frame(avfc, avcc, next, stream); |
485 | 516 | if (err) { |
486 | | - goto end; |
| 517 | + av_frame_free(&next); |
| 518 | + goto cleanup; |
487 | 519 | } |
488 | 520 |
|
489 | 521 | // Analyze only every 3rd frame to cover a larger time frame |
490 | 522 | if (!(i++ % 3)) { |
491 | 523 | frames[size++] = next; |
492 | 524 | next = NULL; |
493 | 525 | if (size == MAX_FRAMES) { |
494 | | - goto end; |
| 526 | + break; |
495 | 527 | } |
496 | 528 | } else { |
497 | 529 | av_frame_free(&next); |
| 530 | + next = NULL; |
498 | 531 | } |
499 | 532 | } |
500 | 533 |
|
501 | | -end: |
502 | | - if (size) { |
| 534 | +cleanup: |
| 535 | + if (size > 0) { |
503 | 536 | int orientation = 0; |
504 | 537 | int rotation = get_rotation(avfc->streams[stream]); |
505 | 538 |
|
@@ -522,8 +555,11 @@ int generate_thumbnail(struct Buffer* img, AVFormatContext* avfc, |
522 | 555 | img, select_best_frame(frames, size), thumb_dims, orientation); |
523 | 556 | } |
524 | 557 |
|
| 558 | + // Clean up all frames |
525 | 559 | for (int i = 0; i < size; i++) { |
526 | | - av_frame_free(&frames[i]); |
| 560 | + if (frames[i]) { |
| 561 | + av_frame_free(&frames[i]); |
| 562 | + } |
527 | 563 | } |
528 | 564 | if (next) { |
529 | 565 | av_frame_free(&next); |
|
0 commit comments