Skip to content

Commit 0cc2bf8

Browse files
committed
Restructure renderBlend so it can return multiple pieces; JS side not ready yet
1 parent 8bc0001 commit 0cc2bf8

File tree

1 file changed

+132
-79
lines changed

1 file changed

+132
-79
lines changed

src/SubtitleOctopus.cpp

Lines changed: 132 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ class ReusableBuffer {
5959
lessen_counter = 0;
6060
return buffer;
6161
}
62+
int capacity() const {
63+
return size;
64+
}
6265

6366
private:
6467
void *buffer;
@@ -79,13 +82,25 @@ const float MAX_UINT8_CAST = 255.9 / 255;
7982

8083
#define CLAMP_UINT8(value) ((value > MIN_UINT8_CAST) ? ((value < MAX_UINT8_CAST) ? (int)(value * 255) : 255) : 0)
8184

85+
typedef struct {
86+
int dest_x, dest_y, dest_width, dest_height;
87+
unsigned char *image;
88+
RenderBlendPart *next;
89+
} RenderBlendPart;
90+
8291
typedef struct {
8392
int changed;
8493
double blend_time;
85-
int dest_x, dest_y, dest_width, dest_height;
86-
unsigned char* image;
94+
RenderBlendPart *part;
8795
} RenderBlendResult;
8896

97+
#define MAX_BLEND_STORAGES 9
98+
typedef struct {
99+
RenderBlendPart part;
100+
ReusableBuffer buf;
101+
bool taken;
102+
} RenderBlendStorage;
103+
89104
typedef struct {
90105
double eventFinish, emptyFinish;
91106
int is_animated;
@@ -376,6 +391,9 @@ class SubtitleOctopus {
376391
}
377392

378393
double start_blend_time = emscripten_get_now();
394+
for (int i = 0; i < MAX_BLEND_STORAGES; i++) {
395+
m_blendParts[i].taken = false;
396+
}
379397

380398
// find bounding rect first
381399
int min_x = img->dst_x, min_y = img->dst_y;
@@ -390,84 +408,11 @@ class SubtitleOctopus {
390408
if (bottom > max_y) max_y = bottom;
391409
}
392410

393-
// make float buffer for blending
394-
int width = max_x - min_x + 1, height = max_y - min_y + 1;
395-
float* buf = (float*)m_blend.take(sizeof(float) * width * height * 4, 0);
396-
if (buf == NULL) {
397-
printf("libass: error: cannot allocate buffer for blending");
398-
return NULL;
399-
}
400-
memset(buf, 0, sizeof(float) * width * height * 4);
401-
402-
// blend things in
403-
for (cur = img; cur != NULL; cur = cur->next) {
404-
int curw = cur->w, curh = cur->h;
405-
if (curw == 0 || curh == 0) continue; // skip empty images
406-
int a = (255 - (cur->color & 0xFF));
407-
if (a == 0) continue; // skip transparent images
408-
409-
int curs = (cur->stride >= curw) ? cur->stride : curw;
410-
int curx = cur->dst_x - min_x, cury = cur->dst_y - min_y;
411-
412-
unsigned char *bitmap = cur->bitmap;
413-
float normalized_a = a / 255.0;
414-
float r = ((cur->color >> 24) & 0xFF) / 255.0;
415-
float g = ((cur->color >> 16) & 0xFF) / 255.0;
416-
float b = ((cur->color >> 8) & 0xFF) / 255.0;
417-
418-
int buf_line_coord = cury * width;
419-
for (int y = 0, bitmap_offset = 0; y < curh; y++, bitmap_offset += curs, buf_line_coord += width)
420-
{
421-
for (int x = 0; x < curw; x++)
422-
{
423-
float pix_alpha = bitmap[bitmap_offset + x] * normalized_a / 255.0;
424-
float inv_alpha = 1.0 - pix_alpha;
425-
426-
int buf_coord = (buf_line_coord + curx + x) << 2;
427-
float *buf_r = buf + buf_coord;
428-
float *buf_g = buf + buf_coord + 1;
429-
float *buf_b = buf + buf_coord + 2;
430-
float *buf_a = buf + buf_coord + 3;
431-
432-
// do the compositing, pre-multiply image RGB with alpha for current pixel
433-
*buf_a = pix_alpha + *buf_a * inv_alpha;
434-
*buf_r = r * pix_alpha + *buf_r * inv_alpha;
435-
*buf_g = g * pix_alpha + *buf_g * inv_alpha;
436-
*buf_b = b * pix_alpha + *buf_b * inv_alpha;
437-
}
438-
}
439-
}
440-
441-
// now build the result;
442-
// NOTE: we use a "view" over [float,float,float,float] array of pixels,
443-
// so we _must_ go left-right top-bottom to not mangle the result
444-
unsigned int *result = (unsigned int*)buf;
445-
for (int y = 0, buf_line_coord = 0; y < height; y++, buf_line_coord += width) {
446-
for (int x = 0; x < width; x++) {
447-
unsigned int pixel = 0;
448-
int buf_coord = (buf_line_coord + x) << 2;
449-
float alpha = buf[buf_coord + 3];
450-
if (alpha > MIN_UINT8_CAST) {
451-
// need to un-multiply the result
452-
float value = buf[buf_coord] / alpha;
453-
pixel |= CLAMP_UINT8(value); // R
454-
value = buf[buf_coord + 1] / alpha;
455-
pixel |= CLAMP_UINT8(value) << 8; // G
456-
value = buf[buf_coord + 2] / alpha;
457-
pixel |= CLAMP_UINT8(value) << 16; // B
458-
pixel |= CLAMP_UINT8(alpha) << 24; // A
459-
}
460-
result[buf_line_coord + x] = pixel;
461-
}
462-
}
463-
464-
// return the thing
465-
m_blendResult.dest_x = min_x;
466-
m_blendResult.dest_y = min_y;
467-
m_blendResult.dest_width = width;
468-
m_blendResult.dest_height = height;
411+
RenderBlendPart *part = renderBlendPart(min_x, min_y, max_x, max_y, img);
412+
part->next = NULL;
413+
m_blendResult.part = part;
469414
m_blendResult.blend_time = emscripten_get_now() - start_blend_time;
470-
m_blendResult.image = (unsigned char*)result;
415+
471416
return &m_blendResult;
472417
}
473418

@@ -562,8 +507,116 @@ class SubtitleOctopus {
562507
}
563508

564509
private:
510+
RenderBlendPart* renderBlendPart(int min_x, int min_y, int max_x, int max_y, ASS_Image* img) {
511+
// make float buffer for blending
512+
int width = max_x - min_x + 1, height = max_y - min_y + 1;
513+
float* buf = (float*)m_blend.take(sizeof(float) * width * height * 4, 0);
514+
if (buf == NULL) {
515+
printf("libass: error: cannot allocate buffer for blending");
516+
return NULL;
517+
}
518+
memset(buf, 0, sizeof(float) * width * height * 4);
519+
520+
// blend things in
521+
for (ASS_Image *cur = img; cur != NULL; cur = cur->next) {
522+
if (cur->dst_x < min_x || cur->dst_y < min_y) continue; // skip images not fully within render region
523+
int curw = cur->w, curh = cur->h;
524+
if (curw == 0 || curh == 0 || cur->dst_x + curw > max_x || cur->dst_y + curh > max_y) continue; // skip empty images or images outside render region
525+
int a = (255 - (cur->color & 0xFF));
526+
if (a == 0) continue; // skip transparent images
527+
528+
int curs = (cur->stride >= curw) ? cur->stride : curw;
529+
int curx = cur->dst_x - min_x, cury = cur->dst_y - min_y;
530+
531+
unsigned char *bitmap = cur->bitmap;
532+
float normalized_a = a / 255.0;
533+
float r = ((cur->color >> 24) & 0xFF) / 255.0;
534+
float g = ((cur->color >> 16) & 0xFF) / 255.0;
535+
float b = ((cur->color >> 8) & 0xFF) / 255.0;
536+
537+
int buf_line_coord = cury * width;
538+
for (int y = 0, bitmap_offset = 0; y < curh; y++, bitmap_offset += curs, buf_line_coord += width)
539+
{
540+
for (int x = 0; x < curw; x++)
541+
{
542+
float pix_alpha = bitmap[bitmap_offset + x] * normalized_a / 255.0;
543+
float inv_alpha = 1.0 - pix_alpha;
544+
545+
int buf_coord = (buf_line_coord + curx + x) << 2;
546+
float *buf_r = buf + buf_coord;
547+
float *buf_g = buf + buf_coord + 1;
548+
float *buf_b = buf + buf_coord + 2;
549+
float *buf_a = buf + buf_coord + 3;
550+
551+
// do the compositing, pre-multiply image RGB with alpha for current pixel
552+
*buf_a = pix_alpha + *buf_a * inv_alpha;
553+
*buf_r = r * pix_alpha + *buf_r * inv_alpha;
554+
*buf_g = g * pix_alpha + *buf_g * inv_alpha;
555+
*buf_b = b * pix_alpha + *buf_b * inv_alpha;
556+
}
557+
}
558+
}
559+
560+
// find closest free buffer
561+
int needed = sizeof(unsigned int) * width * height;
562+
RenderBlendStorage *storage = m_blendParts, *bigBuffer = NULL, *smallBuffer = NULL;
563+
for (int buffer_index = 0; buffer_index < MAX_BLEND_STORAGES; buffer_index++, storage++) {
564+
if (storage->taken) continue;
565+
if (storage->buf.capacity() >= needed) {
566+
if (bigBuffer == NULL || bigBuffer->buf.capacity() > storage->buf.capacity()) bigBuffer = storage;
567+
} else {
568+
if (smallBuffer == NULL || smallBuffer->buf.capacity() > storage->buf.capacity()) smallBuffer = storage;
569+
}
570+
}
571+
572+
if (bigBuffer != NULL) {
573+
storage = bigBuffer;
574+
} else if (smallBuffer != NULL) {
575+
storage = smallBuffer;
576+
} else {
577+
printf("libass: cannot get a buffer for rendering part!\n");
578+
return NULL;
579+
}
580+
581+
unsigned int *result = (unsigned int*)storage->buf.take(needed, false);
582+
if (result == NULL) {
583+
printf("libass: cannot make a buffer for rendering part!\n");
584+
return NULL;
585+
}
586+
storage->taken = true;
587+
588+
// now build the result;
589+
for (int y = 0, buf_line_coord = 0; y < height; y++, buf_line_coord += width) {
590+
for (int x = 0; x < width; x++) {
591+
unsigned int pixel = 0;
592+
int buf_coord = (buf_line_coord + x) << 2;
593+
float alpha = buf[buf_coord + 3];
594+
if (alpha > MIN_UINT8_CAST) {
595+
// need to un-multiply the result
596+
float value = buf[buf_coord] / alpha;
597+
pixel |= CLAMP_UINT8(value); // R
598+
value = buf[buf_coord + 1] / alpha;
599+
pixel |= CLAMP_UINT8(value) << 8; // G
600+
value = buf[buf_coord + 2] / alpha;
601+
pixel |= CLAMP_UINT8(value) << 16; // B
602+
pixel |= CLAMP_UINT8(alpha) << 24; // A
603+
}
604+
result[buf_line_coord + x] = pixel;
605+
}
606+
}
607+
608+
// return the thing
609+
storage->part.dest_x = min_x;
610+
storage->part.dest_y = min_y;
611+
storage->part.dest_width = width;
612+
storage->part.dest_height = height;
613+
storage->part.image = (unsigned char*)result;
614+
return &storage->part;
615+
}
616+
565617
ReusableBuffer m_blend;
566618
RenderBlendResult m_blendResult;
619+
RenderBlendStorage m_blendParts[MAX_BLEND_STORAGES];
567620
int *m_is_event_animated;
568621
bool m_drop_animations;
569622
};

0 commit comments

Comments
 (0)