mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 10:25:46 +01:00 
			
		
		
		
	* handle offset in anim viewer 'vwebp'
* fix gif2webp to handle disposal method and odd offset correctly + remove -scale and -crop option from vwebp, since it'll be broken with offsets and fragments. Needs a revisit. + remove a warning in gif2web Change-Id: If04c6d085806e32540f2f15a37244c4407b719b3
This commit is contained in:
		| @@ -41,7 +41,15 @@ static int MyReader(GifFileType* gif, GifByteType* buffer, int length) { | |||||||
|   return fread(buffer, 1, length, file); |   return fread(buffer, 1, length, file); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void Remap(const uint8_t* const src, GifFileType* const gif, | static void ClearPicture(WebPPicture* const picture, uint32_t color) { | ||||||
|  |   int x, y; | ||||||
|  |   for (y = 0; y < picture->height; ++y) { | ||||||
|  |     uint32_t* const dst = picture->argb + y * picture->argb_stride; | ||||||
|  |     for (x = 0; x < picture->width; ++x) dst[x] = color; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void Remap(const uint8_t* const src, const GifFileType* const gif, | ||||||
|                   uint32_t* dst, int len) { |                   uint32_t* dst, int len) { | ||||||
|   int i; |   int i; | ||||||
|   const GifColorType* colors; |   const GifColorType* colors; | ||||||
| @@ -97,6 +105,9 @@ static int ReadSubImage(GifFileType* gif, WebPPicture* pic, WebPPicture* view) { | |||||||
|       Remap(tmp, gif, dst + y * view->argb_stride, sub_w); |       Remap(tmp, gif, dst + y * view->argb_stride, sub_w); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |   // re-align the view with even offset (and adjust dimensions if needed). | ||||||
|  |   WebPPictureView(pic, offset_x & ~1, offset_y & ~1, | ||||||
|  |                   sub_w + (offset_x & 1), sub_h + (offset_y & 1), view); | ||||||
|   ok = 1; |   ok = 1; | ||||||
|  |  | ||||||
|  End: |  End: | ||||||
| @@ -161,10 +172,9 @@ int main(int argc, const char *argv[]) { | |||||||
|   WebPPicture picture; |   WebPPicture picture; | ||||||
|   WebPPicture view; |   WebPPicture view; | ||||||
|   WebPMemoryWriter memory; |   WebPMemoryWriter memory; | ||||||
|   WebPMuxFrameInfo frame = { |   WebPMuxFrameInfo frame; | ||||||
|       {NULL, 0}, 0, 0, 100, WEBP_CHUNK_ANMF, WEBP_MUX_DISPOSE_NONE |  | ||||||
|   }; |  | ||||||
|   WebPMuxAnimParams anim = { WHITE_COLOR, 0 }; |   WebPMuxAnimParams anim = { WHITE_COLOR, 0 }; | ||||||
|  |  | ||||||
|   int done; |   int done; | ||||||
|   int c; |   int c; | ||||||
|   int quiet = 0; |   int quiet = 0; | ||||||
| @@ -172,6 +182,10 @@ int main(int argc, const char *argv[]) { | |||||||
|   WebPMux* mux = NULL; |   WebPMux* mux = NULL; | ||||||
|   WebPData webp_data = { NULL, 0 }; |   WebPData webp_data = { NULL, 0 }; | ||||||
|  |  | ||||||
|  |   memset(&frame, 0, sizeof(frame)); | ||||||
|  |   frame.id = WEBP_CHUNK_ANMF; | ||||||
|  |   frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND; | ||||||
|  |  | ||||||
|   if (!WebPConfigInit(&config) || !WebPPictureInit(&picture)) { |   if (!WebPConfigInit(&config) || !WebPPictureInit(&picture)) { | ||||||
|     fprintf(stderr, "Error! Version mismatch!\n"); |     fprintf(stderr, "Error! Version mismatch!\n"); | ||||||
|     return -1; |     return -1; | ||||||
| @@ -242,12 +256,14 @@ int main(int argc, const char *argv[]) { | |||||||
|   picture.writer = WebPMemoryWrite; |   picture.writer = WebPMemoryWrite; | ||||||
|   picture.custom_ptr = &memory; |   picture.custom_ptr = &memory; | ||||||
|   if (!WebPPictureAlloc(&picture)) goto End; |   if (!WebPPictureAlloc(&picture)) goto End; | ||||||
|  |  | ||||||
|   if (gif->SColorMap != NULL && |   if (gif->SColorMap != NULL && | ||||||
|       !GetColorFromIndex(gif->SColorMap, gif->SBackGroundColor, |       !GetColorFromIndex(gif->SColorMap, gif->SBackGroundColor, | ||||||
|                          &anim.bgcolor)) { |                          &anim.bgcolor)) { | ||||||
|     fprintf(stderr, "GIF decode error: invalid background color index.\n"); |     fprintf(stderr, "GIF decode error: invalid background color index.\n"); | ||||||
|     goto End; |     goto End; | ||||||
|   } |   } | ||||||
|  |   ClearPicture(&picture, anim.bgcolor); | ||||||
|  |  | ||||||
|   mux = WebPMuxNew(); |   mux = WebPMuxNew(); | ||||||
|   if (mux == NULL) { |   if (mux == NULL) { | ||||||
| @@ -263,11 +279,13 @@ int main(int argc, const char *argv[]) { | |||||||
|  |  | ||||||
|     switch (type) { |     switch (type) { | ||||||
|       case IMAGE_DESC_RECORD_TYPE: { |       case IMAGE_DESC_RECORD_TYPE: { | ||||||
|  |         if (frame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { | ||||||
|  |           ClearPicture(&picture, anim.bgcolor); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (!DGifGetImageDesc(gif)) goto End; |         if (!DGifGetImageDesc(gif)) goto End; | ||||||
|         if (!ReadSubImage(gif, &picture, &view)) goto End; |         if (!ReadSubImage(gif, &picture, &view)) goto End; | ||||||
|  |  | ||||||
|         frame.x_offset = gif->Image.Left; |  | ||||||
|         frame.y_offset = gif->Image.Top; |  | ||||||
|         WebPMemoryWriterInit(&memory); |         WebPMemoryWriterInit(&memory); | ||||||
|         if (!config.lossless) { |         if (!config.lossless) { | ||||||
|           // We need to call BGRA variant because of the way we do Remap(). |           // We need to call BGRA variant because of the way we do Remap(). | ||||||
| @@ -284,18 +302,27 @@ int main(int argc, const char *argv[]) { | |||||||
|           fprintf(stderr, "Error code: %d\n", view.error_code); |           fprintf(stderr, "Error code: %d\n", view.error_code); | ||||||
|           goto End; |           goto End; | ||||||
|         } |         } | ||||||
|         frame.bitstream.bytes = memory.mem; |  | ||||||
|         frame.bitstream.size = memory.size; |  | ||||||
|  |  | ||||||
|         // Now we have all the info about the frame, as a Graphic Control |         // Now we have all the info about the frame, as a Graphic Control | ||||||
|         // Extension Block always appears before the Image Descriptor Block. |         // Extension Block always appears before the Image Descriptor Block. | ||||||
|         // So add the frame to mux. |         // So add the frame to mux. | ||||||
|  |         frame.x_offset = gif->Image.Left & ~1; | ||||||
|  |         frame.y_offset = gif->Image.Top & ~1; | ||||||
|  |         frame.bitstream.bytes = memory.mem; | ||||||
|  |         frame.bitstream.size = memory.size; | ||||||
|         err = WebPMuxPushFrame(mux, &frame, 1); |         err = WebPMuxPushFrame(mux, &frame, 1); | ||||||
|         if (err != WEBP_MUX_OK) { |         if (err != WEBP_MUX_OK) { | ||||||
|           fprintf(stderr, "ERROR (%s): Could not add animation frame.\n", |           fprintf(stderr, "ERROR (%s): Could not add animation frame.\n", | ||||||
|                   ErrorString(err)); |                   ErrorString(err)); | ||||||
|           goto End; |           goto End; | ||||||
|         } |         } | ||||||
|  |         if (verbose) { | ||||||
|  |           fprintf(stderr, "Added frame %dx%d (offset:%d,%d duration:%d) ", | ||||||
|  |                   view.width, view.height, frame.x_offset, frame.y_offset, | ||||||
|  |                   frame.duration); | ||||||
|  |           fprintf(stderr, "dispose:%d transparent index:%d\n", | ||||||
|  |                   frame.dispose_method, transparent_index); | ||||||
|  |         } | ||||||
|         WebPDataClear(&frame.bitstream); |         WebPDataClear(&frame.bitstream); | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
| @@ -315,8 +342,16 @@ int main(int argc, const char *argv[]) { | |||||||
|             const int delay = data[2] | (data[3] << 8);  // In 10 ms units. |             const int delay = data[2] | (data[3] << 8);  // In 10 ms units. | ||||||
|             if (data[0] != 4) goto End; |             if (data[0] != 4) goto End; | ||||||
|             frame.duration = delay * 10;  // Duration is in 1 ms units for WebP. |             frame.duration = delay * 10;  // Duration is in 1 ms units for WebP. | ||||||
|             frame.dispose_method = (dispose == 0) ? |             if (dispose == 3) { | ||||||
|                 WEBP_MUX_DISPOSE_NONE : WEBP_MUX_DISPOSE_BACKGROUND; |               fprintf(stderr, "WARNING: GIF_DISPOSE_RESTORE not supported."); | ||||||
|  |               // failsafe. TODO(urvang): emulate the correct behaviour by | ||||||
|  |               // recoding the whole frame. | ||||||
|  |               frame.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND; | ||||||
|  |             } else { | ||||||
|  |               frame.dispose_method = | ||||||
|  |                 (dispose == 2) ? WEBP_MUX_DISPOSE_BACKGROUND | ||||||
|  |                                : WEBP_MUX_DISPOSE_NONE; | ||||||
|  |             } | ||||||
|             transparent_index = (flags & GIF_TRANSPARENT_MASK) ? data[4] : -1; |             transparent_index = (flags & GIF_TRANSPARENT_MASK) ? data[4] : -1; | ||||||
|             break; |             break; | ||||||
|           } |           } | ||||||
|   | |||||||
| @@ -46,7 +46,9 @@ static struct { | |||||||
|   int decoding_error; |   int decoding_error; | ||||||
|   int print_info; |   int print_info; | ||||||
|  |  | ||||||
|  |   int canvas_width, canvas_height; | ||||||
|   int loop_count; |   int loop_count; | ||||||
|  |   uint32_t bg_color; | ||||||
|  |  | ||||||
|   const char* file_name; |   const char* file_name; | ||||||
|   WebPData data; |   WebPData data; | ||||||
| @@ -106,6 +108,10 @@ static void PrintString(const char* const text) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static float GetColorf(uint32_t color, int shift) { | ||||||
|  |   return (color >> shift) / 255.f; | ||||||
|  | } | ||||||
|  |  | ||||||
| static void DrawCheckerBoard(void) { | static void DrawCheckerBoard(void) { | ||||||
|   const int square_size = 8;  // must be a power of 2 |   const int square_size = 8;  // must be a power of 2 | ||||||
|   int x, y; |   int x, y; | ||||||
| @@ -127,15 +133,20 @@ static void DrawCheckerBoard(void) { | |||||||
| } | } | ||||||
|  |  | ||||||
| static void HandleDisplay(void) { | static void HandleDisplay(void) { | ||||||
|   const WebPDecBuffer* pic = kParams.pic; |   const WebPDecBuffer* const pic = kParams.pic; | ||||||
|  |   const WebPIterator* const iter = &kParams.frameiter; | ||||||
|  |   double xoff, yoff; | ||||||
|   if (pic == NULL) return; |   if (pic == NULL) return; | ||||||
|   glClear(GL_COLOR_BUFFER_BIT); |  | ||||||
|   glPushMatrix(); |   glPushMatrix(); | ||||||
|   glPixelZoom(1, -1); |   glPixelZoom(1, -1); | ||||||
|   glRasterPos2f(-1, 1); |   xoff = 2. * iter->x_offset / kParams.canvas_width; | ||||||
|  |   yoff = 2. * iter->y_offset / kParams.canvas_height; | ||||||
|  |   glRasterPos2f(-1. + xoff, 1. - 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); | ||||||
|   DrawCheckerBoard(); |   if (iter->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { | ||||||
|  |     glClear(GL_COLOR_BUFFER_BIT);  // use clear color | ||||||
|  |   } | ||||||
|   glDrawPixels(pic->width, pic->height, |   glDrawPixels(pic->width, pic->height, | ||||||
|                GL_RGBA, GL_UNSIGNED_BYTE, |                GL_RGBA, GL_UNSIGNED_BYTE, | ||||||
|                (GLvoid*)pic->u.RGBA.rgba); |                (GLvoid*)pic->u.RGBA.rgba); | ||||||
| @@ -150,45 +161,53 @@ static void HandleDisplay(void) { | |||||||
|     glColor4f(0.0, 0.0, 0.0, 1.0); |     glColor4f(0.0, 0.0, 0.0, 1.0); | ||||||
|     glRasterPos2f(-0.95f, 0.80f); |     glRasterPos2f(-0.95f, 0.80f); | ||||||
|     PrintString(tmp); |     PrintString(tmp); | ||||||
|  |     if (iter->x_offset != 0 || iter->y_offset != 0) { | ||||||
|  |       snprintf(tmp, sizeof(tmp), " (offset:%d,%d)", | ||||||
|  |                iter->x_offset, iter->y_offset); | ||||||
|  |       glRasterPos2f(-0.95f, 0.70f); | ||||||
|  |       PrintString(tmp); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|   glPopMatrix(); |   glPopMatrix(); | ||||||
|   glFlush(); |   glFlush(); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void StartDisplay(const WebPDecBuffer* const pic) { | static void StartDisplay(void) { | ||||||
|  |   const int width = kParams.canvas_width; | ||||||
|  |   const int height = kParams.canvas_height; | ||||||
|   glutInitDisplayMode(GLUT_RGBA); |   glutInitDisplayMode(GLUT_RGBA); | ||||||
|   glutInitWindowSize(pic->width, pic->height); |   glutInitWindowSize(width, height); | ||||||
|   glutCreateWindow("WebP viewer"); |   glutCreateWindow("WebP viewer"); | ||||||
|   glutDisplayFunc(HandleDisplay); |   glutDisplayFunc(HandleDisplay); | ||||||
|   glutIdleFunc(NULL); |   glutIdleFunc(NULL); | ||||||
|   glutKeyboardFunc(HandleKey); |   glutKeyboardFunc(HandleKey); | ||||||
|   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||||
|   glEnable(GL_BLEND); |   glEnable(GL_BLEND); | ||||||
|   glClearColor(0.0, 0.0, 0.0, 0.0); |   glClearColor(GetColorf(kParams.bg_color, 0), | ||||||
|   HandleReshape(pic->width, pic->height); |                GetColorf(kParams.bg_color, 8), | ||||||
|  |                GetColorf(kParams.bg_color, 16), | ||||||
|  |                GetColorf(kParams.bg_color, 24)); | ||||||
|  |   HandleReshape(width, height); | ||||||
|  |   glClear(GL_COLOR_BUFFER_BIT); | ||||||
|  |   DrawCheckerBoard(); | ||||||
| } | } | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| // File decoding | // File decoding | ||||||
|  |  | ||||||
| static int Decode(int* const duration) { | static int Decode(void) {   // Fills kParams.frameiter | ||||||
|   const WebPIterator* const iter = &kParams.frameiter; |   const WebPIterator* const iter = &kParams.frameiter; | ||||||
|   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(); | ||||||
|   if (iter->x_offset != 0 || iter->y_offset != 0) { |  | ||||||
|     fprintf(stderr, |  | ||||||
|             "Frame offsets not yet supported! Forcing offset to 0,0\n"); |  | ||||||
|   } |  | ||||||
|   output_buffer->colorspace = MODE_RGBA; |   output_buffer->colorspace = MODE_RGBA; | ||||||
|   ok = (WebPDecode(iter->fragment.bytes, iter->fragment.size, |   ok = (WebPDecode(iter->fragment.bytes, iter->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", iter->frame_num); | ||||||
|   } else { |   } else { | ||||||
|     *duration = iter->duration; |  | ||||||
|     kParams.pic = output_buffer; |     kParams.pic = output_buffer; | ||||||
|   } |   } | ||||||
|   return ok; |   return ok; | ||||||
| @@ -198,10 +217,6 @@ 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) { | ||||||
|       if (!Decode(&duration)) { |  | ||||||
|         kParams.decoding_error = 1; |  | ||||||
|         kParams.done = 1; |  | ||||||
|       } else { |  | ||||||
|       WebPIterator* const iter = &kParams.frameiter; |       WebPIterator* const iter = &kParams.frameiter; | ||||||
|       if (!WebPDemuxNextFrame(iter)) { |       if (!WebPDemuxNextFrame(iter)) { | ||||||
|         WebPDemuxReleaseIterator(iter); |         WebPDemuxReleaseIterator(iter); | ||||||
| @@ -211,13 +226,19 @@ static void decode_callback(int what) { | |||||||
|         } else { |         } else { | ||||||
|           kParams.decoding_error = 1; |           kParams.decoding_error = 1; | ||||||
|           kParams.done = 1; |           kParams.done = 1; | ||||||
|  |           return; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |       duration = iter->duration; | ||||||
|     } |     } | ||||||
|     } |     if (!Decode()) { | ||||||
|  |       kParams.decoding_error = 1; | ||||||
|  |       kParams.done = 1; | ||||||
|  |     } else { | ||||||
|       glutPostRedisplay(); |       glutPostRedisplay(); | ||||||
|       glutTimerFunc(duration, decode_callback, what); |       glutTimerFunc(duration, decode_callback, what); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| @@ -231,8 +252,7 @@ static void Help(void) { | |||||||
|          "  -nofancy ..... don't use the fancy YUV420 upscaler.\n" |          "  -nofancy ..... don't use the fancy YUV420 upscaler.\n" | ||||||
|          "  -nofilter .... disable in-loop filtering.\n" |          "  -nofilter .... disable in-loop filtering.\n" | ||||||
|          "  -mt .......... use multi-threading\n" |          "  -mt .......... use multi-threading\n" | ||||||
|          "  -crop <x> <y> <w> <h> ... crop output with the given rectangle\n" |          "  -info ........ print info.\n" | ||||||
|          "  -scale <w> <h> .......... scale the output (*after* any cropping)\n" |  | ||||||
|          "  -h     ....... this help message.\n" |          "  -h     ....... this help message.\n" | ||||||
|         ); |         ); | ||||||
| } | } | ||||||
| @@ -255,6 +275,8 @@ int main(int argc, char *argv[]) { | |||||||
|       config.options.no_fancy_upsampling = 1; |       config.options.no_fancy_upsampling = 1; | ||||||
|     } else if (!strcmp(argv[c], "-nofilter")) { |     } else if (!strcmp(argv[c], "-nofilter")) { | ||||||
|       config.options.bypass_filtering = 1; |       config.options.bypass_filtering = 1; | ||||||
|  |     } else if (!strcmp(argv[c], "-info")) { | ||||||
|  |       kParams.print_info = 1; | ||||||
|     } else if (!strcmp(argv[c], "-version")) { |     } else if (!strcmp(argv[c], "-version")) { | ||||||
|       const int version = WebPGetDecoderVersion(); |       const int version = WebPGetDecoderVersion(); | ||||||
|       printf("%d.%d.%d\n", |       printf("%d.%d.%d\n", | ||||||
| @@ -262,16 +284,6 @@ int main(int argc, char *argv[]) { | |||||||
|       return 0; |       return 0; | ||||||
|     } else if (!strcmp(argv[c], "-mt")) { |     } else if (!strcmp(argv[c], "-mt")) { | ||||||
|       config.options.use_threads = 1; |       config.options.use_threads = 1; | ||||||
|     } else if (!strcmp(argv[c], "-crop") && c < argc - 4) { |  | ||||||
|       config.options.use_cropping = 1; |  | ||||||
|       config.options.crop_left   = strtol(argv[++c], NULL, 0); |  | ||||||
|       config.options.crop_top    = strtol(argv[++c], NULL, 0); |  | ||||||
|       config.options.crop_width  = strtol(argv[++c], NULL, 0); |  | ||||||
|       config.options.crop_height = strtol(argv[++c], NULL, 0); |  | ||||||
|     } else if (!strcmp(argv[c], "-scale") && c < argc - 2) { |  | ||||||
|       config.options.use_scaling = 1; |  | ||||||
|       config.options.scaled_width  = strtol(argv[++c], NULL, 0); |  | ||||||
|       config.options.scaled_height = strtol(argv[++c], NULL, 0); |  | ||||||
|     } else if (argv[c][0] == '-') { |     } else if (argv[c][0] == '-') { | ||||||
|       printf("Unknown option '%s'\n", argv[c]); |       printf("Unknown option '%s'\n", argv[c]); | ||||||
|       Help(); |       Help(); | ||||||
| @@ -302,26 +314,35 @@ int main(int argc, char *argv[]) { | |||||||
|     fprintf(stderr, "Image fragments are not supported for now!\n"); |     fprintf(stderr, "Image fragments are not supported for now!\n"); | ||||||
|     goto Error; |     goto Error; | ||||||
|   } |   } | ||||||
|  |   kParams.canvas_width = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_WIDTH); | ||||||
|  |   kParams.canvas_height = WebPDemuxGetI(kParams.dmux, WEBP_FF_CANVAS_HEIGHT); | ||||||
|  |   if (kParams.print_info) { | ||||||
|  |     printf("Canvas: %d x %d\n", kParams.canvas_width, kParams.canvas_height); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   if (!WebPDemuxGetFrame(kParams.dmux, 1, &kParams.frameiter)) goto Error; |   if (!WebPDemuxGetFrame(kParams.dmux, 1, &kParams.frameiter)) goto Error; | ||||||
|  |  | ||||||
|   kParams.has_animation = (kParams.frameiter.num_frames > 1); |   kParams.has_animation = (kParams.frameiter.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); | ||||||
|   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); |          kParams.frameiter.num_frames, kParams.loop_count); | ||||||
|  |  | ||||||
|   // Decode first frame |   // Decode first frame | ||||||
|   { |   if (!Decode()) goto Error; | ||||||
|     int duration; |  | ||||||
|     if (!Decode(&duration)) 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); | ||||||
|  |   if (kParams.loop_count) ++kParams.loop_count; | ||||||
|  |  | ||||||
|   // Start display (and timer) |   // Start display (and timer) | ||||||
|   glutInit(&argc, argv); |   glutInit(&argc, argv); | ||||||
| #ifdef FREEGLUT | #ifdef FREEGLUT | ||||||
|   glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); |   glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); | ||||||
| #endif | #endif | ||||||
|   StartDisplay(kParams.pic); |   StartDisplay(); | ||||||
|  |  | ||||||
|   if (kParams.has_animation) glutTimerFunc(0, decode_callback, 0); |   if (kParams.has_animation) glutTimerFunc(0, decode_callback, 0); | ||||||
|   glutMainLoop(); |   glutMainLoop(); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user