diff options
author | Rodger Combs <rodger.combs@gmail.com> | 2016-07-15 03:00:59 -0500 |
---|---|---|
committer | Rodger Combs <rodger.combs@gmail.com> | 2016-07-15 06:01:50 -0500 |
commit | 748d479107b1e19a4f52f0f6acb47f78b2260430 (patch) | |
tree | ac0cd072a7cd8bf2894821bb476451c63d4770aa | |
parent | 669d06d814da42f7046689c97f578756d6cb6aa7 (diff) | |
download | libass-748d479107b1e19a4f52f0f6acb47f78b2260430.tar.bz2 libass-748d479107b1e19a4f52f0f6acb47f78b2260430.tar.xz |
WIP: RGBA API
-rw-r--r-- | libass/ass.h | 10 | ||||
-rw-r--r-- | libass/ass_bitmap.c | 32 | ||||
-rw-r--r-- | libass/ass_bitmap.h | 8 | ||||
-rw-r--r-- | libass/ass_func_template.h | 7 | ||||
-rw-r--r-- | libass/ass_render.c | 83 | ||||
-rw-r--r-- | test/test.c | 84 |
6 files changed, 149 insertions, 75 deletions
diff --git a/libass/ass.h b/libass/ass.h index bd8bb1a..873f2c2 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -56,6 +56,11 @@ typedef struct ass_image { IMAGE_TYPE_SHADOW } type; + enum { + ASS_BITMAP_TYPE_ALPHA, + ASS_BITMAP_TYPE_RGBA + } bitmapType; + } ASS_Image; /* @@ -493,6 +498,9 @@ void ass_set_cache_limits(ASS_Renderer *priv, int glyph_max, ASS_Image *ass_render_frame(ASS_Renderer *priv, ASS_Track *track, long long now, int *detect_change); +ASS_Image *ass_render_rgba_frame(ASS_Renderer *priv, ASS_Track *track, + long long now, int *detect_change, + int force_max_size); /* * The following functions operate on track objects and do not need @@ -542,6 +550,8 @@ void ass_free_style(ASS_Track *track, int sid); */ void ass_free_event(ASS_Track *track, int eid); +void ass_free_image(ASS_Image *img); + /** * \brief Parse a chunk of subtitle stream data. * \param track track diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 2c354b3..78894c9 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -624,3 +624,35 @@ void ass_mul_bitmaps_c(uint8_t *dst, intptr_t dst_stride, src2 += src2_stride; } } + +void ass_rgba_blend_c(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t src_w, intptr_t src_h, + uint32_t color) +{ + const unsigned int r = (color >> 24) & 0xff; + const unsigned int g = (color >> 16) & 0xff; + const unsigned int b = (color >> 8) & 0xff; + const unsigned int a = 0xff - (color & 0xff); + + for (int y = 0; y < src_h; y++, dst += dst_stride, src += src_stride) { + uint32_t *dstrow = (uint32_t *) dst; + for (int x = 0; x < src_w; x++) { + const unsigned int v = src[x]; + int rr = (r * a * v); + int gg = (g * a * v); + int bb = (b * a * v); + int aa = a * v; + uint32_t dstpix = dstrow[x]; + unsigned int dstb = dstpix & 0xFF; + unsigned int dstg = (dstpix >> 8) & 0xFF; + unsigned int dstr = (dstpix >> 16) & 0xFF; + unsigned int dsta = (dstpix >> 24) & 0xFF; + dstb = (bb + dstb * (255 * 255 - aa)) / (255 * 255); + dstg = (gg + dstg * (255 * 255 - aa)) / (255 * 255); + dstr = (rr + dstr * (255 * 255 - aa)) / (255 * 255); + dsta = (aa * 255 + dsta * (255 * 255 - aa)) / (255 * 255); + dstrow[x] = dstb | (dstg << 8) | (dstr << 16) | (dsta << 24); + } + } +} diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index 36df816..71a3f5e 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -42,6 +42,11 @@ typedef void (*BitmapMulFunc)(uint8_t *dst, intptr_t dst_stride, uint8_t *src2, intptr_t src2_stride, intptr_t width, intptr_t height); +typedef void (*RGBABlendFunc)(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t src_w, intptr_t src_h, + uint32_t color); + typedef void (*BeBlurFunc)(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride, uint16_t *tmp); @@ -73,6 +78,9 @@ typedef struct { BitmapBlendFunc add_bitmaps, sub_bitmaps; BitmapMulFunc mul_bitmaps; + // rgba blend functions + RGBABlendFunc rgba_blend; + // be blur function BeBlurFunc be_blur; diff --git a/libass/ass_func_template.h b/libass/ass_func_template.h index 3fea779..6c72021 100644 --- a/libass/ass_func_template.h +++ b/libass/ass_func_template.h @@ -42,6 +42,11 @@ void DECORATE(mul_bitmaps)(uint8_t *dst, intptr_t dst_stride, uint8_t *src2, intptr_t src2_stride, intptr_t width, intptr_t height); +void DECORATE(rgba_blend)(uint8_t *dst, intptr_t dst_stride, + uint8_t *src, intptr_t src_stride, + intptr_t src_w, intptr_t src_h, + uint32_t color); + void DECORATE(be_blur)(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride, uint16_t *tmp); @@ -115,6 +120,8 @@ const BitmapEngine DECORATE(bitmap_engine) = { .mul_bitmaps = ass_mul_bitmaps_c, #endif + .rgba_blend = ass_rgba_blend_c, + #ifdef __x86_64__ .be_blur = DECORATE(be_blur), #else diff --git a/libass/ass_render.c b/libass/ass_render.c index 9bbaaa3..f124114 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -174,6 +174,7 @@ static ASS_Image *my_draw_bitmap(unsigned char *bitmap, int bitmap_w, img->result.color = color; img->result.dst_x = dst_x; img->result.dst_y = dst_y; + img->result.bitmapType = ASS_BITMAP_TYPE_ALPHA; img->source = source; ass_cache_inc_ref(source); @@ -3047,3 +3048,85 @@ void ass_frame_unref(ASS_Image *img) free(priv); } while (img); } + +/** + * \brief render an RGBA frame + * \param priv library handle + * \param track track + * \param now current video timestamp (ms) + * \param detect_change a value describing how the new images differ from the previous ones will be written here: + * 0 if identical, >0 if different. + * Can be NULL, in that case no detection is performed. + */ +ASS_Image *ass_render_rgba_frame(ASS_Renderer *priv, ASS_Track *track, + long long now, int *detect_change, + int force_max_size) +{ + ASS_Image *list = ass_render_frame(priv, track, now, detect_change); + + unsigned min_x = INT_MAX, min_y = INT_MAX; + unsigned max_x = 0, max_y = 0; + unsigned char *bitmap = NULL; + ASS_ImagePriv *out = NULL; + if (force_max_size) { + min_x = 0; min_y = 0; + max_x = priv->width; + max_y = priv->height; + } else { + for (ASS_Image *current = list; current; current = current->next) { + if (!current->w || !current->h) + continue; + min_x = FFMIN(current->dst_x, min_x); + min_y = FFMIN(current->dst_y, min_y); + max_x = FFMAX(current->dst_x + current->w, max_x); + max_x = FFMAX(current->dst_y + current->h, max_y); + } + + if (max_x <= min_x || max_y <= min_y) + goto fail; + } + + unsigned width = max_x - min_x; + unsigned height = max_y - min_y; + unsigned stride = ass_align(32, width * 4); + bitmap = ass_aligned_alloc(32, height * stride); + if (!bitmap) + goto fail; + + memset(bitmap, 0, stride * height); + + out = malloc(sizeof(ASS_ImagePriv)); + if (!out) + goto fail; + + out->result.w = width; + out->result.h = height; + out->result.stride = stride; + out->result.bitmap = bitmap; + out->result.color = 0x0; // N/A + out->result.dst_x = min_x; + out->result.dst_y = min_y; + out->result.bitmapType = ASS_BITMAP_TYPE_RGBA; + out->result.next = NULL; + out->ref_count = 1; + out->source = NULL; + + for (ASS_Image *current = list; current; current = current->next) { + if (!current->w || !current->h) + continue; + + unsigned char *dst = bitmap + (current->dst_y - min_y) * stride + + (current->dst_x - min_x) * 4; + priv->engine->rgba_blend(dst, stride, current->bitmap, current->stride, + current->w, current->h, current->color); + } + + return &out->result; + + fail: + if (bitmap) + free(bitmap); + if (out) + free(out); + return NULL; +} diff --git a/test/test.c b/test/test.c index 4884b28..125c9ad 100644 --- a/test/test.c +++ b/test/test.c @@ -24,11 +24,6 @@ #include "../libass/ass.h" #include <png.h> -typedef struct image_s { - int width, height, stride; - unsigned char *buffer; // RGB24 -} image_t; - ASS_Library *ass_library; ASS_Renderer *ass_renderer; @@ -41,7 +36,7 @@ void msg_callback(int level, const char *fmt, va_list va, void *data) printf("\n"); } -static void write_png(char *fname, image_t *img) +static void write_png(char *fname, ASS_Image *img) { FILE *fp; png_structp png_ptr; @@ -69,17 +64,15 @@ static void write_png(char *fname, image_t *img) png_init_io(png_ptr, fp); png_set_compression_level(png_ptr, 0); - png_set_IHDR(png_ptr, info_ptr, img->width, img->height, - 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + png_set_IHDR(png_ptr, info_ptr, img->w, img->h, + 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); - png_set_bgr(png_ptr); - - row_pointers = (png_byte **) malloc(img->height * sizeof(png_byte *)); - for (k = 0; k < img->height; k++) - row_pointers[k] = img->buffer + img->stride * k; + row_pointers = (png_byte **) malloc(img->h * sizeof(png_byte *)); + for (k = 0; k < img->h; k++) + row_pointers[k] = img->bitmap + img->stride * k; png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, info_ptr); @@ -111,61 +104,6 @@ static void init(int frame_w, int frame_h) ASS_FONTPROVIDER_AUTODETECT, NULL, 1); } -static image_t *gen_image(int width, int height) -{ - image_t *img = malloc(sizeof(image_t)); - img->width = width; - img->height = height; - img->stride = width * 3; - img->buffer = (unsigned char *) calloc(1, height * width * 3); - memset(img->buffer, 63, img->stride * img->height); - //for (int i = 0; i < height * width * 3; ++i) - // img->buffer[i] = (i/3/50) % 100; - return img; -} - -#define _r(c) ((c)>>24) -#define _g(c) (((c)>>16)&0xFF) -#define _b(c) (((c)>>8)&0xFF) -#define _a(c) ((c)&0xFF) - -static void blend_single(image_t * frame, ASS_Image *img) -{ - int x, y; - unsigned char opacity = 255 - _a(img->color); - unsigned char r = _r(img->color); - unsigned char g = _g(img->color); - unsigned char b = _b(img->color); - - unsigned char *src; - unsigned char *dst; - - src = img->bitmap; - dst = frame->buffer + img->dst_y * frame->stride + img->dst_x * 3; - for (y = 0; y < img->h; ++y) { - for (x = 0; x < img->w; ++x) { - unsigned k = ((unsigned) src[x]) * opacity / 255; - // possible endianness problems - dst[x * 3] = (k * b + (255 - k) * dst[x * 3]) / 255; - dst[x * 3 + 1] = (k * g + (255 - k) * dst[x * 3 + 1]) / 255; - dst[x * 3 + 2] = (k * r + (255 - k) * dst[x * 3 + 2]) / 255; - } - src += img->stride; - dst += frame->stride; - } -} - -static void blend(image_t * frame, ASS_Image *img) -{ - int cnt = 0; - while (img) { - blend_single(frame, img); - ++cnt; - img = img->next; - } - printf("%d images blended\n", cnt); -} - char *font_provider_labels[] = { [ASS_FONTPROVIDER_NONE] = "None", [ASS_FONTPROVIDER_AUTODETECT] = "Autodetect", @@ -210,18 +148,14 @@ int main(int argc, char *argv[]) return 1; } - ASS_Image *img = - ass_render_frame(ass_renderer, track, (int) (tm * 1000), NULL); - image_t *frame = gen_image(frame_w, frame_h); - blend(frame, img); + ASS_Image *img = ass_render_rgba_frame(ass_renderer, track, (int) (tm * 1000), NULL, 1); ass_free_track(track); ass_renderer_done(ass_renderer); ass_library_done(ass_library); - write_png(imgfile, frame); - free(frame->buffer); - free(frame); + write_png(imgfile, img); + ass_frame_unref(img); return 0; } |