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

/**
 * SECTION:element-pcapparse
22
 * @title: pcapparse
23
 *
24
25
 * Extracts payloads from Ethernet-encapsulated IP packets.
 * Use #GstPcapParse:src-ip, #GstPcapParse:dst-ip,
26
27
28
 * #GstPcapParse:src-port and #GstPcapParse:dst-port to restrict which packets
 * should be included.
 *
29
 * ## Example pipelines
30
 * |[
31
 * gst-launch-1.0 filesrc location=h264crasher.pcap ! pcapparse ! rtph264depay
32
33
34
 * ! 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
 */

/* 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));

141
142
  gst_element_class_add_static_pad_template (element_class, &sink_template);
  gst_element_class_add_static_pad_template (element_class, &src_template);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
143

144
145
  element_class->change_state = gst_pcap_parse_change_state;

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

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

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

  self->adapter = gst_adapter_new ();

  gst_pcap_parse_reset (self);
}

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

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

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

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

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

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

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

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;
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
  switch (self->linktype) {
363
    case LINKTYPE_ETHER:
364
365
      if (buf_size < ETH_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
        return FALSE;
366

367
368
369
      eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + 12)));
      buf_ip = buf + ETH_HEADER_LEN;
      break;
370
    case LINKTYPE_SLL:
371
372
373
      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
379
380
381
382
383
384
    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;

385
386
    default:
      return FALSE;
387
  }
388

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

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

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

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

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

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

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

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

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

  return TRUE;
}

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

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

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

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

            gst_adapter_unmap (self->adapter);
            gst_adapter_flush (self->adapter, offset);
487
488
489
490
            /* 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() */
491
492
493
494
495
            if (payload_size > 0) {
              out_buf = gst_adapter_take_buffer (self->adapter, payload_size);
            } else {
              out_buf = gst_buffer_new ();
            }
496
497
            gst_adapter_flush (self->adapter,
                self->cur_packet_size - offset - payload_size);
498
499
500
501
502
503
504

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

509

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

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

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

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

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

      if (avail < 24)
        break;

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

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

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

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

584
      GST_DEBUG_OBJECT (self, "linktype %u", linktype);
585
586
      self->linktype = linktype;

587
588
      gst_adapter_flush (self->adapter, 24);
      self->initialized = TRUE;
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);
599
      segment.start = self->base_ts;
600
601
602
603
604
605
606
607
      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;
  }

608
out:
609
610
611
612

  if (list)
    gst_buffer_list_unref (list);

613
614
615
  return ret;
}

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

  switch (GST_EVENT_TYPE (event)) {
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
623
    case GST_EVENT_SEGMENT:
624
      /* Drop it, we'll replace it with our own */
Wim Taymans's avatar
Wim Taymans committed
625
      gst_event_unref (event);
626
      break;
627
628
    case GST_EVENT_FLUSH_STOP:
      gst_pcap_parse_reset (self);
629
630
      /* Push event down the pipeline so that other elements stop flushing */
      /* fall through */
631
632
    default:
      ret = gst_pad_push_event (self->src_pad, event);
Wim Taymans's avatar
Wim Taymans committed
633
      break;
634
635
  }

636
637
638
639
640
641
642
643
644
645
646
647
648
  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:
649
      gst_pcap_parse_reset (self);
650
651
652
653
654
655
      break;
    default:
      break;
  }


656
657
  return ret;
}