jpeg: port to 0.11

Also disable smoke for now.
This commit is contained in:
Wim Taymans 2011-08-17 15:39:27 +02:00
parent 48e47ad702
commit be4f60b062
7 changed files with 407 additions and 403 deletions

View file

@ -315,7 +315,7 @@ dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED=" deinterlace flx goom2k1 icydemux id3demux \
imagefreeze interleave law matroska monoscope shapewipe smpte \
videobox videocrop videomixer \
annodex apetag cairo cairo_gobject dv1394 flac gdk_pixbuf jpeg libdv libpng \
annodex apetag cairo cairo_gobject dv1394 flac gdk_pixbuf libdv libpng \
oss oss4 shout2 \
soup taglib wavpack "
AC_SUBST(GST_PLUGINS_NONPORTED)

View file

@ -3,10 +3,8 @@ plugin_LTLIBRARIES = libgstjpeg.la
libgstjpeg_la_SOURCES = \
gstjpeg.c \
gstjpegenc.c \
gstjpegdec.c \
gstsmokeenc.c \
smokecodec.c \
gstsmokedec.c
gstjpegdec.c
# deprected gstsmokeenc.c smokecodec.c gstsmokedec.c
libgstjpeg_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgstjpeg_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
@ -16,6 +14,5 @@ libgstjpeg_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = \
gstjpeg.h \
gstjpegdec.h gstjpegenc.h \
gstsmokeenc.h gstsmokedec.h \
smokecodec.h smokeformat.h
gstjpegdec.h gstjpegenc.h
# deprecated gstsmokeenc.h gstsmokedec.h smokecodec.h smokeformat.h

View file

@ -27,8 +27,10 @@
#include "gstjpeg.h"
#include "gstjpegdec.h"
#include "gstjpegenc.h"
#if 0
#include "gstsmokeenc.h"
#include "gstsmokedec.h"
#endif
GType
gst_idct_method_get_type (void)
@ -59,6 +61,7 @@ plugin_init (GstPlugin * plugin)
GST_TYPE_JPEG_DEC))
return FALSE;
#if 0
if (!gst_element_register (plugin, "smokeenc", GST_RANK_PRIMARY,
GST_TYPE_SMOKEENC))
return FALSE;
@ -66,6 +69,7 @@ plugin_init (GstPlugin * plugin)
if (!gst_element_register (plugin, "smokedec", GST_RANK_PRIMARY,
GST_TYPE_SMOKEDEC))
return FALSE;
#endif
return TRUE;
}

View file

@ -66,12 +66,10 @@ static GstStaticPadTemplate gst_jpeg_dec_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420") "; "
GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_BGR "; "
GST_VIDEO_CAPS_RGBx "; " GST_VIDEO_CAPS_xRGB "; "
GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_xBGR "; "
GST_VIDEO_CAPS_GRAY8)
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
("{ I420, RGB, BGR, RGBx, xRGB, BGRx, xBGR, GRAY8 }"))
);
/* *INDENT-ON* */
static GstStaticPadTemplate gst_jpeg_dec_sink_pad_template =
@ -88,31 +86,12 @@ GST_DEBUG_CATEGORY_STATIC (jpeg_dec_debug);
#define GST_CAT_DEFAULT jpeg_dec_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
/* These macros are adapted from videotestsrc.c
* and/or gst-plugins/gst/games/gstvideoimage.c */
#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
#define I420_Y_OFFSET(w,h) (0)
#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
#define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
static GstElementClass *parent_class; /* NULL */
static void gst_jpeg_dec_base_init (gpointer g_class);
static void gst_jpeg_dec_class_init (GstJpegDecClass * klass);
static void gst_jpeg_dec_init (GstJpegDec * jpegdec);
static void gst_jpeg_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_jpeg_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstFlowReturn gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps);
static gboolean gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event);
static gboolean gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event);
static GstStateChangeReturn gst_jpeg_dec_change_state (GstElement * element,
@ -123,29 +102,8 @@ static void gst_jpeg_dec_reset_qos (GstJpegDec * dec);
static void gst_jpeg_dec_read_qos (GstJpegDec * dec, gdouble * proportion,
GstClockTime * time);
GType
gst_jpeg_dec_get_type (void)
{
static GType type = 0;
if (!type) {
static const GTypeInfo jpeg_dec_info = {
sizeof (GstJpegDecClass),
(GBaseInitFunc) gst_jpeg_dec_base_init,
NULL,
(GClassInitFunc) gst_jpeg_dec_class_init,
NULL,
NULL,
sizeof (GstJpegDec),
0,
(GInstanceInitFunc) gst_jpeg_dec_init,
};
type = g_type_register_static (GST_TYPE_ELEMENT, "GstJpegDec",
&jpeg_dec_info, 0);
}
return type;
}
#define gst_jpeg_dec_parent_class parent_class
G_DEFINE_TYPE (GstJpegDec, gst_jpeg_dec, GST_TYPE_ELEMENT);
static void
gst_jpeg_dec_finalize (GObject * object)
@ -159,20 +117,6 @@ gst_jpeg_dec_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_jpeg_dec_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_jpeg_dec_src_pad_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_jpeg_dec_sink_pad_template));
gst_element_class_set_details_simple (element_class, "JPEG image decoder",
"Codec/Decoder/Image",
"Decode images from JPEG format", "Wim Taymans <wim@fluendo.com>");
}
static void
gst_jpeg_dec_class_init (GstJpegDecClass * klass)
{
@ -209,6 +153,14 @@ gst_jpeg_dec_class_init (GstJpegDecClass * klass)
-1, G_MAXINT, JPEG_DEFAULT_MAX_ERRORS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_jpeg_dec_src_pad_template));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_jpeg_dec_sink_pad_template));
gst_element_class_set_details_simple (gstelement_class, "JPEG image decoder",
"Codec/Decoder/Image",
"Decode images from JPEG format", "Wim Taymans <wim@fluendo.com>");
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_jpeg_dec_change_state);
@ -404,8 +356,6 @@ gst_jpeg_dec_init (GstJpegDec * dec)
gst_pad_new_from_static_template (&gst_jpeg_dec_sink_pad_template,
"sink");
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
gst_pad_set_setcaps_function (dec->sinkpad,
GST_DEBUG_FUNCPTR (gst_jpeg_dec_setcaps));
gst_pad_set_chain_function (dec->sinkpad,
GST_DEBUG_FUNCPTR (gst_jpeg_dec_chain));
gst_pad_set_event_function (dec->sinkpad,
@ -743,21 +693,19 @@ guarantee_huff_tables (j_decompress_ptr dinfo)
}
static gboolean
gst_jpeg_dec_setcaps (GstPad * pad, GstCaps * caps)
gst_jpeg_dec_setcaps (GstJpegDec * dec, GstCaps * caps)
{
GstStructure *s;
GstJpegDec *dec;
const GValue *framerate;
dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad));
s = gst_caps_get_structure (caps, 0);
if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) {
dec->framerate_numerator = gst_value_get_fraction_numerator (framerate);
dec->framerate_denominator = gst_value_get_fraction_denominator (framerate);
dec->in_fps_n = gst_value_get_fraction_numerator (framerate);
dec->in_fps_d = gst_value_get_fraction_denominator (framerate);
dec->packetized = TRUE;
GST_DEBUG ("got framerate of %d/%d fps => packetized mode",
dec->framerate_numerator, dec->framerate_denominator);
dec->in_fps_n, dec->in_fps_d);
}
/* do not extract width/height here. we do that in the chain
@ -806,7 +754,7 @@ gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
{
gint i;
if (G_LIKELY (dec->idr_width_allocated == maxrowbytes))
if (G_LIKELY (dec->idr_width_allocated >= maxrowbytes))
return TRUE;
/* FIXME: maybe just alloc one or three blocks altogether? */
@ -827,19 +775,28 @@ gst_jpeg_dec_ensure_buffers (GstJpegDec * dec, guint maxrowbytes)
}
static void
gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, guchar * base[1],
guint width, guint height, guint pstride, guint rstride)
gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, GstVideoFrame * frame)
{
guchar *rows[16];
guchar **scanarray[1] = { rows };
gint i, j, k;
gint lines;
guint8 *base[1];
gint width, height;
gint pstride, rstride;
GST_DEBUG_OBJECT (dec, "indirect decoding of grayscale");
width = GST_VIDEO_FRAME_WIDTH (frame);
height = GST_VIDEO_FRAME_HEIGHT (frame);
if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
return;
base[0] = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
memcpy (rows, dec->idr_y, 16 * sizeof (gpointer));
i = 0;
@ -863,19 +820,30 @@ gst_jpeg_dec_decode_grayscale (GstJpegDec * dec, guchar * base[1],
}
static void
gst_jpeg_dec_decode_rgb (GstJpegDec * dec, guchar * base[3],
guint width, guint height, guint pstride, guint rstride)
gst_jpeg_dec_decode_rgb (GstJpegDec * dec, GstVideoFrame * frame)
{
guchar *r_rows[16], *g_rows[16], *b_rows[16];
guchar **scanarray[3] = { r_rows, g_rows, b_rows };
gint i, j, k;
gint lines;
guint8 *base[3];
guint pstride, rstride;
gint width, height;
GST_DEBUG_OBJECT (dec, "indirect decoding of RGB");
width = GST_VIDEO_FRAME_WIDTH (frame);
height = GST_VIDEO_FRAME_HEIGHT (frame);
if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
return;
for (i = 0; i < 3; i++)
base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
pstride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
rstride = GST_VIDEO_FRAME_COMP_STRIDE (frame, 0);
memcpy (r_rows, dec->idr_y, 16 * sizeof (gpointer));
memcpy (g_rows, dec->idr_u, 16 * sizeof (gpointer));
memcpy (b_rows, dec->idr_v, 16 * sizeof (gpointer));
@ -905,20 +873,35 @@ gst_jpeg_dec_decode_rgb (GstJpegDec * dec, guchar * base[3],
}
static void
gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
guchar * last[3], guint width, guint height, gint r_v, gint r_h, gint comp)
gst_jpeg_dec_decode_indirect (GstJpegDec * dec, GstVideoFrame * frame,
gint r_v, gint r_h, gint comp)
{
guchar *y_rows[16], *u_rows[16], *v_rows[16];
guchar **scanarray[3] = { y_rows, u_rows, v_rows };
gint i, j, k;
gint lines;
guchar *base[3], *last[3];
gint stride[3];
gint width, height;
GST_DEBUG_OBJECT (dec,
"unadvantageous width or r_h, taking slow route involving memcpy");
width = GST_VIDEO_FRAME_WIDTH (frame);
height = GST_VIDEO_FRAME_HEIGHT (frame);
if (G_UNLIKELY (!gst_jpeg_dec_ensure_buffers (dec, GST_ROUND_UP_32 (width))))
return;
for (i = 0; i < 3; i++) {
base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
/* make sure we don't make jpeglib write beyond our buffer,
* which might happen if (height % (r_v*DCTSIZE)) != 0 */
last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
(GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
}
memcpy (y_rows, dec->idr_y, 16 * sizeof (gpointer));
memcpy (u_rows, dec->idr_u, 16 * sizeof (gpointer));
memcpy (v_rows, dec->idr_v, 16 * sizeof (gpointer));
@ -937,30 +920,30 @@ gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
if (G_LIKELY (lines > 0)) {
for (j = 0, k = 0; j < (r_v * DCTSIZE); j += r_v, k++) {
if (G_LIKELY (base[0] <= last[0])) {
memcpy (base[0], y_rows[j], I420_Y_ROWSTRIDE (width));
base[0] += I420_Y_ROWSTRIDE (width);
memcpy (base[0], y_rows[j], stride[0]);
base[0] += stride[0];
}
if (r_v == 2) {
if (G_LIKELY (base[0] <= last[0])) {
memcpy (base[0], y_rows[j + 1], I420_Y_ROWSTRIDE (width));
base[0] += I420_Y_ROWSTRIDE (width);
memcpy (base[0], y_rows[j + 1], stride[0]);
base[0] += stride[0];
}
}
if (G_LIKELY (base[1] <= last[1] && base[2] <= last[2])) {
if (r_h == 2) {
memcpy (base[1], u_rows[k], I420_U_ROWSTRIDE (width));
memcpy (base[2], v_rows[k], I420_V_ROWSTRIDE (width));
memcpy (base[1], u_rows[k], stride[1]);
memcpy (base[2], v_rows[k], stride[2]);
} else if (r_h == 1) {
hresamplecpy1 (base[1], u_rows[k], I420_U_ROWSTRIDE (width));
hresamplecpy1 (base[2], v_rows[k], I420_V_ROWSTRIDE (width));
hresamplecpy1 (base[1], u_rows[k], stride[1]);
hresamplecpy1 (base[2], v_rows[k], stride[2]);
} else {
/* FIXME: implement (at least we avoid crashing by doing nothing) */
}
}
if (r_v == 2 || (k & 1) != 0) {
base[1] += I420_U_ROWSTRIDE (width);
base[2] += I420_V_ROWSTRIDE (width);
base[1] += stride[1];
base[2] += stride[2];
}
}
} else {
@ -969,27 +952,8 @@ gst_jpeg_dec_decode_indirect (GstJpegDec * dec, guchar * base[3],
}
}
#ifndef GST_DISABLE_GST_DEBUG
static inline void
dump_lines (guchar * base[3], guchar ** line[3], int v_samp0, int width)
{
int j;
for (j = 0; j < (v_samp0 * DCTSIZE); ++j) {
GST_LOG ("[%02d] %5d %5d %5d", j,
(line[0][j] >= base[0]) ?
(int) (line[0][j] - base[0]) / I420_Y_ROWSTRIDE (width) : -1,
(line[1][j] >= base[1]) ?
(int) (line[1][j] - base[1]) / I420_U_ROWSTRIDE (width) : -1,
(line[2][j] >= base[2]) ?
(int) (line[2][j] - base[2]) / I420_V_ROWSTRIDE (width) : -1);
}
}
#endif
static GstFlowReturn
gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3],
guchar * last[3], guint width, guint height)
gst_jpeg_dec_decode_direct (GstJpegDec * dec, GstVideoFrame * frame)
{
guchar **line[3]; /* the jpeg line buffer */
guchar *y[4 * DCTSIZE] = { NULL, }; /* alloc enough for the lines */
@ -997,6 +961,9 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3],
guchar *v[4 * DCTSIZE] = { NULL, };
gint i, j;
gint lines, v_samp[3];
guchar *base[3], *last[3];
gint stride[3];
guint width, height;
line[0] = y;
line[1] = u;
@ -1009,35 +976,45 @@ gst_jpeg_dec_decode_direct (GstJpegDec * dec, guchar * base[3],
if (G_UNLIKELY (v_samp[0] > 2 || v_samp[1] > 2 || v_samp[2] > 2))
goto format_not_supported;
width = GST_VIDEO_FRAME_WIDTH (frame);
height = GST_VIDEO_FRAME_HEIGHT (frame);
for (i = 0; i < 3; i++) {
base[i] = GST_VIDEO_FRAME_COMP_DATA (frame, i);
stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
/* make sure we don't make jpeglib write beyond our buffer,
* which might happen if (height % (r_v*DCTSIZE)) != 0 */
last[i] = base[i] + (GST_VIDEO_FRAME_COMP_STRIDE (frame, i) *
(GST_VIDEO_FRAME_COMP_HEIGHT (frame, i) - 1));
}
/* let jpeglib decode directly into our final buffer */
GST_DEBUG_OBJECT (dec, "decoding directly into output buffer");
for (i = 0; i < height; i += v_samp[0] * DCTSIZE) {
for (j = 0; j < (v_samp[0] * DCTSIZE); ++j) {
/* Y */
line[0][j] = base[0] + (i + j) * I420_Y_ROWSTRIDE (width);
line[0][j] = base[0] + (i + j) * stride[0];
if (G_UNLIKELY (line[0][j] > last[0]))
line[0][j] = last[0];
/* U */
if (v_samp[1] == v_samp[0]) {
line[1][j] = base[1] + ((i + j) / 2) * I420_U_ROWSTRIDE (width);
line[1][j] = base[1] + ((i + j) / 2) * stride[1];
} else if (j < (v_samp[1] * DCTSIZE)) {
line[1][j] = base[1] + ((i / 2) + j) * I420_U_ROWSTRIDE (width);
line[1][j] = base[1] + ((i / 2) + j) * stride[1];
}
if (G_UNLIKELY (line[1][j] > last[1]))
line[1][j] = last[1];
/* V */
if (v_samp[2] == v_samp[0]) {
line[2][j] = base[2] + ((i + j) / 2) * I420_V_ROWSTRIDE (width);
line[2][j] = base[2] + ((i + j) / 2) * stride[2];
} else if (j < (v_samp[2] * DCTSIZE)) {
line[2][j] = base[2] + ((i / 2) + j) * I420_V_ROWSTRIDE (width);
line[2][j] = base[2] + ((i / 2) + j) * stride[2];
}
if (G_UNLIKELY (line[2][j] > last[2]))
line[2][j] = last[2];
}
/* dump_lines (base, line, v_samp[0], width); */
lines = jpeg_read_raw_data (&dec->cinfo, line, v_samp[0] * DCTSIZE);
if (G_UNLIKELY (!lines)) {
GST_INFO_OBJECT (dec, "jpeg_read_raw_data() returned 0");
@ -1127,38 +1104,96 @@ gst_jpeg_dec_do_qos (GstJpegDec * dec, GstClockTime timestamp)
return TRUE;
}
static void
static gboolean
gst_jpeg_dec_buffer_pool (GstJpegDec * dec, GstCaps * caps)
{
GstQuery *query;
GstBufferPool *pool = NULL;
guint size, min, max, prefix, alignment;
GstStructure *config;
GST_DEBUG_OBJECT (dec, "setting up bufferpool");
/* find a pool for the negotiated caps now */
query = gst_query_new_allocation (caps, TRUE);
if (gst_pad_peer_query (dec->srcpad, query)) {
/* we got configuration from our peer, parse them */
gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
&alignment, &pool);
size = MAX (size, dec->info.size);
} else {
GST_DEBUG_OBJECT (dec, "peer query failed, using defaults");
size = dec->info.size;
min = max = 0;
prefix = 0;
alignment = 15;
}
gst_query_unref (query);
if (pool == NULL) {
/* we did not get a pool, make one ourselves then */
pool = gst_buffer_pool_new ();
}
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set (config, caps, size, min, max, prefix,
alignment | 15);
/* and store */
gst_buffer_pool_set_config (pool, config);
if (dec->pool) {
gst_buffer_pool_set_active (dec->pool, FALSE);
gst_object_unref (dec->pool);
}
dec->pool = pool;
/* and activate */
gst_buffer_pool_set_active (pool, TRUE);
return TRUE;
}
static gboolean
gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
{
GstCaps *caps;
GstVideoFormat format;
GstVideoInfo info;
if (G_UNLIKELY (width == dec->caps_width && height == dec->caps_height &&
dec->framerate_numerator == dec->caps_framerate_numerator &&
dec->framerate_denominator == dec->caps_framerate_denominator &&
clrspc == dec->clrspc))
return;
if (G_UNLIKELY (width == dec->info.width && height == dec->info.height &&
dec->in_fps_n == dec->info.fps_n && dec->in_fps_d == dec->info.fps_d
&& clrspc == dec->clrspc))
return TRUE;
gst_video_info_init (&info);
/* framerate == 0/1 is a still frame */
if (dec->framerate_denominator == 0) {
dec->framerate_numerator = 0;
dec->framerate_denominator = 1;
if (dec->in_fps_d == 0) {
info.fps_n = 0;
info.fps_d = 1;
} else {
info.fps_n = dec->in_fps_n;
info.fps_d = dec->in_fps_d;
}
/* calculate or assume an average frame duration for QoS purposes */
GST_OBJECT_LOCK (dec);
if (dec->framerate_numerator != 0) {
dec->qos_duration = gst_util_uint64_scale (GST_SECOND,
dec->framerate_denominator, dec->framerate_numerator);
if (info.fps_n != 0) {
dec->qos_duration =
gst_util_uint64_scale (GST_SECOND, info.fps_d, info.fps_n);
dec->duration = dec->qos_duration;
} else {
/* if not set just use 25fps */
dec->qos_duration = gst_util_uint64_scale (GST_SECOND, 1, 25);
dec->duration = GST_CLOCK_TIME_NONE;
}
GST_OBJECT_UNLOCK (dec);
if (dec->cinfo.jpeg_color_space == JCS_RGB) {
gint i;
GstCaps *allowed_caps;
GstVideoInfo tmpinfo;
GST_DEBUG_OBJECT (dec, "selecting RGB format");
/* retrieve allowed caps, and find the first one that reasonably maps
@ -1170,7 +1205,7 @@ gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
* and get_pad_template_caps doesn't */
caps = gst_caps_copy (gst_pad_get_pad_template_caps (dec->srcpad));
}
/* avoid lists of fourcc, etc */
/* avoid lists of formats, etc */
allowed_caps = gst_caps_normalize (caps);
gst_caps_unref (caps);
caps = NULL;
@ -1183,10 +1218,11 @@ gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
/* sigh, ds and _parse_caps need fixed caps for parsing, fixate */
gst_pad_fixate_caps (dec->srcpad, caps);
GST_LOG_OBJECT (dec, "checking caps %" GST_PTR_FORMAT, caps);
if (!gst_video_format_parse_caps (caps, &format, NULL, NULL))
if (!gst_video_info_from_caps (&tmpinfo, caps))
continue;
/* we'll settle for the first (preferred) downstream rgb format */
if (gst_video_format_is_rgb (format))
if (GST_VIDEO_INFO_IS_RGB (&tmpinfo))
break;
/* default fall-back */
format = GST_VIDEO_FORMAT_RGB;
@ -1194,51 +1230,31 @@ gst_jpeg_dec_negotiate (GstJpegDec * dec, gint width, gint height, gint clrspc)
if (caps)
gst_caps_unref (caps);
gst_caps_unref (allowed_caps);
caps = gst_video_format_new_caps (format, width, height,
dec->framerate_numerator, dec->framerate_denominator, 1, 1);
dec->outsize = gst_video_format_get_size (format, width, height);
/* some format info */
dec->offset[0] =
gst_video_format_get_component_offset (format, 0, width, height);
dec->offset[1] =
gst_video_format_get_component_offset (format, 1, width, height);
dec->offset[2] =
gst_video_format_get_component_offset (format, 2, width, height);
/* equal for all components */
dec->stride = gst_video_format_get_row_stride (format, 0, width);
dec->inc = gst_video_format_get_pixel_stride (format, 0);
} else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) {
/* TODO is anything else then 8bit supported in jpeg? */
format = GST_VIDEO_FORMAT_GRAY8;
caps = gst_video_format_new_caps (format, width, height,
dec->framerate_numerator, dec->framerate_denominator, 1, 1);
dec->outsize = gst_video_format_get_size (format, width, height);
dec->offset[0] =
gst_video_format_get_component_offset (format, 0, width, height);
dec->stride = gst_video_format_get_row_stride (format, 0, width);
dec->inc = gst_video_format_get_pixel_stride (format, 0);
} else {
/* go for plain and simple I420 */
/* TODO other YUV cases ? */
caps = gst_caps_new_simple ("video/x-raw-yuv",
"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
"width", G_TYPE_INT, width, "height", G_TYPE_INT, height,
"framerate", GST_TYPE_FRACTION, dec->framerate_numerator,
dec->framerate_denominator, NULL);
dec->outsize = I420_SIZE (width, height);
format = GST_VIDEO_FORMAT_I420;
}
gst_video_info_set_format (&info, format, width, height);
caps = gst_video_info_to_caps (&info);
GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);
GST_DEBUG_OBJECT (dec, "max_v_samp_factor=%d", dec->cinfo.max_v_samp_factor);
GST_DEBUG_OBJECT (dec, "max_h_samp_factor=%d", dec->cinfo.max_h_samp_factor);
gst_pad_set_caps (dec->srcpad, caps);
dec->info = info;
dec->clrspc = clrspc;
gst_jpeg_dec_buffer_pool (dec, caps);
gst_caps_unref (caps);
dec->caps_width = width;
dec->caps_height = height;
dec->caps_framerate_numerator = dec->framerate_numerator;
dec->caps_framerate_denominator = dec->framerate_denominator;
return TRUE;
}
static GstFlowReturn
@ -1247,17 +1263,12 @@ gst_jpeg_dec_chain (GstPad * pad, GstBuffer * buf)
GstFlowReturn ret = GST_FLOW_OK;
GstJpegDec *dec;
GstBuffer *outbuf = NULL;
#ifndef GST_DISABLE_GST_DEBUG
guchar *data;
#endif
guchar *outdata;
guchar *base[3], *last[3];
gint img_len;
guint outsize;
gint width, height;
gint r_h, r_v;
guint code, hdr_ok;
GstClockTime timestamp, duration;
GstVideoFrame frame;
dec = GST_JPEG_DEC (GST_PAD_PARENT (pad));
@ -1323,9 +1334,13 @@ again:
goto skip_decoding;
#ifndef GST_DISABLE_GST_DEBUG
data = (guint8 *) gst_adapter_peek (dec->adapter, 4);
GST_LOG_OBJECT (dec, "reading header %02x %02x %02x %02x", data[0], data[1],
data[2], data[3]);
{
guchar data[4];
gst_adapter_copy (dec->adapter, data, 0, 4);
GST_LOG_OBJECT (dec, "reading header %02x %02x %02x %02x", data[0], data[1],
data[2], data[3]);
}
#endif
gst_jpeg_dec_fill_input_buffer (&dec->cinfo);
@ -1425,16 +1440,14 @@ again:
gst_jpeg_dec_negotiate (dec, width, height, dec->cinfo.jpeg_color_space);
ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
dec->outsize, GST_PAD_CAPS (dec->srcpad), &outbuf);
ret = gst_buffer_pool_acquire_buffer (dec->pool, &outbuf, NULL);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto alloc_failed;
outdata = GST_BUFFER_DATA (outbuf);
outsize = GST_BUFFER_SIZE (outbuf);
if (!gst_video_frame_map (&frame, &dec->info, outbuf, GST_MAP_READWRITE))
goto invalid_frame;
GST_LOG_OBJECT (dec, "width %d, height %d, buffer size %d, required size %d",
width, height, outsize, dec->outsize);
GST_LOG_OBJECT (dec, "width %d, height %d", width, height);
GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts;
@ -1442,10 +1455,9 @@ again:
if (GST_CLOCK_TIME_IS_VALID (duration)) {
/* use duration from incoming buffer for outgoing buffer */
dec->next_ts += duration;
} else if (dec->framerate_numerator != 0) {
duration = gst_util_uint64_scale (GST_SECOND,
dec->framerate_denominator, dec->framerate_numerator);
dec->next_ts += duration;
} else if (GST_CLOCK_TIME_IS_VALID (dec->duration)) {
duration = dec->duration;
dec->next_ts += dec->duration;
} else {
duration = GST_CLOCK_TIME_NONE;
dec->next_ts = GST_CLOCK_TIME_NONE;
@ -1457,32 +1469,10 @@ again:
GST_BUFFER_DURATION (outbuf) = duration;
if (dec->cinfo.jpeg_color_space == JCS_RGB) {
base[0] = outdata + dec->offset[0];
base[1] = outdata + dec->offset[1];
base[2] = outdata + dec->offset[2];
gst_jpeg_dec_decode_rgb (dec, base, width, height, dec->inc, dec->stride);
gst_jpeg_dec_decode_rgb (dec, &frame);
} else if (dec->cinfo.jpeg_color_space == JCS_GRAYSCALE) {
base[0] = outdata + dec->offset[0];
gst_jpeg_dec_decode_grayscale (dec, base, width, height, dec->inc,
dec->stride);
gst_jpeg_dec_decode_grayscale (dec, &frame);
} else {
/* mind the swap, jpeglib outputs blue chroma first
* ensonic: I see no swap?
*/
base[0] = outdata + I420_Y_OFFSET (width, height);
base[1] = outdata + I420_U_OFFSET (width, height);
base[2] = outdata + I420_V_OFFSET (width, height);
/* make sure we don't make jpeglib write beyond our buffer,
* which might happen if (height % (r_v*DCTSIZE)) != 0 */
last[0] = base[0] + (I420_Y_ROWSTRIDE (width) * (height - 1));
last[1] =
base[1] + (I420_U_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
1));
last[2] =
base[2] + (I420_V_ROWSTRIDE (width) * ((GST_ROUND_UP_2 (height) / 2) -
1));
GST_LOG_OBJECT (dec, "decompressing (reqired scanline buffer height = %u)",
dec->cinfo.rec_outbuf_height);
@ -1497,11 +1487,10 @@ again:
|| dec->cinfo.comp_info[2].h_samp_factor != 1)) {
GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
"indirect decoding using extra buffer copy");
gst_jpeg_dec_decode_indirect (dec, base, last, width, height, r_v, r_h,
gst_jpeg_dec_decode_indirect (dec, &frame, r_v, r_h,
dec->cinfo.num_components);
} else {
ret = gst_jpeg_dec_decode_direct (dec, base, last, width, height);
ret = gst_jpeg_dec_decode_direct (dec, &frame);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto decode_direct_failed;
}
@ -1510,9 +1499,11 @@ again:
GST_LOG_OBJECT (dec, "decompressing finished");
jpeg_finish_decompress (&dec->cinfo);
gst_video_frame_unmap (&frame);
/* Clipping */
if (dec->segment.format == GST_FORMAT_TIME) {
gint64 start, stop, clip_start, clip_stop;
guint64 start, stop, clip_start, clip_stop;
GST_LOG_OBJECT (dec, "Attempting clipping");
@ -1618,6 +1609,13 @@ alloc_failed:
}
goto exit;
}
invalid_frame:
{
jpeg_abort_decompress (&dec->cinfo);
gst_buffer_unref (outbuf);
ret = GST_FLOW_OK;
goto exit;
}
drop_buffer:
{
GST_WARNING_OBJECT (dec, "Outgoing buffer is outside configured segment");
@ -1663,11 +1661,12 @@ gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_QOS:{
GstQOSType type;
GstClockTimeDiff diff;
GstClockTime timestamp;
gdouble proportion;
gst_event_parse_qos (event, &proportion, &diff, &timestamp);
gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
gst_jpeg_dec_update_qos (dec, proportion, diff, timestamp);
break;
}
@ -1684,7 +1683,7 @@ gst_jpeg_dec_src_event (GstPad * pad, GstEvent * event)
static gboolean
gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event)
{
gboolean ret = TRUE;
gboolean ret = TRUE, forward = TRUE;
GstJpegDec *dec = GST_JPEG_DEC (GST_OBJECT_PARENT (pad));
GST_DEBUG_OBJECT (dec, "event : %s", GST_EVENT_TYPE_NAME (event));
@ -1702,30 +1701,28 @@ gst_jpeg_dec_sink_event (GstPad * pad, GstEvent * event)
dec->parse_resync = FALSE;
gst_jpeg_dec_reset_qos (dec);
break;
case GST_EVENT_NEWSEGMENT:{
gboolean update;
gdouble rate, applied_rate;
GstFormat format;
gint64 start, stop, position;
gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
&format, &start, &stop, &position);
GST_DEBUG_OBJECT (dec, "Got NEWSEGMENT [%" GST_TIME_FORMAT
" - %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "]",
GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
GST_TIME_ARGS (position));
gst_segment_set_newsegment_full (&dec->segment, update, rate,
applied_rate, format, start, stop, position);
case GST_EVENT_SEGMENT:
gst_event_copy_segment (event, &dec->segment);
GST_DEBUG_OBJECT (dec, "Got NEWSEGMENT %" GST_SEGMENT_FORMAT,
&dec->segment);
break;
case GST_EVENT_CAPS:
{
GstCaps *caps;
gst_event_parse_caps (event, &caps);
ret = gst_jpeg_dec_setcaps (dec, caps);
forward = FALSE;
break;
}
default:
break;
}
ret = gst_pad_push_event (dec->srcpad, event);
if (forward)
ret = gst_pad_push_event (dec->srcpad, event);
else
gst_event_unref (event);
return ret;
}
@ -1786,11 +1783,9 @@ gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_READY_TO_PAUSED:
dec->error_count = 0;
dec->good_count = 0;
dec->framerate_numerator = 0;
dec->framerate_denominator = 1;
dec->caps_framerate_numerator = dec->caps_framerate_denominator = 0;
dec->caps_width = -1;
dec->caps_height = -1;
dec->in_fps_n = 0;
dec->in_fps_d = 1;
gst_video_info_init (&dec->info);
dec->clrspc = -1;
dec->packetized = FALSE;
dec->next_ts = 0;
@ -1815,6 +1810,11 @@ gst_jpeg_dec_change_state (GstElement * element, GstStateChange transition)
g_free (dec->cur_buf);
dec->cur_buf = NULL;
gst_jpeg_dec_free_buffers (dec);
if (dec->pool) {
gst_buffer_pool_set_active (dec->pool, FALSE);
gst_object_unref (dec->pool);
}
dec->pool = NULL;
break;
default:
break;

View file

@ -90,22 +90,17 @@ struct _GstJpegDec {
GstClockTime earliest_time;
GstClockTime qos_duration;
/* video state */
gint framerate_numerator;
gint framerate_denominator;
/* input state */
gint in_fps_n;
gint in_fps_d;
/* negotiated output state */
GstBufferPool *pool;
GstVideoInfo info;
GstClockTime duration;
/* negotiated state */
gint caps_framerate_numerator;
gint caps_framerate_denominator;
gint caps_width;
gint caps_height;
gint outsize;
gint clrspc;
gint offset[3];
gint stride;
gint inc;
/* parse state */
gint parse_offset;
gint parse_entropy_len;

View file

@ -54,7 +54,6 @@ GST_DEBUG_CATEGORY_STATIC (jpegenc_debug);
/* JpegEnc signals and args */
enum
{
FRAME_ENCODED,
/* FILL ME */
LAST_SIGNAL
};
@ -71,8 +70,8 @@ static void gst_jpegenc_reset (GstJpegEnc * enc);
static void gst_jpegenc_finalize (GObject * object);
static GstFlowReturn gst_jpegenc_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps);
static GstCaps *gst_jpegenc_getcaps (GstPad * pad);
static gboolean gst_jpegenc_sink_event (GstPad * pad, GstEvent * event);
static GstCaps *gst_jpegenc_getcaps (GstPad * pad, GstCaps * filter);
static void gst_jpegenc_resync (GstJpegEnc * jpegenc);
static void gst_jpegenc_set_property (GObject * object, guint prop_id,
@ -82,8 +81,6 @@ static void gst_jpegenc_get_property (GObject * object, guint prop_id,
static GstStateChangeReturn gst_jpegenc_change_state (GstElement * element,
GstStateChange transition);
static guint gst_jpegenc_signals[LAST_SIGNAL] = { 0 };
#define gst_jpegenc_parent_class parent_class
G_DEFINE_TYPE (GstJpegEnc, gst_jpegenc, GST_TYPE_ELEMENT);
@ -121,11 +118,6 @@ gst_jpegenc_class_init (GstJpegEncClass * klass)
gobject_class->set_property = gst_jpegenc_set_property;
gobject_class->get_property = gst_jpegenc_get_property;
gst_jpegenc_signals[FRAME_ENCODED] =
g_signal_new ("frame-encoded", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstJpegEncClass, frame_encoded), NULL,
NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
g_object_class_install_property (gobject_class, PROP_QUALITY,
g_param_spec_int ("quality", "Quality", "Quality of encoding",
0, 100, JPEG_DEFAULT_QUALITY,
@ -159,6 +151,42 @@ gst_jpegenc_class_init (GstJpegEncClass * klass)
"JPEG encoding element");
}
static void
ensure_memory (GstJpegEnc * jpegenc)
{
GstMemory *new_memory;
gsize old_size, desired_size, new_size;
guint8 *new_data;
old_size = jpegenc->output_size;
if (old_size == 0)
desired_size = jpegenc->bufsize;
else
desired_size = old_size * 2;
/* Our output memory wasn't big enough.
* Make a new memory that's twice the size, */
new_memory = gst_allocator_alloc (NULL, desired_size, 3);
new_data = gst_memory_map (new_memory, &new_size, NULL, GST_MAP_READWRITE);
/* copy previous data if any */
if (jpegenc->output_mem) {
memcpy (new_data, jpegenc->output_data, old_size);
gst_memory_unmap (jpegenc->output_mem, jpegenc->output_data,
jpegenc->output_size);
gst_memory_unref (jpegenc->output_mem);
}
/* drop it into place, */
jpegenc->output_mem = new_memory;
jpegenc->output_data = new_data;
jpegenc->output_size = new_size;
/* and last, update libjpeg on where to work. */
jpegenc->jdest.next_output_byte = new_data + old_size;
jpegenc->jdest.free_in_buffer = new_size - old_size;
}
static void
gst_jpegenc_init_destination (j_compress_ptr cinfo)
{
@ -168,34 +196,12 @@ gst_jpegenc_init_destination (j_compress_ptr cinfo)
static boolean
gst_jpegenc_flush_destination (j_compress_ptr cinfo)
{
GstBuffer *overflow_buffer;
guint32 old_buffer_size;
GstJpegEnc *jpegenc = (GstJpegEnc *) (cinfo->client_data);
GST_DEBUG_OBJECT (jpegenc,
"gst_jpegenc_chain: flush_destination: buffer too small");
/* Our output buffer wasn't big enough.
* Make a new buffer that's twice the size, */
old_buffer_size = GST_BUFFER_SIZE (jpegenc->output_buffer);
gst_pad_alloc_buffer_and_set_caps (jpegenc->srcpad,
GST_BUFFER_OFFSET_NONE, old_buffer_size * 2,
GST_PAD_CAPS (jpegenc->srcpad), &overflow_buffer);
memcpy (GST_BUFFER_DATA (overflow_buffer),
GST_BUFFER_DATA (jpegenc->output_buffer), old_buffer_size);
gst_buffer_copy_metadata (overflow_buffer, jpegenc->output_buffer,
GST_BUFFER_COPY_TIMESTAMPS);
/* drop it into place, */
gst_buffer_unref (jpegenc->output_buffer);
jpegenc->output_buffer = overflow_buffer;
/* and last, update libjpeg on where to work. */
jpegenc->jdest.next_output_byte =
GST_BUFFER_DATA (jpegenc->output_buffer) + old_buffer_size;
jpegenc->jdest.free_in_buffer =
GST_BUFFER_SIZE (jpegenc->output_buffer) - old_buffer_size;
ensure_memory (jpegenc);
return TRUE;
}
@ -206,14 +212,11 @@ gst_jpegenc_term_destination (j_compress_ptr cinfo)
GstJpegEnc *jpegenc = (GstJpegEnc *) (cinfo->client_data);
GST_DEBUG_OBJECT (jpegenc, "gst_jpegenc_chain: term_source");
/* Trim the buffer size and push it. */
GST_BUFFER_SIZE (jpegenc->output_buffer) =
GST_BUFFER_SIZE (jpegenc->output_buffer) - jpegenc->jdest.free_in_buffer;
g_signal_emit (G_OBJECT (jpegenc), gst_jpegenc_signals[FRAME_ENCODED], 0);
jpegenc->last_ret = gst_pad_push (jpegenc->srcpad, jpegenc->output_buffer);
jpegenc->output_buffer = NULL;
/* Trim the buffer size. we will push it in the chain function */
gst_memory_unmap (jpegenc->output_mem, jpegenc->output_data,
jpegenc->output_size - jpegenc->jdest.free_in_buffer);
jpegenc->output_data = NULL;
jpegenc->output_size = 0;
}
static void
@ -226,8 +229,8 @@ gst_jpegenc_init (GstJpegEnc * jpegenc)
GST_DEBUG_FUNCPTR (gst_jpegenc_chain));
gst_pad_set_getcaps_function (jpegenc->sinkpad,
GST_DEBUG_FUNCPTR (gst_jpegenc_getcaps));
gst_pad_set_setcaps_function (jpegenc->sinkpad,
GST_DEBUG_FUNCPTR (gst_jpegenc_setcaps));
gst_pad_set_event_function (jpegenc->sinkpad,
GST_DEBUG_FUNCPTR (gst_jpegenc_sink_event));
gst_element_add_pad (GST_ELEMENT (jpegenc), jpegenc->sinkpad);
jpegenc->srcpad =
@ -236,8 +239,7 @@ gst_jpegenc_init (GstJpegEnc * jpegenc)
gst_element_add_pad (GST_ELEMENT (jpegenc), jpegenc->srcpad);
/* reset the initial video state */
jpegenc->width = -1;
jpegenc->height = -1;
gst_video_info_init (&jpegenc->info);
/* setup jpeglib */
memset (&jpegenc->cinfo, 0, sizeof (jpegenc->cinfo));
@ -277,11 +279,7 @@ gst_jpegenc_reset (GstJpegEnc * enc)
}
}
enc->width = -1;
enc->height = -1;
enc->format = GST_VIDEO_FORMAT_UNKNOWN;
enc->fps_den = enc->par_den = 0;
enc->height = enc->width = 0;
gst_video_info_init (&enc->info);
}
static void
@ -295,7 +293,7 @@ gst_jpegenc_finalize (GObject * object)
}
static GstCaps *
gst_jpegenc_getcaps (GstPad * pad)
gst_jpegenc_getcaps (GstPad * pad, GstCaps * filter)
{
GstJpegEnc *jpegenc = GST_JPEGENC (gst_pad_get_parent (pad));
GstCaps *caps, *othercaps;
@ -306,7 +304,7 @@ gst_jpegenc_getcaps (GstPad * pad)
/* we want to proxy properties like width, height and framerate from the
other end of the element */
othercaps = gst_pad_peer_get_caps_reffed (jpegenc->srcpad);
othercaps = gst_pad_peer_get_caps (jpegenc->srcpad, filter);
if (othercaps == NULL ||
gst_caps_is_empty (othercaps) || gst_caps_is_any (othercaps)) {
caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
@ -343,59 +341,41 @@ done:
}
static gboolean
gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps)
gst_jpegenc_setcaps (GstJpegEnc * enc, GstCaps * caps)
{
GstJpegEnc *enc = GST_JPEGENC (gst_pad_get_parent (pad));
GstVideoFormat format;
gint width, height;
gint fps_num, fps_den;
gint par_num, par_den;
GstVideoInfo info;
gint i;
GstCaps *othercaps;
gboolean ret;
const GstVideoFormatInfo *vinfo;
/* get info from caps */
if (!gst_video_format_parse_caps (caps, &format, &width, &height))
if (!gst_video_info_from_caps (&info, caps))
goto refuse_caps;
/* optional; pass along if present */
fps_num = fps_den = -1;
par_num = par_den = -1;
gst_video_parse_caps_framerate (caps, &fps_num, &fps_den);
gst_video_parse_caps_pixel_aspect_ratio (caps, &par_num, &par_den);
if (width == enc->width && height == enc->height && enc->format == format
&& fps_num == enc->fps_num && fps_den == enc->fps_den
&& par_num == enc->par_num && par_den == enc->par_den)
return TRUE;
/* store input description */
enc->format = format;
enc->width = width;
enc->height = height;
enc->fps_num = fps_num;
enc->fps_den = fps_den;
enc->par_num = par_num;
enc->par_den = par_den;
enc->info = info;
vinfo = info.finfo;
/* prepare a cached image description */
enc->channels = 3 + (gst_video_format_has_alpha (format) ? 1 : 0);
enc->channels = 3 + (GST_VIDEO_FORMAT_INFO_HAS_ALPHA (vinfo) ? 1 : 0);
/* ... but any alpha is disregarded in encoding */
if (gst_video_format_is_gray (format))
if (GST_VIDEO_FORMAT_INFO_IS_GRAY (vinfo))
enc->channels = 1;
else
enc->channels = 3;
enc->h_max_samp = 0;
enc->v_max_samp = 0;
for (i = 0; i < enc->channels; ++i) {
enc->cwidth[i] = gst_video_format_get_component_width (format, i, width);
enc->cheight[i] = gst_video_format_get_component_height (format, i, height);
enc->offset[i] = gst_video_format_get_component_offset (format, i, width,
height);
enc->stride[i] = gst_video_format_get_row_stride (format, i, width);
enc->inc[i] = gst_video_format_get_pixel_stride (format, i);
enc->h_samp[i] = GST_ROUND_UP_4 (width) / enc->cwidth[i];
enc->cwidth[i] = GST_VIDEO_INFO_COMP_WIDTH (&info, i);
enc->cheight[i] = GST_VIDEO_INFO_COMP_HEIGHT (&info, i);
enc->inc[i] = GST_VIDEO_INFO_COMP_PSTRIDE (&info, i);
enc->h_samp[i] = GST_ROUND_UP_4 (info.width) / enc->cwidth[i];
enc->h_max_samp = MAX (enc->h_max_samp, enc->h_samp[i]);
enc->v_samp[i] = GST_ROUND_UP_4 (height) / enc->cheight[i];
enc->v_samp[i] = GST_ROUND_UP_4 (info.height) / enc->cheight[i];
enc->v_max_samp = MAX (enc->v_max_samp, enc->v_samp[i]);
}
/* samp should only be 1, 2 or 4 */
@ -411,14 +391,13 @@ gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps)
othercaps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad));
gst_caps_set_simple (othercaps,
"width", G_TYPE_INT, enc->width, "height", G_TYPE_INT, enc->height, NULL);
if (enc->fps_den > 0)
"width", G_TYPE_INT, info.width, "height", G_TYPE_INT, info.height, NULL);
if (info.fps_d > 0)
gst_caps_set_simple (othercaps,
"framerate", GST_TYPE_FRACTION, enc->fps_num, enc->fps_den, NULL);
if (enc->par_den > 0)
"framerate", GST_TYPE_FRACTION, info.fps_n, info.fps_d, NULL);
if (info.par_d > 0)
gst_caps_set_simple (othercaps,
"pixel-aspect-ratio", GST_TYPE_FRACTION, enc->par_num, enc->par_den,
NULL);
"pixel-aspect-ratio", GST_TYPE_FRACTION, info.par_n, info.par_d, NULL);
ret = gst_pad_set_caps (enc->srcpad, othercaps);
gst_caps_unref (othercaps);
@ -426,38 +405,64 @@ gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps)
if (ret)
gst_jpegenc_resync (enc);
gst_object_unref (enc);
return ret;
/* ERRORS */
refuse_caps:
{
GST_WARNING_OBJECT (enc, "refused caps %" GST_PTR_FORMAT, caps);
gst_object_unref (enc);
return FALSE;
}
}
static gboolean
gst_jpegenc_sink_event (GstPad * pad, GstEvent * event)
{
gboolean res;
GstJpegEnc *enc = GST_JPEGENC (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
{
GstCaps *caps;
gst_event_parse_caps (event, &caps);
res = gst_jpegenc_setcaps (enc, caps);
break;
}
default:
res = gst_pad_event_default (pad, event);
break;
}
gst_object_unref (enc);
return res;
}
static void
gst_jpegenc_resync (GstJpegEnc * jpegenc)
{
gint width, height;
gint i, j;
const GstVideoFormatInfo *finfo;
GST_DEBUG_OBJECT (jpegenc, "resync");
jpegenc->cinfo.image_width = width = jpegenc->width;
jpegenc->cinfo.image_height = height = jpegenc->height;
finfo = jpegenc->info.finfo;
jpegenc->cinfo.image_width = width = GST_VIDEO_INFO_WIDTH (&jpegenc->info);
jpegenc->cinfo.image_height = height = GST_VIDEO_INFO_HEIGHT (&jpegenc->info);
jpegenc->cinfo.input_components = jpegenc->channels;
GST_DEBUG_OBJECT (jpegenc, "width %d, height %d", width, height);
GST_DEBUG_OBJECT (jpegenc, "format %d", jpegenc->format);
GST_DEBUG_OBJECT (jpegenc, "format %d",
GST_VIDEO_INFO_FORMAT (&jpegenc->info));
if (gst_video_format_is_rgb (jpegenc->format)) {
if (GST_VIDEO_FORMAT_INFO_IS_RGB (finfo)) {
GST_DEBUG_OBJECT (jpegenc, "RGB");
jpegenc->cinfo.in_color_space = JCS_RGB;
} else if (gst_video_format_is_gray (jpegenc->format)) {
} else if (GST_VIDEO_FORMAT_INFO_IS_GRAY (finfo)) {
GST_DEBUG_OBJECT (jpegenc, "gray");
jpegenc->cinfo.in_color_space = JCS_GRAYSCALE;
} else {
@ -466,7 +471,7 @@ gst_jpegenc_resync (GstJpegEnc * jpegenc)
}
/* input buffer size as max output */
jpegenc->bufsize = gst_video_format_get_size (jpegenc->format, width, height);
jpegenc->bufsize = GST_VIDEO_INFO_SIZE (&jpegenc->info);
jpeg_set_defaults (&jpegenc->cinfo);
jpegenc->cinfo.raw_data_in = TRUE;
/* duh, libjpeg maps RGB to YUV ... and don't expect some conversion */
@ -506,42 +511,41 @@ gst_jpegenc_chain (GstPad * pad, GstBuffer * buf)
{
GstFlowReturn ret;
GstJpegEnc *jpegenc;
guchar *data;
gulong size;
guint height;
guint height, width;
guchar *base[3], *end[3];
guint stride[3];
gint i, j, k;
GstBuffer *outbuf;
GstVideoFrame frame;
jpegenc = GST_JPEGENC (GST_OBJECT_PARENT (pad));
if (G_UNLIKELY (jpegenc->width <= 0 || jpegenc->height <= 0))
if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&jpegenc->info) ==
GST_VIDEO_FORMAT_UNKNOWN))
goto not_negotiated;
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
if (!gst_video_frame_map (&frame, &jpegenc->info, buf, GST_MAP_READ))
goto invalid_frame;
GST_LOG_OBJECT (jpegenc, "got buffer of %lu bytes", size);
height = GST_VIDEO_FRAME_HEIGHT (&frame);
width = GST_VIDEO_FRAME_WIDTH (&frame);
ret =
gst_pad_alloc_buffer_and_set_caps (jpegenc->srcpad,
GST_BUFFER_OFFSET_NONE, jpegenc->bufsize, GST_PAD_CAPS (jpegenc->srcpad),
&jpegenc->output_buffer);
if (ret != GST_FLOW_OK)
goto done;
gst_buffer_copy_metadata (jpegenc->output_buffer, buf,
GST_BUFFER_COPY_TIMESTAMPS);
height = jpegenc->height;
GST_LOG_OBJECT (jpegenc, "got buffer of %lu bytes",
gst_buffer_get_size (buf));
for (i = 0; i < jpegenc->channels; i++) {
base[i] = data + jpegenc->offset[i];
end[i] = base[i] + jpegenc->cheight[i] * jpegenc->stride[i];
base[i] = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
end[i] = base[i] + GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i) * stride[i];
}
jpegenc->jdest.next_output_byte = GST_BUFFER_DATA (jpegenc->output_buffer);
jpegenc->jdest.free_in_buffer = GST_BUFFER_SIZE (jpegenc->output_buffer);
jpegenc->output_mem = gst_allocator_alloc (NULL, jpegenc->bufsize, 3);
jpegenc->output_data =
gst_memory_map (jpegenc->output_mem, &jpegenc->output_size, NULL,
GST_MAP_READWRITE);
jpegenc->jdest.next_output_byte = jpegenc->output_data;
jpegenc->jdest.free_in_buffer = jpegenc->output_size;
/* prepare for raw input */
#if JPEG_LIB_VERSION >= 70
@ -559,8 +563,8 @@ gst_jpegenc_chain (GstPad * pad, GstBuffer * buf)
for (k = 0; k < jpegenc->channels; k++) {
for (j = 0; j < jpegenc->v_samp[k] * DCTSIZE; j++) {
jpegenc->line[k][j] = base[k];
if (base[k] + jpegenc->stride[k] < end[k])
base[k] += jpegenc->stride[k];
if (base[k] + stride[k] < end[k])
base[k] += stride[k];
}
}
jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line,
@ -581,8 +585,8 @@ gst_jpegenc_chain (GstPad * pad, GstBuffer * buf)
src += jpegenc->inc[k];
dst++;
}
if (base[k] + jpegenc->stride[k] < end[k])
base[k] += jpegenc->stride[k];
if (base[k] + stride[k] < end[k])
base[k] += stride[k];
}
}
jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line,
@ -590,22 +594,34 @@ gst_jpegenc_chain (GstPad * pad, GstBuffer * buf)
}
}
/* This will ensure that gst_jpegenc_term_destination is called; we push
the final output buffer from there */
/* This will ensure that gst_jpegenc_term_destination is called */
jpeg_finish_compress (&jpegenc->cinfo);
GST_LOG_OBJECT (jpegenc, "compressing done");
done:
outbuf = gst_buffer_new ();
gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
gst_buffer_take_memory (outbuf, -1, jpegenc->output_mem);
jpegenc->output_mem = NULL;
ret = gst_pad_push (jpegenc->srcpad, outbuf);
gst_video_frame_unmap (&frame);
gst_buffer_unref (buf);
return ret;
/* ERRORS */
/* ERRORS */
not_negotiated:
{
GST_WARNING_OBJECT (jpegenc, "no input format set (no caps on buffer)");
ret = GST_FLOW_NOT_NEGOTIATED;
goto done;
gst_buffer_unref (buf);
return GST_FLOW_NOT_NEGOTIATED;
}
invalid_frame:
{
GST_WARNING_OBJECT (jpegenc, "invalid frame received");
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
}

View file

@ -46,8 +46,6 @@ G_BEGIN_DECLS
typedef struct _GstJpegEnc GstJpegEnc;
typedef struct _GstJpegEncClass GstJpegEncClass;
#define GST_JPEG_ENC_MAX_COMPONENT 4
struct _GstJpegEnc
{
GstElement element;
@ -56,20 +54,15 @@ struct _GstJpegEnc
GstPad *sinkpad, *srcpad;
/* stream/image properties */
GstVideoFormat format;
gint width;
gint height;
GstVideoInfo info;
gint channels;
gint fps_num, fps_den;
gint par_num, par_den;
/* standard video_format indexed */
gint stride[GST_JPEG_ENC_MAX_COMPONENT];
gint offset[GST_JPEG_ENC_MAX_COMPONENT];
gint inc[GST_JPEG_ENC_MAX_COMPONENT];
gint cwidth[GST_JPEG_ENC_MAX_COMPONENT];
gint cheight[GST_JPEG_ENC_MAX_COMPONENT];
gint h_samp[GST_JPEG_ENC_MAX_COMPONENT];
gint v_samp[GST_JPEG_ENC_MAX_COMPONENT];
gint inc[GST_VIDEO_MAX_COMPONENTS];
gint cwidth[GST_VIDEO_MAX_COMPONENTS];
gint cheight[GST_VIDEO_MAX_COMPONENTS];
gint h_samp[GST_VIDEO_MAX_COMPONENTS];
gint v_samp[GST_VIDEO_MAX_COMPONENTS];
gint h_max_samp;
gint v_max_samp;
gboolean planar;
@ -92,15 +85,14 @@ struct _GstJpegEnc
/* cached return state for any problems that may occur in callbacks */
GstFlowReturn last_ret;
GstBuffer *output_buffer;
GstMemory *output_mem;
gpointer output_data;
gsize output_size;
};
struct _GstJpegEncClass
{
GstElementClass parent_class;
/* signals */
void (*frame_encoded) (GstElement * element);
};
GType gst_jpegenc_get_type (void);