gstpcapparse.c 18 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
 * </refsect2>
 */

/* TODO:
 * - Implement support for timestamping the buffers.
 */

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

46
47
#include "gstpcapparse.h"

48
49
#include <string.h>

50
#ifndef G_OS_WIN32
51
52
#include <arpa/inet.h>
#include <netinet/in.h>
53
#include <string.h>
54
55
56
57
58
59
60
61
62
63
64
#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
65
  PROP_CAPS,
66
  PROP_TS_OFFSET
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
};

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
82
static void gst_pcap_parse_finalize (GObject * object);
83
84
85
86
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);
87
88
static GstStateChangeReturn
gst_pcap_parse_change_state (GstElement * element, GstStateChange transition);
89
90
91

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

97

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

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

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

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

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

  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,
129
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
130

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

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

146
147
  element_class->change_state = gst_pcap_parse_change_state;

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

153
154
155
156
  GST_DEBUG_CATEGORY_INIT (gst_pcap_parse_debug, "pcapparse", 0, "pcap parser");
}

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

  self->adapter = gst_adapter_new ();

  gst_pcap_parse_reset (self);
}

static void
Wim Taymans's avatar
Wim Taymans committed
183
gst_pcap_parse_finalize (GObject * object)
184
185
186
187
{
  GstPcapParse *self = GST_PCAP_PARSE (object);

  g_object_unref (self->adapter);
Wim Taymans's avatar
Wim Taymans committed
188
189
  if (self->caps)
    gst_caps_unref (self->caps);
190

Wim Taymans's avatar
Wim Taymans committed
191
  G_OBJECT_CLASS (parent_class)->finalize (object);
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
238
239
240
}

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
241
242
243
244
    case PROP_CAPS:
      gst_value_set_caps (value, self->caps);
      break;

245
    case PROP_TS_OFFSET:
246
247
248
      g_value_set_int64 (value, self->offset);
      break;

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
    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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
    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;
    }
298

299
    case PROP_TS_OFFSET:
300
301
302
      self->offset = g_value_get_int64 (value);
      break;

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

  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
339
#define SLL_HEADER_LEN    16
340
341
342
343
#define IP_HEADER_MIN_LEN 20
#define UDP_HEADER_LEN     8

#define IP_PROTO_UDP      17
344
345
#define IP_PROTO_TCP      6

346
347
348
349
350
351

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

364
  switch (self->linktype) {
365
    case LINKTYPE_ETHER:
366
367
      if (buf_size < ETH_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
        return FALSE;
368

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

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

387
388
    default:
      return FALSE;
389
  }
390

Felipe Contreras's avatar
Felipe Contreras committed
391
392
393
  if (eth_type != 0x800)
    return FALSE;

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

405
  if (ip_protocol != IP_PROTO_UDP && ip_protocol != IP_PROTO_TCP)
406
407
    return FALSE;

408
409
  /* ip info */
  ip_src_addr = *((guint32 *) (buf_ip + 12));
410
  ip_dst_addr = *((guint32 *) (buf_ip + 16));
411
  buf_proto = buf_ip + ip_header_size;
412

413
414
415
  /* ok for tcp and udp */
  src_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 0)));
  dst_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 2)));
416

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

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

444
  if (self->src_port >= 0 && src_port != self->src_port)
445
446
    return FALSE;

447
448
  if (self->dst_port >= 0 && dst_port != self->dst_port)
    return FALSE;
449
450
451
452
453

  return TRUE;
}

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

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

479
          GST_LOG_OBJECT (self, "examining packet size %" G_GINT64_FORMAT,
480
481
              self->cur_packet_size);

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

            gst_adapter_unmap (self->adapter);
            gst_adapter_flush (self->adapter, offset);
489
490
491
492
493
            /* we don't use _take_buffer_fast() on purpose here, we need a
             * buffer with a single memory, since the RTP depayloaders expect
             * the complete RTP header to be in the first memory if there are
             * multiple ones and we can't guarantee that with _fast() */
            out_buf = gst_adapter_take_buffer (self->adapter, payload_size);
494
495
            gst_adapter_flush (self->adapter,
                self->cur_packet_size - offset - payload_size);
496
497
498
499
500
501
502

            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;
503
              }
504
505
            }
            GST_BUFFER_TIMESTAMP (out_buf) = self->cur_ts;
506

507

508
509
510
511
512
513
            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);
514
515
516
517
518
519
520
521
522
523
524
525
          }
        }

        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
526
        data = gst_adapter_map (self->adapter, 16);
527
528
529
530

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

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

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

      if (avail < 24)
        break;

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

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

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

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

582
      GST_DEBUG_OBJECT (self, "linktype %u", linktype);
583
584
      self->linktype = linktype;

585
586
      gst_adapter_flush (self->adapter, 24);
      self->initialized = TRUE;
587
588
589
    }
  }

590
591
592
593
594
595
596
  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);
597
      segment.start = self->base_ts;
598
599
600
601
602
603
604
605
      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;
  }

606
out:
607
608
609
610

  if (list)
    gst_buffer_list_unref (list);

611
612
613
  return ret;
}

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

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

633
634
635
636
637
638
639
640
641
642
643
644
645
  return ret;
}

static GstStateChangeReturn
gst_pcap_parse_change_state (GstElement * element, GstStateChange transition)
{
  GstPcapParse *self = GST_PCAP_PARSE (element);
  GstStateChangeReturn ret;

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
646
      gst_pcap_parse_reset (self);
647
648
649
650
651
652
      break;
    default:
      break;
  }


653
654
  return ret;
}