Support for 'do not blend' option in vwebp

Change-Id: I563e192fa727816d11d8647c559ec407205ef40b
This commit is contained in:
Urvang Joshi 2013-08-09 14:40:31 -07:00
parent 6284854bd5
commit dcf652223a

View File

@ -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)