Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: src/trusted/sel_universal/multimedia_sdl.cc

Issue 7046064: Some small refactoring and renaming of sel_universel pepper emulation components. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client/
Patch Set: '' Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright 2010 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can
4 * be found in the LICENSE file.
5 */
6
7 /*
8 * Concrete implemenatation of IMultimedia interface using SDL
9 */
10
11 #include <SDL/SDL.h>
12 #include <SDL/SDL_timer.h>
13
14 #include <string.h>
15
16 #include <functional>
17 #include <queue>
18 #include "ppapi/c/pp_input_event.h"
19
20 #include "native_client/src/shared/platform/nacl_log.h"
21 #include "native_client/src/shared/platform/nacl_sync.h"
22 #include "native_client/src/shared/platform/nacl_sync_checked.h"
23
24 // TODO(robertm): the next include file should be moved to src/untrusted
25 #include "native_client/src/trusted/sel_universal/multimedia.h"
26 #include "native_client/src/trusted/sel_universal/workqueue.h"
27
28 // from sdl_ppapi_event_translator.cc
29 // TODO(robertm): add header when this becomes more complex
30 /* @IGNORE_LINES_FOR_CODE_HYGIENE[2] */
31 extern bool ConvertSDLEventToPPAPI(
32 const SDL_Event& sdl_event, PP_InputEvent* pp_event);
33
34 // This file implements a IMultimedia interface using SDL
35
36 struct InfoVideo {
37 int32_t width;
38 int32_t height;
39 int32_t format;
40 int32_t bits_per_pixel;
41 int32_t bytes_per_pixel;
42 int32_t rmask;
43 int32_t gmask;
44 int32_t bmask;
45 SDL_Surface* screen;
46 };
47
48
49 struct InfoAudio {
50 int32_t frequency;
51 int32_t channels;
52 int32_t frame_size;
53 };
54
55
56 struct SDLInfo {
57 int32_t initialized_sdl;
58 InfoVideo video;
59 InfoAudio audio;
60 };
61
62
63 class MultimediaSDL;
64
65
66 struct TimerEventState {
67 MultimediaSDL* mm;
68
69 int code;
70 int data1;
71 int data2;
72 };
73
74
75 static Uint32 TimerCallBack(Uint32 interval, void* data);
76
77
78 // Wrap each call to SDL into Job so we can submit them to a workqueue
79 // which guarantees that they are all executed by the same thread.
80 class JobSdlInit: public Job {
81 public:
82 int result;
83 JobSdlInit(SDLInfo* info, int width, int height, const char* title)
84 : info_(info),
85 width_(width),
86 height_(height),
87 title_(title)
88 {}
89
90 private:
91 SDLInfo* info_;
92 int width_;
93 int height_;
94 const char* title_;
95
96 virtual void Action() {
97 NaClLog(3, "JobSdlInit::Action\n");
98 const int flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
99 const uint32_t sdl_video_flags = SDL_DOUBLEBUF | SDL_HWSURFACE;
100
101 memset(info_, 0, sizeof(*info_));
102 if (SDL_Init(flags)) {
103 NaClLog(LOG_FATAL, "MultimediaModuleInit: SDL_Init failed\n");
104 }
105 info_->initialized_sdl = 1;
106
107 info_->video.screen = SDL_SetVideoMode(width_,
108 height_,
109 0,
110 sdl_video_flags);
111
112 if (!info_->video.screen) {
113 NaClLog(LOG_FATAL, "NaClSysVideo_Init: SDL_SetVideoMode failed\n");
114 }
115
116 // width, height and format validated in top half
117 info_->video.width = width_;
118 info_->video.height = height_;
119 // video format always BGRA
120 info_->video.rmask = 0x00FF0000;
121 info_->video.gmask = 0x0000FF00;
122 info_->video.bmask = 0x000000FF;
123 info_->video.bits_per_pixel = 32;
124 info_->video.bytes_per_pixel = 4;
125
126 // TODO(robertm): verify non-ownership of title_
127 SDL_WM_SetCaption(title_, title_);
128 }
129 };
130
131
132 class JobSdlQuit: public Job {
133 private:
134 SDLInfo* info_;
135
136 public:
137 explicit JobSdlQuit(SDLInfo* info) : info_(info) {}
138
139 virtual void Action() {
140 NaClLog(3, "JobSdlQuit::Action\n");
141 if (!info_->initialized_sdl) {
142 NaClLog(LOG_FATAL, "sdl not initialized\n");
143 }
144
145 SDL_Quit();
146 memset(info_, 0, sizeof(*info_));
147 }
148 };
149
150
151 class JobSdlAudioStart: public Job {
152 private:
153 SDLInfo* info_;
154
155 public:
156 explicit JobSdlAudioStart(SDLInfo* info) : info_(info) {}
157
158 virtual void Action() {
159 NaClLog(3, "JobSdlAudioStart::Action\n");
160 if (!info_->initialized_sdl) {
161 NaClLog(LOG_FATAL, "sdl not initialized\n");
162 }
163 SDL_PauseAudio(0);
164 }
165 };
166
167
168 class JobSdlAudioStop: public Job {
169 private:
170 SDLInfo* info_;
171
172 public:
173 explicit JobSdlAudioStop(SDLInfo* info) : info_(info) {}
174
175 virtual void Action() {
176 NaClLog(3, "JobSdlAudioStop::Action\n");
177 if (!info_->initialized_sdl) {
178 NaClLog(LOG_FATAL, "sdl not initialized\n");
179 }
180 SDL_PauseAudio(1);
181 }
182 };
183
184
185 class JobSdlAudioInit: public Job {
186 private:
187 SDLInfo* info_;
188 AUDIO_CALLBACK cb_;
189
190 public:
191 explicit JobSdlAudioInit(SDLInfo* info,
192 int frequency,
193 int channels,
194 int frame_size,
195 AUDIO_CALLBACK cb) : info_(info), cb_(cb) {
196 info->audio.frequency = frequency;
197 info->audio.channels = channels;
198 info->audio.frame_size = frame_size;
199 }
200
201 virtual void Action() {
202 NaClLog(3, "JobSdlAudioInit::Action\n");
203 if (!info_->initialized_sdl) {
204 NaClLog(LOG_FATAL, "sdl not initialized\n");
205 }
206
207 SDL_AudioSpec fmt;
208 fmt.freq = info_->audio.frequency;
209 fmt.format = AUDIO_S16;
210 fmt.channels = info_->audio.channels;
211 // NOTE: SDL seems to halve that the sample count for the callback
212 // so we compensate here by doubling
213 fmt.samples = info_->audio.frame_size * 2;
214 fmt.callback = cb_;
215 fmt.userdata = NULL;
216 NaClLog(LOG_INFO, "JobSdlAudioInit %d %d %d %d\n",
217 fmt.freq, fmt.format, fmt.channels, fmt.samples);
218 if (SDL_OpenAudio(&fmt, NULL) < 0) {
219 NaClLog(LOG_FATAL, "could not initialize SDL audio\n");
220 }
221 }
222 };
223
224
225 class JobSdlUpdate: public Job {
226 public:
227 JobSdlUpdate(SDLInfo* info, const void* data) : info_(info), data_(data) {}
228
229 virtual void Action() {
230 NaClLog(3, "JobSdlUpdate::Action\n");
231 SDL_Surface* image = NULL;
232 InfoVideo* video_info = &info_->video;
233 image = NULL;
234
235 if (!info_->initialized_sdl) {
236 NaClLog(LOG_FATAL, "MultimediaVideoUpdate: video not initialized\n");
237 }
238
239 image = SDL_CreateRGBSurfaceFrom((unsigned char*) data_,
240 video_info->width,
241 video_info->height,
242 video_info->bits_per_pixel,
243 video_info->width *
244 video_info->bytes_per_pixel,
245 video_info->rmask,
246 video_info->gmask,
247 video_info->bmask,
248 0);
249 if (NULL == image) {
250 NaClLog(LOG_FATAL, "SDL_CreateRGBSurfaceFrom failed\n");
251 }
252
253 if (0 != SDL_SetAlpha(image, 0, 255)) {
254 NaClLog(LOG_FATAL, "SDL_SetAlpha failed\n");
255 }
256
257 if (0 != SDL_BlitSurface(image, NULL, video_info->screen, NULL)) {
258 NaClLog(LOG_FATAL, "SDL_BlitSurface failed\n");
259 }
260
261 if (0 != SDL_Flip(video_info->screen)) {
262 NaClLog(LOG_FATAL, "SDL_Flip failed\n");
263 }
264
265 SDL_FreeSurface(image);
266 }
267
268 private:
269 SDLInfo* info_;
270 const void* data_;
271 };
272
273
274 class JobSdlEventPoll: public Job {
275 public:
276 JobSdlEventPoll(SDLInfo* info, PP_InputEvent* pp_event, bool poll)
277 : info_(info), pp_event_(pp_event), poll_(poll) {}
278
279 virtual void Action() {
280 NaClLog(3, "JobSdlEventPoll::Action\n");
281
282 if (!info_->initialized_sdl) {
283 NaClLog(LOG_FATAL, "MultimediaEventPoll: sdl not initialized\n");
284 }
285
286 for (;;) {
287 SDL_Event sdl_event;
288 const int32_t result = poll_ ?
289 SDL_PollEvent(&sdl_event) :
290 SDL_WaitEvent(&sdl_event);
291
292 if (result == 0) {
293 if (poll_) {
294 MakeInvalidEvent(pp_event_);
295 return;
296 } else {
297 NaClLog(LOG_WARNING, "SDL_WaitEvent failed\n");
298 }
299 }
300
301 if (!ConvertSDLEventToPPAPI(sdl_event, pp_event_)) {
302 continue;
303 }
304
305 break;
306 }
307 }
308
309 private:
310 SDLInfo* info_;
311 PP_InputEvent* pp_event_;
312 bool poll_;
313 };
314
315
316 // Again, the issue that all this wrapping magic is trying to work around
317 // is that SDL requires certain calls to be made from the same thread
318 class MultimediaSDL : public IMultimedia {
319 public:
320 MultimediaSDL(int width, int heigth, const char* title) {
321 NaClLog(2, "MultimediaSDL::Constructor\n");
322 sdl_workqueue_.StartInAnotherThread();
323 JobSdlInit job(&sdl_info_, width, heigth, title);
324 sdl_workqueue_.JobPut(&job);
325 job.Wait();
326 }
327
328 virtual ~MultimediaSDL() {
329 JobSdlQuit job(&sdl_info_);
330 sdl_workqueue_.JobPut(&job);
331 job.Wait();
332 }
333
334 virtual int VideoBufferSize() {
335 InfoVideo* video_info = &sdl_info_.video;
336 return video_info->bytes_per_pixel *
337 video_info->width *
338 video_info->height;
339 }
340
341 virtual void VideoUpdate(const void* data) {
342 JobSdlUpdate job(&sdl_info_, data);
343 sdl_workqueue_.JobPut(&job);
344 job.Wait();
345 }
346
347 virtual void PushUserEvent(int delay, int code, int data1, int data2) {
348 // NOTE: this is intentionally not using the queue
349 // so we can unblock a queue that is waiting for an event
350 NaClLog(3, "JobSdlPushUserEvent::Action\n");
351 if (!sdl_info_.initialized_sdl) {
352 NaClLog(LOG_FATAL, "sdl not initialized\n");
353 }
354 if (delay == 0) {
355 SDL_Event event;
356 event.type = SDL_USEREVENT;
357 event.user.code = code;
358 event.user.data1 = reinterpret_cast<void*>(data1);
359 event.user.data2 = reinterpret_cast<void*>(data2);
360 SDL_PushEvent(&event);
361 } else {
362 // schedule a timer to inject the event into the event stream
363 TimerEventState* state = new TimerEventState();
364 state->mm = this;
365 state->code = code;
366 state->data1 = data1;
367 state->data2 = data2;
368 SDL_AddTimer(delay, TimerCallBack, state);
369 }
370 }
371
372 virtual void EventPoll(PP_InputEvent* event) {
373 JobSdlEventPoll job(&sdl_info_, event, true);
374 sdl_workqueue_.JobPut(&job);
375 job.Wait();
376 }
377
378 virtual void EventGet(PP_InputEvent* event) {
379 JobSdlEventPoll job(&sdl_info_, event, false);
380 sdl_workqueue_.JobPut(&job);
381 job.Wait();
382 }
383
384 virtual void AudioInit16Bit(int frequency,
385 int channels,
386 int frame_size,
387 AUDIO_CALLBACK cb) {
388 JobSdlAudioInit job(&sdl_info_, frequency, channels, frame_size, cb);
389 sdl_workqueue_.JobPut(&job);
390 job.Wait();
391 }
392
393 virtual void AudioStart() {
394 JobSdlAudioStart job(&sdl_info_);
395 sdl_workqueue_.JobPut(&job);
396 job.Wait();
397 }
398
399 virtual void AudioStop() {
400 JobSdlAudioStop job(&sdl_info_);
401 sdl_workqueue_.JobPut(&job);
402 job.Wait();
403 }
404
405 private:
406 ThreadedWorkQueue sdl_workqueue_;
407 SDLInfo sdl_info_;
408 };
409
410
411 static Uint32 TimerCallBack(Uint32 interval, void* data) {
412 UNREFERENCED_PARAMETER(interval);
413 TimerEventState* state = reinterpret_cast<TimerEventState*>(data);
414 state->mm->PushUserEvent(0, state->code, state->data1, state->data2);
415 delete state;
416 // stop timer
417 return 0;
418 }
419
420 // Factor, so we can hide class MultimediaSDL from the outside world
421 IMultimedia* MakeMultimediaSDL(int width, int heigth, const char* title) {
422 return new MultimediaSDL(width, heigth, title);
423 }
OLDNEW
« no previous file with comments | « src/trusted/sel_universal/multimedia_handler.cc ('k') | src/trusted/sel_universal/non_standard_pepper_events.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698