gstpcapparse.c 16.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Copyright 2007 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
 *
 * 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.
 */

/**
 * SECTION:element-pcapparse
 *
23
24
 * Extracts payloads from Ethernet-encapsulated IP packets.
 * Use #GstPcapParse:src-ip, #GstPcapParse:dst-ip,
25
26
27
 * #GstPcapParse:src-port and #GstPcapParse:dst-port to restrict which packets
 * should be included.
 *
28
 * <refsect2>
29
30
31
32
33
34
 * <title>Example pipelines</title>
 * |[
 * gst-launch-0.10 filesrc location=h264crasher.pcap ! pcapparse ! rtph264depay
 * ! ffdec_h264 ! fakesink
 * ]| Read from a pcap dump file using filesrc, extract the raw UDP packets,
 * depayload and decode them.
35
36
37
38
39
40
41
42
43
 * </refsect2>
 */

/* TODO:
 * - React on state-change and update state accordingly.
 * - Implement support for timestamping the buffers.
 */

#ifdef HAVE_CONFIG_H
44
#include <config.h>
45
46
#endif

47
48
#include "gstpcapparse.h"

49
50
#include <string.h>

51
#ifndef G_OS_WIN32
52
53
#include <arpa/inet.h>
#include <netinet/in.h>
54
#include <string.h>
55
56
57
58
59
60
61
62
63
64
65
#else
#include <winsock2.h>
#endif

enum
{
  PROP_0,
  PROP_SRC_IP,
  PROP_DST_IP,
  PROP_SRC_PORT,
  PROP_DST_PORT,
Wim Taymans's avatar
Wim Taymans committed
66
  PROP_CAPS,
67
  PROP_TS_OFFSET,
Wim Taymans's avatar
Wim Taymans committed
68
  PROP_LAST
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
};

GST_DEBUG_CATEGORY_STATIC (gst_pcap_parse_debug);
#define GST_CAT_DEFAULT gst_pcap_parse_debug

static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("raw/x-pcap"));

static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS_ANY);

Wim Taymans's avatar
Wim Taymans committed
84
static void gst_pcap_parse_finalize (GObject * object);
85
86
87
88
89
90
91
static void gst_pcap_parse_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
static void gst_pcap_parse_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);

static void gst_pcap_parse_reset (GstPcapParse * self);

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
92
93
94
95
static GstFlowReturn gst_pcap_parse_chain (GstPad * pad,
    GstObject * parent, GstBuffer * buffer);
static gboolean gst_pcap_sink_event (GstPad * pad,
    GstObject * parent, GstEvent * event);
96

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
97
98
#define parent_class gst_pcap_parse_parent_class
G_DEFINE_TYPE (GstPcapParse, gst_pcap_parse, GST_TYPE_ELEMENT);
99
100
101
102
103

static void
gst_pcap_parse_class_init (GstPcapParseClass * klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
104
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
105

Wim Taymans's avatar
Wim Taymans committed
106
  gobject_class->finalize = gst_pcap_parse_finalize;
107
108
109
110
111
  gobject_class->get_property = gst_pcap_parse_get_property;
  gobject_class->set_property = gst_pcap_parse_set_property;

  g_object_class_install_property (gobject_class,
      PROP_SRC_IP, g_param_spec_string ("src-ip", "Source IP",
112
113
          "Source IP to restrict to", "",
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114
115
116

  g_object_class_install_property (gobject_class,
      PROP_DST_IP, g_param_spec_string ("dst-ip", "Destination IP",
117
118
          "Destination IP to restrict to", "",
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
119
120
121
122

  g_object_class_install_property (gobject_class,
      PROP_SRC_PORT, g_param_spec_int ("src-port", "Source port",
          "Source port to restrict to", -1, G_MAXUINT16, -1,
123
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
124
125
126
127

  g_object_class_install_property (gobject_class,
      PROP_DST_PORT, g_param_spec_int ("dst-port", "Destination port",
          "Destination port to restrict to", -1, G_MAXUINT16, -1,
128
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129

Wim Taymans's avatar
Wim Taymans committed
130
131
  g_object_class_install_property (gobject_class, PROP_CAPS,
      g_param_spec_boxed ("caps", "Caps",
132
133
          "The caps of the source pad", GST_TYPE_CAPS,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
134

135
136
  g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
      g_param_spec_int64 ("ts-offset", "Timestamp Offset",
137
138
139
          "Relative timestamp offset (ns) to apply (-1 = use absolute packet time)",
          -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
140
141
142
143
144
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&sink_template));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&src_template));

145
  gst_element_class_set_static_metadata (element_class, "PCapParse",
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
146
147
148
149
      "Raw/Parser",
      "Parses a raw pcap stream",
      "Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>");

150
151
152
153
  GST_DEBUG_CATEGORY_INIT (gst_pcap_parse_debug, "pcapparse", 0, "pcap parser");
}

static void
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
154
gst_pcap_parse_init (GstPcapParse * self)
155
156
157
158
159
{
  self->sink_pad = gst_pad_new_from_static_template (&sink_template, "sink");
  gst_pad_set_chain_function (self->sink_pad,
      GST_DEBUG_FUNCPTR (gst_pcap_parse_chain));
  gst_pad_use_fixed_caps (self->sink_pad);
160
161
  gst_pad_set_event_function (self->sink_pad,
      GST_DEBUG_FUNCPTR (gst_pcap_sink_event));
162
163
164
165
166
167
168
169
170
171
  gst_element_add_pad (GST_ELEMENT (self), self->sink_pad);

  self->src_pad = gst_pad_new_from_static_template (&src_template, "src");
  gst_pad_use_fixed_caps (self->src_pad);
  gst_element_add_pad (GST_ELEMENT (self), self->src_pad);

  self->src_ip = -1;
  self->dst_ip = -1;
  self->src_port = -1;
  self->dst_port = -1;
172
  self->offset = -1;
173
174
175
176
177
178
179

  self->adapter = gst_adapter_new ();

  gst_pcap_parse_reset (self);
}

static void
Wim Taymans's avatar
Wim Taymans committed
180
gst_pcap_parse_finalize (GObject * object)
181
182
183
184
{
  GstPcapParse *self = GST_PCAP_PARSE (object);

  g_object_unref (self->adapter);
Wim Taymans's avatar
Wim Taymans committed
185
186
  if (self->caps)
    gst_caps_unref (self->caps);
187

Wim Taymans's avatar
Wim Taymans committed
188
  G_OBJECT_CLASS (parent_class)->finalize (object);
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
}

static const gchar *
get_ip_address_as_string (gint64 ip_addr)
{
  if (ip_addr >= 0) {
    struct in_addr addr;
    addr.s_addr = ip_addr;
    return inet_ntoa (addr);
  } else {
    return "";
  }
}

static void
set_ip_address_from_string (gint64 * ip_addr, const gchar * ip_str)
{
  if (ip_str[0] != '\0') {
    gulong addr = inet_addr (ip_str);
    if (addr != INADDR_NONE)
      *ip_addr = addr;
  } else {
    *ip_addr = -1;
  }
}

static void
gst_pcap_parse_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstPcapParse *self = GST_PCAP_PARSE (object);

  switch (prop_id) {
    case PROP_SRC_IP:
      g_value_set_string (value, get_ip_address_as_string (self->src_ip));
      break;

    case PROP_DST_IP:
      g_value_set_string (value, get_ip_address_as_string (self->dst_ip));
      break;

    case PROP_SRC_PORT:
      g_value_set_int (value, self->src_port);
      break;

    case PROP_DST_PORT:
      g_value_set_int (value, self->dst_port);
      break;

Wim Taymans's avatar
Wim Taymans committed
238
239
240
241
    case PROP_CAPS:
      gst_value_set_caps (value, self->caps);
      break;

242
    case PROP_TS_OFFSET:
243
244
245
      g_value_set_int64 (value, self->offset);
      break;

246
247
248
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
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_pcap_parse_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstPcapParse *self = GST_PCAP_PARSE (object);

  switch (prop_id) {
    case PROP_SRC_IP:
      set_ip_address_from_string (&self->src_ip, g_value_get_string (value));
      break;

    case PROP_DST_IP:
      set_ip_address_from_string (&self->dst_ip, g_value_get_string (value));
      break;

    case PROP_SRC_PORT:
      self->src_port = g_value_get_int (value);
      break;

    case PROP_DST_PORT:
      self->dst_port = g_value_get_int (value);
      break;

Wim Taymans's avatar
Wim Taymans committed
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
    case PROP_CAPS:
    {
      const GstCaps *new_caps_val;
      GstCaps *new_caps, *old_caps;

      new_caps_val = gst_value_get_caps (value);
      if (new_caps_val == NULL) {
        new_caps = gst_caps_new_any ();
      } else {
        new_caps = gst_caps_copy (new_caps_val);
      }

      old_caps = self->caps;
      self->caps = new_caps;
      if (old_caps)
        gst_caps_unref (old_caps);

      gst_pad_set_caps (self->src_pad, new_caps);
      break;
    }
295

296
    case PROP_TS_OFFSET:
297
298
299
      self->offset = g_value_get_int64 (value);
      break;

300
301
302
303
304
305
306
307
308
309
310
311
312
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_pcap_parse_reset (GstPcapParse * self)
{
  self->initialized = FALSE;
  self->swap_endian = FALSE;
  self->cur_packet_size = -1;
  self->buffer_offset = 0;
313
  self->cur_ts = GST_CLOCK_TIME_NONE;
314
  self->base_ts = GST_CLOCK_TIME_NONE;
315
  self->newsegment_sent = FALSE;
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

  gst_adapter_clear (self->adapter);
}

static guint32
gst_pcap_parse_read_uint32 (GstPcapParse * self, const guint8 * p)
{
  guint32 val = *((guint32 *) p);

  if (self->swap_endian) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
    return GUINT32_FROM_BE (val);
#else
    return GUINT32_FROM_LE (val);
#endif
  } else {
    return val;
  }
}

#define ETH_HEADER_LEN    14
337
#define SLL_HEADER_LEN    16
338
339
340
341
#define IP_HEADER_MIN_LEN 20
#define UDP_HEADER_LEN     8

#define IP_PROTO_UDP      17
342
343
#define IP_PROTO_TCP      6

344
345
346
347
348
349

static gboolean
gst_pcap_parse_scan_frame (GstPcapParse * self,
    const guint8 * buf,
    gint buf_size, const guint8 ** payload, gint * payload_size)
{
350
  const guint8 *buf_ip = 0;
351
  const guint8 *buf_proto;
352
353
354
355
356
357
  guint16 eth_type;
  guint8 b;
  guint8 ip_header_size;
  guint8 ip_protocol;
  guint32 ip_src_addr;
  guint32 ip_dst_addr;
358
359
360
  guint16 src_port;
  guint16 dst_port;
  guint16 len;
361

362
363
364
365
  switch (self->linktype) {
    case DLT_ETHER:
      if (buf_size < ETH_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
        return FALSE;
366

367
368
369
370
371
372
373
      eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + 12)));
      buf_ip = buf + ETH_HEADER_LEN;
      break;
    case DLT_SLL:
      if (buf_size < SLL_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
        return FALSE;

Felipe Contreras's avatar
Felipe Contreras committed
374
      eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + 14)));
375
376
      buf_ip = buf + SLL_HEADER_LEN;
      break;
377
378
    default:
      return FALSE;
379
  }
380

Felipe Contreras's avatar
Felipe Contreras committed
381
382
383
  if (eth_type != 0x800)
    return FALSE;

384
385
386
387
388
389
390
391
392
  b = *buf_ip;
  if (((b >> 4) & 0x0f) != 4)
    return FALSE;

  ip_header_size = (b & 0x0f) * 4;
  if (buf_ip + ip_header_size > buf + buf_size)
    return FALSE;

  ip_protocol = *(buf_ip + 9);
393
  GST_LOG_OBJECT (self, "ip proto %d", (gint) ip_protocol);
394

395
  if (ip_protocol != IP_PROTO_UDP && ip_protocol != IP_PROTO_TCP)
396
397
    return FALSE;

398
399
  /* ip info */
  ip_src_addr = *((guint32 *) (buf_ip + 12));
400
  ip_dst_addr = *((guint32 *) (buf_ip + 16));
401
  buf_proto = buf_ip + ip_header_size;
402

403
404
405
  /* ok for tcp and udp */
  src_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 0)));
  dst_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 2)));
406

407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  /* extract some params and data according to protocol */
  if (ip_protocol == IP_PROTO_UDP) {
    len = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 4)));
    if (len < UDP_HEADER_LEN || buf_proto + len > buf + buf_size)
      return FALSE;

    *payload = buf_proto + UDP_HEADER_LEN;
    *payload_size = len - UDP_HEADER_LEN;
  } else {
    if (buf_proto + 12 >= buf + buf_size)
      return FALSE;
    len = (buf_proto[12] >> 4) * 4;
    if (buf_proto + len > buf + buf_size)
      return FALSE;

    /* all remaining data following tcp header is payload */
    *payload = buf_proto + len;
    *payload_size = self->cur_packet_size - (buf_proto - buf) - len;
  }

  /* but still filter as configured */
  if (self->src_ip >= 0 && ip_src_addr != self->src_ip)
429
430
    return FALSE;

431
  if (self->dst_ip >= 0 && ip_dst_addr != self->dst_ip)
432
433
    return FALSE;

434
  if (self->src_port >= 0 && src_port != self->src_port)
435
436
    return FALSE;

437
438
  if (self->dst_port >= 0 && dst_port != self->dst_port)
    return FALSE;
439
440
441
442
443

  return TRUE;
}

static GstFlowReturn
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
444
gst_pcap_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
445
{
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
446
  GstPcapParse *self = GST_PCAP_PARSE (parent);
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  GstFlowReturn ret = GST_FLOW_OK;

  gst_adapter_push (self->adapter, buffer);

  while (ret == GST_FLOW_OK) {
    gint avail;
    const guint8 *data;

    avail = gst_adapter_available (self->adapter);

    if (self->initialized) {
      if (self->cur_packet_size >= 0) {
        if (avail < self->cur_packet_size)
          break;

        if (self->cur_packet_size > 0) {
          const guint8 *payload_data;
          gint payload_size;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
466
          data = gst_adapter_map (self->adapter, self->cur_packet_size);
467

468
          GST_LOG_OBJECT (self, "examining packet size %" G_GINT64_FORMAT,
469
470
              self->cur_packet_size);

471
472
473
          if (gst_pcap_parse_scan_frame (self, data, self->cur_packet_size,
                  &payload_data, &payload_size)) {
            GstBuffer *out_buf;
474
            GstMapInfo map;
475

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
476
477
            out_buf = gst_buffer_new_and_alloc (payload_size);
            if (out_buf) {
478

479
480
481
              if (GST_CLOCK_TIME_IS_VALID (self->cur_ts)) {
                if (!GST_CLOCK_TIME_IS_VALID (self->base_ts))
                  self->base_ts = self->cur_ts;
482
483
484
485
                if (self->offset >= 0) {
                  self->cur_ts -= self->base_ts;
                  self->cur_ts += self->offset;
                }
486
487
              }

488
489
490
              gst_buffer_map (out_buf, &map, GST_MAP_WRITE);
              memcpy (map.data, payload_data, payload_size);
              gst_buffer_unmap (out_buf, &map);
491
492
493
494
              GST_BUFFER_TIMESTAMP (out_buf) = self->cur_ts;

              if (!self->newsegment_sent &&
                  GST_CLOCK_TIME_IS_VALID (self->cur_ts)) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
495
496
497
498
499
500
501
                GstSegment segment;

                gst_pad_set_caps (self->src_pad, self->caps);
                gst_segment_init (&segment, GST_FORMAT_TIME);
                segment.start = self->cur_ts;
                gst_pad_push_event (self->src_pad,
                    gst_event_new_segment (&segment));
502
503
                self->newsegment_sent = TRUE;
              }
504
505
506
507
508
509
510

              ret = gst_pad_push (self->src_pad, out_buf);

              self->buffer_offset += payload_size;
            }
          }

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
511
          gst_adapter_unmap (self->adapter);
512
513
514
515
516
517
518
519
520
521
522
523
          gst_adapter_flush (self->adapter, self->cur_packet_size);
        }

        self->cur_packet_size = -1;
      } else {
        guint32 ts_sec;
        guint32 ts_usec;
        guint32 incl_len;

        if (avail < 16)
          break;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
524
        data = gst_adapter_map (self->adapter, 16);
525
526
527
528

        ts_sec = gst_pcap_parse_read_uint32 (self, data + 0);
        ts_usec = gst_pcap_parse_read_uint32 (self, data + 4);
        incl_len = gst_pcap_parse_read_uint32 (self, data + 8);
529
        /* orig_len = gst_pcap_parse_read_uint32 (self, data + 12); */
530

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
531
        gst_adapter_unmap (self->adapter);
532
533
        gst_adapter_flush (self->adapter, 16);

534
        self->cur_ts = ts_sec * GST_SECOND + ts_usec * GST_USECOND;
535
536
537
        self->cur_packet_size = incl_len;
      }
    } else {
538
539
540
      guint32 magic;
      guint32 linktype;
      guint16 major_version;
541
542
543
544

      if (avail < 24)
        break;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
545
      data = gst_adapter_map (self->adapter, 24);
546
547

      magic = *((guint32 *) data);
548
      major_version = *((guint16 *) (data + 4));
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
549
550
      linktype = gst_pcap_parse_read_uint32 (self, data + 20);
      gst_adapter_unmap (self->adapter);
551

552
      if (magic == 0xa1b2c3d4) {
553
        self->swap_endian = FALSE;
554
      } else if (magic == 0xd4c3b2a1) {
555
        self->swap_endian = TRUE;
556
557
558
559
560
561
562
563
564
        major_version = major_version << 8 | major_version >> 8;
      } else {
        GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
            ("File is not a libpcap file, magic is %X", magic));
        ret = GST_FLOW_ERROR;
        goto out;
      }

      if (major_version != 2) {
565
        GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
566
            ("File is not a libpcap major version 2, but %u", major_version));
567
        ret = GST_FLOW_ERROR;
568
        goto out;
569
      }
570

571
      if (linktype != DLT_ETHER && linktype != DLT_SLL) {
572
        GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
573
            ("Only dumps of type Ethernet or Linux Coooked (SLL) understood,"
574
575
576
577
578
                " type %d unknown", linktype));
        ret = GST_FLOW_ERROR;
        goto out;
      }

579
      GST_DEBUG_OBJECT (self, "linktype %u", linktype);
580
581
      self->linktype = linktype;

582
583
      gst_adapter_flush (self->adapter, 24);
      self->initialized = TRUE;
584
585
586
    }
  }

587
out:
588
589
590
591
592
593
  if (ret != GST_FLOW_OK)
    gst_pcap_parse_reset (self);

  return ret;
}

594
static gboolean
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
595
gst_pcap_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
596
597
{
  gboolean ret = TRUE;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
598
  GstPcapParse *self = GST_PCAP_PARSE (parent);
599
600

  switch (GST_EVENT_TYPE (event)) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
601
    case GST_EVENT_SEGMENT:
602
      /* Drop it, we'll replace it with our own */
Wim Taymans's avatar
Wim Taymans committed
603
      gst_event_unref (event);
604
605
606
      break;
    default:
      ret = gst_pad_push_event (self->src_pad, event);
Wim Taymans's avatar
Wim Taymans committed
607
      break;
608
609
610
611
612
613
  }

  gst_object_unref (self);

  return ret;
}