[PATCH 0/2] jpeg decoder

117 views
Skip to first unread message

Víctor Manuel Jáquez Leal

unread,
Jun 12, 2010, 1:49:32 PM6/12/10
to gst...@googlegroups.com, Víctor Manuel Jáquez Leal
Hi,

This is a first approach to the JPEG decoder in gst-dsp.

At least it decodes my shrek.jpg correctly:

gst-launch filesrc location=/jpeg-test/shrek.jpg ! jpegparse
! dspvdec ! freeze ! omapfbsink -v

jpegparse, from jpegformat plugin in gst-plugins-bad is required.

The bad news, is that jpepgdec SN only supports one input buffer, so a temporal
hack is required, which may affect the rest of video decoders.

Víctor Manuel Jáquez Leal (2):
temporal hack for one buffer per port
jpegdec: initial implementation

gstdspvdec.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
gstdspvdec.h | 1 +
2 files changed, 250 insertions(+), 2 deletions(-)

Víctor Manuel Jáquez Leal

unread,
Jun 12, 2010, 1:49:33 PM6/12/10
to gst...@googlegroups.com, Víctor Manuel Jáquez Leal
This hack is only temporal for jpegdec, because this SN can not
have more than one buffer in the input port.

Signed-off-by: Víctor Manuel Jáquez Leal <vja...@igalia.com>
---
gstdspvdec.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/gstdspvdec.c b/gstdspvdec.c
index 7621a7d..bbc6a6d 100644
--- a/gstdspvdec.c
+++ b/gstdspvdec.c
@@ -1146,8 +1146,8 @@ instance_init(GTypeInstance *instance,
base->use_pad_alloc = TRUE;
base->create_node = create_node;

- base->ports[0] = du_port_new(0, 2);
- base->ports[1] = du_port_new(1, 2);
+ base->ports[0] = du_port_new(0, 1);
+ base->ports[1] = du_port_new(1, 1);

gst_pad_set_setcaps_function(base->sinkpad, sink_setcaps);
}
--
1.7.0.2

Víctor Manuel Jáquez Leal

unread,
Jun 12, 2010, 1:49:34 PM6/12/10
to gst...@googlegroups.com, Víctor Manuel Jáquez Leal
Signed-off-by: Víctor Manuel Jáquez Leal <vja...@igalia.com>
---
gstdspvdec.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gstdspvdec.h | 1 +
2 files changed, 248 insertions(+), 0 deletions(-)

diff --git a/gstdspvdec.c b/gstdspvdec.c
index bbc6a6d..7e262d4 100644
--- a/gstdspvdec.c
+++ b/gstdspvdec.c
@@ -39,6 +39,7 @@ enum {
GSTDSP_H264DEC,
GSTDSP_H263DEC,
GSTDSP_WMVDEC,
+ GSTDSP_JPEGDEC,
};

static GstDspBaseClass *parent_class;
@@ -91,6 +92,12 @@ generate_sink_template(void)

gst_caps_append_structure(caps, struc);

+ struc = gst_structure_new("image/jpeg",
+ "parsed", G_TYPE_BOOLEAN, TRUE,
+ NULL);
+
+ gst_caps_append_structure(caps, struc);
+
return caps;
}

@@ -838,6 +845,202 @@ setup_h264params(GstDspBase *base)
p->recv_cb = h264dec_out_recv_cb;
}

+struct jpegdec_args
+{
+ uint16_t num_streams;
+
+ uint16_t in_id;
+ uint16_t in_type;
+ uint16_t in_count;
+
+ uint16_t out_id;
+ uint16_t out_type;
+ uint16_t out_count;
+
+ uint16_t max_height;
+ uint16_t max_width;
+ uint16_t progressive;
+
+ uint16_t color_format;
+ uint16_t unknown;
+ uint16_t sections_input;
+ uint16_t sections_output;
+
+ uint16_t is_argb32;
+};
+
+struct jpegdec_in_params {
+ int32_t buf_count;
+ uint32_t frame_count;
+ uint32_t frame_align;
+ uint32_t frame_size;
+ uint32_t display_width;
+ uint32_t reserved_0;
+ uint32_t reserved_1;
+ uint32_t reserved_2;
+ uint32_t reserved_3;
+ uint32_t resize_option;
+ uint32_t num_mcu;
+ uint32_t decode_header;
+ uint32_t max_height;
+ uint32_t max_width;
+ uint32_t max_scans;
+ uint32_t endianness;
+ uint32_t color_format;
+ uint32_t rgb_format;
+ uint32_t num_mcu_row;
+ uint32_t x_org;
+ uint32_t y_org;
+ uint32_t x_lenght;
+ uint32_t y_length;
+ uint32_t argb;
+ uint32_t total_size;
+};
+
+struct jpegdec_out_params {
+ int32_t buf_count;
+ uint32_t frame_count;
+ uint32_t frame_align;
+ uint32_t frame_size;
+ uint32_t img_format;
+ uint32_t width;
+ uint32_t height;
+ uint32_t progressive;
+ uint32_t error_code;
+ uint32_t reserved_0;
+ uint32_t reserved_1;
+ uint32_t reserved_2;
+ uint32_t last_mcu;
+ uint32_t stride[3];
+ uint32_t output_height;
+ uint32_t output_width;
+ uint32_t total_au;
+ uint32_t bytes_consumed;
+ uint32_t current_au;
+ uint32_t current_scan;
+ int32_t dsp_error;
+};
+
+static inline void *
+get_jpeg_args(GstDspVDec *self)
+{
+ GstDspBase *base = GST_DSP_BASE(self);
+
+ struct jpegdec_args args = {
+ .num_streams = 2,
+ .in_id = 0,
+ .in_type = 0,
+ .in_count = base->ports[0]->num_buffers,
+ .out_id = 1,
+ .out_type = 0,
+ .out_count = base->ports[1]->num_buffers,
+ .max_height = self->height,
+ .max_width = self->width,
+ .progressive = self->jpeg_is_interlaced ? 1 : 0,
+ .color_format = 4,
+ .sections_input = 0,
+ .sections_output = 0,
+ .is_argb32 = 0,
+ };
+
+ struct foo_data *cb_data;
+
+ cb_data = malloc(sizeof(*cb_data));
+ cb_data->size = sizeof(args);
+ memcpy(&cb_data->data, &args, sizeof(args));
+
+ return cb_data;
+}
+
+static inline dmm_buffer_t *
+setup_jpegparams_in(GstDspBase *base)
+{
+ struct jpegdec_in_params *in_param;
+ dmm_buffer_t *tmp;
+
+ tmp = dmm_buffer_new(base->dsp_handle, base->proc);
+ dmm_buffer_allocate(tmp, sizeof(*in_param));
+
+ in_param = tmp->data;
+ memset(in_param, 0, sizeof(*in_param));
+
+ in_param->frame_count = 1;
+ in_param->frame_align = 4;
+ in_param->display_width = 1600;
+ in_param->color_format = 4;
+ in_param->rgb_format = 9;
+
+ return tmp;
+}
+
+static void
+jpegdec_in_send_cb(GstDspBase *base,
+ du_port_t *port,
+ dmm_buffer_t *p,
+ dmm_buffer_t *b)
+{
+ GstDspVDec *self = GST_DSP_VDEC(base);
+ struct jpegdec_in_params *param;
+ param = p->data;
+
+ param->frame_size = b->size;
+ pr_debug(self, "buffer size = %u", param->frame_size);
+
+ param->buf_count = g_atomic_int_exchange_and_add(&self->frame_index, 1);
+ dmm_buffer_clean(p, sizeof(*param));
+}
+
+static void
+jpegdec_out_send_cb(GstDspBase *base,
+ du_port_t *port,
+ dmm_buffer_t *p,
+ dmm_buffer_t *b)
+{
+ struct jpegdec_out_params *param;
+ param = p->data;
+ dmm_buffer_invalidate(p, sizeof(*param));
+}
+
+static void
+jpegdec_out_recv_cb(GstDspBase *base,
+ du_port_t *port,
+ dmm_buffer_t *p,
+ dmm_buffer_t *b)
+{
+ GstDspVDec *self = GST_DSP_VDEC(base);
+ struct jpegdec_out_params *param;
+ param = p->data;
+
+ pr_debug(self, "output buffer size: %u", b->size);
+ pr_debug(self, "error: 0x%x, dsp error: 0x%x, frame count: %u",
+ param->error_code, param->dsp_error, param->frame_count);
+}
+
+static inline void
+setup_jpegdec_params(GstDspBase *base)
+{
+ struct jpegdec_out_params *out_param;
+ unsigned i;
+ du_port_t *p;
+
+ p = base->ports[0];
+ for (i = 0; i < p->num_buffers; i++) {
+ p->params[i] = setup_jpegparams_in(base);
+ }
+ p->send_cb = jpegdec_in_send_cb;
+
+ p = base->ports[1];
+ for (i = 0; i < p->num_buffers; i++) {
+ dmm_buffer_t *tmp;
+ tmp = dmm_buffer_new(base->dsp_handle, base->proc);
+ dmm_buffer_allocate(tmp, sizeof(*out_param));
+ memset(tmp->data, 0, sizeof(*out_param));
+ p->params[i] = tmp;
+ }
+ p->send_cb = jpegdec_out_send_cb;
+ p->recv_cb = jpegdec_out_recv_cb;
+}
+
static void *
create_node(GstDspBase *base)
{
@@ -861,6 +1064,9 @@ create_node(GstDspBase *base)
const dsp_uuid_t wmv_dec_uuid = { 0x609DAB97, 0x3DFC, 0x471F, 0x8A, 0xB9,
{ 0x4E, 0x56, 0xE8, 0x34, 0x50, 0x1B } };

+ const dsp_uuid_t jpeg_dec_uuid = { 0x5D9CB711, 0x4645, 0x11d6, 0xb0, 0xdc,
+ { 0x00, 0xc0, 0x4f, 0x1f, 0xc0, 0x36 } };
+
#if SN_API >= 1
const dsp_uuid_t conversions_uuid = { 0x722DD0DA, 0xF532, 0x4238, 0xB8, 0x46,
{ 0xAB, 0xFF, 0x5D, 0xA4, 0xBA, 0x02 } };
@@ -893,6 +1099,10 @@ create_node(GstDspBase *base)
alg_uuid = &wmv_dec_uuid;
alg_fn = "wmv9dec_sn.dll64P";
break;
+ case GSTDSP_JPEGDEC:
+ alg_uuid = &jpeg_dec_uuid;
+ alg_fn = "jpegdec_sn.dll64P";
+ break;
default:
pr_err(self, "unknown algorithm");
return NULL;
@@ -958,6 +1168,33 @@ create_node(GstDspBase *base)
attrs.profile_id = 1;
cb_data = get_wmv_args(self);
break;
+ case GSTDSP_JPEGDEC:
+ if (self->jpeg_is_interlaced) {
+ if (self->width * self->height > 2560 * 2048)
+ attrs.profile_id = 9;
+ else if (self->width * self->height > 2560 * 1600)
+ attrs.profile_id = 8;
+ else if (self->width * self->height > 2048 * 1536)
+ attrs.profile_id = 7;
+ else if (self->width * self->height > 1920 * 1200)
+ attrs.profile_id = 6;
+ else if (self->width * self->height > 1280 * 1024)
+ attrs.profile_id = 5;
+ else if (self->width * self->height > 800 * 600)
+ attrs.profile_id = 4;
+ else if (self->width * self->height > 640 * 480)
+ attrs.profile_id = 3;
+ else if (self->width * self->height > 352 * 288)
+ attrs.profile_id = 2;
+ else if (self->width * self->height > 176 * 144)
+ attrs.profile_id = 1;
+ else
+ attrs.profile_id = 0;
+ }
+ else
+ attrs.profile_id = -1;
+ cb_data = get_jpeg_args(self);
+ break;
default:
cb_data = NULL;
}
@@ -989,6 +1226,9 @@ create_node(GstDspBase *base)
case GSTDSP_MPEG4VDEC:
setup_mp4vdec_params(base);
break;
+ case GSTDSP_JPEGDEC:
+ setup_jpegdec_params(base);
+ break;
default:
break;
}
@@ -1097,6 +1337,13 @@ sink_setcaps(GstPad *pad,
self->wmv_is_vc1 = FALSE;
}
}
+ else if (strcmp(name, "image/jpeg") == 0) {
+ base->alg = GSTDSP_JPEGDEC;
+ base->use_eos_align = TRUE;
+
+ gst_structure_get_boolean(in_struc, "interlaced",
+ &self->jpeg_is_interlaced);
+ }
else
base->alg = GSTDSP_MPEG4VDEC;

diff --git a/gstdspvdec.h b/gstdspvdec.h
index 5c7e440..50dc577 100644
--- a/gstdspvdec.h
+++ b/gstdspvdec.h
@@ -46,6 +46,7 @@ struct GstDspVDec {
gint width, height;
gint frame_index;
gboolean wmv_is_vc1;
+ gboolean jpeg_is_interlaced;
GstBuffer *codec_data;
gboolean codec_data_sent;

--
1.7.0.2

Víctor M. Jáquez L.

unread,
Jun 29, 2010, 6:11:00 AM6/29/10
to gst...@googlegroups.com
Felipec,

Any comments about these patches and the buffer number ones?

vmjl

On Sat, Jun 12, 2010 at 07:49:32PM +0200, V�ctor M. J�quez L. wrote:
> Hi,
>
> This is a first approach to the JPEG decoder in gst-dsp.
>
> At least it decodes my shrek.jpg correctly:
>
> gst-launch filesrc location=/jpeg-test/shrek.jpg ! jpegparse
> ! dspvdec ! freeze ! omapfbsink -v
>
> jpegparse, from jpegformat plugin in gst-plugins-bad is required.
>
> The bad news, is that jpepgdec SN only supports one input buffer, so a temporal
> hack is required, which may affect the rest of video decoders.
>

> V�ctor Manuel J�quez Leal (2):

Felipe Contreras

unread,
Jul 3, 2010, 7:36:17 PM7/3/10
to Víctor Manuel Jáquez Leal, gst...@googlegroups.com
2010/6/12 Víctor Manuel Jáquez Leal <vja...@igalia.com>:
> --- a/gstdspvdec.c
> +++ b/gstdspvdec.c

> +static inline void *
> +get_jpeg_args(GstDspVDec *self)
> +{
> +       GstDspBase *base = GST_DSP_BASE(self);
> +
> +       struct jpegdec_args args = {
> +               .num_streams = 2,
> +               .in_id = 0,
> +               .in_type = 0,
> +               .in_count = base->ports[0]->num_buffers,
> +               .out_id = 1,
> +               .out_type = 0,
> +               .out_count = base->ports[1]->num_buffers,
> +               .max_height = self->height,
> +               .max_width = self->width,
> +               .progressive = self->jpeg_is_interlaced ? 1 : 0,
> +               .color_format = 4,

> +               .sections_input = 0,
> +               .sections_output = 0,
> +               .is_argb32 = 0,

No need to initialize these to 0 (new guideline in gst-dsp). They are
zeroed as static storage.

Decoders should not need to update a frame index.

I tried to remove that and the code still seems to work.

> +       dmm_buffer_clean(p, sizeof(*param));
> +}

Which means this whole function can go away.

This one is not doing anything. But it's good that you send the code
so that we might add it later if needed.

For now this can go away.

> +static inline void
> +setup_jpegdec_params(GstDspBase *base)
> +{
> +       struct jpegdec_out_params *out_param;
> +       unsigned i;
> +       du_port_t *p;
> +
> +       p = base->ports[0];
> +       for (i = 0; i < p->num_buffers; i++) {
> +               p->params[i] = setup_jpegparams_in(base);
> +       }
> +       p->send_cb = jpegdec_in_send_cb;
> +
> +       p = base->ports[1];
> +       for (i = 0; i < p->num_buffers; i++) {
> +               dmm_buffer_t *tmp;
> +               tmp = dmm_buffer_new(base->dsp_handle, base->proc);
> +               dmm_buffer_allocate(tmp, sizeof(*out_param));
> +               memset(tmp->data, 0, sizeof(*out_param));
> +               p->params[i] = tmp;
> +       }
> +       p->send_cb = jpegdec_out_send_cb;
> +       p->recv_cb = jpegdec_out_recv_cb;
> +}

All this code has to change completely for the new cache maintenance
API. I've done the update and will send the code soonish.

Thanks! It seems to work for me.

--
Felipe Contreras

Felipe Contreras

unread,
Jul 3, 2010, 7:37:19 PM7/3/10
to gst...@googlegroups.com
2010/6/29 Víctor M. Jáquez L. <vja...@igalia.com>:

> Any comments about these patches and the buffer number ones?

Sorry, I've been busy.

I'm about to send the 'next' patch series with your patches included
(with modifications). Please review.

--
Felipe Contreras

Reply all
Reply to author
Forward
0 new messages