mirror of
https://github.com/webmproject/libwebp.git
synced 2025-07-13 06:24:27 +02:00
add extra meaning to WebPDecBuffer::is_external_memory
If value is '2', it means the buffer is a 'slow' one, like GPU-mapped memory. This change is backward compatible (setting is_external_memory to 2 will be a no-op in previous libraries) dwebp: add flags to force a particular colorspace format new flags is: -pixel_format {RGB,RGBA,BGR,BGRA,ARGB,RGBA_4444,RGB_565, rgbA,bgrA,Argb,rgbA_4444,YUV,YUVA} and also,external_memory {0,1,2} These flags are mostly for debuggging purpose, and hence are not documented. Change-Id: Iac88ce1e10b35163dd7af57f9660f062f5d8ed5e
This commit is contained in:
@ -92,7 +92,7 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
|
||||
return VP8_STATUS_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (!buffer->is_external_memory && buffer->private_memory == NULL) {
|
||||
if (buffer->is_external_memory <= 0 && buffer->private_memory == NULL) {
|
||||
uint8_t* output;
|
||||
int uv_stride = 0, a_stride = 0;
|
||||
uint64_t uv_size = 0, a_size = 0, total_size;
|
||||
@ -227,7 +227,7 @@ int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
|
||||
|
||||
void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
|
||||
if (buffer != NULL) {
|
||||
if (!buffer->is_external_memory) {
|
||||
if (buffer->is_external_memory <= 0) {
|
||||
WebPSafeFree(buffer->private_memory);
|
||||
}
|
||||
buffer->private_memory = NULL;
|
||||
@ -256,5 +256,45 @@ void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
VP8StatusCode WebPCopyDecBufferPixels(const WebPDecBuffer* const src_buf,
|
||||
WebPDecBuffer* const dst_buf) {
|
||||
assert(src_buf != NULL && dst_buf != NULL);
|
||||
assert(src_buf->colorspace == dst_buf->colorspace);
|
||||
|
||||
dst_buf->width = src_buf->width;
|
||||
dst_buf->height = src_buf->height;
|
||||
if (CheckDecBuffer(dst_buf) != VP8_STATUS_OK) {
|
||||
return VP8_STATUS_INVALID_PARAM;
|
||||
}
|
||||
if (WebPIsRGBMode(src_buf->colorspace)) {
|
||||
const WebPRGBABuffer* const src = &src_buf->u.RGBA;
|
||||
const WebPRGBABuffer* const dst = &dst_buf->u.RGBA;
|
||||
WebPCopyPlane(src->rgba, src->stride, dst->rgba, dst->stride,
|
||||
src_buf->width * kModeBpp[src_buf->colorspace],
|
||||
src_buf->height);
|
||||
} else {
|
||||
const WebPYUVABuffer* const src = &src_buf->u.YUVA;
|
||||
const WebPYUVABuffer* const dst = &dst_buf->u.YUVA;
|
||||
WebPCopyPlane(src->y, src->y_stride, dst->y, dst->y_stride,
|
||||
src_buf->width, src_buf->height);
|
||||
WebPCopyPlane(src->u, src->u_stride, dst->u, dst->u_stride,
|
||||
(src_buf->width + 1) / 2, (src_buf->height + 1) / 2);
|
||||
WebPCopyPlane(src->v, src->v_stride, dst->v, dst->v_stride,
|
||||
(src_buf->width + 1) / 2, (src_buf->height + 1) / 2);
|
||||
if (WebPIsAlphaMode(src_buf->colorspace)) {
|
||||
WebPCopyPlane(src->a, src->a_stride, dst->a, dst->a_stride,
|
||||
src_buf->width, src_buf->height);
|
||||
}
|
||||
}
|
||||
return VP8_STATUS_OK;
|
||||
}
|
||||
|
||||
int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
|
||||
const WebPBitstreamFeatures* const features) {
|
||||
assert(output != NULL);
|
||||
return (output->is_external_memory >= 2) &&
|
||||
WebPIsPremultipliedMode(output->colorspace) &&
|
||||
(features != NULL && features->has_alpha);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -70,7 +70,9 @@ struct WebPIDecoder {
|
||||
VP8Io io_;
|
||||
|
||||
MemBuffer mem_; // input memory buffer.
|
||||
WebPDecBuffer output_; // output buffer (when no external one is supplied)
|
||||
WebPDecBuffer output_; // output buffer (when no external one is supplied,
|
||||
// or if the external one has slow-memory)
|
||||
WebPDecBuffer* final_output_; // Slow-memory output to copy to eventually.
|
||||
size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header.
|
||||
|
||||
int last_mb_y_; // last row reached for intra-mode decoding
|
||||
@ -249,10 +251,16 @@ static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
|
||||
|
||||
idec->state_ = STATE_DONE;
|
||||
if (options != NULL && options->flip) {
|
||||
return WebPFlipBuffer(output);
|
||||
} else {
|
||||
return VP8_STATUS_OK;
|
||||
const VP8StatusCode status = WebPFlipBuffer(output);
|
||||
if (status != VP8_STATUS_OK) return status;
|
||||
}
|
||||
if (idec->final_output_ != NULL) {
|
||||
WebPCopyDecBufferPixels(output, idec->final_output_); // do the slow-copy
|
||||
WebPFreeDecBuffer(&idec->output_);
|
||||
*output = *idec->final_output_;
|
||||
idec->final_output_ = NULL;
|
||||
}
|
||||
return VP8_STATUS_OK;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -575,9 +583,10 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public functions
|
||||
// Internal constructor
|
||||
|
||||
WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
|
||||
static WebPIDecoder* NewDecoder(WebPDecBuffer* const output_buffer,
|
||||
const WebPBitstreamFeatures* const features) {
|
||||
WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
|
||||
if (idec == NULL) {
|
||||
return NULL;
|
||||
@ -593,25 +602,46 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
|
||||
VP8InitIo(&idec->io_);
|
||||
|
||||
WebPResetDecParams(&idec->params_);
|
||||
idec->params_.output = (output_buffer != NULL) ? output_buffer
|
||||
: &idec->output_;
|
||||
if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) {
|
||||
idec->params_.output = &idec->output_;
|
||||
idec->final_output_ = output_buffer;
|
||||
if (output_buffer != NULL) {
|
||||
idec->params_.output->colorspace = output_buffer->colorspace;
|
||||
}
|
||||
} else {
|
||||
idec->params_.output = output_buffer;
|
||||
idec->final_output_ = NULL;
|
||||
}
|
||||
WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions.
|
||||
|
||||
return idec;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public functions
|
||||
|
||||
WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
|
||||
return NewDecoder(output_buffer, NULL);
|
||||
}
|
||||
|
||||
WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
|
||||
WebPDecoderConfig* config) {
|
||||
WebPIDecoder* idec;
|
||||
WebPBitstreamFeatures tmp_features;
|
||||
WebPBitstreamFeatures* const features =
|
||||
(config == NULL) ? &tmp_features : &config->input;
|
||||
memset(&tmp_features, 0, sizeof(tmp_features));
|
||||
|
||||
// Parse the bitstream's features, if requested:
|
||||
if (data != NULL && data_size > 0 && config != NULL) {
|
||||
if (WebPGetFeatures(data, data_size, &config->input) != VP8_STATUS_OK) {
|
||||
if (data != NULL && data_size > 0) {
|
||||
if (WebPGetFeatures(data, data_size, features) != VP8_STATUS_OK) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Create an instance of the incremental decoder
|
||||
idec = WebPINewDecoder(config ? &config->output : NULL);
|
||||
idec = (config != NULL) ? NewDecoder(&config->output, features)
|
||||
: NewDecoder(NULL, features);
|
||||
if (idec == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@ -645,11 +675,11 @@ void WebPIDelete(WebPIDecoder* idec) {
|
||||
|
||||
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
|
||||
size_t output_buffer_size, int output_stride) {
|
||||
const int is_external_memory = (output_buffer != NULL);
|
||||
const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
|
||||
WebPIDecoder* idec;
|
||||
|
||||
if (mode >= MODE_YUV) return NULL;
|
||||
if (!is_external_memory) { // Overwrite parameters to sane values.
|
||||
if (is_external_memory == 0) { // Overwrite parameters to sane values.
|
||||
output_buffer_size = 0;
|
||||
output_stride = 0;
|
||||
} else { // A buffer was passed. Validate the other params.
|
||||
@ -671,11 +701,11 @@ WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
|
||||
uint8_t* u, size_t u_size, int u_stride,
|
||||
uint8_t* v, size_t v_size, int v_stride,
|
||||
uint8_t* a, size_t a_size, int a_stride) {
|
||||
const int is_external_memory = (luma != NULL);
|
||||
const int is_external_memory = (luma != NULL) ? 1 : 0;
|
||||
WebPIDecoder* idec;
|
||||
WEBP_CSP_MODE colorspace;
|
||||
|
||||
if (!is_external_memory) { // Overwrite parameters to sane values.
|
||||
if (is_external_memory == 0) { // Overwrite parameters to sane values.
|
||||
luma_size = u_size = v_size = a_size = 0;
|
||||
luma_stride = u_stride = v_stride = a_stride = 0;
|
||||
u = v = a = NULL;
|
||||
@ -783,6 +813,9 @@ static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) {
|
||||
if (idec->state_ <= STATE_VP8_PARTS0) {
|
||||
return NULL;
|
||||
}
|
||||
if (idec->final_output_ != NULL) {
|
||||
return NULL; // not yet slow-copied
|
||||
}
|
||||
return idec->params_.output;
|
||||
}
|
||||
|
||||
@ -792,7 +825,7 @@ const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
|
||||
const WebPDecBuffer* const src = GetOutputBuffer(idec);
|
||||
if (left != NULL) *left = 0;
|
||||
if (top != NULL) *top = 0;
|
||||
if (src) {
|
||||
if (src != NULL) {
|
||||
if (width != NULL) *width = src->width;
|
||||
if (height != NULL) *height = idec->params_.last_y;
|
||||
} else {
|
||||
|
@ -32,7 +32,7 @@ extern "C" {
|
||||
// version numbers
|
||||
#define DEC_MAJ_VERSION 0
|
||||
#define DEC_MIN_VERSION 5
|
||||
#define DEC_REV_VERSION 0
|
||||
#define DEC_REV_VERSION 1
|
||||
|
||||
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
|
||||
// Constraints are: We need to store one 16x16 block of luma samples (y),
|
||||
|
@ -514,6 +514,8 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
|
||||
WebPFreeDecBuffer(params->output);
|
||||
} else {
|
||||
if (params->options != NULL && params->options->flip) {
|
||||
// This restores the original stride values if options->flip was used
|
||||
// during the call to WebPAllocateDecBuffer above.
|
||||
status = WebPFlipBuffer(params->output);
|
||||
}
|
||||
}
|
||||
@ -758,9 +760,24 @@ VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
|
||||
}
|
||||
|
||||
WebPResetDecParams(¶ms);
|
||||
params.output = &config->output;
|
||||
params.options = &config->options;
|
||||
status = DecodeInto(data, data_size, ¶ms);
|
||||
params.output = &config->output;
|
||||
if (WebPAvoidSlowMemory(params.output, &config->input)) {
|
||||
// decoding to slow memory: use a temporary in-mem buffer to decode into.
|
||||
WebPDecBuffer in_mem_buffer;
|
||||
WebPInitDecBuffer(&in_mem_buffer);
|
||||
in_mem_buffer.colorspace = config->output.colorspace;
|
||||
in_mem_buffer.width = config->input.width;
|
||||
in_mem_buffer.height = config->input.height;
|
||||
params.output = &in_mem_buffer;
|
||||
status = DecodeInto(data, data_size, ¶ms);
|
||||
if (status == VP8_STATUS_OK) { // do the slow-copy
|
||||
status = WebPCopyDecBufferPixels(&in_mem_buffer, &config->output);
|
||||
}
|
||||
WebPFreeDecBuffer(&in_mem_buffer);
|
||||
} else {
|
||||
status = DecodeInto(data, data_size, ¶ms);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -826,4 +843,3 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -45,11 +45,20 @@ struct WebPDecParams {
|
||||
OutputFunc emit; // output RGB or YUV samples
|
||||
OutputAlphaFunc emit_alpha; // output alpha channel
|
||||
OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values
|
||||
|
||||
WebPDecBuffer* final_output; // In case the user supplied a slow-memory
|
||||
// output, we decode image in temporary buffer
|
||||
// (this::output) and copy it here.
|
||||
WebPDecBuffer tmp_buffer; // this::output will point to this one in case
|
||||
// of slow memory.
|
||||
};
|
||||
|
||||
// Should be called first, before any use of the WebPDecParams object.
|
||||
void WebPResetDecParams(WebPDecParams* const params);
|
||||
|
||||
// Delete all memory (after an error occurred, for instance)
|
||||
void WebPFreeDecParams(WebPDecParams* const params);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Header parsing helpers
|
||||
|
||||
@ -107,13 +116,23 @@ VP8StatusCode WebPAllocateDecBuffer(int width, int height,
|
||||
VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer);
|
||||
|
||||
// Copy 'src' into 'dst' buffer, making sure 'dst' is not marked as owner of the
|
||||
// memory (still held by 'src').
|
||||
// memory (still held by 'src'). No pixels are copied.
|
||||
void WebPCopyDecBuffer(const WebPDecBuffer* const src,
|
||||
WebPDecBuffer* const dst);
|
||||
|
||||
// Copy and transfer ownership from src to dst (beware of parameter order!)
|
||||
void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst);
|
||||
|
||||
// Copy pixels from 'src' into a *preallocated* 'dst' buffer. Returns
|
||||
// VP8_STATUS_INVALID_PARAM if the 'dst' is not set up correctly for the copy.
|
||||
VP8StatusCode WebPCopyDecBufferPixels(const WebPDecBuffer* const src,
|
||||
WebPDecBuffer* const dst);
|
||||
|
||||
// Returns true if decoding will be slow with the current configuration
|
||||
// and bitstream features.
|
||||
int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
|
||||
const WebPBitstreamFeatures* const features);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -197,7 +197,10 @@ struct WebPYUVABuffer { // view as YUVA
|
||||
struct WebPDecBuffer {
|
||||
WEBP_CSP_MODE colorspace; // Colorspace.
|
||||
int width, height; // Dimensions.
|
||||
int is_external_memory; // If true, 'internal_memory' pointer is not used.
|
||||
int is_external_memory; // If non-zero, 'internal_memory' pointer is not
|
||||
// used. If value is '2' or more, the external
|
||||
// memory is considered 'slow' and multiple
|
||||
// read/write will be avoided.
|
||||
union {
|
||||
WebPRGBABuffer RGBA;
|
||||
WebPYUVABuffer YUVA;
|
||||
@ -205,7 +208,7 @@ struct WebPDecBuffer {
|
||||
uint32_t pad[4]; // padding for later use
|
||||
|
||||
uint8_t* private_memory; // Internally allocated memory (only when
|
||||
// is_external_memory is false). Should not be used
|
||||
// is_external_memory is 0). Should not be used
|
||||
// externally, but accessed via the buffer union.
|
||||
};
|
||||
|
||||
@ -269,7 +272,7 @@ typedef enum VP8StatusCode {
|
||||
// that of the returned WebPIDecoder object.
|
||||
// The supplied 'output_buffer' content MUST NOT be changed between calls to
|
||||
// WebPIAppend() or WebPIUpdate() unless 'output_buffer.is_external_memory' is
|
||||
// set to 1. In such a case, it is allowed to modify the pointers, size and
|
||||
// not set to 0. In such a case, it is allowed to modify the pointers, size and
|
||||
// stride of output_buffer.u.RGBA or output_buffer.u.YUVA, provided they remain
|
||||
// within valid bounds.
|
||||
// All other fields of WebPDecBuffer MUST remain constant between calls.
|
||||
|
Reference in New Issue
Block a user