gstpcapparse.c 17.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 * 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
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
16
17
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
18
19
20
21
22
 */

/**
 * 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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
};

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
83
static void gst_pcap_parse_finalize (GObject * object);
84
85
86
87
88
89
90
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
91
92
93
94
static GstFlowReturn gst_pcap_parse_chain (GstPad * pad,
    GstObject * parent, GstBuffer * buffer);
static gboolean gst_pcap_sink_event (GstPad * pad,
    GstObject * parent, GstEvent * event);
95

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

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

Wim Taymans's avatar
Wim Taymans committed
105
  gobject_class->finalize = gst_pcap_parse_finalize;
106
107
108
109
110
  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",
111
112
          "Source IP to restrict to", "",
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
113
114
115

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

  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,
122
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
123
124
125
126

  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,
127
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
128

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

134
135
  g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
      g_param_spec_int64 ("ts-offset", "Timestamp Offset",
136
137
138
          "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
139
140
141
142
143
  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));

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

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

static void
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
153
gst_pcap_parse_init (GstPcapParse * self)
154
155
156
157
158
{
  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);
159
160
  gst_pad_set_event_function (self->sink_pad,
      GST_DEBUG_FUNCPTR (gst_pcap_sink_event));
161
162
163
164
165
166
167
168
169
170
  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;
171
  self->offset = -1;
172
173
174
175
176
177
178

  self->adapter = gst_adapter_new ();

  gst_pcap_parse_reset (self);
}

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

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

Wim Taymans's avatar
Wim Taymans committed
187
  G_OBJECT_CLASS (parent_class)->finalize (object);
188
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
}

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
237
238
239
240
    case PROP_CAPS:
      gst_value_set_caps (value, self->caps);
      break;

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

245
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
    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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
    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;
    }
294

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

299
300
301
302
303
304
305
306
307
308
309
310
    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;
311
  self->cur_ts = GST_CLOCK_TIME_NONE;
312
  self->base_ts = GST_CLOCK_TIME_NONE;
313
  self->newsegment_sent = FALSE;
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334

  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
335
#define SLL_HEADER_LEN    16
336
337
338
339
#define IP_HEADER_MIN_LEN 20
#define UDP_HEADER_LEN     8

#define IP_PROTO_UDP      17
340
341
#define IP_PROTO_TCP      6

342
343
344
345
346
347

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

360
  switch (self->linktype) {
361
    case LINKTYPE_ETHER:
362
363
      if (buf_size < ETH_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
        return FALSE;
364

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

Felipe Contreras's avatar
Felipe Contreras committed
372
      eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + 14)));
373
374
      buf_ip = buf + SLL_HEADER_LEN;
      break;
375
376
377
378
379
380
381
382
    case LINKTYPE_RAW:
      if (buf_size < IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
        return FALSE;

      eth_type = 0x800;         /* This is fine since IPv4/IPv6 is parse elsewhere */
      buf_ip = buf;
      break;

383
384
    default:
      return FALSE;
385
  }
386

Felipe Contreras's avatar
Felipe Contreras committed
387
388
389
  if (eth_type != 0x800)
    return FALSE;

390
391
392
393
394
395
396
397
398
  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);
399
  GST_LOG_OBJECT (self, "ip proto %d", (gint) ip_protocol);
400

401
  if (ip_protocol != IP_PROTO_UDP && ip_protocol != IP_PROTO_TCP)
402
403
    return FALSE;

404
405
  /* ip info */
  ip_src_addr = *((guint32 *) (buf_ip + 12));
406
  ip_dst_addr = *((guint32 *) (buf_ip + 16));
407
  buf_proto = buf_ip + ip_header_size;
408

409
410
411
  /* ok for tcp and udp */
  src_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 0)));
  dst_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 2)));
412

413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  /* 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)
435
436
    return FALSE;

437
  if (self->dst_ip >= 0 && ip_dst_addr != self->dst_ip)
438
439
    return FALSE;

440
  if (self->src_port >= 0 && src_port != self->src_port)
441
442
    return FALSE;

443
444
  if (self->dst_port >= 0 && dst_port != self->dst_port)
    return FALSE;
445
446
447
448
449

  return TRUE;
}

static GstFlowReturn
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
450
gst_pcap_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
451
{
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
452
  GstPcapParse *self = GST_PCAP_PARSE (parent);
453
  GstFlowReturn ret = GST_FLOW_OK;
454
  GstBufferList *list = NULL;
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

  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
473
          data = gst_adapter_map (self->adapter, self->cur_packet_size);
474

475
          GST_LOG_OBJECT (self, "examining packet size %" G_GINT64_FORMAT,
476
477
              self->cur_packet_size);

478
479
480
          if (gst_pcap_parse_scan_frame (self, data, self->cur_packet_size,
                  &payload_data, &payload_size)) {
            GstBuffer *out_buf;
481
482
483
484
485
486
            guintptr offset = payload_data - data;

            gst_adapter_unmap (self->adapter);
            gst_adapter_flush (self->adapter, offset);
            out_buf = gst_adapter_take_buffer_fast (self->adapter,
                payload_size);
487
488
            gst_adapter_flush (self->adapter,
                self->cur_packet_size - offset - payload_size);
489
490
491
492
493
494
495

            if (GST_CLOCK_TIME_IS_VALID (self->cur_ts)) {
              if (!GST_CLOCK_TIME_IS_VALID (self->base_ts))
                self->base_ts = self->cur_ts;
              if (self->offset >= 0) {
                self->cur_ts -= self->base_ts;
                self->cur_ts += self->offset;
496
              }
497
498
            }
            GST_BUFFER_TIMESTAMP (out_buf) = self->cur_ts;
499

500

501
502
503
504
505
506
            if (list == NULL)
              list = gst_buffer_list_new ();
            gst_buffer_list_add (list, out_buf);
          } else {
            gst_adapter_unmap (self->adapter);
            gst_adapter_flush (self->adapter, self->cur_packet_size);
507
508
509
510
511
512
513
514
515
516
517
518
          }
        }

        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
519
        data = gst_adapter_map (self->adapter, 16);
520
521
522
523

        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);
524
        /* orig_len = gst_pcap_parse_read_uint32 (self, data + 12); */
525

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
526
        gst_adapter_unmap (self->adapter);
527
528
        gst_adapter_flush (self->adapter, 16);

529
        self->cur_ts = ts_sec * GST_SECOND + ts_usec * GST_USECOND;
530
531
532
        self->cur_packet_size = incl_len;
      }
    } else {
533
534
535
      guint32 magic;
      guint32 linktype;
      guint16 major_version;
536
537
538
539

      if (avail < 24)
        break;

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
540
      data = gst_adapter_map (self->adapter, 24);
541
542

      magic = *((guint32 *) data);
543
      major_version = *((guint16 *) (data + 4));
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
544
545
      linktype = gst_pcap_parse_read_uint32 (self, data + 20);
      gst_adapter_unmap (self->adapter);
546

547
      if (magic == 0xa1b2c3d4) {
548
        self->swap_endian = FALSE;
549
      } else if (magic == 0xd4c3b2a1) {
550
        self->swap_endian = TRUE;
551
552
553
554
555
556
557
558
559
        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) {
560
        GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
561
            ("File is not a libpcap major version 2, but %u", major_version));
562
        ret = GST_FLOW_ERROR;
563
        goto out;
564
      }
565

566
567
      if (linktype != LINKTYPE_ETHER && linktype != LINKTYPE_SLL &&
          linktype != LINKTYPE_RAW) {
568
        GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
569
570
            ("Only dumps of type Ethernet, raw IP or Linux Cooked (SLL) "
                "understood; type %d unknown", linktype));
571
572
573
574
        ret = GST_FLOW_ERROR;
        goto out;
      }

575
      GST_DEBUG_OBJECT (self, "linktype %u", linktype);
576
577
      self->linktype = linktype;

578
579
      gst_adapter_flush (self->adapter, 24);
      self->initialized = TRUE;
580
581
582
    }
  }

583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
  if (list) {
    if (!self->newsegment_sent && GST_CLOCK_TIME_IS_VALID (self->cur_ts)) {
      GstSegment segment;

      if (self->caps)
        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));
      self->newsegment_sent = TRUE;
    }

    ret = gst_pad_push_list (self->src_pad, list);
    list = NULL;
  }

599
out:
600
601
602
603

  if (list)
    gst_buffer_list_unref (list);

604
605
606
607
608
609
  if (ret != GST_FLOW_OK)
    gst_pcap_parse_reset (self);

  return ret;
}

610
static gboolean
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
611
gst_pcap_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
612
613
{
  gboolean ret = TRUE;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
614
  GstPcapParse *self = GST_PCAP_PARSE (parent);
615
616

  switch (GST_EVENT_TYPE (event)) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
617
    case GST_EVENT_SEGMENT:
618
      /* Drop it, we'll replace it with our own */
Wim Taymans's avatar
Wim Taymans committed
619
      gst_event_unref (event);
620
621
622
      break;
    default:
      ret = gst_pad_push_event (self->src_pad, event);
Wim Taymans's avatar
Wim Taymans committed
623
      break;
624
625
626
627
  }

  return ret;
}