gstbasesrc.c 25.9 KB
Newer Older
1 2
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3
 *               2000,2005 Wim Taymans <wim@fluendo.com>
4
 *
5
 * gstbasesrc.c:
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *
 * 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 <stdlib.h>
#include <string.h>

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "gstbasesrc.h"
Wim Taymans's avatar
Wim Taymans committed
32
#include "gsttypefindhelper.h"
33 34 35
#include <gst/gstmarshal.h>

#define DEFAULT_BLOCKSIZE	4096
36
#define DEFAULT_NUM_BUFFERS	-1
37

38 39
GST_DEBUG_CATEGORY_STATIC (gst_base_src_debug);
#define GST_CAT_DEFAULT gst_base_src_debug
40 41 42 43 44 45 46 47 48 49

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

enum
{
50 51
  PROP_0,
  PROP_BLOCKSIZE,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
52
  PROP_HAS_LOOP,
53
  PROP_HAS_GETRANGE,
54
  PROP_NUM_BUFFERS,
55 56 57 58
};

static GstElementClass *parent_class = NULL;

59 60 61
static void gst_base_src_base_init (gpointer g_class);
static void gst_base_src_class_init (GstBaseSrcClass * klass);
static void gst_base_src_init (GstBaseSrc * src, gpointer g_class);
62 63
static void gst_base_src_finalize (GObject * object);

64 65

GType
66
gst_base_src_get_type (void)
67
{
68
  static GType base_src_type = 0;
69

70 71
  if (!base_src_type) {
    static const GTypeInfo base_src_info = {
72
      sizeof (GstBaseSrcClass),
73
      (GBaseInitFunc) gst_base_src_base_init,
74
      NULL,
75
      (GClassInitFunc) gst_base_src_class_init,
76 77 78 79
      NULL,
      NULL,
      sizeof (GstBaseSrc),
      0,
80
      (GInstanceInitFunc) gst_base_src_init,
81 82
    };

83 84
    base_src_type = g_type_register_static (GST_TYPE_ELEMENT,
        "GstBaseSrc", &base_src_info, G_TYPE_FLAG_ABSTRACT);
85
  }
86
  return base_src_type;
87
}
88 89
static GstCaps *gst_base_src_getcaps (GstPad * pad);
static gboolean gst_base_src_setcaps (GstPad * pad, GstCaps * caps);
90

91 92 93
static gboolean gst_base_src_activate_push (GstPad * pad, gboolean active);
static gboolean gst_base_src_activate_pull (GstPad * pad, gboolean active);
static void gst_base_src_set_property (GObject * object, guint prop_id,
94
    const GValue * value, GParamSpec * pspec);
95
static void gst_base_src_get_property (GObject * object, guint prop_id,
96
    GValue * value, GParamSpec * pspec);
97
static gboolean gst_base_src_event_handler (GstPad * pad, GstEvent * event);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
98

99
static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
100

101
#if 0
102
static const GstEventMask *gst_base_src_get_event_mask (GstPad * pad);
103
#endif
104
static gboolean gst_base_src_default_negotiate (GstBaseSrc * basesrc);
105

106 107 108 109
static gboolean gst_base_src_unlock (GstBaseSrc * basesrc);
static gboolean gst_base_src_get_size (GstBaseSrc * basesrc, guint64 * size);
static gboolean gst_base_src_start (GstBaseSrc * basesrc);
static gboolean gst_base_src_stop (GstBaseSrc * basesrc);
110

111
static GstElementStateReturn gst_base_src_change_state (GstElement * element);
112

113 114 115 116
static void gst_base_src_set_dataflow_funcs (GstBaseSrc * this);
static void gst_base_src_loop (GstPad * pad);
static gboolean gst_base_src_check_get_range (GstPad * pad);
static GstFlowReturn gst_base_src_get_range (GstPad * pad, guint64 offset,
117 118 119
    guint length, GstBuffer ** buf);

static void
120
gst_base_src_base_init (gpointer g_class)
121
{
122
  GST_DEBUG_CATEGORY_INIT (gst_base_src_debug, "basesrc", 0, "basesrc element");
123 124 125
}

static void
126
gst_base_src_class_init (GstBaseSrcClass * klass)
127 128 129 130 131 132 133 134 135
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

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

  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);

136
  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_src_finalize);
137 138
  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_src_set_property);
  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_src_get_property);
139

140
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
141 142 143 144
      g_param_spec_ulong ("blocksize", "Block size",
          "Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
          G_PARAM_READWRITE));

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
145 146 147 148 149 150 151 152 153 154
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
      g_param_spec_boolean ("has-loop", "Has loop function",
          "True if the element should expose a loop function", TRUE,
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT));

  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
      g_param_spec_boolean ("has-getrange", "Has getrange function",
          "True if the element should expose a getrange function", TRUE,
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT));

155 156 157 158 159
  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_BUFFERS,
      g_param_spec_int ("num-buffers", "num-buffers",
          "Number of buffers to output before sending EOS", -1, G_MAXINT,
          DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE));

160 161
  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_base_src_change_state);
162 163

  klass->negotiate = gst_base_src_default_negotiate;
164 165 166
}

static void
167
gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
168 169 170 171
{
  GstPad *pad;
  GstPadTemplate *pad_template;

172 173 174
  basesrc->is_live = FALSE;
  basesrc->live_lock = g_mutex_new ();
  basesrc->live_cond = g_cond_new ();
175 176
  basesrc->num_buffers = DEFAULT_NUM_BUFFERS;
  basesrc->num_buffers_left = -1;
177

178 179 180 181 182 183
  pad_template =
      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
  g_return_if_fail (pad_template != NULL);

  pad = gst_pad_new_from_template (pad_template, "src");

184 185 186 187 188
  gst_pad_set_activatepush_function (pad, gst_base_src_activate_push);
  gst_pad_set_activatepull_function (pad, gst_base_src_activate_pull);
  gst_pad_set_event_function (pad, gst_base_src_event_handler);
  gst_pad_set_query_function (pad, gst_base_src_query);
  gst_pad_set_checkgetrange_function (pad, gst_base_src_check_get_range);
189 190
  gst_pad_set_getcaps_function (pad, gst_base_src_getcaps);
  gst_pad_set_setcaps_function (pad, gst_base_src_setcaps);
191

192 193
  /* hold ref to pad */
  basesrc->srcpad = pad;
194 195 196 197
  gst_element_add_pad (GST_ELEMENT (basesrc), pad);

  basesrc->segment_start = -1;
  basesrc->segment_end = -1;
198
  basesrc->need_discont = TRUE;
199
  basesrc->blocksize = DEFAULT_BLOCKSIZE;
Wim Taymans's avatar
Wim Taymans committed
200
  basesrc->clock_id = NULL;
201

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
202
  GST_FLAG_UNSET (basesrc, GST_BASE_SRC_STARTED);
203 204
}

205 206 207 208 209 210 211 212 213 214 215 216 217
static void
gst_base_src_finalize (GObject * object)
{
  GstBaseSrc *basesrc;

  basesrc = GST_BASE_SRC (object);

  g_mutex_free (basesrc->live_lock);
  g_cond_free (basesrc->live_cond);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

218
void
219
gst_base_src_set_live (GstBaseSrc * src, gboolean live)
220 221 222 223 224 225 226
{
  GST_LIVE_LOCK (src);
  src->is_live = live;
  GST_LIVE_UNLOCK (src);
}

gboolean
227
gst_base_src_is_live (GstBaseSrc * src)
228 229 230 231 232 233 234 235 236 237
{
  gboolean result;

  GST_LIVE_LOCK (src);
  result = src->is_live;
  GST_LIVE_UNLOCK (src);

  return result;
}

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
238
static void
239
gst_base_src_set_dataflow_funcs (GstBaseSrc * this)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
240
{
241 242
  GST_DEBUG ("updating dataflow functions");

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
243
  if (this->has_getrange)
244
    gst_pad_set_getrange_function (this->srcpad, gst_base_src_get_range);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
245 246 247 248
  else
    gst_pad_set_getrange_function (this->srcpad, NULL);
}

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
static gboolean
gst_base_src_setcaps (GstPad * pad, GstCaps * caps)
{
  GstBaseSrcClass *bclass;
  GstBaseSrc *bsrc;
  gboolean res = TRUE;

  bsrc = GST_BASE_SRC (GST_PAD_PARENT (pad));
  bclass = GST_BASE_SRC_GET_CLASS (bsrc);

  if (bclass->set_caps)
    res = bclass->set_caps (bsrc, caps);

  return res;
}

static GstCaps *
gst_base_src_getcaps (GstPad * pad)
{
  GstBaseSrcClass *bclass;
  GstBaseSrc *bsrc;
  GstCaps *caps = NULL;

  bsrc = GST_BASE_SRC (GST_PAD_PARENT (pad));
  bclass = GST_BASE_SRC_GET_CLASS (bsrc);
  if (bclass->get_caps)
    caps = bclass->get_caps (bsrc);

  if (caps == NULL) {
    GstPadTemplate *pad_template;

    pad_template =
        gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
    if (pad_template != NULL) {
      caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
    }
  }
  return caps;
}

289
static gboolean
290
gst_base_src_query (GstPad * pad, GstQuery * query)
291
{
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
292 293 294 295
  gboolean b;
  guint64 ui64;
  gint64 i64;
  GstBaseSrc *src;
296

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
297
  src = GST_BASE_SRC (GST_PAD_PARENT (pad));
298

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
299
  switch (GST_QUERY_TYPE (query)) {
300
    case GST_QUERY_POSITION:
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
301 302 303
    {
      GstFormat format;

304
      gst_query_parse_position (query, &format, NULL, NULL);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
305 306
      switch (format) {
        case GST_FORMAT_DEFAULT:
307
        case GST_FORMAT_BYTES:
308
          b = gst_base_src_get_size (src, &ui64);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
309 310 311 312
          /* better to make get_size take an int64 */
          i64 = b ? (gint64) ui64 : -1;
          gst_query_set_position (query, GST_FORMAT_BYTES, src->offset, i64);
          return TRUE;
313
        case GST_FORMAT_PERCENT:
314
          b = gst_base_src_get_size (src, &ui64);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
315 316 317 318
          i64 = GST_FORMAT_PERCENT_MAX;
          i64 *= b ? (src->offset / (gdouble) ui64) : 1.0;
          gst_query_set_position (query, GST_FORMAT_PERCENT,
              i64, GST_FORMAT_PERCENT_MAX);
319 320 321 322
          return TRUE;
        default:
          return FALSE;
      }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
323 324 325 326 327
    }

    case GST_QUERY_SEEKING:
      gst_query_set_seeking (query, GST_FORMAT_BYTES,
          src->seekable, src->segment_start, src->segment_end);
328
      return TRUE;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
329 330 331 332

    case GST_QUERY_FORMATS:
      gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT,
          GST_FORMAT_BYTES, GST_FORMAT_PERCENT);
333
      return TRUE;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
334 335 336 337 338

    case GST_QUERY_LATENCY:
    case GST_QUERY_JITTER:
    case GST_QUERY_RATE:
    case GST_QUERY_CONVERT:
339
    default:
340
      return gst_pad_query_default (pad, query);
341 342 343
  }
}

344
#if 0
345
static const GstEventMask *
346
gst_base_src_get_event_mask (GstPad * pad)
347 348
{
  static const GstEventMask masks[] = {
349 350 351
    {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET |
          GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH |
          GST_SEEK_FLAG_SEGMENT_LOOP},
352
    {GST_EVENT_FLUSH, 0},
353
    {GST_EVENT_SIZE, 0},
354 355 356 357
    {0, 0},
  };
  return masks;
}
358
#endif
359

360 361 362 363 364
static gboolean
gst_base_src_send_discont (GstBaseSrc * src)
{
  GstEvent *event;

Wim Taymans's avatar
Wim Taymans committed
365
  event = gst_event_new_newsegment (1.0,
366
      GST_FORMAT_BYTES,
Wim Taymans's avatar
Wim Taymans committed
367
      (gint64) src->segment_start, (gint64) src->segment_end, (gint64) 0);
368 369 370 371

  return gst_pad_push_event (src->srcpad, event);
}

372
static gboolean
373
gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
374
{
Wim Taymans's avatar
Wim Taymans committed
375
  gdouble rate;
376
  GstFormat format;
Wim Taymans's avatar
Wim Taymans committed
377 378 379
  GstSeekFlags flags;
  GstSeekType cur_type, stop_type;
  gint64 cur, stop;
380

Wim Taymans's avatar
Wim Taymans committed
381 382
  gst_event_parse_seek (event, &rate, &format, &flags,
      &cur_type, &cur, &stop_type, &stop);
383 384 385 386 387 388 389 390 391

  /* get seek format */
  if (format == GST_FORMAT_DEFAULT)
    format = GST_FORMAT_BYTES;
  /* we can only seek bytes */
  if (format != GST_FORMAT_BYTES)
    return FALSE;

  /* get seek positions */
Wim Taymans's avatar
Wim Taymans committed
392
  src->segment_loop = flags & GST_SEEK_FLAG_SEGMENT;
393

Wim Taymans's avatar
Wim Taymans committed
394
  /* send flush start */
Wim Taymans's avatar
Wim Taymans committed
395
  gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());
Wim Taymans's avatar
Wim Taymans committed
396 397 398 399 400 401 402

  /* unblock streaming thread */
  gst_base_src_unlock (src);

  /* grab streaming lock */
  GST_STREAM_LOCK (src->srcpad);

Wim Taymans's avatar
Wim Taymans committed
403 404
  /* send flush stop */
  gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());
Wim Taymans's avatar
Wim Taymans committed
405 406

  /* perform the seek */
Wim Taymans's avatar
Wim Taymans committed
407 408 409
  switch (cur_type) {
    case GST_SEEK_TYPE_SET:
      if (cur < 0)
410
        goto error;
Wim Taymans's avatar
Wim Taymans committed
411
      src->offset = MIN (cur, src->size);
412
      src->segment_start = src->offset;
Wim Taymans's avatar
Wim Taymans committed
413
      src->segment_end = MIN (stop, src->size);
414 415 416
      GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
          src->offset);
      break;
Wim Taymans's avatar
Wim Taymans committed
417 418 419
    case GST_SEEK_TYPE_CUR:
      cur += src->offset;
      src->offset = CLAMP (cur, 0, src->size);
420
      src->segment_start = src->offset;
Wim Taymans's avatar
Wim Taymans committed
421
      src->segment_end = stop;
422 423 424
      GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
          src->offset);
      break;
Wim Taymans's avatar
Wim Taymans committed
425 426
    case GST_SEEK_TYPE_END:
      if (cur > 0)
427
        goto error;
Wim Taymans's avatar
Wim Taymans committed
428 429
      cur = src->size + cur;
      src->offset = MAX (0, cur);
430
      src->segment_start = src->offset;
Wim Taymans's avatar
Wim Taymans committed
431
      src->segment_end = stop;
432 433 434 435 436 437
      GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
          src->offset);
      break;
    default:
      goto error;
  }
438

439 440
  /* now make sure the discont will be send */
  src->need_discont = TRUE;
441 442

  /* and restart the task */
443
  gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
444
      src->srcpad);
445 446 447 448 449 450 451 452 453 454
  GST_STREAM_UNLOCK (src->srcpad);

  gst_event_unref (event);

  return TRUE;

  /* ERROR */
error:
  {
    GST_DEBUG_OBJECT (src, "seek error");
Wim Taymans's avatar
Wim Taymans committed
455
    GST_STREAM_UNLOCK (src->srcpad);
456 457 458 459 460
    gst_event_unref (event);
    return FALSE;
  }
}

461
static gboolean
462
gst_base_src_event_handler (GstPad * pad, GstEvent * event)
463 464
{
  GstBaseSrc *src;
Wim Taymans's avatar
Wim Taymans committed
465 466
  GstBaseSrcClass *bclass;
  gboolean result;
467

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
468 469
  src = GST_BASE_SRC (GST_PAD_PARENT (pad));
  bclass = GST_BASE_SRC_GET_CLASS (src);
Wim Taymans's avatar
Wim Taymans committed
470 471 472

  if (bclass->event)
    result = bclass->event (src, event);
473 474 475

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
476
      return gst_base_src_do_seek (src, event);
Wim Taymans's avatar
Wim Taymans committed
477
    case GST_EVENT_FLUSH_START:
478
      /* cancel any blocking getrange */
Wim Taymans's avatar
Wim Taymans committed
479 480 481
      gst_base_src_unlock (src);
      break;
    case GST_EVENT_FLUSH_STOP:
482 483 484 485 486 487 488 489 490 491
      break;
    default:
      break;
  }
  gst_event_unref (event);

  return TRUE;
}

static void
492 493
gst_base_src_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
494 495 496
{
  GstBaseSrc *src;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
497
  src = GST_BASE_SRC (object);
498 499

  switch (prop_id) {
500 501
    case PROP_BLOCKSIZE:
      src->blocksize = g_value_get_ulong (value);
502
      break;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
503 504
    case PROP_HAS_LOOP:
      src->has_loop = g_value_get_boolean (value);
505
      gst_base_src_set_dataflow_funcs (src);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
506 507 508
      break;
    case PROP_HAS_GETRANGE:
      src->has_getrange = g_value_get_boolean (value);
509
      gst_base_src_set_dataflow_funcs (src);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
510
      break;
511 512 513
    case PROP_NUM_BUFFERS:
      src->num_buffers = g_value_get_int (value);
      break;
514 515 516 517 518 519 520
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
521
gst_base_src_get_property (GObject * object, guint prop_id, GValue * value,
522 523 524 525
    GParamSpec * pspec)
{
  GstBaseSrc *src;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
526
  src = GST_BASE_SRC (object);
527 528

  switch (prop_id) {
529 530
    case PROP_BLOCKSIZE:
      g_value_set_ulong (value, src->blocksize);
531
      break;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
532 533 534 535 536 537
    case PROP_HAS_LOOP:
      g_value_set_boolean (value, src->has_loop);
      break;
    case PROP_HAS_GETRANGE:
      g_value_set_boolean (value, src->has_getrange);
      break;
538 539 540
    case PROP_NUM_BUFFERS:
      g_value_set_int (value, src->num_buffers);
      break;
541 542 543 544 545 546 547
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static GstFlowReturn
548
gst_base_src_get_range (GstPad * pad, guint64 offset, guint length,
549 550 551 552 553 554
    GstBuffer ** buf)
{
  GstFlowReturn ret;
  GstBaseSrc *src;
  GstBaseSrcClass *bclass;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
555 556
  src = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
  bclass = GST_BASE_SRC_GET_CLASS (src);
557

558 559 560
  GST_LIVE_LOCK (src);
  if (src->is_live) {
    while (!src->live_running) {
561 562
      GST_DEBUG ("live source signal waiting");
      GST_LIVE_SIGNAL (src);
563 564 565 566 567 568 569
      GST_DEBUG ("live source waiting for running state");
      GST_LIVE_WAIT (src);
      GST_DEBUG ("live source unlocked");
    }
  }
  GST_LIVE_UNLOCK (src);

570 571 572 573 574
  GST_LOCK (pad);
  if (GST_PAD_IS_FLUSHING (pad))
    goto flushing;
  GST_UNLOCK (pad);

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
575
  if (!GST_FLAG_IS_SET (src, GST_BASE_SRC_STARTED))
576 577 578 579 580 581 582
    goto not_started;

  if (!bclass->create)
    goto no_function;

  /* check size */
  if (src->size != -1) {
583 584 585
    if (offset > src->size)
      goto unexpected_length;

586 587 588 589 590 591 592 593 594 595
    if (offset + length > src->size) {
      if (bclass->get_size)
        bclass->get_size (src, &src->size);

      if (offset + length > src->size) {
        length = src->size - offset;
      }
    }
  }
  if (length == 0)
Wim Taymans's avatar
Wim Taymans committed
596
    goto unexpected_length;
597

598 599 600 601 602 603 604
  if (src->num_buffers_left == 0) {
    goto reached_num_buffers;
  } else {
    if (src->num_buffers_left > 0)
      src->num_buffers_left--;
  }

605
  ret = bclass->create (src, offset, length, buf);
606 607

  return ret;
608 609

  /* ERROR */
610 611 612 613 614 615
flushing:
  {
    GST_DEBUG_OBJECT (src, "pad is flushing");
    GST_UNLOCK (pad);
    return GST_FLOW_WRONG_STATE;
  }
616 617 618 619 620 621 622 623 624 625
not_started:
  {
    GST_DEBUG_OBJECT (src, "getrange but not started");
    return GST_FLOW_WRONG_STATE;
  }
no_function:
  {
    GST_DEBUG_OBJECT (src, "no create function");
    return GST_FLOW_ERROR;
  }
Wim Taymans's avatar
Wim Taymans committed
626 627 628 629 630
unexpected_length:
  {
    GST_DEBUG_OBJECT (src, "unexpected length %u", length);
    return GST_FLOW_UNEXPECTED;
  }
631 632 633 634 635
reached_num_buffers:
  {
    GST_DEBUG_OBJECT (src, "sent all buffers");
    return GST_FLOW_UNEXPECTED;
  }
636 637
}

638
static gboolean
639
gst_base_src_check_get_range (GstPad * pad)
640 641 642
{
  GstBaseSrc *src;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
643
  src = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
644

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
645
  if (!GST_FLAG_IS_SET (src, GST_BASE_SRC_STARTED)) {
646 647
    gst_base_src_start (src);
    gst_base_src_stop (src);
648 649 650 651 652
  }

  return src->seekable;
}

653
static void
654
gst_base_src_loop (GstPad * pad)
655 656 657 658 659
{
  GstBaseSrc *src;
  GstBuffer *buf = NULL;
  GstFlowReturn ret;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
660
  src = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
661

662
  if (src->need_discont) {
663
    /* now send discont */
664
    gst_base_src_send_discont (src);
665
    src->need_discont = FALSE;
666 667
  }

668
  ret = gst_base_src_get_range (pad, src->offset, src->blocksize, &buf);
669
  if (ret != GST_FLOW_OK)
670
    goto eos;
671

672 673 674
  if (buf == NULL)
    goto error;

675 676 677 678 679 680 681 682
  src->offset += GST_BUFFER_SIZE (buf);

  ret = gst_pad_push (pad, buf);
  if (ret != GST_FLOW_OK)
    goto pause;

  return;

683 684 685
eos:
  {
    GST_DEBUG_OBJECT (src, "going to EOS");
686
    gst_pad_pause_task (pad);
Wim Taymans's avatar
Wim Taymans committed
687
    gst_pad_push_event (pad, gst_event_new_eos ());
688 689
    return;
  }
690 691
pause:
  {
692
    GST_DEBUG_OBJECT (src, "pausing task");
693
    gst_pad_pause_task (pad);
694
    if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
695 696
      /* for fatal errors we post an error message */
      GST_ELEMENT_ERROR (src, STREAM, STOPPED,
697 698
          ("streaming stopped, reason %s", gst_flow_get_name (ret)),
          ("streaming stopped, reason %s", gst_flow_get_name (ret)));
Wim Taymans's avatar
Wim Taymans committed
699
      gst_pad_push_event (pad, gst_event_new_eos ());
700
    }
701 702
    return;
  }
703 704
error:
  {
705 706 707
    GST_ELEMENT_ERROR (src, STREAM, STOPPED,
        ("internal: element returned NULL buffer"),
        ("internal: element returned NULL buffer"));
708
    gst_pad_pause_task (pad);
Wim Taymans's avatar
Wim Taymans committed
709
    gst_pad_push_event (pad, gst_event_new_eos ());
710 711
    return;
  }
712 713 714
}

static gboolean
715
gst_base_src_unlock (GstBaseSrc * basesrc)
716 717 718 719
{
  GstBaseSrcClass *bclass;
  gboolean result = FALSE;

720
  GST_DEBUG ("unlock");
Wim Taymans's avatar
Wim Taymans committed
721
  /* unblock whatever the subclass is doing */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
722
  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
723 724 725
  if (bclass->unlock)
    result = bclass->unlock (basesrc);

726
  GST_DEBUG ("unschedule clock");
Wim Taymans's avatar
Wim Taymans committed
727 728 729 730 731 732 733
  /* and unblock the clock as well, if any */
  GST_LOCK (basesrc);
  if (basesrc->clock_id) {
    gst_clock_id_unschedule (basesrc->clock_id);
  }
  GST_UNLOCK (basesrc);

734 735
  GST_DEBUG ("unlock done");

736 737 738 739
  return result;
}

static gboolean
740
gst_base_src_get_size (GstBaseSrc * basesrc, guint64 * size)
741
{
742
  GstBaseSrcClass *bclass;
743
  gboolean result = FALSE;
744

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
745
  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
746 747 748 749 750 751 752 753 754
  if (bclass->get_size)
    result = bclass->get_size (basesrc, size);

  if (result)
    basesrc->size = *size;

  return result;
}

755
static gboolean
756
gst_base_src_is_seekable (GstBaseSrc * basesrc)
757 758 759
{
  GstBaseSrcClass *bclass;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
760
  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
761 762 763 764 765 766 767 768 769 770

  /* check if we can seek */
  if (bclass->is_seekable)
    basesrc->seekable = bclass->is_seekable (basesrc);
  else
    basesrc->seekable = FALSE;

  return basesrc->seekable;
}

771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
static gboolean
gst_base_src_default_negotiate (GstBaseSrc * basesrc)
{
  GstCaps *thiscaps;
  GstCaps *caps = NULL;
  GstCaps *peercaps = NULL;
  gboolean result = FALSE;

  thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
  GST_DEBUG ("caps of src: %" GST_PTR_FORMAT, thiscaps);
  if (thiscaps == NULL || gst_caps_is_any (thiscaps))
    goto no_nego_needed;

  peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
  GST_DEBUG ("caps of peer: %" GST_PTR_FORMAT, peercaps);
  if (peercaps) {
    GstCaps *icaps;

    icaps = gst_caps_intersect (thiscaps, peercaps);
    GST_DEBUG ("intersect: %" GST_PTR_FORMAT, icaps);
    gst_caps_unref (thiscaps);
    gst_caps_unref (peercaps);
    if (icaps) {
      caps = gst_caps_copy_nth (icaps, 0);
      gst_caps_unref (icaps);
    }
  } else {
    caps = thiscaps;
  }
  if (caps) {
801
    caps = gst_caps_make_writable (caps);
802 803
    gst_caps_truncate (caps);

804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
    gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
    GST_DEBUG ("fixated to: %" GST_PTR_FORMAT, caps);

    if (gst_caps_is_any (caps)) {
      gst_caps_unref (caps);
      result = TRUE;
    } else if (gst_caps_is_fixed (caps)) {
      gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
      gst_caps_unref (caps);
      result = TRUE;
    }
  }
  return result;

no_nego_needed:
  {
    GST_DEBUG ("no negotiation needed");
    if (thiscaps)
      gst_caps_unref (thiscaps);
    return TRUE;
  }
}

static gboolean
gst_base_src_negotiate (GstBaseSrc * basesrc)
{
  GstBaseSrcClass *bclass;
831
  gboolean result = TRUE;
832 833 834 835 836 837 838 839 840

  bclass = GST_BASE_SRC_GET_CLASS (basesrc);

  if (bclass->negotiate)
    result = bclass->negotiate (basesrc);

  return result;
}

841
static gboolean
842
gst_base_src_start (GstBaseSrc * basesrc)
843 844 845 846
{
  GstBaseSrcClass *bclass;
  gboolean result;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
847
  if (GST_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED))
848 849
    return TRUE;

850 851
  basesrc->num_buffers_left = basesrc->num_buffers;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
852
  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
853 854 855 856 857 858 859 860
  if (bclass->start)
    result = bclass->start (basesrc);
  else
    result = TRUE;

  if (!result)
    goto could_not_start;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
861
  GST_FLAG_SET (basesrc, GST_BASE_SRC_STARTED);
862 863 864 865 866

  /* start in the beginning */
  basesrc->offset = 0;

  /* figure out the size */
Wim Taymans's avatar
Wim Taymans committed
867
  if (bclass->get_size) {
868
    result = bclass->get_size (basesrc, &basesrc->size);
Wim Taymans's avatar
Wim Taymans committed
869 870
    if (result == FALSE)
      basesrc->size = -1;
Wim Taymans's avatar
Wim Taymans committed
871
  } else {
872
    result = FALSE;
Wim Taymans's avatar
Wim Taymans committed
873 874
    basesrc->size = -1;
  }
875

Wim Taymans's avatar
Wim Taymans committed
876
  GST_DEBUG ("size %d %lld", result, basesrc->size);
877 878

  /* we always run to the end */
879
  basesrc->segment_start = 0;
880
  basesrc->segment_end = basesrc->size;
881
  basesrc->need_discont = TRUE;
882

883
  /* check if we can seek, updates ->seekable */
884
  gst_base_src_is_seekable (basesrc);
885 886

  /* run typefind */
Wim Taymans's avatar
Wim Taymans committed
887
#if 0
888 889 890
  if (basesrc->seekable) {
    GstCaps *caps;

Wim Taymans's avatar
Wim Taymans committed
891
    caps = gst_type_find_helper (basesrc->srcpad, basesrc->size);
892
    gst_pad_set_caps (basesrc->srcpad, caps);
893
    gst_caps_unref (caps);
894
  }
Wim Taymans's avatar
Wim Taymans committed
895 896
#endif

897 898 899
  if (!gst_base_src_negotiate (basesrc))
    goto could_not_negotiate;

900 901 902 903 904 905 906 907
  return TRUE;

  /* ERROR */
could_not_start:
  {
    GST_DEBUG_OBJECT (basesrc, "could not start");
    return FALSE;
  }
908 909 910
could_not_negotiate:
  {
    GST_DEBUG_OBJECT (basesrc, "could not negotiate, stopping");
911 912 913
    GST_ELEMENT_ERROR (basesrc, STREAM, FORMAT,
        ("Could not connect source to pipeline"),
        ("Check your filtered caps, if any"));
914 915 916
    gst_base_src_stop (basesrc);
    return FALSE;
  }
917 918 919
}

static gboolean
920
gst_base_src_stop (GstBaseSrc * basesrc)
921 922 923 924
{
  GstBaseSrcClass *bclass;
  gboolean result = TRUE;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
925
  if (!GST_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED))
926 927
    return TRUE;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
928
  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
929 930 931 932
  if (bclass->stop)
    result = bclass->stop (basesrc);

  if (result)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
933
    GST_FLAG_UNSET (basesrc, GST_BASE_SRC_STARTED);
934 935 936 937 938

  return result;
}

static gboolean
939
gst_base_src_deactivate (GstBaseSrc * basesrc, GstPad * pad)
940 941
{
  gboolean result;
942 943 944 945 946 947 948

  GST_LIVE_LOCK (basesrc);
  basesrc->live_running = TRUE;
  GST_LIVE_SIGNAL (basesrc);
  GST_LIVE_UNLOCK (basesrc);

  /* step 1, unblock clock sync (if any) */
949
  gst_base_src_unlock (basesrc);
950 951 952 953 954 955 956 957

  /* step 2, make sure streaming finishes */
  result = gst_pad_stop_task (pad);

  return result;
}

static gboolean
958
gst_base_src_activate_push (GstPad * pad, gboolean active)
959
{
960 961
  GstBaseSrc *basesrc;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
962
  basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
963

964
  /* prepare subclass first */
965
  if (active) {
966
    if (!gst_base_src_start (basesrc))
967 968
      goto error_start;

969
    return gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
970
  } else {
971
    return gst_base_src_deactivate (basesrc, pad);
972 973
  }

974 975 976 977 978 979
error_start:
  {
    GST_DEBUG_OBJECT (basesrc, "failed to start");
    return FALSE;
  }
}
980

981
static gboolean
982
gst_base_src_activate_pull (GstPad * pad, gboolean active)
983 984
{
  GstBaseSrc *basesrc;
985

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
986
  basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
987 988 989

  /* prepare subclass first */
  if (active) {
990
    if (!gst_base_src_start (basesrc))
991 992 993
      goto error_start;

    if (!basesrc->seekable) {
994
      gst_base_src_stop (basesrc);
995 996 997 998 999
      return FALSE;
    }

    return TRUE;
  } else {
1000
    return gst_base_src_deactivate (basesrc, pad);
1001
  }
1002 1003 1004 1005 1006 1007

error_start:
  {
    GST_DEBUG_OBJECT (basesrc, "failed to start");
    return FALSE;
  }
1008 1009 1010
}

static GstElementStateReturn
1011
gst_base_src_change_state (GstElement * element)
1012 1013
{
  GstBaseSrc *basesrc;
1014 1015
  GstElementStateReturn result = GST_STATE_SUCCESS;
  GstElementStateReturn presult;
1016 1017
  GstElementState transition;

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1018
  basesrc = GST_BASE_SRC (element);
1019 1020 1021