1 /*
2 * squeakAudioVideoPipeLineSignalInterface.c
3 * GStreamer
4 *
5 * Created by John M McIntosh on 3/29/08.
6 * Copyright 2008 Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.con All rights reserved.
7 * Written for Viewpoints Research Institute http://www.vpri.org/
8 * http://www.opensource.org/licenses/mit-license.php
9 *
10 */
11
12 #include <gst/gst.h>
13 #include <gst/gstobject.h>
14 #include <string.h>
15 #include "squeakAudioVideoPipeLineSignalInterface.h"
16 #include "sqVirtualMachine.h"
17
18
19 void gst_SqueakVideoSink_set_caps (SqueakAudioVideoSinkPtr sink, GstCaps * caps);
20 void gst_SqueakAudioSink_sink_write(GstElement* plugin, SqueakAudioVideoSinkPtr sink, gpointer data, guint length, GstClockTime duration);
21
22
23 /* Element Signals:
24 "handoff" : void user_function (GstElement* object,
25 GstBuffer* arg0,
26 GstPad* arg1,
27 gpointer user_data);
28 "preroll-handoff" : void user_function (GstElement* object,
29 GstBuffer* arg0,
30 GstPad* arg1,
31 gpointer user_data); */
32
33
squeakVideoHandOff(GstElement * object,GstBuffer * buf,GstPad * pad,gpointer user_data)34 void squeakVideoHandOff (GstElement* object,
35 GstBuffer* buf,
36 GstPad* pad,
37 gpointer user_data) {
38
39 GST_LOCK(object);
40 {
41 SqueakAudioVideoSinkPtr squeaker = (SqueakAudioVideoSinkPtr) user_data;
42
43 if (squeaker->width == 0)
44 gst_SqueakVideoSink_set_caps(squeaker,GST_BUFFER_CAPS(buf));
45
46
47 if (squeaker->width == 0) {
48 GST_UNLOCK(object);
49 return; /* should not happen but let's check */
50 }
51
52 if (GST_BUFFER_DATA(buf)) {
53 guint totalBytes = (squeaker->depth == 24 ? 4 : 2)*squeaker->width*squeaker->height;
54 squeaker->frame_ready = TRUE;
55 if (totalBytes != squeaker->allocbytes) {
56 if (squeaker->copyToSendToSqueakVideo)
57 g_free(squeaker->copyToSendToSqueakVideo);
58 squeaker->copyToSendToSqueakVideo = g_malloc(totalBytes);
59 squeaker->allocbytes = totalBytes;
60 }
61 memcpy(squeaker->copyToSendToSqueakVideo,GST_BUFFER_DATA(buf),totalBytes);
62 }
63 }
64 GST_UNLOCK(object);
65
66
67 }
68
squeakSrcHandOff(GstElement * object,GstBuffer * buf,GstPad * pad,gpointer user_data)69 void squeakSrcHandOff (GstElement* object,
70 GstBuffer* buf,
71 GstPad* pad,
72 gpointer user_data) {
73
74 GST_LOCK(object);
75 {
76 SqueakAudioVideoSinkPtr squeaker = (SqueakAudioVideoSinkPtr) user_data;
77
78 if (squeaker->frame_ready) {
79 squeaker->frame_ready = FALSE;
80 if (squeaker->semaphoreIndexForSink && squeaker->interpreterProxy) {
81 squeaker->interpreterProxy->signalSemaphoreWithIndex(squeaker->semaphoreIndexForSink);
82 }
83 if (GST_BUFFER_SIZE (buf) >= squeaker->actualbytes)
84 memcpy(GST_BUFFER_DATA(buf),squeaker->copyToSendToSqueakVideo,squeaker->actualbytes);
85 GST_BUFFER_TIMESTAMP(buf) = squeaker->startTime;
86 GST_BUFFER_DURATION(buf) = squeaker->duration;
87 }
88 }
89 GST_UNLOCK(object);
90
91 }
92
93 void
gst_SqueakVideoSink_set_caps(SqueakAudioVideoSinkPtr sink,GstCaps * caps)94 gst_SqueakVideoSink_set_caps (SqueakAudioVideoSinkPtr sink, GstCaps * caps) {
95 GstStructure *structure;
96 int width, height, depth;
97 gboolean ret;
98 const GValue *fps;
99 structure = gst_caps_get_structure (caps, 0);
100 ret = gst_structure_get_int (structure, "width", &width);
101 ret = ret && gst_structure_get_int (structure, "height", &height);
102 ret = ret && gst_structure_get_int (structure, "depth", &depth);
103 fps = gst_structure_get_value (structure, "framerate");
104 ret = ret && (fps != NULL);
105 if (!ret) return;
106 sink->width = width;
107 sink->height = height;
108 sink->depth = depth;
109 sink->fps_n = gst_value_get_fraction_numerator(fps);
110 sink->fps_d = gst_value_get_fraction_denominator(fps);
111 sink->width = width;
112 sink->height = height;
113 }
114
115
squeakAudioHandOff(GstElement * object,GstBuffer * buf,GstPad * pad,gpointer user_data)116 void squeakAudioHandOff (GstElement* object,
117 GstBuffer* buf,
118 GstPad* pad,
119 gpointer user_data) {
120
121 SqueakAudioVideoSinkPtr squeaker = (SqueakAudioVideoSinkPtr) user_data;
122
123 if (GST_BUFFER_DATA(buf)) {
124 gst_SqueakAudioSink_sink_write(object, squeaker,GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf),GST_BUFFER_DURATION(buf));
125 }
126
127 }
128
129
130
gst_SqueakAudioSink_sink_write(GstElement * plugin,SqueakAudioVideoSinkPtr sink,gpointer data,guint length,GstClockTime duration)131 void gst_SqueakAudioSink_sink_write(GstElement* plugin, SqueakAudioVideoSinkPtr sink, gpointer data,guint length, GstClockTime duration)
132 {
133 guint64 squeakbuffersize;
134 guint8 * startLocation;
135
136
137 GST_LOCK(plugin);
138
139 if (sink->copyToSendToSqueakAudio == NULL) {
140 sink->copyToSendToSqueakAudio = gst_buffer_new_and_alloc(22050*8); /* 2.0 second of data */
141 GST_BUFFER_OFFSET_END(sink->copyToSendToSqueakAudio) = 0;
142 }
143
144 squeakbuffersize = GST_BUFFER_OFFSET_END(sink->copyToSendToSqueakAudio);
145 /* semaphore not signalled and if we go over X then we want to signal the semaphore if it exits, but only once */
146
147 if ((sink->semaphoreWasSignaled == 0) &&
148 ((squeakbuffersize + length) > 22050))
149 { sink->semaphoreWasSignaled = 1;
150 if (sink->semaphoreIndexForSink && sink->interpreterProxy) {
151 sink->interpreterProxy->signalSemaphoreWithIndex(sink->semaphoreIndexForSink);
152 }
153 }
154
155 /* if squeakbuffersize + incoming length <= 22050*8 then allow the copy, otherwise we FLUSH the buffer and start over */
156
157 if ((squeakbuffersize + length) <= 22050*8) {
158 startLocation = GST_BUFFER_DATA(sink->copyToSendToSqueakAudio) + squeakbuffersize;
159 } else {
160 /* buffer full and squeak not getting data, please wait */
161
162 GST_BUFFER_OFFSET_END(sink->copyToSendToSqueakAudio) = 0;
163 startLocation = GST_BUFFER_DATA(sink->copyToSendToSqueakAudio);
164 }
165
166 /* copy data to the start of the squeak buffer or to some offset, and not run over the end! */
167
168 memcpy(startLocation,data,length);
169 GST_BUFFER_OFFSET_END(sink->copyToSendToSqueakAudio) = GST_BUFFER_OFFSET_END(sink->copyToSendToSqueakAudio) + length;
170 if (sink->prerollCounter) {
171 sink->prerollCounter = sink->prerollCounter -1;
172 GST_UNLOCK(plugin);
173 return;
174 }
175
176 GST_UNLOCK(plugin);
177
178
179 {
180 /* Wait for this many milliseconds so squeak can catch up per buffer write */
181
182 /* GstClock *clock;
183 GstClockID id;
184 GstClockTime base;
185 GstClockReturn result;
186 gdouble millisecondestimate;
187
188 millisecondestimate = (duration/1000000);
189
190 clock = gst_system_clock_obtain ();
191 base = gst_clock_get_time (clock);
192 id = gst_clock_new_single_shot_id (clock, base + (gint)millisecondestimate);
193 result = gst_clock_id_wait (id, NULL);
194 gst_clock_id_unref(id); */
195 }
196
197 return;
198 }
199