[gst-devel] jpegenc, v4lsrc, and egocam

dichro at eris.rcpt.to dichro at eris.rcpt.to
Thu Jul 5 16:46:38 CEST 2001


  More hammering on the plugins was required to make egocam work again.
Once again, these are the changes that made things work for me; they
may well just break things for anybody else (is anybody else using
v4lsrc or jpegenc?).

  The changes are mostly to do with capability handling; v4lsrc just
makes sure that it advertises some capabilities where it didn't before,
and also copies some variable initialization to somewhere where it
will actually get called... the whole capability setup thing in there
seems horribly broken, and I'll probably try tearing it all out and
writing in something vastly simpler that works for my test cases at 
some stage.

  The jpegenc changes remove a heap of more or less useless code and
all attempts at supporting YUV, simplify the libjpeg interface, and
handle capability negotiation correctly (with the modified v4lsrc, 
anyway). 

  Some general points.

  Having gstosshelper override ioctl and fcntl is nasty. Having now
caught on the mailing list, that's probably part of the problem 
mentioned with having a non-up-to-date registry; everything gets 
mapped into the running process, which will derail anything that uses 
ioctl.

  It would be nice to be able to supply a partial set of caps and a
template and let auto-negotiation duke out the rest of it (eg, app
supplies width and height to v4lsrc, but the format is determined
by negotiation with the rest of the pipeline).

  There seem to be two ways of being notified of the results of a
negotiation, the caps_changed signal and gst_set_newcaps_function
(and obviously having a custom negotiation function). Should they
be used differently?

m.

-------------- next part --------------
--- gstreamer/plugins/capture/v4l/gstv4lsrc.c.old	Fri Jul  6 00:10:25 2001
+++ gstreamer/plugins/capture/v4l/gstv4lsrc.c	Thu Jul  5 23:59:57 2001
@@ -309,13 +309,13 @@
   width = src->width;
   height = src->height;
 
+	/* Don't think it's ever correct to return NULL :( */
   switch (src->format) {
     case VIDEO_RGB08:
     case VIDEO_GRAY:
     case VIDEO_LUT2:
     case VIDEO_LUT4:
-      caps = NULL;
-      break;
+			return NULL;
     case VIDEO_RGB15_LE:
     case VIDEO_RGB16_LE:
     case VIDEO_RGB15_BE:
@@ -324,7 +324,7 @@
     case VIDEO_BGR32:
     case VIDEO_RGB24:
     case VIDEO_RGB32:
-      caps = NULL;
+			fourcc = GST_MAKE_FOURCC('R', 'G', 'B', ' ');
       break;
     case VIDEO_YUV422:
     case VIDEO_YUV422P:
@@ -344,20 +344,19 @@
         		      width * height / 2;
       }
       
-      caps = GST_CAPS_NEW (
-		      "v4lsrc_caps",
-		      "video/raw",
-		        "format",	GST_PROPS_FOURCC (fourcc),
-			"width",	GST_PROPS_INT (src->width),
-			"height",	GST_PROPS_INT (src->height)
-			);
       break;
     }
     default:
-      caps = NULL;
-      break;
+			return NULL;
   }
 
+	caps = GST_CAPS_NEW
+		( "v4lsrc_caps",
+			"video/raw",
+			"format",	GST_PROPS_FOURCC (fourcc),
+			"width",	GST_PROPS_INT (src->width),
+			"height",	GST_PROPS_INT (src->height));
+
   return caps;
 }
 
@@ -578,6 +577,7 @@
   else {
     GST_DEBUG (0,"v4lsrc: resynced to %d %d %d\n", src->width, src->height, src->buffer_size);
     success = TRUE;
+    src->buffer_size = src->width * src->height * 3;
   }
   return success;
 }
-------------- next part --------------
--- gstreamer/plugins/jpeg/gstjpeg.c.old	Fri Jul  6 00:13:03 2001
+++ gstreamer/plugins/jpeg/gstjpeg.c	Thu Jul  5 23:50:01 2001
@@ -45,12 +45,10 @@
     gst_caps_new (
   	"jpeg_raw",
   	"video/raw",
-	gst_props_new (
-  	  "format",    GST_PROPS_LIST (
-                 	 GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0'))
-               	       ),
-  	  "width",     GST_PROPS_INT_RANGE (16, 4096),
-  	  "height",    GST_PROPS_INT_RANGE (16, 4096),
+		gst_props_new (
+  	  "format",    GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R','G','B',' ')),
+  	  "width",     GST_PROPS_INT_RANGE (1, 65535),
+  	  "height",    GST_PROPS_INT_RANGE (1, 65535),
   	  NULL));
 }
 
--- gstreamer/plugins/jpeg/gstjpegenc.c.old	Fri Jul  6 00:13:04 2001
+++ gstreamer/plugins/jpeg/gstjpegenc.c	Thu Jul  5 23:42:56 2001
@@ -22,6 +22,8 @@
 
 #include "gstjpegenc.h"
 
+static void gst_jpegenc_pushbuf(GstJpegEnc *);
+
 /* elementfactory information */
 GstElementDetails gst_jpegenc_details = {
   "jpeg image encoder",
@@ -43,14 +45,13 @@
   ARG_0,
   /* FILL ME */
 };
+		
 
+extern GstPadTemplate *jpegenc_sink_template;
 static void		gst_jpegenc_class_init	(GstJpegEnc *klass);
 static void		gst_jpegenc_init	(GstJpegEnc *jpegenc);
 
 static void		gst_jpegenc_chain	(GstPad *pad,GstBuffer *buf);
-static GstBuffer	*gst_jpegenc_get	(GstPad *pad);
-
-static void		gst_jpegenc_resync	(GstJpegEnc *jpegenc);
 
 static GstElementClass *parent_class = NULL;
 static guint gst_jpegenc_signals[LAST_SIGNAL] = { 0 };
@@ -97,143 +98,118 @@
 static void
 gst_jpegenc_init_destination (j_compress_ptr cinfo)
 {
+	GstJpegEnc *g = cinfo->client_data;
+	g->buf = NULL;
+	gst_jpegenc_pushbuf(g);
   GST_DEBUG (0,"gst_jpegenc_chain: init_destination\n");
+	
 }
 
 static gboolean
 gst_jpegenc_flush_destination (j_compress_ptr cinfo)
 {
+	GstJpegEnc *g = cinfo->client_data;
+	gst_jpegenc_pushbuf(g);
   GST_DEBUG (0,"gst_jpegenc_chain: flush_destination: buffer too small !!!\n");
+	
   return TRUE;
 }
 
 static void gst_jpegenc_term_destination (j_compress_ptr cinfo)
 {
+	GstJpegEnc *g = cinfo->client_data;
+	GstJpegEncChunk *ptr = g->buf;
+	int lastchunk, size, copied;
+	guchar *outbuf;
+	
+	size = lastchunk = GSTJPEGENCCHUNKSIZE - cinfo->dest->free_in_buffer;
+	copied = 0;
   GST_DEBUG (0,"gst_jpegenc_chain: term_source\n");
+	while(ptr->prev) {
+		size += GSTJPEGENCCHUNKSIZE;
+		ptr = ptr->prev;
+	}
+	GST_BUFFER_SIZE(g->buffer) = size;
+	GST_BUFFER_DATA(g->buffer) = outbuf = g_malloc(size);
+	while(ptr->next) {
+		memcpy(outbuf + copied, ptr->data, GSTJPEGENCCHUNKSIZE);
+		copied += GSTJPEGENCCHUNKSIZE;
+		ptr = ptr->next;
+		g_free(ptr->prev);
+	}
+	memcpy(outbuf + copied, ptr->data, lastchunk);
+	g_free(ptr);
+	ptr = NULL;
+}
+
+static void gst_jpegenc_pushbuf(GstJpegEnc *jpegenc) {
+	GstJpegEncChunk *b = g_malloc(sizeof(*b));
+	memset(b, 0, sizeof(*b));
+	GST_DEBUG(0, "Initializing %p to prev %p\n", b, jpegenc->buf);
+	b->prev = jpegenc->buf;
+	b->done = 23;
+	if(jpegenc->buf)
+		jpegenc->buf->next = b;
+	jpegenc->buf = b;
+  jpegenc->jdest.next_output_byte = b->data;
+  jpegenc->jdest.free_in_buffer = GSTJPEGENCCHUNKSIZE;
+}
+
+static void	gst_jpegenc_newcaps(GstPad *pad, GstCaps *caps) {
+	GstJpegEnc *jpegenc = GST_JPEGENC(gst_pad_get_parent(pad));
+	gulong format;
+	gint width, height;
+
+	GST_DEBUG(0, "gst_jpegenc_newcaps %p, %p\n", pad, caps);
+
+	/* These are all guaranteed to exist and be correct because the
+		 template negotiation requires them. Right? */
+	format = gst_caps_get_fourcc_int (caps, "format");
+	width =  gst_caps_get_int (caps, "width");
+	height =  gst_caps_get_int (caps, "height");
+
+	jpegenc->cinfo.image_width = jpegenc->width = width;
+	jpegenc->cinfo.image_height = jpegenc->height = height;
+	jpeg_set_defaults(&jpegenc->cinfo);
 }
-
+											
 static void
 gst_jpegenc_init (GstJpegEnc *jpegenc)
 {
   /* create the sink and src pads */
-  jpegenc->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
+	jpegenc->sinkpad = gst_pad_new_from_template
+		(jpegenc_sink_template, "sink");
+
+	gst_pad_set_newcaps_function(jpegenc->sinkpad, gst_jpegenc_newcaps);
   gst_element_add_pad(GST_ELEMENT(jpegenc),jpegenc->sinkpad);
   gst_pad_set_chain_function(jpegenc->sinkpad,gst_jpegenc_chain);
-  gst_pad_set_get_function(jpegenc->sinkpad,gst_jpegenc_get);
   jpegenc->srcpad = gst_pad_new("src",GST_PAD_SRC);
   gst_element_add_pad(GST_ELEMENT(jpegenc),jpegenc->srcpad);
 
   // reset the initial video state
-  jpegenc->width = -1;
-  jpegenc->height = -1;
+  jpegenc->width = 320;
+  jpegenc->height = 240;
+
+	jpegenc->buf = NULL;
 
   /* setup jpeglib */
   memset(&jpegenc->cinfo, 0, sizeof(jpegenc->cinfo));
   memset(&jpegenc->jerr, 0, sizeof(jpegenc->jerr));
+	jpegenc->cinfo.client_data = jpegenc;
   jpegenc->cinfo.err = jpeg_std_error(&jpegenc->jerr);
   jpeg_create_compress(&jpegenc->cinfo);
 
-  GST_DEBUG (0,"gst_jpegenc_init: setting line buffers\n");
-  jpegenc->line[0] = NULL;
-  jpegenc->line[1] = NULL;
-  jpegenc->line[2] = NULL;
-
-  gst_jpegenc_resync(jpegenc);
 
+	jpegenc->cinfo.image_width = 320;
+	jpegenc->cinfo.image_height = 240;
+	jpegenc->cinfo.input_components = 3;
+	jpegenc->cinfo.in_color_space = JCS_RGB;
+	jpeg_set_defaults(&jpegenc->cinfo);
+	
   jpegenc->jdest.init_destination = gst_jpegenc_init_destination;
   jpegenc->jdest.empty_output_buffer = gst_jpegenc_flush_destination;
   jpegenc->jdest.term_destination = gst_jpegenc_term_destination;
   jpegenc->cinfo.dest = &jpegenc->jdest;
-
-}
-
-static void
-gst_jpegenc_resync (GstJpegEnc *jpegenc)
-{
-  guint size = 0;
-  gint width, height;
-
-  GST_DEBUG (0,"gst_jpegenc_resync: resync\n");
-
-  jpegenc->cinfo.image_width = width = jpegenc->width;
-  jpegenc->cinfo.image_height = height = jpegenc->height;
-  jpegenc->cinfo.input_components = 3;
-
-  GST_DEBUG (0,"gst_jpegenc_resync: wdith %d, height %d\n", width, height);
-
-  jpeg_set_defaults(&jpegenc->cinfo);
-  jpegenc->cinfo.dct_method = JDCT_FASTEST;
-  //jpegenc->cinfo.dct_method = JDCT_DEFAULT;
-  //jpegenc->cinfo.smoothing_factor = 10;
-  jpeg_set_quality(&jpegenc->cinfo, 85, TRUE);
-
-  /*
-  switch (jpegenc->format) {
-    case GST_COLORSPACE_RGB24:
-      size = 3;
-      GST_DEBUG (0,"gst_jpegenc_resync: setting format to RGB24\n");
-      jpegenc->cinfo.in_color_space = JCS_RGB;
-      jpegenc->cinfo.raw_data_in = FALSE;
-      break;
-    case GST_COLORSPACE_YUV420P:
-      size = 2;
-      jpegenc->cinfo.raw_data_in = TRUE;
-      jpegenc->cinfo.in_color_space = JCS_YCbCr;
-      GST_DEBUG (0,"gst_jpegenc_resync: setting format to YUV420P\n");
-      jpegenc->cinfo.comp_info[0].h_samp_factor = 2;
-      jpegenc->cinfo.comp_info[0].v_samp_factor = 2;
-      jpegenc->cinfo.comp_info[1].h_samp_factor = 1;
-      jpegenc->cinfo.comp_info[1].v_samp_factor = 1;
-      jpegenc->cinfo.comp_info[2].h_samp_factor = 1;
-      jpegenc->cinfo.comp_info[2].v_samp_factor = 1;
-
-      if (height != -1) {
-        jpegenc->line[0] = g_realloc(jpegenc->line[0], height*sizeof(char*));
-        jpegenc->line[1] = g_realloc(jpegenc->line[1], height*sizeof(char*)/2);
-        jpegenc->line[2] = g_realloc(jpegenc->line[2], height*sizeof(char*)/2);
-      }
-
-      GST_DEBUG (0,"gst_jpegenc_resync: setting format done\n");
-      break;
-    default:
-      printf("gst_jpegenc_resync: unsupported colorspace, using RGB\n");
-      size = 3;
-      jpegenc->cinfo.in_color_space = JCS_RGB;
-      break;
-  }
-*/
-  jpegenc->bufsize = jpegenc->width*jpegenc->height*size;
-  jpegenc->row_stride = width * size;
-
-  jpeg_suppress_tables(&jpegenc->cinfo, TRUE);
-
-  jpegenc->buffer = NULL;
-  GST_DEBUG (0,"gst_jpegenc_resync: resync done\n");
-}
-
-static GstBuffer*
-gst_jpegenc_get (GstPad *pad)
-{
-  GstJpegEnc *jpegenc;
-  GstBuffer *newbuf;
-
-  GST_DEBUG (0,"gst_jpegenc_chain: pull buffer\n");
-
-  g_return_val_if_fail (pad != NULL, NULL);
-  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
-
-  jpegenc = GST_JPEGENC (GST_OBJECT_PARENT (pad));
-
-  if (jpegenc->buffer == NULL || GST_BUFFER_REFCOUNT(jpegenc->buffer) != 1) {
-    if (jpegenc->buffer) gst_buffer_unref(jpegenc->buffer);
-    GST_DEBUG (0,"gst_jpegenc_chain: new buffer\n");
-    newbuf = jpegenc->buffer = gst_buffer_new();
-    GST_BUFFER_DATA(newbuf) = g_malloc(jpegenc->bufsize);
-    GST_BUFFER_SIZE(newbuf) = jpegenc->bufsize;
-  }
-  gst_buffer_ref(jpegenc->buffer);
-
-  return jpegenc->buffer;
 }
 
 static void
@@ -244,9 +220,11 @@
   gulong size, outsize;
   GstBuffer *outbuf;
 //  GstMeta *meta;
-  guint height, width, width2;
+  guint height, width;
   guchar *base[3];
-  gint i,j, k;
+
+	// straight out of the manual
+	JSAMPROW row[1];
 
   g_return_if_fail (pad != NULL);
   g_return_if_fail (GST_IS_PAD (pad));
@@ -258,7 +236,7 @@
 
   data = GST_BUFFER_DATA(buf);
   size = GST_BUFFER_SIZE(buf);
-
+	
   GST_DEBUG (0,"gst_jpegenc_chain: got buffer of %ld bytes in '%s'\n",size,
           GST_OBJECT_NAME (jpegenc));
 
@@ -274,29 +252,19 @@
   base[1] = base[0]+width*height;
   base[2] = base[1]+width*height/4;
 
-  jpegenc->jdest.next_output_byte = outdata;
-  jpegenc->jdest.free_in_buffer = outsize;
+  jpegenc->buffer = gst_buffer_new();
+  GST_BUFFER_TIMESTAMP(jpegenc->buffer) = GST_BUFFER_TIMESTAMP(buf);
 
   jpeg_start_compress(&jpegenc->cinfo, TRUE);
 
-  width2 = width>>1;
-  GST_DEBUG (0,"gst_jpegdec_chain: compressing\n");
-
-  for (i = 0; i < height; i += 2*DCTSIZE) {
-    for (j=0, k=0; j<2*DCTSIZE;j+=2, k++) {
-      jpegenc->line[0][j]   = base[0]; base[0] += width;
-      jpegenc->line[0][j+1] = base[0]; base[0] += width;
-      jpegenc->line[1][k]   = base[1]; base[1] += width2;
-      jpegenc->line[2][k]   = base[2]; base[2] += width2;
-    }
-    jpeg_write_raw_data(&jpegenc->cinfo, jpegenc->line, 2*DCTSIZE);
-  }
-  jpeg_finish_compress(&jpegenc->cinfo);
-  GST_DEBUG (0,"gst_jpegdec_chain: compressing done\n");
+	while(jpegenc->cinfo.next_scanline < jpegenc->height) {
+		row[0] = data + jpegenc->cinfo.next_scanline * jpegenc->width * 3;
+		jpeg_write_scanlines(&jpegenc->cinfo, row, 1);
+	}
 
-  GST_BUFFER_SIZE(outbuf) = (((outsize - jpegenc->jdest.free_in_buffer)+3)&~3);
+	jpeg_finish_compress(&jpegenc->cinfo);
 
-  gst_pad_push(jpegenc->srcpad, outbuf);
+  gst_pad_push(jpegenc->srcpad, jpegenc->buffer);
 
   gtk_signal_emit(G_OBJECT(jpegenc),gst_jpegenc_signals[FRAME_ENCODED]);
 
--- gstreamer/plugins/jpeg/gstjpegenc.h.old	Fri Jul  6 00:13:04 2001
+++ gstreamer/plugins/jpeg/gstjpegenc.h	Tue Jun 26 00:06:45 2001
@@ -45,7 +45,16 @@
 
 typedef struct _GstJpegEnc GstJpegEnc;
 typedef struct _GstJpegEncClass GstJpegEncClass;
+typedef struct _GstJpegEncChunk GstJpegEncChunk;
 
+#define GSTJPEGENCCHUNKSIZE 8192
+struct _GstJpegEncChunk {
+	guchar data[GSTJPEGENCCHUNKSIZE];
+	int done;
+	struct _GstJpegEncChunk *prev;
+	struct _GstJpegEncChunk *next;
+};
+	
 struct _GstJpegEnc {
   GstElement element;
 
@@ -67,6 +76,7 @@
   struct jpeg_error_mgr jerr;
   struct jpeg_destination_mgr jdest;
 
+	GstJpegEncChunk *buf;
 };
 
 struct _GstJpegEncClass {


More information about the gstreamer-devel mailing list