Argus Camera Sample Argus Camera Sample

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
StreamConsumer.cpp
Go to the documentation of this file.
1 /*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of NVIDIA CORPORATION nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define GL_GLEXT_PROTOTYPES
30
31 #include <GLES3/gl31.h>
32 #include <GLES2/gl2ext.h>
33
34 #include <unistd.h>
35
36 #include "StreamConsumer.h"
37 #include "Renderer.h"
38 #include "Thread.h"
39 #include "Error.h"
40 #include "Util.h" // for TimeValue
41
42 namespace ArgusSamples
43 {
44
45 StreamConsumer::StreamConsumer(EGLStreamKHR eglStream)
46 : m_eglStream(eglStream)
47 , m_streamState(EGL_NONE)
48 , m_streamTexture(0)
49 , m_aspectRatio(1.0f)
50 #ifdef WAR_EGL_STREAM_RACE
51 , m_sync(EGL_NO_SYNC_KHR)
52 #endif // WAR_EGL_STREAM_RACE
53 {
54 }
55
56 StreamConsumer::~StreamConsumer()
57 {
58 shutdown();
59 }
60
61 bool StreamConsumer::initialize()
62 {
63 #ifdef WAR_EGL_STREAM_RACE
64 PROPAGATE_ERROR(m_mutex.initialize());
65 #endif // WAR_EGL_STREAM_RACE
66 PROPAGATE_ERROR(Thread::initialize());
67 PROPAGATE_ERROR(Thread::waitRunning());
68 return true;
69 }
70
71 bool StreamConsumer::shutdown()
72 {
73 PROPAGATE_ERROR(Thread::shutdown());
74 return true;
75 }
76
77 bool StreamConsumer::isEGLStream(EGLStreamKHR eglStream) const
78 {
79 return (m_eglStream == eglStream);
80 }
81
82 uint32_t StreamConsumer::getStreamTextureID() const
83 {
84 return m_streamTexture;
85 }
86
87 bool StreamConsumer::setStreamAspectRatio(float aspectRatio)
88 {
89 m_aspectRatio = aspectRatio;
90 return true;
91 }
92
93 float StreamConsumer::getStreamAspectRatio() const
94 {
95 return m_aspectRatio;
96 }
97
98 #ifdef WAR_EGL_STREAM_RACE
99 Mutex& StreamConsumer::getStreamTextureMutex()
100 {
101 return m_mutex;
102 }
103 #endif // WAR_EGL_STREAM_RACE
104
105 bool StreamConsumer::threadInitialize()
106 {
107 Renderer &renderer = Renderer::getInstance();
108
109 // Initialize the GL context and make it current.
110 PROPAGATE_ERROR(m_context.initialize(&renderer.getComposerContext()));
111 PROPAGATE_ERROR(m_context.makeCurrent());
112
113 // Create an external texture and connect it to the stream as a the consumer.
114 glGenTextures(1, &m_streamTexture);
115 if (m_streamTexture == 0)
116 ORIGINATE_ERROR("Failed to create GL texture");
117
118 glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_streamTexture);
119 if (!eglStreamConsumerGLTextureExternalKHR(renderer.getEGLDisplay(), m_eglStream))
120 ORIGINATE_ERROR("Unable to connect GL as consumer");
121 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
122
123 #if defined(WAR_EGL_STREAM_RACE) && defined(EGL_NV_stream_sync)
124 // create a sync object
125 m_sync = eglCreateStreamSyncNV(renderer.getEGLDisplay(), m_eglStream, EGL_SYNC_NEW_FRAME_NV,
126 NULL);
127 if (m_sync == EGL_NO_SYNC_KHR)
128 ORIGINATE_ERROR("eglCreateStreamSyncNV failed (error 0x%04x)", eglGetError());
129 #endif // WAR_EGL_STREAM_RACE && EGL_NV_stream_sync
130
131 // Set a negative timeout for the stream acquire so that it blocks indefinitely.
132 if (!eglStreamAttribKHR(renderer.getEGLDisplay(), m_eglStream,
133 EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, -1))
134 {
135 ORIGINATE_ERROR("eglStreamAttribKHR failed (error 0x%04x)", eglGetError());
136 }
137
138 return true;
139 }
140
141 bool StreamConsumer::threadExecute()
142 {
143 Renderer &renderer = Renderer::getInstance();
144 const EGLDisplay display = renderer.getEGLDisplay();
145
146 // check the stream state
147 if ((m_streamState == EGL_NONE) ||
148 (m_streamState == EGL_STREAM_STATE_CONNECTING_KHR)
149 #ifdef WAR_EGL_STREAM_RACE
150 || !m_sync
151 #endif // WAR_EGL_STREAM_RACE
152 )
153 {
154 if (!eglQueryStreamKHR(display, m_eglStream, EGL_STREAM_STATE_KHR, &m_streamState))
155 ORIGINATE_ERROR("eglQueryStreamKHR failed");
156
157 if (m_streamState == EGL_STREAM_STATE_CONNECTING_KHR)
158 {
159 // if the producer is not yet connected sleep and try again
160 usleep(1000);
161 }
162 }
163
164 if ((m_streamState == EGL_BAD_STREAM_KHR) ||
165 (m_streamState == EGL_BAD_STATE_KHR))
166 {
167 ORIGINATE_ERROR("EGL stream is in bad state (0x%04x)", m_streamState);
168 }
169 else if ((m_streamState == EGL_STREAM_STATE_EMPTY_KHR) ||
170 (m_streamState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) ||
171 (m_streamState == EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR))
172 {
173 #ifdef WAR_EGL_STREAM_RACE
174 bool hasNewFrame = false;
175
176 if (m_sync)
177 {
178 // wait for the sync object, use a timeout so that the thread can be shutdown if the
179 // sync is never signaled.
180 const EGLint ret = eglClientWaitSyncKHR(display, m_sync, 0 /*flags*/,
181 TimeValue::fromMSec(1).toNSec());
182 if (ret == EGL_CONDITION_SATISFIED_KHR)
183 {
184 // reset the sync object to unsignaled
185 if (!eglSignalSyncKHR(display, m_sync, EGL_UNSIGNALED_KHR))
186 ORIGINATE_ERROR("eglSignalSyncKHR failed (error 0x%04x)", eglGetError());
187
188 hasNewFrame = true;
189 }
190 else if (ret != EGL_TIMEOUT_EXPIRED_KHR)
191 {
192 ORIGINATE_ERROR("eglClientWaitSyncKHR failed with 0x%04x (error 0x%04x)", ret,
193 eglGetError());
194 }
195 }
196 else
197 {
198 if (m_streamState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR)
199 {
200 hasNewFrame = true;
201 }
202 else
203 {
204 // no new frame, sleep for a while
205 usleep(1000);
206 }
207 }
208
209 if (hasNewFrame)
210 {
211 bool acquired = false;
212
213 {
214 // hold the mutex while acquiring to avoid a race with the composer thread
215 ScopedMutex sm(m_mutex);
216 PROPAGATE_ERROR(sm.expectLocked());
217
218 acquired = eglStreamConsumerAcquireKHR(display, m_eglStream);
219 }
220
221 if (acquired)
222 {
223 // request a recompose from the renderer with the new image
224 PROPAGATE_ERROR(renderer.reCompose());
225 }
226 else
227 {
228 // if the stream had been disconnected request a thread shutdown
229 if (eglGetError() == EGL_BAD_STATE_KHR)
230 PROPAGATE_ERROR(requestShutdown());
231 else
232 ORIGINATE_ERROR("Failed to aquire from egl stream");
233 }
234 }
235 #else // WAR_EGL_STREAM_RACE
236 if (eglStreamConsumerAcquireKHR(display, m_eglStream))
237 {
238 // request a recompose from the renderer with the new image
239 PROPAGATE_ERROR(renderer.reCompose());
240 }
241 else
242 {
243 // if the stream had been disconnected request a thread shutdown
244 if (eglGetError() == EGL_BAD_STATE_KHR)
245 PROPAGATE_ERROR(requestShutdown());
246 else
247 ORIGINATE_ERROR("Failed to aquire from egl stream");
248 }
249 #endif // WAR_EGL_STREAM_RACE
250 }
251
252 return true;
253 }
254
255 bool StreamConsumer::threadShutdown()
256 {
257 #if defined(WAR_EGL_STREAM_RACE) && defined(EGL_NV_stream_sync)
258 if (m_sync)
259 {
260 if (!eglDestroySyncKHR(Renderer::getInstance().getEGLDisplay(), m_sync))
261 REPORT_ERROR("eglDestroySyncKHR failed (error 0x%04x)", eglGetError());
262 m_sync = 0;
263 }
264 #endif // WAR_EGL_STREAM_RACE && EGL_NV_stream_sync
265
266 glDeleteTextures(1, &m_streamTexture);
267 m_streamTexture = 0;
268
269 PROPAGATE_ERROR(m_context.cleanup());
270
271 return true;
272 }
273
274 }; // namespace ArgusSamples