@@ -59,6 +59,9 @@ class ReusableBuffer {
5959 lessen_counter = 0 ;
6060 return buffer;
6161 }
62+ int capacity () const {
63+ return size;
64+ }
6265
6366private:
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+
8291typedef 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+
89104typedef 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
564509private:
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