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;
const WebPDecBuffer* pic;
WebPDemuxer* dmux;
WebPIterator frameiter;
struct {
int width, height;
int x_offset, y_offset;
enum WebPMuxAnimDispose dispose_method;
} prev_frame;
WebPIterator curr_frame;
WebPIterator prev_frame;
WebPChunkIterator iccp;
} kParams;
@ -77,7 +73,8 @@ static void ClearPreviousPic(void) {
static void ClearParams(void) {
ClearPreviousPic();
WebPDataClear(&kParams.data);
WebPDemuxReleaseIterator(&kParams.frameiter);
WebPDemuxReleaseIterator(&kParams.curr_frame);
WebPDemuxReleaseIterator(&kParams.prev_frame);
WebPDemuxReleaseChunkIterator(&kParams.iccp);
WebPDemuxDelete(kParams.dmux);
kParams.dmux = NULL;
@ -147,25 +144,25 @@ static int ApplyColorProfile(const WebPData* const profile,
//------------------------------------------------------------------------------
// File decoding
static int Decode(void) { // Fills kParams.frameiter
const WebPIterator* const iter = &kParams.frameiter;
static int Decode(void) { // Fills kParams.curr_frame
const WebPIterator* const curr = &kParams.curr_frame;
WebPDecoderConfig* const config = kParams.config;
WebPDecBuffer* const output_buffer = &config->output;
int ok = 0;
ClearPreviousPic();
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);
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 {
kParams.pic = output_buffer;
if (kParams.use_color_profile) {
ok = ApplyColorProfile(&kParams.iccp.chunk, output_buffer);
if (!ok) {
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) {
int duration = 0;
if (kParams.dmux != NULL) {
WebPIterator* const iter = &kParams.frameiter;
if (!WebPDemuxNextFrame(iter)) {
WebPDemuxReleaseIterator(iter);
if (WebPDemuxGetFrame(kParams.dmux, 1, iter)) {
WebPIterator* const curr = &kParams.curr_frame;
if (!WebPDemuxNextFrame(curr)) {
WebPDemuxReleaseIterator(curr);
if (WebPDemuxGetFrame(kParams.dmux, 1, curr)) {
--kParams.loop_count;
kParams.done = (kParams.loop_count == 0);
} else {
@ -188,7 +185,7 @@ static void decode_callback(int what) {
return;
}
}
duration = iter->duration;
duration = curr->duration;
}
if (!Decode()) {
kParams.decoding_error = 1;
@ -281,40 +278,45 @@ static void DrawCheckerBoard(void) {
static void HandleDisplay(void) {
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;
if (pic == NULL) return;
glPushMatrix();
glPixelZoom(1, -1);
xoff = (GLfloat)(2. * iter->x_offset / kParams.canvas_width);
yoff = (GLfloat)(2. * iter->y_offset / kParams.canvas_height);
xoff = (GLfloat)(2. * curr->x_offset / kParams.canvas_width);
yoff = (GLfloat)(2. * curr->y_offset / kParams.canvas_height);
glRasterPos2f(-1.f + xoff, 1.f - yoff);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
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.
// they will be incorrect if the window is resized.
// glScissor() takes window coordinates (0,0 at bottom left).
const int window_x = kParams.prev_frame.x_offset;
const int window_y = kParams.canvas_height -
kParams.prev_frame.y_offset -
kParams.prev_frame.height;
int window_x, window_y;
if (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
// Clear the previous frame rectangle.
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);
// Only updated the requested area, not the whole canvas.
glScissor(window_x, window_y,
kParams.prev_frame.width, kParams.prev_frame.height);
// Only update the requested area, not the whole canvas.
glScissor(window_x, window_y, prev->width, prev->height);
glClear(GL_COLOR_BUFFER_BIT); // use clear color
DrawCheckerBoard();
glDisable(GL_SCISSOR_TEST);
}
kParams.prev_frame.width = iter->width;
kParams.prev_frame.height = iter->height;
kParams.prev_frame.x_offset = iter->x_offset;
kParams.prev_frame.y_offset = iter->y_offset;
kParams.prev_frame.dispose_method = iter->dispose_method;
*prev = *curr;
glDrawPixels(pic->width, pic->height,
GL_RGBA, GL_UNSIGNED_BYTE,
@ -330,9 +332,9 @@ static void HandleDisplay(void) {
glColor4f(0.90f, 0.0f, 0.90f, 1.0f);
glRasterPos2f(-0.95f, 0.80f);
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)",
iter->x_offset, iter->y_offset);
curr->x_offset, curr->y_offset);
glRasterPos2f(-0.95f, 0.70f);
PrintString(tmp);
}
@ -386,6 +388,8 @@ static void Help(void) {
int main(int argc, char *argv[]) {
WebPDecoderConfig config;
int c;
const WebPIterator* const curr = &kParams.curr_frame;
WebPIterator* const prev = &kParams.prev_frame;
if (!WebPInitDecoderConfig(&config)) {
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);
}
kParams.prev_frame.width = kParams.canvas_width;
kParams.prev_frame.height = kParams.canvas_height;
kParams.prev_frame.x_offset = kParams.prev_frame.y_offset = 0;
kParams.prev_frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
prev->width = kParams.canvas_width;
prev->height = kParams.canvas_height;
prev->x_offset = prev->y_offset = 0;
prev->dispose_method = WEBP_MUX_DISPOSE_BACKGROUND;
memset(&kParams.iccp, 0, sizeof(kParams.iccp));
kParams.has_color_profile =
@ -476,20 +480,20 @@ int main(int argc, char *argv[]) {
#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.bg_color = WebPDemuxGetI(kParams.dmux, WEBP_FF_BACKGROUND_COLOR);
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
if (!Decode()) goto Error;
// Position iterator to last frame. Next call to HandleDisplay will wrap over.
// 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;
// Start display (and timer)