1 /* smplayer, GUI front-end for mplayer.
2 Copyright (C) 2006-2021 Ricardo Villalba <ricardo@smplayer.info>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "connectionshm.h"
20 #include <QCoreApplication>
21 #include <QTimer>
22 #include <QDebug>
23
24 #include <fcntl.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <stdint.h>
28 #include <errno.h>
29
30 static struct header_t {
31 uint32_t header_size;
32 uint32_t video_buffer_size;
33 uint32_t width;
34 uint32_t height;
35 uint32_t bytes;
36 uint32_t stride[3];
37 uint32_t planes;
38 uint32_t format;
39 uint32_t frame_count;
40 uint32_t busy;
41 float fps;
42 // MPV
43 int32_t rotate;
44 int32_t colorspace;
45 int32_t colorspace_levels;
46 int32_t colorspace_primaries;
47 int32_t colorspace_gamma;
48 int32_t colorspace_light;
49 float colorspace_sig_peak;
50 int32_t chroma_location;
51 uint32_t reserved[20];
52 } * header = 0;
53
54
ConnectionShm(VideoLayerRender * parent)55 ConnectionShm::ConnectionShm(VideoLayerRender * parent)
56 : ConnectionBase(parent)
57 , buffer_size(0)
58 , image_data(0)
59 {
60 buffer_name = QString("/smplayer-%1").arg(QCoreApplication::applicationPid());
61
62 render_timer = new QTimer(this);
63 connect(render_timer, SIGNAL(timeout()), this, SLOT(render_slot()));
64 render_timer->setInterval(1000 / 60);
65
66 connect_timer = new QTimer(this);
67 connect(connect_timer, SIGNAL(timeout()), this, SLOT(start_connection()));
68 connect_timer->setInterval(100);
69 }
70
~ConnectionShm()71 ConnectionShm::~ConnectionShm() {
72 }
73
start()74 void ConnectionShm::start() {
75 qDebug("ConnectionShm::start");
76 connect_timer->start();
77 }
78
stop()79 void ConnectionShm::stop() {
80 qDebug("ConnectionShm::stop");
81 stop_connection();
82 }
83
render_slot()84 void ConnectionShm::render_slot() {
85 static uint32_t last_frame = 0;
86 //qDebug("ConnectionShm::render_slot");
87
88 if (header == 0) return;
89
90 if (header->frame_count == last_frame) return;
91
92 //qDebug("ConnectionShm::render_slot: frame_count: %d", header->frame_count);
93 //qDebug("ConnectionShm::render_slot: %d %d", header->width, header->height);
94 //qDebug("ConnectionShm::render_slot: header size: %d busy: %d", header->header_size, header->busy);
95 //qDebug("ConnectionShm::render_slot: %p %p", header, image_data);
96
97
98 if (header->busy == 1) {
99 //qDebug("ConnectionShm::render_slot: busy (f: %d)", header->frame_count);
100 return;
101 }
102 //qDebug("ConnectionShm::render_slot: frame_count: %d", header->frame_count);
103
104
105 /*
106 uint32_t count = 0;
107 while (header->busy == 1 && count < 1000000) { count++; }
108 if (count != 0) {
109 qDebug("ConnectionShm::render_slot: count: %d", count);
110 }
111 */
112
113 video_window->render();
114 last_frame = header->frame_count;
115 }
116
stop_slot()117 void ConnectionShm::stop_slot() {
118 qDebug("ConnectionShm::stop_slot");
119 }
120
start_connection()121 void ConnectionShm::start_connection() {
122 qDebug("ConnectionShm::start_connection");
123
124 shm_fd = shm_open(buffer_name.toLatin1().constData(), O_RDONLY, S_IRUSR);
125
126 if (shm_fd == -1) {
127 qDebug("ConnectionShm::start_connection: shm_open failed");
128 return;
129 }
130
131 header = (header_t *) mmap(NULL, sizeof(header), PROT_READ, MAP_SHARED, shm_fd, 0);
132
133 if (header == MAP_FAILED) {
134 qDebug("ConnectionShm::start_connection: mmap failed");
135 return;
136 }
137
138 qDebug("ConnectionShm::start_connection: bytes: %d stride: %d %d %d planes: %d", header->bytes, header->stride[0], header->stride[1], header->stride[2], header->planes);
139 qDebug("ConnectionShm::start_connection: header size: %d videobuffer size: %d", header->header_size, header->video_buffer_size);
140
141 int image_width = header->width;
142 int image_height = header->height;
143 int image_bytes = header->bytes;
144
145 buffer_size = header->header_size + header->video_buffer_size;
146 qDebug("ConnectionShm::start_connection: %d %d %d %f", image_width, image_height, image_bytes, header->fps);
147
148 header = (header_t *) mmap(NULL, buffer_size, PROT_READ, MAP_SHARED, shm_fd, 0);
149
150 if (header == MAP_FAILED) {
151 qDebug("ConnectionShm::start_connection: mmap failed");
152 return;
153 }
154
155 if (image_width == 0 || image_height == 0) {
156 qDebug("ConnectionShm::start_connection: wrong image size");
157 return;
158 }
159
160 image_data = (unsigned char*) header + header->header_size;
161 //qDebug("ConnectionShm::start_connection: header: %p image_data: %p", header, image_data);
162
163 // Convert formats from mpv
164 uint32_t format = header->format;
165 switch (format) {
166 case ConnectionBase::MP_YUV420P: format = ConnectionBase::I420; break;
167 case ConnectionBase::MP_UYVY422: format = ConnectionBase::UYVY; break;
168 case ConnectionBase::MP_RGB24: format = ConnectionBase::RGB24; break;
169 }
170
171 video_window->init(image_width, image_height, image_bytes, format, image_data);
172 qDebug("ConnectionShm::start_connection: header_size: %d format: %s", header->header_size,
173 formatToString(format).toLatin1().constData());
174
175 connect_timer->stop();
176
177 int fps = header->fps;
178 if (fps < 10) fps = 60;
179 render_timer->setInterval(1000 / fps / 2);
180 render_timer->start();
181 qDebug("ConnectionShm::start_connection: timer interval: %d", render_timer->interval());
182
183 qDebug("ConnectionShm::start_connection: rotate: %d chroma_location: %d", header->rotate, header->chroma_location);
184 qDebug("ConnectionShm::start_connection: colorspace: %d levels: %d primaries: %d gamma: %d light: %d sig_peak: %f",
185 header->colorspace, header->colorspace_levels, header->colorspace_primaries,
186 header->colorspace_gamma, header->colorspace_light, header->colorspace_sig_peak);
187 }
188
stop_connection()189 void ConnectionShm::stop_connection() {
190 render_timer->stop();
191 connect_timer->stop();
192
193 if (header == 0) return;
194
195 // Destroy the shared buffer
196 if (munmap(header, buffer_size) == -1) {
197 qDebug("ConnectionShm::stop_connection: munmap failed");
198 }
199 header = 0;
200 image_data = 0;
201 }
202
203 #include "moc_connectionshm.cpp"
204