gstv4lsrc.c 21.7 KB
Newer Older
1
/* G-Streamer BT8x8/V4L frame grabber plugin
Ronald S. Bultje's avatar
Ronald S. Bultje committed
2
 * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <string.h>
21 22
#include <sys/time.h>
#include "v4lsrc_calls.h"
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
23 24 25


static GstElementDetails gst_v4lsrc_details = {
26
  "Video (video4linux/raw) Source",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
27
  "Source/Video",
28
  "Reads raw frames from a video4linux (BT8x8) device",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
29
  VERSION,
30 31
  "Ronald Bultje <rbultje@ronald.bitfreak.net>",
  "(C) 2001",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
32 33 34 35 36 37 38 39
};

/* V4lSrc signals and args */
enum {
  /* FILL ME */
  LAST_SIGNAL
};

40
/* arguments */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
41 42 43 44
enum {
  ARG_0,
  ARG_WIDTH,
  ARG_HEIGHT,
45 46 47 48
  ARG_PALETTE,
  ARG_PALETTE_NAME,
  ARG_NUMBUFS,
  ARG_BUFSIZE
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
49 50 51
};


52 53 54 55 56
/* init functions */
static void                  gst_v4lsrc_class_init   (GstV4lSrcClass *klass);
static void                  gst_v4lsrc_init         (GstV4lSrc      *v4lsrc);

/* pad/buffer functions */
57 58
static GstPadConnectReturn   gst_v4lsrc_srcconnect   (GstPad         *pad,
                                                      GstCaps        *caps);
59
static GstBuffer*            gst_v4lsrc_get          (GstPad         *pad);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
60

61 62 63 64 65 66 67 68 69
/* get/set params */
static void                  gst_v4lsrc_set_property (GObject        *object,
                                                      guint          prop_id,
                                                      const GValue   *value,
                                                      GParamSpec     *pspec);
static void                  gst_v4lsrc_get_property (GObject        *object,
                                                      guint          prop_id,
                                                      GValue         *value,
                                                      GParamSpec     *pspec);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
70

71 72
/* state handling */
static GstElementStateReturn gst_v4lsrc_change_state (GstElement     *element);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
73

74 75 76 77 78 79 80
/* bufferpool functions */
static GstBuffer*            gst_v4lsrc_buffer_new   (GstBufferPool  *pool,
                                                      gint64         location,
                                                      gint           size,
                                                      gpointer       user_data);
static GstBuffer*            gst_v4lsrc_buffer_copy  (GstBuffer      *srcbuf);
static void                  gst_v4lsrc_buffer_free  (GstBuffer      *buf);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
81 82


83 84 85
static GstCaps *capslist = NULL;
static GstPadTemplate *src_template;

86
static GstElementClass *parent_class = NULL;\
87
/*static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 }; */
88

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
89 90 91 92 93 94 95 96

GType
gst_v4lsrc_get_type (void)
{
  static GType v4lsrc_type = 0;

  if (!v4lsrc_type) {
    static const GTypeInfo v4lsrc_info = {
97 98
      sizeof(GstV4lSrcClass),
      NULL,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
99 100 101 102 103 104 105 106 107
      NULL,
      (GClassInitFunc)gst_v4lsrc_class_init,
      NULL,
      NULL,
      sizeof(GstV4lSrc),
      0,
      (GInstanceInitFunc)gst_v4lsrc_init,
      NULL
    };
108
    v4lsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lSrc", &v4lsrc_info, 0);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
109 110 111 112
  }
  return v4lsrc_type;
}

113

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
114 115 116 117 118 119 120 121 122
static void
gst_v4lsrc_class_init (GstV4lSrcClass *klass)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

  gobject_class = (GObjectClass*)klass;
  gstelement_class = (GstElementClass*)klass;

123
  parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
124 125

  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH,
126 127
    g_param_spec_int("width","width","width",
    G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
128
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HEIGHT,
129 130
    g_param_spec_int("height","height","height",
    G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
131
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PALETTE,
132
    g_param_spec_int("palette","palette","palette",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
133
    G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
134 135 136 137 138 139 140 141 142
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PALETTE_NAME,
    g_param_spec_string("palette_name","palette_name","palette_name",
    NULL, G_PARAM_READABLE));
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
    g_param_spec_int("num_buffers","num_buffers","num_buffers",
    G_MININT,G_MAXINT,0,G_PARAM_READABLE));
  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
    g_param_spec_int("buffer_size","buffer_size","buffer_size",
    G_MININT,G_MAXINT,0,G_PARAM_READABLE));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
143 144 145 146 147 148 149

  gobject_class->set_property = gst_v4lsrc_set_property;
  gobject_class->get_property = gst_v4lsrc_get_property;

  gstelement_class->change_state = gst_v4lsrc_change_state;
}

150

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
151 152 153
static void
gst_v4lsrc_init (GstV4lSrc *v4lsrc)
{
154
  v4lsrc->srcpad = gst_pad_new_from_template (src_template, "src");
155 156 157
  gst_element_add_pad(GST_ELEMENT(v4lsrc), v4lsrc->srcpad);

  gst_pad_set_get_function (v4lsrc->srcpad, gst_v4lsrc_get);
158
  gst_pad_set_connect_function (v4lsrc->srcpad, gst_v4lsrc_srcconnect);
159 160 161 162 163 164 165

  v4lsrc->bufferpool = gst_buffer_pool_new();
  gst_buffer_pool_set_buffer_new_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_new);
  gst_buffer_pool_set_buffer_copy_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_copy);
  gst_buffer_pool_set_buffer_free_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_free);
  gst_buffer_pool_set_user_data(v4lsrc->bufferpool, v4lsrc);

166
  v4lsrc->palette = 0; /* means 'any' - user can specify a specific palette */
167 168 169 170
  v4lsrc->width = 160;
  v4lsrc->height = 120;
  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;

171
  v4lsrc->capslist = capslist;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
172 173
}

174

175 176 177
static GstPadConnectReturn
gst_v4lsrc_srcconnect (GstPad  *pad,
                       GstCaps *vscapslist)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
178 179
{
  GstV4lSrc *v4lsrc;
180
  GstCaps *caps, *newcaps;
181
  gint palette;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
182 183 184

  v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));

185 186
  palette = v4lsrc->palette;

187 188 189
  /* TODO: caps = gst_caps_normalize(capslist); */
  for (caps = vscapslist ; caps != NULL ; caps = vscapslist = vscapslist->next)
  {
Wim Taymans's avatar
Wim Taymans committed
190 191 192 193 194
    guint32 fourcc;
    gint depth;

    gst_caps_get_fourcc_int (caps, "format", &fourcc);

195
    if (v4lsrc->palette > 0)
196
    {
197 198 199
      switch (v4lsrc->palette)
      {
        case VIDEO_PALETTE_YUV420P:
Wim Taymans's avatar
Wim Taymans committed
200 201
          if (fourcc != GST_MAKE_FOURCC('I','4','2','0') &&
              fourcc != GST_MAKE_FOURCC('I','Y','U','V'))
202
            goto try_next;
Wim Taymans's avatar
Wim Taymans committed
203
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;
204 205 206
          goto try_caps;
        case VIDEO_PALETTE_YUV422:
        case VIDEO_PALETTE_YUYV:
Wim Taymans's avatar
Wim Taymans committed
207
          if (fourcc != GST_MAKE_FOURCC('Y','U','Y','2'))
208
            goto try_next;
Wim Taymans's avatar
Wim Taymans committed
209
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
210 211
          goto try_caps;
        case VIDEO_PALETTE_UYVY:
Wim Taymans's avatar
Wim Taymans committed
212
          if (fourcc != GST_MAKE_FOURCC('U','Y','V','Y'))
213
            goto try_next;
Wim Taymans's avatar
Wim Taymans committed
214
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
215 216
          goto try_caps;
        case VIDEO_PALETTE_YUV411:
Wim Taymans's avatar
Wim Taymans committed
217
          if (fourcc != GST_MAKE_FOURCC('Y','4','1','P'))
218
            goto try_next;
Wim Taymans's avatar
Wim Taymans committed
219
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;
220
          goto try_caps;
221
        case VIDEO_PALETTE_RGB555:
Wim Taymans's avatar
Wim Taymans committed
222 223 224
	  depth = gst_caps_get_int (caps, "depth", &depth);
          if (fourcc != GST_MAKE_FOURCC('R','G','B',' ') ||
              depth != 15)
225
            goto try_next;
Wim Taymans's avatar
Wim Taymans committed
226
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
227
          goto try_caps;
228
        case VIDEO_PALETTE_RGB565:
Wim Taymans's avatar
Wim Taymans committed
229 230 231
	  depth = gst_caps_get_int (caps, "depth", &depth);
          if (fourcc != GST_MAKE_FOURCC('R','G','B',' ') ||
              depth != 16)
232
            goto try_next;
Wim Taymans's avatar
Wim Taymans committed
233
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
234
          goto try_caps;
235
        case VIDEO_PALETTE_RGB24:
Wim Taymans's avatar
Wim Taymans committed
236 237 238
	  depth = gst_caps_get_int (caps, "depth", &depth);
          if (fourcc != GST_MAKE_FOURCC('R','G','B',' ') ||
              depth != 24)
239
            goto try_next;
Wim Taymans's avatar
Wim Taymans committed
240
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 3;
241
          goto try_caps;
242
        case VIDEO_PALETTE_RGB32:
Wim Taymans's avatar
Wim Taymans committed
243 244 245
	  depth = gst_caps_get_int (caps, "depth", &depth);
          if (fourcc != GST_MAKE_FOURCC('R','G','B',' ') ||
              depth != 32)
246
            goto try_next;
Wim Taymans's avatar
Wim Taymans committed
247
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 4;
248 249 250
          goto try_caps;
        default:
          goto try_next;
251 252
      }
    }
253
    else
254
    {
Wim Taymans's avatar
Wim Taymans committed
255
      switch (fourcc)
256 257 258 259
      {
        case GST_MAKE_FOURCC('I','4','2','0'):
        case GST_MAKE_FOURCC('I','Y','U','V'):
          palette = VIDEO_PALETTE_YUV420P;
Wim Taymans's avatar
Wim Taymans committed
260
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;
261 262 263
          goto try_caps;
        case GST_MAKE_FOURCC('Y','U','Y','2'):
          palette = VIDEO_PALETTE_YUV422;
Wim Taymans's avatar
Wim Taymans committed
264
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
265 266 267
          goto try_caps;
        case GST_MAKE_FOURCC('U','Y','V','Y'):
          palette = VIDEO_PALETTE_UYVY;
Wim Taymans's avatar
Wim Taymans committed
268
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
269 270 271
          goto try_caps;
        case GST_MAKE_FOURCC('Y','4','1','P'):
          palette = VIDEO_PALETTE_YUV411;
Wim Taymans's avatar
Wim Taymans committed
272
	  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;
273 274
          goto try_caps;
        case GST_MAKE_FOURCC('R','G','B',' '):
Wim Taymans's avatar
Wim Taymans committed
275 276
	  depth = gst_caps_get_int (caps, "depth", &depth);
          switch (depth)
277 278 279
          {
            case 15:
              palette = VIDEO_PALETTE_RGB555;
Wim Taymans's avatar
Wim Taymans committed
280
	      v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
281 282 283
              goto try_caps;
            case 16:
              palette = VIDEO_PALETTE_RGB565;
Wim Taymans's avatar
Wim Taymans committed
284
	      v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
285 286 287
              goto try_caps;
            case 24:
              palette = VIDEO_PALETTE_RGB24;
Wim Taymans's avatar
Wim Taymans committed
288
	      v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 3;
289 290 291
              goto try_caps;
            case 32:
              palette = VIDEO_PALETTE_RGB32;
Wim Taymans's avatar
Wim Taymans committed
292
	      v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 4;
293 294 295 296 297 298
              goto try_caps;
            default:
              goto try_next;
          }
        default:
          goto try_next;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
299 300
      }
    }
301

302 303 304 305 306 307 308 309 310 311 312 313
  /* if this caps wasn't useful, try the next one */
  try_next:
    continue;

  /* if this caps was useful, try it out */
  try_caps:
    /* TODO: try the current 'palette' out on the video device */

    if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, palette))
      continue;

    /* try to connect the pad/caps with the actual width/height */
Wim Taymans's avatar
Wim Taymans committed
314 315 316 317 318 319 320
    if (palette >= VIDEO_PALETTE_RGB565 && palette <= VIDEO_PALETTE_RGB555) {
       gint depth;
       gint bpp;

       gst_caps_get_int(caps, "bpp", &bpp),
       gst_caps_get_int(caps, "depth", &depth),

321 322 323
       newcaps = gst_caps_new("v4lsrc_caps",
                              "video/raw",
                              gst_props_new(
Wim Taymans's avatar
Wim Taymans committed
324
                                 "format", GST_PROPS_FOURCC(fourcc),
325
                                 "width",  GST_PROPS_INT(v4lsrc->width),
Wim Taymans's avatar
Wim Taymans committed
326
                                 "height", GST_PROPS_INT(v4lsrc->height),
Wim Taymans's avatar
Wim Taymans committed
327 328
                                 "bpp",    GST_PROPS_INT(bpp),
                                 "depth",  GST_PROPS_INT(depth),
329
                                 NULL      ) );
Wim Taymans's avatar
Wim Taymans committed
330 331
    }
    else {
332 333 334
       newcaps = gst_caps_new("v4lsrc_caps",
                              "video/raw",
                              gst_props_new(
Wim Taymans's avatar
Wim Taymans committed
335
                                 "format", GST_PROPS_FOURCC(fourcc),
336 337 338
                                 "width",  GST_PROPS_INT(v4lsrc->width),
                                 "height", GST_PROPS_INT(v4lsrc->height),
                                 NULL      ) );
Wim Taymans's avatar
Wim Taymans committed
339
    }
340

341
    gst_caps_debug (newcaps, "new caps to set on v4lsrc's src pad");
Wim Taymans's avatar
Wim Taymans committed
342

343 344 345
    if (!gst_pad_try_set_caps(v4lsrc->srcpad, newcaps))
      continue;
    else
346
      return GST_PAD_CONNECT_OK;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
347 348
  }

349 350
  /* still nothing - no good caps */
  return GST_PAD_CONNECT_REFUSED;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
351 352
}

353

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
354 355 356 357
static GstBuffer*
gst_v4lsrc_get (GstPad *pad)
{
  GstV4lSrc *v4lsrc;
358 359
  GstBuffer *buf;
  gint num;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
360 361 362 363 364

  g_return_val_if_fail (pad != NULL, NULL);

  v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));

365 366 367 368 369 370 371
  buf = gst_buffer_new_from_pool(v4lsrc->bufferpool, 0, 0);
  if (!buf)
  {
    gst_element_error(GST_ELEMENT(v4lsrc),
      "Failed to create a new GstBuffer");
    return NULL;
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
372

373 374 375 376 377
  /* grab a frame from the device */
  if (!gst_v4lsrc_grab_frame(v4lsrc, &num))
    return NULL;
  GST_BUFFER_DATA(buf) = gst_v4lsrc_get_buffer(v4lsrc, num);
  GST_BUFFER_SIZE(buf) = v4lsrc->buffer_size;
378 379
  buf->timestamp = v4lsrc->timestamp_soft_sync[num].tv_sec * 1000000000 +
    v4lsrc->timestamp_soft_sync[num].tv_usec * 1000;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
380 381 382 383

  return buf;
}

384

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
385
static void
386 387 388 389
gst_v4lsrc_set_property (GObject      *object,
                         guint        prop_id,
                         const GValue *value,
                         GParamSpec   *pspec)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
390
{
391
  GstV4lSrc *v4lsrc;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
392 393

  g_return_if_fail(GST_IS_V4LSRC(object));
394
  v4lsrc = GST_V4LSRC(object);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
395 396 397

  switch (prop_id) {
    case ARG_WIDTH:
398
      v4lsrc->width = g_value_get_int(value);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
399
      break;
400

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
401
    case ARG_HEIGHT:
402
      v4lsrc->height = g_value_get_int(value);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
403
      break;
404 405 406

    case ARG_PALETTE:
      v4lsrc->palette = g_value_get_int(value);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
407
      break;
408

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
409
    default:
410
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
411 412 413 414
      break;
  }
}

415

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
416
static void
417 418 419 420
gst_v4lsrc_get_property (GObject    *object,
                         guint      prop_id,
                         GValue     *value,
                         GParamSpec *pspec)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
421
{
422
  GstV4lSrc *v4lsrc;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
423 424

  g_return_if_fail(GST_IS_V4LSRC(object));
425
  v4lsrc = GST_V4LSRC(object);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
426 427 428

  switch (prop_id) {
    case ARG_WIDTH:
429
      g_value_set_int(value, v4lsrc->mmap.width);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
430
      break;
431

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
432
    case ARG_HEIGHT:
433
      g_value_set_int(value, v4lsrc->mmap.height);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
434
      break;
435 436 437

    case ARG_PALETTE:
      g_value_set_int(value, v4lsrc->mmap.format);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
438
      break;
439

440 441 442 443 444 445 446 447 448 449 450 451
    case ARG_PALETTE_NAME:
      g_value_set_string(value, g_strdup(palette_name[v4lsrc->mmap.format]));
      break;

    case ARG_NUMBUFS:
      g_value_set_int(value, v4lsrc->mbuf.frames);
      break;

    case ARG_BUFSIZE:
      g_value_set_int(value, v4lsrc->mbuf.size/(v4lsrc->mbuf.frames*1024));
      break;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
452
    default:
453
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
454 455 456 457
      break;
  }
}

458

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
459 460 461
static GstElementStateReturn
gst_v4lsrc_change_state (GstElement *element)
{
462
  GstV4lSrc *v4lsrc;
Wim Taymans's avatar
Wim Taymans committed
463
  gint transition = GST_STATE_TRANSITION (element);
464 465 466
  guint32 fourcc;
  gint depth=0, bpp=0;
  GstCaps *caps;
467 468

  g_return_val_if_fail(GST_IS_V4LSRC(element), GST_STATE_FAILURE);
469 470 471
  
  v4lsrc = GST_V4LSRC(element);

Wim Taymans's avatar
Wim Taymans committed
472 473 474
  switch (transition) {
    case GST_STATE_NULL_TO_READY:
      break;
475
    case GST_STATE_READY_TO_PAUSED:
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
      /* extremely ugly hack for a weird behaviour in the capsnego system - try capsnego again */
      switch (v4lsrc->mmap.format)
      {
        case VIDEO_PALETTE_RGB555:
          fourcc = GST_MAKE_FOURCC('R','G','B',' ');
          bpp = 16;
          depth = 15;
          break;
        case VIDEO_PALETTE_RGB565:
          fourcc = GST_MAKE_FOURCC('R','G','B',' ');
          bpp = 16;
          depth = 16;
          break;
        case VIDEO_PALETTE_RGB24:
          fourcc = GST_MAKE_FOURCC('R','G','B',' ');
          bpp = 24;
          depth = 24;
          break;
        case VIDEO_PALETTE_RGB32:
          fourcc = GST_MAKE_FOURCC('R','G','B',' ');
          bpp = 32;
          depth = 32;
          break;
        case VIDEO_PALETTE_YUV411:
          fourcc = GST_MAKE_FOURCC('Y','4','1','P');
          break;
        case VIDEO_PALETTE_YUV422:
          fourcc = GST_MAKE_FOURCC('Y','U','Y','2');
          break;
        case VIDEO_PALETTE_YUV420P:
          fourcc = GST_MAKE_FOURCC('I','4','2','0');
          break;
        case VIDEO_PALETTE_UYVY:
          fourcc = GST_MAKE_FOURCC('U','Y','V','Y');
          break;
Wim Taymans's avatar
Wim Taymans committed
511 512
	default:
	  return GST_STATE_FAILURE;
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
      }
      if (bpp && depth)
        caps = gst_caps_new("v4lsrc_caps",
                            "video/raw",
                            gst_props_new(
                              "format", GST_PROPS_FOURCC(fourcc),
                              "width",  GST_PROPS_INT(v4lsrc->width),
                              "height", GST_PROPS_INT(v4lsrc->height),
                              "bpp",    GST_PROPS_INT(bpp),
                              "depth",  GST_PROPS_INT(depth),
                              NULL      ) );
      else
        caps = gst_caps_new("v4lsrc_caps",
                            "video/raw",
                            gst_props_new(
                              "format", GST_PROPS_FOURCC(fourcc),
                              "width",  GST_PROPS_INT(v4lsrc->width),
                              "height", GST_PROPS_INT(v4lsrc->height),
                              NULL      ) );
      if (!gst_pad_try_set_caps(v4lsrc->srcpad, caps))
        return GST_STATE_FAILURE;

535 536
      if (!gst_v4lsrc_capture_init(v4lsrc))
        return GST_STATE_FAILURE;
537
      break;
538
    case GST_STATE_PAUSED_TO_PLAYING:
539 540 541 542
      /* queue all buffer, start streaming capture */
      if (!gst_v4lsrc_capture_start(v4lsrc))
        return GST_STATE_FAILURE;
      break;
543 544 545 546 547 548 549 550 551 552
    case GST_STATE_PLAYING_TO_PAUSED:
      /* de-queue all queued buffers */
      if (!gst_v4lsrc_capture_stop(v4lsrc))
        return GST_STATE_FAILURE;
      break;
    case GST_STATE_PAUSED_TO_READY:
      /* stop capturing, unmap all buffers */
      if (!gst_v4lsrc_capture_deinit(v4lsrc))
        return GST_STATE_FAILURE;
      break;
Wim Taymans's avatar
Wim Taymans committed
553 554
    case GST_STATE_READY_TO_NULL:
      break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
555 556
  }

557
  if (GST_ELEMENT_CLASS (parent_class)->change_state)
Wim Taymans's avatar
Wim Taymans committed
558 559 560 561 562 563 564 565 566 567 568 569
    GST_ELEMENT_CLASS (parent_class)->change_state (element);

  /* FIXME, this gives a not supported error on my machine?
  switch (transition) {
    case GST_STATE_NULL_TO_READY:
      if ((GST_V4LELEMENT(v4lsrc)->norm >= VIDEO_MODE_PAL ||
           GST_V4LELEMENT(v4lsrc)->norm < VIDEO_MODE_AUTO) ||
          GST_V4LELEMENT(v4lsrc)->channel < 0)
        if (!gst_v4l_set_chan_norm(GST_V4LELEMENT(v4lsrc),
             0, GST_V4LELEMENT(v4lsrc)->norm))
          return GST_STATE_FAILURE;
      break;
570
  }
Wim Taymans's avatar
Wim Taymans committed
571
  */
572 573


Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
574 575 576 577
  return GST_STATE_SUCCESS;
}


578 579 580 581 582 583 584
static GstBuffer*
gst_v4lsrc_buffer_new (GstBufferPool *pool,
                       gint64        location,
                       gint          size,
                       gpointer      user_data)
{
  GstBuffer *buffer;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
585

586 587 588
  buffer = gst_buffer_new();
  if (!buffer) return NULL;
  buffer->pool_private = user_data;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
589

590
  /* TODO: add interlacing info to buffer as metadata (height>288 or 240 = topfieldfirst, else noninterlaced) */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
591

592
  return buffer;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
593 594
}

595 596 597

static GstBuffer*
gst_v4lsrc_buffer_copy (GstBuffer *srcbuf)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
598
{
599
  GstBuffer *buffer;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
600

601 602 603 604 605 606 607 608 609
  buffer = gst_buffer_new();
  if (!buffer) return NULL;
  GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
  if (!GST_BUFFER_DATA(buffer)) return NULL;
  GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
  memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
  GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);

  return buffer;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
610 611
}

612

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
613
static void
614
gst_v4lsrc_buffer_free (GstBuffer *buf)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
615
{
616 617 618 619 620 621 622 623 624
  GstV4lSrc *v4lsrc = buf->pool_private;
  int n;

  for (n=0;n<v4lsrc->mbuf.frames;n++)
    if (GST_BUFFER_DATA(buf) == gst_v4lsrc_get_buffer(v4lsrc, n))
    {
      gst_v4lsrc_requeue_frame(v4lsrc, n);
      return;
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
625

626
  gst_element_error(GST_ELEMENT(v4lsrc),
627
    "Couldn\'t find the buffer");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
628 629
}

630

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
631
static gboolean
632 633
plugin_init (GModule   *module,
             GstPlugin *plugin)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
634 635
{
  GstElementFactory *factory;
636 637 638 639 640 641 642 643
  GstCaps *caps;
  gint i;
  gulong format[5] = { GST_MAKE_FOURCC('Y','U','Y','2'), /* VIDEO_PALETTE_YUV422/_YUYV */
                       GST_MAKE_FOURCC('I','4','2','0'), /* VIDEO_PALETTE_YUV420P */
                       GST_MAKE_FOURCC('I','Y','U','V'), /* VIDEO_PALETTE_YUV420P */
                       GST_MAKE_FOURCC('U','Y','V','Y'), /* VIDEO_PALETTE_UYVY */
                       GST_MAKE_FOURCC('Y','4','1','P')  /* VIDEO_PALETTE_YUV411 */
                     };
Wim Taymans's avatar
Wim Taymans committed
644
  gint rgb_bpp[4] = { 16, 16, 24, 32 };
645
  gint rgb_depth[4] = { 15, 16, 24, 32 };
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
646

647
  /* create an elementfactory for the v4lsrc */
648
  factory = gst_element_factory_new("v4lsrc",GST_TYPE_V4LSRC,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
649 650
                                   &gst_v4lsrc_details);
  g_return_val_if_fail(factory != NULL, FALSE);
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681

  /* make a list of all available caps - first the YUV formats */
  for (i=0;i<5;i++)
  {
    caps = gst_caps_new ("v4lsrc_caps",
                         "video/raw",
                         gst_props_new (
                            "format", GST_PROPS_FOURCC(format[i]),
                            "width",  GST_PROPS_INT_RANGE (0, G_MAXINT),
                            "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
                            NULL       )
                        );
    capslist = gst_caps_append(capslist, caps);
  }

  /* now all the RGB formats */
  for (i=0;i<4;i++)
  {
    caps = gst_caps_new ("v4lsrc_caps",
                         "video/raw",
                         gst_props_new (
                            "format", GST_PROPS_FOURCC(GST_MAKE_FOURCC('R','G','B',' ')),
                            "width",  GST_PROPS_INT_RANGE (0, G_MAXINT),
                            "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
                            "bpp",    GST_PROPS_INT(rgb_bpp[i]),
                            "depth",  GST_PROPS_INT(rgb_depth[i]),
                            NULL       )
                        );
    capslist = gst_caps_append(capslist, caps);
  }

682
  src_template = gst_pad_template_new (
683 684 685 686 687
		  "src",
                  GST_PAD_SRC,
  		  GST_PAD_ALWAYS,
		  capslist, NULL);

688
  gst_element_factory_add_pad_template (factory, src_template);
689

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
690 691 692 693 694
  gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));

  return TRUE;
}

695

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
696 697 698 699 700 701
GstPluginDesc plugin_desc = {
  GST_VERSION_MAJOR,
  GST_VERSION_MINOR,
  "v4lsrc",
  plugin_init
};