AnimEncoder: Add a GetError() method.

We now get error string instead of printing it.
The verbose option is now only used to print info and warnings.

Change-Id: I985c5acd427a9d1973068e7b7a8af5dd0d6d2585
This commit is contained in:
Urvang Joshi 2015-11-11 15:48:47 -08:00
parent 688b265d5e
commit c13245c7d8
3 changed files with 69 additions and 39 deletions

View File

@ -314,7 +314,12 @@ int main(int argc, const char *argv[]) {
// Initialize encoder. // Initialize encoder.
enc = WebPAnimEncoderNew(curr_canvas.width, curr_canvas.height, enc = WebPAnimEncoderNew(curr_canvas.width, curr_canvas.height,
&enc_options); &enc_options);
if (enc == NULL) goto End; if (enc == NULL) {
fprintf(stderr,
"Error! Could not create encoder object. Possibly due to "
"a memory error.\n");
goto End;
}
is_first_frame = 0; is_first_frame = 0;
} }
@ -332,8 +337,7 @@ int main(int argc, const char *argv[]) {
GIFBlendFrames(&frame, &gif_rect, &curr_canvas); GIFBlendFrames(&frame, &gif_rect, &curr_canvas);
if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) { if (!WebPAnimEncoderAdd(enc, &curr_canvas, frame_timestamp, &config)) {
fprintf(stderr, "Error! Cannot encode frame as WebP\n"); fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
fprintf(stderr, "Error code: %d\n", curr_canvas.error_code);
} }
// Update canvases. // Update canvases.
@ -431,11 +435,11 @@ int main(int argc, const char *argv[]) {
// Last NULL frame. // Last NULL frame.
if (!WebPAnimEncoderAdd(enc, NULL, frame_timestamp, NULL)) { if (!WebPAnimEncoderAdd(enc, NULL, frame_timestamp, NULL)) {
fprintf(stderr, "Error flushing WebP muxer.\n"); fprintf(stderr, "Error flushing WebP muxer.\n");
fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
} }
if (!WebPAnimEncoderAssemble(enc, &webp_data)) { if (!WebPAnimEncoderAssemble(enc, &webp_data)) {
// TODO(urvang): Print actual error code. fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc));
fprintf(stderr, "ERROR assembling the WebP file.\n");
goto End; goto End;
} }

View File

@ -20,6 +20,12 @@
#include "../webp/format_constants.h" #include "../webp/format_constants.h"
#include "../webp/mux.h" #include "../webp/mux.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
#define ERROR_STR_MAX_LENGTH 100
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Internal structs. // Internal structs.
@ -86,6 +92,7 @@ struct WebPAnimEncoder {
// different from 'in_frame_count_' due to merging. // different from 'in_frame_count_' due to merging.
WebPMux* mux_; // Muxer to assemble the WebP bitstream. WebPMux* mux_; // Muxer to assemble the WebP bitstream.
char error_str_[ERROR_STR_MAX_LENGTH]; // Error string. Empty if no error.
}; };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -166,7 +173,6 @@ static void DefaultEncoderOptions(WebPAnimEncoderOptions* const enc_options) {
enc_options->minimize_size = 0; enc_options->minimize_size = 0;
DisableKeyframes(enc_options); DisableKeyframes(enc_options);
enc_options->allow_mixed = 0; enc_options->allow_mixed = 0;
enc_options->verbose = 0;
} }
int WebPAnimEncoderOptionsInitInternal(WebPAnimEncoderOptions* enc_options, int WebPAnimEncoderOptionsInitInternal(WebPAnimEncoderOptions* enc_options,
@ -203,6 +209,24 @@ static void WebPUtilClearPic(WebPPicture* const picture,
} }
} }
static void MarkNoError(WebPAnimEncoder* const enc) {
enc->error_str_[0] = '\0'; // Empty string.
}
static void MarkError(WebPAnimEncoder* const enc, const char* str) {
if (snprintf(enc->error_str_, ERROR_STR_MAX_LENGTH, "%s.", str) < 0) {
assert(0); // FIX ME!
}
}
static void MarkError2(WebPAnimEncoder* const enc,
const char* str, int error_code) {
if (snprintf(enc->error_str_, ERROR_STR_MAX_LENGTH, "%s: %d.", str,
error_code) < 0) {
assert(0); // FIX ME!
}
}
WebPAnimEncoder* WebPAnimEncoderNewInternal( WebPAnimEncoder* WebPAnimEncoderNewInternal(
int width, int height, const WebPAnimEncoderOptions* enc_options, int width, int height, const WebPAnimEncoderOptions* enc_options,
int abi_version) { int abi_version) {
@ -221,6 +245,7 @@ WebPAnimEncoder* WebPAnimEncoderNewInternal(
// sanity inits, so we can call WebPAnimEncoderDelete(): // sanity inits, so we can call WebPAnimEncoderDelete():
enc->encoded_frames_ = NULL; enc->encoded_frames_ = NULL;
enc->mux_ = NULL; enc->mux_ = NULL;
MarkNoError(enc);
// Dimensions and options. // Dimensions and options.
*(int*)&enc->canvas_width_ = width; *(int*)&enc->canvas_width_ = width;
@ -236,7 +261,7 @@ WebPAnimEncoder* WebPAnimEncoderNewInternal(
if (!WebPPictureInit(&enc->curr_canvas_copy_) || if (!WebPPictureInit(&enc->curr_canvas_copy_) ||
!WebPPictureInit(&enc->prev_canvas_) || !WebPPictureInit(&enc->prev_canvas_) ||
!WebPPictureInit(&enc->prev_canvas_disposed_)) { !WebPPictureInit(&enc->prev_canvas_disposed_)) {
return NULL; goto Err;
} }
enc->curr_canvas_copy_.width = width; enc->curr_canvas_copy_.width = width;
enc->curr_canvas_copy_.height = height; enc->curr_canvas_copy_.height = height;
@ -287,7 +312,7 @@ static void FrameRelease(EncodedFrame* const encoded_frame) {
} }
void WebPAnimEncoderDelete(WebPAnimEncoder* enc) { void WebPAnimEncoderDelete(WebPAnimEncoder* enc) {
if (enc != NULL) {; if (enc != NULL) {
WebPPictureFree(&enc->curr_canvas_copy_); WebPPictureFree(&enc->curr_canvas_copy_);
WebPPictureFree(&enc->prev_canvas_); WebPPictureFree(&enc->prev_canvas_);
WebPPictureFree(&enc->prev_canvas_disposed_); WebPPictureFree(&enc->prev_canvas_disposed_);
@ -1106,9 +1131,8 @@ static int CacheFrame(WebPAnimEncoder* const enc,
// We reset some counters, as the frame addition failed/was skipped. // We reset some counters, as the frame addition failed/was skipped.
--enc->count_; --enc->count_;
if (!enc->is_first_frame_) --enc->count_since_key_frame_; if (!enc->is_first_frame_) --enc->count_since_key_frame_;
if (!ok && enc->options_.verbose) { if (!ok) {
fprintf(stderr, "ERROR adding frame. WebPEncodingError: %d.\n", MarkError2(enc, "ERROR adding frame. WebPEncodingError", error_code);
error_code);
} }
} }
enc->curr_canvas_->error_code = error_code; // report error_code enc->curr_canvas_->error_code = error_code; // report error_code
@ -1125,13 +1149,11 @@ static int FlushFrames(WebPAnimEncoder* const enc) {
assert(enc->mux_ != NULL); assert(enc->mux_ != NULL);
err = WebPMuxPushFrame(enc->mux_, info, 1); err = WebPMuxPushFrame(enc->mux_, info, 1);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
if (enc->options_.verbose) { MarkError2(enc, "ERROR adding frame. WebPMuxError", err);
fprintf(stderr, "ERROR adding frame. WebPMuxError: %d.\n", err);
}
return 0; return 0;
} }
if (enc->options_.verbose) { if (enc->options_.verbose) {
fprintf(stderr, "Added frame. offset:%d,%d dispose:%d blend:%d\n", fprintf(stderr, "INFO: Added frame. offset:%d,%d dispose:%d blend:%d\n",
info->x_offset, info->y_offset, info->dispose_method, info->x_offset, info->y_offset, info->dispose_method,
info->blend_method); info->blend_method);
} }
@ -1165,6 +1187,7 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
if (enc == NULL) { if (enc == NULL) {
return 0; return 0;
} }
MarkNoError(enc);
if (!enc->is_first_frame_) { if (!enc->is_first_frame_) {
// Make sure timestamps are non-decreasing (integer wrap-around is OK). // Make sure timestamps are non-decreasing (integer wrap-around is OK).
@ -1174,10 +1197,7 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
if (frame != NULL) { if (frame != NULL) {
frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION;
} }
if (enc->options_.verbose) { MarkError(enc, "ERROR adding frame: timestamps must be non-decreasing");
fprintf(stderr,
"ERROR adding frame: timestamps must be non-decreasing.\n");
}
return 0; return 0;
} }
if (!IncreasePreviousDuration(enc, (int)prev_frame_duration)) { if (!IncreasePreviousDuration(enc, (int)prev_frame_duration)) {
@ -1196,9 +1216,7 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
if (frame->width != enc->canvas_width_ || if (frame->width != enc->canvas_width_ ||
frame->height != enc->canvas_height_) { frame->height != enc->canvas_height_) {
frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION; frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION;
if (enc->options_.verbose) { MarkError(enc, "ERROR adding frame: Invalid frame dimensions");
fprintf(stderr, "ERROR adding frame: Invalid frame dimensions.\n");
}
return 0; return 0;
} }
@ -1208,7 +1226,7 @@ int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
"this incurs a small loss.\n"); "this incurs a small loss.\n");
} }
if (!WebPPictureYUVAToARGB(frame)) { if (!WebPPictureYUVAToARGB(frame)) {
fprintf(stderr, "ERROR converting frame from YUV(A) to ARGB\n"); MarkError(enc, "ERROR converting frame from YUV(A) to ARGB");
return 0; return 0;
} }
} }
@ -1348,17 +1366,15 @@ int WebPAnimEncoderAssemble(WebPAnimEncoder* enc, WebPData* webp_data) {
if (enc == NULL) { if (enc == NULL) {
return 0; return 0;
} }
MarkNoError(enc);
if (webp_data == NULL) { if (webp_data == NULL) {
if (enc->options_.verbose) { MarkError(enc, "ERROR assembling: NULL input");
fprintf(stderr, "ERROR assembling: NULL input\n");
}
return 0; return 0;
} }
if (enc->in_frame_count_ == 0) { if (enc->in_frame_count_ == 0) {
if (enc->options_.verbose) { MarkError(enc, "ERROR: No frames to assemble");
fprintf(stderr, "ERROR: No frames to assemble\n");
}
return 0; return 0;
} }
@ -1393,14 +1409,16 @@ int WebPAnimEncoderAssemble(WebPAnimEncoder* enc, WebPData* webp_data) {
err = OptimizeSingleFrame(enc, webp_data); err = OptimizeSingleFrame(enc, webp_data);
if (err != WEBP_MUX_OK) goto Err; if (err != WEBP_MUX_OK) goto Err;
} }
return 1; return 1;
Err: Err:
if (enc->options_.verbose) { MarkError2(enc, "ERROR assembling WebP", err);
fprintf(stderr, "ERROR assembling WebP: %d\n", err);
}
return 0; return 0;
} }
const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc) {
if (enc == NULL) return NULL;
return enc->error_str_;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -21,7 +21,7 @@
extern "C" { extern "C" {
#endif #endif
#define WEBP_MUX_ABI_VERSION 0x0105 // MAJOR(8b) + MINOR(8b) #define WEBP_MUX_ABI_VERSION 0x0106 // MAJOR(8b) + MINOR(8b)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Mux API // Mux API
@ -436,10 +436,8 @@ struct WebPAnimEncoderOptions {
// then all frames will be key-frames. // then all frames will be key-frames.
int allow_mixed; // If true, use mixed compression mode; may choose int allow_mixed; // If true, use mixed compression mode; may choose
// either lossy and lossless for each frame. // either lossy and lossless for each frame.
int verbose; // If true, print info and warning messages to stderr.
// TODO(urvang): Instead of printing errors to STDERR, we should have an error
// string attached to the encoder.
int verbose; // If true, print encoding info.
uint32_t padding[4]; // Padding for later use. uint32_t padding[4]; // Padding for later use.
}; };
@ -508,10 +506,20 @@ WEBP_EXTERN(int) WebPAnimEncoderAdd(
WEBP_EXTERN(int) WebPAnimEncoderAssemble(WebPAnimEncoder* enc, WEBP_EXTERN(int) WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
WebPData* webp_data); WebPData* webp_data);
// Get error string corresponding to the most recent call using 'enc'. The
// returned string is owned by 'enc' and is valid only until the next call to
// WebPAnimEncoderAdd() or WebPAnimEncoderAssemble() or WebPAnimEncoderDelete().
// Parameters:
// enc - (in/out) object from which the error string is to be fetched.
// Returns:
// NULL if 'enc' is NULL. Otherwise, returns the error string if the last call
// to 'enc' had an error, or an empty string if the last call was a success.
WEBP_EXTERN(const char*) WebPAnimEncoderGetError(WebPAnimEncoder* enc);
// Deletes the WebPAnimEncoder object. // Deletes the WebPAnimEncoder object.
// Parameters: // Parameters:
// anim_enc - (in/out) object to be deleted // enc - (in/out) object to be deleted
WEBP_EXTERN(void) WebPAnimEncoderDelete(WebPAnimEncoder* anim_enc); WEBP_EXTERN(void) WebPAnimEncoderDelete(WebPAnimEncoder* enc);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------