25 #include <EGL/eglext.h> 26 #include <GLES2/gl2.h> 27 #include <GLES2/gl2ext.h> 29 #include <sys/types.h> 30 #include <sys/socket.h> 50 struct iovec io = { .iov_base = &data->meta,
51 .iov_len =
sizeof data->meta };
58 msg.msg_control = c_buffer;
59 msg.msg_controllen =
sizeof c_buffer;
61 if ((res = recvmsg(socket, &msg, 0)) == -1) {
62 MH_ERROR(
"Failed to receive message");
64 }
else if (res == 0) {
65 MH_ERROR(
"Socket shutdown while receiving buffer data");
69 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
71 memmove(&data->fd, CMSG_DATA(cmsg),
sizeof data->fd);
73 MH_DEBUG(
"Extracted fd %d", data->fd);
74 MH_DEBUG(
"width %d", data->meta.width);
75 MH_DEBUG(
"height %d", data->meta.height);
76 MH_DEBUG(
"fourcc 0x%X", data->meta.fourcc);
77 MH_DEBUG(
"stride %d", data->meta.stride);
78 MH_DEBUG(
"offset %d", data->meta.offset);
85 promise<BufferData>& prom_buff,
86 core::Signal<void>& frame_available)
88 static const char *consumer_socket =
"media-consumer";
90 struct sockaddr_un local;
95 MH_ERROR(
"Cannot create buffer consumer socket: %s (%d)",
96 strerror(errno), errno);
100 ostringstream sock_name_ss;
101 sock_name_ss << consumer_socket << key;
102 local.sun_family = AF_UNIX;
103 local.sun_path[0] =
'\0';
104 strcpy(local.sun_path + 1, sock_name_ss.str().c_str());
105 len =
sizeof(local.sun_family) + sock_name_ss.str().length() + 1;
106 if (bind(sock_fd, (
struct sockaddr *) &local, len) == -1) {
107 MH_ERROR(
"Cannot bind consumer socket: %s (%d)",
108 strerror(errno), errno);
113 if (!receive_buff(sock_fd, &buff_data))
116 prom_buff.set_value(buff_data);
123 res = recv(sock_fd, &c,
sizeof c, 0);
125 MH_ERROR(
"while waiting sync: %s (%d)",
126 strerror(errno), errno);
128 }
else if (res == 0) {
139 size_t len_all = extensions.length();
140 size_t len = ext.length();
143 while ((pos = extensions.find(ext, pos)) != string::npos) {
144 if (pos + len == len_all || extensions[pos + len] ==
' ')
154 : gl_texture{gl_texture},
156 fut_buff{prom_buff.get_future()},
157 sock_fd{socket(AF_UNIX, SOCK_DGRAM, 0)},
158 sock_thread{read_sock_events, key, sock_fd,
159 ref(prom_buff), ref(frame_available)},
160 egl_image{EGL_NO_IMAGE_KHR},
163 const char *extensions;
164 const char *egl_needed[] = {
"EGL_KHR_image_base",
165 "EGL_EXT_image_dma_buf_import"};
166 EGLDisplay egl_display = eglGetCurrentDisplay();
171 extensions = eglQueryString (egl_display, EGL_EXTENSIONS);
173 throw runtime_error {
"Error querying EGL extensions"};
175 for (i = 0; i <
sizeof(egl_needed)/
sizeof(egl_needed[0]); ++i) {
176 if (!find_extension(extensions, egl_needed[i])) {
177 MH_DEBUG(
"%s not supported", egl_needed[i]);
199 _eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)
200 eglGetProcAddress(
"eglCreateImageKHR");
201 _eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)
202 eglGetProcAddress(
"eglDestroyImageKHR");
203 _glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
204 eglGetProcAddress(
"glEGLImageTargetTexture2DOES");
206 if (_eglCreateImageKHR ==
nullptr || _eglDestroyImageKHR ==
nullptr ||
207 _glEGLImageTargetTexture2DOES ==
nullptr)
208 throw runtime_error {
"Error when loading extensions"};
214 shutdown(sock_fd, SHUT_RDWR);
222 if (egl_image != EGL_NO_IMAGE_KHR)
223 _eglDestroyImageKHR(eglGetCurrentDisplay(), egl_image);
233 EGLDisplay egl_display = eglGetCurrentDisplay();
234 EGLint image_attrs[] = {
235 EGL_WIDTH, buf_data->meta.width,
236 EGL_HEIGHT, buf_data->meta.height,
237 EGL_LINUX_DRM_FOURCC_EXT, buf_data->meta.fourcc,
238 EGL_DMA_BUF_PLANE0_FD_EXT, buf_data->fd,
239 EGL_DMA_BUF_PLANE0_OFFSET_EXT, buf_data->meta.offset,
240 EGL_DMA_BUF_PLANE0_PITCH_EXT, buf_data->meta.stride,
244 buf_fd = buf_data->fd;
245 egl_image = _eglCreateImageKHR(egl_display, EGL_NO_CONTEXT,
246 EGL_LINUX_DMA_BUF_EXT, NULL, image_attrs);
247 if (egl_image == EGL_NO_IMAGE_KHR) {
248 MH_ERROR(
"eglCreateImageKHR error 0x%X", eglGetError());
253 glBindTexture(GL_TEXTURE_2D, gl_texture);
254 _glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image);
256 while((err = glGetError()) != GL_NO_ERROR)
259 MH_DEBUG(
"Image successfully imported");
277 function<video::Sink::Ptr(uint32_t)>
280 return [key](uint32_t texture)
286 video::EglSink::EglSink(uint32_t gl_texture,
288 : d{
new Private{gl_texture, key}}
298 return d->frame_available;
304 static const float identity_4x4[] = { 1, 0, 0, 0,
309 memcpy(matrix, identity_4x4,
sizeof identity_4x4);
316 if (d->egl_image == EGL_NO_IMAGE_KHR) {
317 BufferData buf_data = d->fut_buff.get();
318 if (!d->import_buffer(&buf_data))
static void read_sock_events(const media::Player::PlayerKey key, int sock_fd, promise< BufferData > &prom_buff, core::Signal< void > &frame_available)
bool find_extension(const string &extensions, const string &ext)
bool import_buffer(const BufferData *buf_data)
PFNEGLCREATEIMAGEKHRPROC _eglCreateImageKHR
PFNEGLDESTROYIMAGEKHRPROC _eglDestroyImageKHR
static bool receive_buff(int socket, BufferData *data)
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC _glEGLImageTargetTexture2DOES
future< BufferData > fut_buff
promise< BufferData > prom_buff
Private(uint32_t gl_texture, const media::Player::PlayerKey key)
core::Signal< void > frame_available