[FFmpeg-devel] [PATCH] OpenEXR decoder rev-16
Reimar Döffinger
Reimar.Doeffinger
Tue Sep 8 16:20:28 CEST 2009
On Tue, Sep 08, 2009 at 03:30:26PM +0200, Jimmy Christensen wrote:
> +static const unsigned int bytes_per_color_table[3] = {
> + 1, 2, 4
> +};
Currently that is of course the same as 1 << n.
Anyway the main point is
a) this is used only in one function so better declare it there
b) should use uint8_t so it does not take up so much space.
> +static inline int check_header_variable(const uint8_t *buf,
> + const uint8_t *buf_end,
> + const char *value_name,
> + const char *value_type,
> + unsigned int minimum_length)
I think all functions lack doxygen documentation.
Also since speed is not very relevant for header parsing most of these
probably should not be inline
> +{
> + if (buf_end - buf >= minimum_length && !strncmp(buf, value_name, strlen(value_name))) {
> + buf += strlen(value_name)+1;
> + if (!strncmp(buf, value_type, strlen(value_type)))
> + return 1;
> + av_log(NULL, AV_LOG_ERROR, "Unknown data type for header variable %s\n", value_name);
> + }
> + return 0;
Please don't do this, for return values either use
1 good, 0 error
or
0 good, < 0 error
> + unsigned int variable_buffer_data_size = bytestream_get_le32(buf);
> + if (buf_end - *buf <= variable_buffer_data_size) {
> + av_log(NULL, AV_LOG_ERROR, "Incomplete header\n");
> + return 0;
> + } else {
> + return variable_buffer_data_size;
> + }
You return in the if path, there is no need for "else".
> + if (!strncmp(*buf, "R", 2))
> + s->red_channel = channel_iter;
> + if (!strncmp(*buf, "G", 2))
> + s->green_channel = channel_iter;
> + if (!strncmp(*buf, "B", 2))
> + s->blue_channel = channel_iter;
strcmp, no need for strncmp.
> + if (channel_iter == s->red_channel ||
> + channel_iter == s->green_channel ||
> + channel_iter == s->blue_channel) {
> + *buf += 2;
> + current_bits_per_color_id = bytestream_get_le32(buf);
> + if (current_bits_per_color_id > 2)
> + return -1;
> + if (channel_iter == s->red_channel) {
> + s->bits_per_color_id = current_bits_per_color_id;
> + s->red_channel_offset = *current_channel_offset;
> + }
> + if (channel_iter == s->green_channel)
> + s->green_channel_offset = *current_channel_offset;
> + if (channel_iter == s->blue_channel)
> + s->blue_channel_offset = *current_channel_offset;
This seems very convoluted, why is red special? And are you misusing
those "channel_iter == s->red_channel" tests to check which one you've
just assigned?
This might be nicer with
{red,green,blue}_channel_offset instead being and array channel_offsets
and maybe enum {RED_CHANNEL, GREEN_CHANNEL, BLUE_CHANNEL} (or just 0 - 2
manually).
> + if (*buf < channel_list_end) {
> + while (*buf[0] != 0x0)
> + *buf += 1;
> + *buf += 1;
e.g.
while (bytestream_get(&buf)) /* skip */;
More importantly though this still misses a check so it will not overrun
beyond the end of the buffer.
> + current_bits_per_color_id = bytestream_get_le32(buf);
> + if (current_bits_per_color_id > 2)
> + return -1;
> + *current_channel_offset += bytes_per_color_table[current_bits_per_color_id];
> + *buf += 12;
> + }
This duplicates code from the RGB case.
> + if (buf_end - buf < 10) {
> + av_log(avctx, AV_LOG_ERROR, "Too short header to parse\n");
> + return -1;
> + } else {
Return in if -> do not add else to avoid unnecessary indentation and to
avoid cluttering the "default" code path due to error handling.
> + channel_list_end += variable_buffer_data_size;
> + while (channel_list_end >= buf + 19) {
Thanks to padding it is probably not wrong, but it is inconsistent when
channel_list_end - buf >= 19 is used elsewhere.
> + if (get_rgb_channel(&buf,
> + channel_list_end,
> + s,
> + channel_iter,
> + ¤t_channel_offset) == -1) {
> + // Process the dataWindow variable
> + if (check_header_variable(buf, buf_end, "dataWindow", "box2i", 31) == 1) {
Which so specific (i.e. == -1 and == 1?) If someone extended those
functions to return other value, would it really make sense?
Or in other words, it should be
if (get_rgb_channel() < 0)
and
if (check_header_variable())
> + while (buf++ < buf_end)
> + if (buf[0] == 0x0)
> + break;
That skips a string just like another piece of code but checks for the
buffer end.
Maybe this should just be a function, then you can't forgot some of the checks
in half of the places.
> + if (buf < buf_end) {
> + // Move pointer out of header
> + buf++;
> + } else {
> + av_log(avctx, AV_LOG_ERROR, "Incomplete file\n");
> + return -1;
> + }
Huh? I thought you had the "fixed" once already:
if (buf >= buf_end) {
av_log();
return -1;
}
buf++;
> + if (s->red_channel != -1 &&
> + s->blue_channel != -1 &&
> + s->green_channel != -1) {
> + if (s->picture.data[0])
> + avctx->release_buffer(avctx, &s->picture);
> + if (avcodec_check_dimensions(avctx, w, h))
> + return -1;
> + if (w != avctx->width || h != avctx->height) {
> + // Verify the xmin, xmax, ymin, ymax and xdelta before setting the actual image size
> + if (xmin > w || xmin == ~0 ||
> + xmax > w || xmax == ~0 ||
> + ymin > h || ymin == ~0 ||
> + ymax > h || ymax == ~0 ||
> + xdelta == ~0) {
> + av_log(avctx, AV_LOG_ERROR, "Wrong sizing or missing size information\n");
> + return -1;
> + }
> + avcodec_set_dimensions(avctx, w, h);
> + }
> +
> + if (avctx->get_buffer(avctx, p) < 0) {
> + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
> + return -1;
> + }
> + } else {
> + if (s->red_channel == -1)
> + av_log(avctx, AV_LOG_ERROR, "Missing red channel\n");
> + if (s->green_channel == -1)
> + av_log(avctx, AV_LOG_ERROR, "Missing green channel\n");
> + if (s->blue_channel == -1)
> + av_log(avctx, AV_LOG_ERROR, "Missing blue channel\n");
> + return -1;
> + }
As always, where possible do not indent the non-error code-path.
More information about the ffmpeg-devel
mailing list