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