mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
Support for 'do not blend' option in vwebp
Change-Id: I563e192fa727816d11d8647c559ec407205ef40b
This commit is contained in:
parent
6284854bd5
commit
dcf652223a
@ -60,12 +60,8 @@ static struct {
|
|||||||
WebPDecoderConfig* config;
|
WebPDecoderConfig* config;
|
||||||
const WebPDecBuffer* pic;
|
const WebPDecBuffer* pic;
|
||||||
WebPDemuxer* dmux;
|
WebPDemuxer* dmux;
|
||||||
WebPIterator frameiter;
|
WebPIterator curr_frame;
|
||||||
struct {
|
WebPIterator prev_frame;
|
||||||
int width, height;
|
|
||||||
int x_offset, y_offset;
|
|
||||||
enum WebPMuxAnimDispose dispose_method;
|
|
||||||
} prev_frame;
|
|
||||||
WebPChunkIterator iccp;
|
WebPChunkIterator iccp;
|
||||||
} kParams;
|
} kParams;
|
||||||
|
|
||||||
@ -77,7 +73,8 @@ static void ClearPreviousPic(void) {
|
|||||||
static void ClearParams(void) {
|
static void ClearParams(void) {
|
||||||
ClearPreviousPic();
|
ClearPreviousPic();
|
||||||
WebPDataClear(&kParams.data);
|
WebPDataClear(&kParams.data);
|
||||||
WebPDemuxReleaseIterator(&kParams.frameiter);
|
WebPDemuxReleaseIterator(&kParams.curr_frame);
|
||||||
|
WebPDemuxReleaseIterator(&kParams.prev_frame);
|
||||||
WebPDemuxReleaseChunkIterator(&kParams.iccp);
|
WebPDemuxReleaseChunkIterator(&kParams.iccp);
|
||||||
WebPDemuxDelete(kParams.dmux);
|
WebPDemuxDelete(kParams.dmux);
|
||||||
kParams.dmux = NULL;
|
kParams.dmux = NULL;
|
||||||
@ -147,25 +144,25 @@ static int ApplyColorProfile(const WebPData* const profile,
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// File decoding
|
// File decoding
|
||||||
|
|
||||||
static int Decode(void) { // Fills kParams.frameiter
|
static int Decode(void) { // Fills kParams.curr_frame
|
||||||
const WebPIterator* const iter = &kParams.frameiter;
|
const WebPIterator* const curr = &kParams.curr_frame;
|
||||||
WebPDecoderConfig* const config = kParams.config;
|
WebPDecoderConfig* const config = kParams.config;
|
||||||
WebPDecBuffer* const output_buffer = &config->output;
|
WebPDecBuffer* const output_buffer = &config->output;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
|
||||||
ClearPreviousPic();
|
ClearPreviousPic();
|
||||||
output_buffer->colorspace = MODE_RGBA;
|
output_buffer->colorspace = MODE_RGBA;
|
||||||
ok = (WebPDecode(iter->fragment.bytes, iter->fragment.size,
|
ok = (WebPDecode(curr->fragment.bytes, curr->fragment.size,
|
||||||
config) == VP8_STATUS_OK);
|
config) == VP8_STATUS_OK);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr, "Decoding of frame #%d failed!\n", iter->frame_num);
|
fprintf(stderr, "Decoding of frame #%d failed!\n", curr->frame_num);
|
||||||
} else {
|
} else {
|
||||||
kParams.pic = output_buffer;
|
kParams.pic = output_buffer;
|
||||||
if (kParams.use_color_profile) {
|
if (kParams.use_color_profile) {
|
||||||
ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer);
|
ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr, "Applying color profile to frame #%d failed!\n",
|
fprintf(stderr, "Applying color profile to frame #%d failed!\n",
|
||||||
iter->frame_num);
|
curr->frame_num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,10 +173,10 @@ static void decode_callback(int what) {
|
|||||||
if (what == 0 && !kParams.done) {
|
if (what == 0 && !kParams.done) {
|
||||||
int duration = 0;
|
int duration = 0;
|
||||||
if (kParams.dmux != NULL) {
|
if (kParams.dmux != NULL) {
|
||||||
WebPIterator* const iter = &kParams.frameiter;
|
WebPIterator* const curr = &kParams.curr_frame;
|
||||||
if (!WebPDemuxNextFrame(iter)) {
|
if (!WebPDemuxNextFrame(curr)) {
|
||||||
WebPDemuxReleaseIterator(iter);
|
WebPDemuxReleaseIterator(curr);
|
||||||
if (WebPDemuxGetFrame(kParams.dmux, 1, iter)) {
|
if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) {
|
||||||
--kParams.loop_count;
|
--kParams.loop_count;
|
||||||
kParams.done = (kParams.loop_count == 0);
|
kParams.done = (kParams.loop_count == 0);
|
||||||
} else {
|
} else {
|
||||||
@ -188,7 +185,7 @@ static void decode_callback(int what) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
duration = iter->duration;
|
duration = curr->duration;
|
||||||
}
|
}
|
||||||
if (!Decode()) {
|
if (!Decode()) {
|
||||||
kParams.decoding_error = 1;
|
kParams.decoding_error = 1;
|
||||||
@ -281,40 +278,45 @@ static void DrawCheckerBoard(void) {
|
|||||||
|
|
||||||
static void HandleDisplay(void) {
|
static void HandleDisplay(void) {
|
||||||
const WebPDecBuffer* const pic = kParams.pic;
|
const WebPDecBuffer* const pic = kParams.pic;
|
||||||
const WebPIterator* const iter = &kParams.frameiter;
|
const WebPIterator* const curr = &kParams.curr_frame;
|
||||||
|
WebPIterator* const prev = &kParams.prev_frame;
|
||||||
GLfloat xoff, yoff;
|
GLfloat xoff, yoff;
|
||||||
if (pic == NULL) return;
|
if (pic == NULL) return;
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glPixelZoom(1, -1);
|
glPixelZoom(1, -1);
|
||||||
xoff = (GLfloat)(2. * iter->x_offset / kParams.canvas_width);
|
xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width);
|
||||||
yoff = (GLfloat)(2. * iter->y_offset / kParams.canvas_height);
|
yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height);
|
||||||
glRasterPos2f(-1.f + xoff, 1.f - yoff);
|
glRasterPos2f(-1.f + xoff, 1.f - yoff);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, pic->u.RGBA.stride / 4);
|
||||||
|
|
||||||
if (kParams.prev_frame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
|
if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
|
||||||
|
curr->blend_method == WEBP_MUX_NO_BLEND) {
|
||||||
// TODO(later): these offsets and those above should factor in window size.
|
// TODO(later): these offsets and those above should factor in window size.
|
||||||
// they will be incorrect if the window is resized.
|
// they will be incorrect if the window is resized.
|
||||||
// glScissor() takes window coordinates (0,0 at bottom left).
|
// glScissor() takes window coordinates (0,0 at bottom left).
|
||||||
const int window_x = kParams.prev_frame.x_offset;
|
int window_x, window_y;
|
||||||
const int window_y = kParams.canvas_height -
|
if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
|
||||||
kParams.prev_frame.y_offset -
|
// Clear the previous frame rectangle.
|
||||||
kParams.prev_frame.height;
|
window_x = prev->x_offset;
|
||||||
|
window_y = kParams.canvas_height - prev->y_offset - prev->height;
|
||||||
|
} else { // curr->blend_method == WEBP_MUX_NO_BLEND.
|
||||||
|
// We simulate no-blending behavior by first clearing the current frame
|
||||||
|
// rectangle (to a checker-board) and then alpha-blending against it.
|
||||||
|
window_x = curr->x_offset;
|
||||||
|
window_y = kParams.canvas_height - curr->y_offset - curr->height;
|
||||||
|
}
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
// Only updated the requested area, not the whole canvas.
|
// Only update the requested area, not the whole canvas.
|
||||||
glScissor(window_x, window_y,
|
glScissor(window_x, window_y, prev->width, prev->height);
|
||||||
kParams.prev_frame.width, kParams.prev_frame.height);
|
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT); // use clear color
|
glClear(GL_COLOR_BUFFER_BIT); // use clear color
|
||||||
DrawCheckerBoard();
|
DrawCheckerBoard();
|
||||||
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
kParams.prev_frame.width = iter->width;
|
|
||||||
kParams.prev_frame.height = iter->height;
|
*prev = *curr;
|
||||||
kParams.prev_frame.x_offset = iter->x_offset;
|
|
||||||
kParams.prev_frame.y_offset = iter->y_offset;
|
|
||||||
kParams.prev_frame.dispose_method = iter->dispose_method;
|
|
||||||
|
|
||||||
glDrawPixels(pic->width, pic->height,
|
glDrawPixels(pic->width, pic->height,
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
@ -330,9 +332,9 @@ static void HandleDisplay(void) {
|
|||||||
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
|
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
|
||||||
glRasterPos2f(-0.95f, 0.80f);
|
glRasterPos2f(-0.95f, 0.80f);
|
||||||
PrintString(tmp);
|
PrintString(tmp);
|
||||||
if (iter->x_offset != 0 || iter->y_offset != 0) {
|
if (curr->x_offset != 0 || curr->y_offset != 0) {
|
||||||
snprintf(tmp, sizeof(tmp), " (offset:%d,%d)",
|
snprintf(tmp, sizeof(tmp), " (offset:%d,%d)",
|
||||||
iter->x_offset, iter->y_offset);
|
curr->x_offset, curr->y_offset);
|
||||||
glRasterPos2f(-0.95f, 0.70f);
|
glRasterPos2f(-0.95f, 0.70f);
|
||||||
PrintString(tmp);
|
PrintString(tmp);
|
||||||
}
|
}
|
||||||
@ -386,6 +388,8 @@ static void Help(void) {
|
|||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
WebPDecoderConfig config;
|
WebPDecoderConfig config;
|
||||||
int c;
|
int c;
|
||||||
|
const WebPIterator* const curr = &kParams.curr_frame;
|
||||||
|
WebPIterator* const prev = &kParams.prev_frame;
|
||||||
|
|
||||||
if (!WebPInitDecoderConfig(&config)) {
|
if (!WebPInitDecoderConfig(&config)) {
|
||||||
fprintf(stderr, "Library version mismatch!\n");
|
fprintf(stderr, "Library version mismatch!\n");
|
||||||
@ -457,10 +461,10 @@ int main(int argc, char *argv[]) {
|
|||||||
printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height);
|
printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
kParams.prev_frame.width = kParams.canvas_width;
|
prev->width = kParams.canvas_width;
|
||||||
kParams.prev_frame.height = kParams.canvas_height;
|
prev->height = kParams.canvas_height;
|
||||||
kParams.prev_frame.x_offset = kParams.prev_frame.y_offset = 0;
|
prev->x_offset = prev->y_offset = 0;
|
||||||
kParams.prev_frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
|
prev->dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
|
||||||
|
|
||||||
memset(&kParams.iccp, 0, sizeof(kParams.iccp));
|
memset(&kParams.iccp, 0, sizeof(kParams.iccp));
|
||||||
kParams.has_color_profile =
|
kParams.has_color_profile =
|
||||||
@ -476,20 +480,20 @@ int main(int argc, char *argv[]) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WebPDemuxGetFrame(kParams.dmux, 1, &kParams.frameiter)) goto Error;
|
if (!WebPDemuxGetFrame(kParams.dmux, 1, curr)) goto Error;
|
||||||
|
|
||||||
kParams.has_animation = (kParams.frameiter.num_frames > 1);
|
kParams.has_animation = (curr->num_frames > 1);
|
||||||
kParams.loop_count = (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT);
|
kParams.loop_count = (int)WebPDemuxGetI(kParams.dmux, WEBP_FF_LOOP_COUNT);
|
||||||
kParams.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR);
|
kParams.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR);
|
||||||
printf("VP8X: Found %d images in file (loop count = %d)\n",
|
printf("VP8X: Found %d images in file (loop count = %d)\n",
|
||||||
kParams.frameiter.num_frames, kParams.loop_count);
|
curr->num_frames, kParams.loop_count);
|
||||||
|
|
||||||
// Decode first frame
|
// Decode first frame
|
||||||
if (!Decode()) goto Error;
|
if (!Decode()) goto Error;
|
||||||
|
|
||||||
// Position iterator to last frame. Next call to HandleDisplay will wrap over.
|
// Position iterator to last frame. Next call to HandleDisplay will wrap over.
|
||||||
// We take this into account by bumping up loop_count.
|
// We take this into account by bumping up loop_count.
|
||||||
WebPDemuxGetFrame(kParams.dmux, 0, &kParams.frameiter);
|
WebPDemuxGetFrame(kParams.dmux, 0, curr);
|
||||||
if (kParams.loop_count) ++kParams.loop_count;
|
if (kParams.loop_count) ++kParams.loop_count;
|
||||||
|
|
||||||
// Start display (and timer)
|
// Start display (and timer)
|
||||||
|
Loading…
Reference in New Issue
Block a user