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,
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
    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;
312
  self->cur_ts = GST_CLOCK_TIME_NONE;
313
  self->base_ts = GST_CLOCK_TIME_NONE;
314
  self->newsegment_sent = FALSE;
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335

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

#define IP_PROTO_UDP      17
341
342
#define IP_PROTO_TCP      6

343
344
345
346
347
348

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

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

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

Felipe Contreras's avatar
Felipe Contreras committed
373
      eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + 14)));
374
375
      buf_ip = buf + SLL_HEADER_LEN;
      break;
376
377
378
379
380
381
382
383
    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;

384
385
    default:
      return FALSE;
386
  }
387

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

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

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

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

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

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

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

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

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

  return TRUE;
}

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

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

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

479
480
481
          if (gst_pcap_parse_scan_frame (self, data, self->cur_packet_size,
                  &payload_data, &payload_size)) {
            GstBuffer *out_buf;
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
            guintptr offset = payload_data - data;

            self->cur_packet_size -= offset;
            self->cur_packet_size -= payload_size;

            gst_adapter_unmap (self->adapter);
            gst_adapter_flush (self->adapter, offset);
            out_buf = gst_adapter_take_buffer_fast (self->adapter,
                payload_size);

            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;
498
              }
499
500
            }
            GST_BUFFER_TIMESTAMP (out_buf) = self->cur_ts;
501

502

503
504
505
506
507
508
            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);
509
510
511
512
513
514
515
516
517
518
519
520
          }
        }

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

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

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

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

      if (avail < 24)
        break;

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

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

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

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

577
      GST_DEBUG_OBJECT (self, "linktype %u", linktype);
578
579
      self->linktype = linktype;

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

585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
  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;
  }

601
out:
602
603
604
605

  if (list)
    gst_buffer_list_unref (list);

606
607
608
609
610
611
  if (ret != GST_FLOW_OK)
    gst_pcap_parse_reset (self);

  return ret;
}

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

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

  return ret;
}