summaryrefslogtreecommitdiff
path: root/gst/playondemand/filter.func
blob: 7c9f4de7598fc134f4f95257dace3d2257fa6e81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/* -*- C -*- */

_TYPE_ *data_in, *data_out, *filter_data;

filter_data = (_TYPE_ *) filter->buffer;
num_filter = filter->buffer_bytes / sizeof(_TYPE_);

do {
  if (in == NULL && ! filter->eos) in = gst_pad_pull(filter->sinkpad);

  /****************************************************************************/
  /* see if we've got any events coming through ... */

  while (! filter->eos && GST_IS_EVENT(in)) {
    if (GST_EVENT_TYPE(in) == GST_EVENT_EOS) {
      gst_event_unref(in);
      gst_buffer_free(in);
      filter->eos = TRUE;
    } else if ((GST_EVENT_TYPE(in) == GST_EVENT_SEEK) ||
               (GST_EVENT_TYPE(in) == GST_EVENT_FLUSH)) {
      gst_event_unref(in);
      gst_buffer_free(in);
      filter->eos = FALSE;
      filter->write = 0;
    } else {
      gst_pad_push(filter->srcpad, in);
    }

    in = gst_pad_pull(filter->sinkpad);
  }

  /****************************************************************************/
  /* handle data from the input buffer. */

  if (! filter->eos) {
    register guint j, w = filter->write;

    data_in = (_TYPE_ *) GST_BUFFER_DATA(in);
    num_in = GST_BUFFER_SIZE(in) / sizeof(_TYPE_);

    for (j = 0; (j < num_in) && (w+j < num_filter); j++)
      filter_data[w+j] = data_in[j];

    filter->write += j;

    if (filter->write >= num_filter) filter->eos = TRUE;

    out = in;
  } else {
    out = gst_buffer_new_from_pool(filter->bufpool, 0, 0);
  }

  in = NULL;

  /****************************************************************************/
  /* check to see if we have to add new play pointers. */

  if (filter->clock) {
    register gint t, tick_offset;

    guint total_ticks = filter->total_ticks;
    guint current_tick = \
      ((guint) (gst_clock_get_time(filter->clock) * filter->tick_rate /
                GST_SECOND)) % total_ticks;

    /* for some reason modulo arithmetic isn't working for me here, i suspect
       some unsigned/signed voodoo. but it's probably safe to do this with an if
       statement since it doesn't happen all that often ... */

    tick_offset = current_tick - last_tick;
    if (tick_offset < 0) tick_offset += total_ticks;

    for (tick_offset -= 1, t = current_tick - tick_offset;
         tick_offset >= 0;
         tick_offset--, t--) {

      if (t < 0) t += total_ticks;

      if (filter->ticks[t / 32] & (1 << t % 32))
        play_on_demand_add_play_pointer(
          filter, filter->rate * tick_offset / filter->tick_rate);
    }

    last_tick = current_tick;
  }

  /****************************************************************************/
  /* handle output data. */

  {
    register guint k, p;

    data_out = (_TYPE_ *) GST_BUFFER_DATA(out);
    num_out = GST_BUFFER_SIZE(out) / sizeof(_TYPE_);

    for (k = 0; k < num_out; k++) data_out[k] = zero;

    for (p = 0; p < filter->max_plays; p++) {
      guint offset = filter->plays[p];

      if (offset != G_MAXUINT) {

        /* only copy audio data if the element's not muted. */
        if (! filter->mute)
          for (k = 0; (k < num_out) && (offset+k < num_filter); k++)
            data_out[k] = CLAMP(data_out[k] + filter_data[offset+k], min, max);

        /* update the play pointer. k > 0 even if the filter is muted. */
        filter->plays[p] = (offset+k >= num_filter) ? G_MAXUINT : offset + k;
      }
    }
  }

  /****************************************************************************/
  /* push out the buffer. */

  gst_pad_push(filter->srcpad, out);

  if (gst_element_interrupt (GST_ELEMENT (filter))) break;

} while (TRUE);