3
* Ekiga -- A VoIP and Video-Conferencing application
4
* Copyright (C) 2000-2008 Damien Sandras
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or (at
9
* your option) any later version. This program is distributed in the hope
10
* that it will be useful, but WITHOUT ANY WARRANTY; without even the
11
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
* See the GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License along
15
* with this program; if not, write to the Free Software Foundation, Inc.,
16
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18
* Ekiga is licensed under the GPL license and as a special exception, you
19
* have permission to link or otherwise combine this program with the
20
* programs OPAL, OpenH323 and PWLIB, and distribute the combination, without
21
* applying the requirements of the GNU GPL to the OPAL, OpenH323 and PWLIB
22
* programs, as long as you do follow the requirements of the GNU GPL for all
23
* the rest of the software thus combined.
28
* videoinput-core.cpp - description
29
* ------------------------------------------
30
* begin : written in 2008 by Matthias Schneider
31
* copyright : (c) 2008 by Matthias Schneider
32
* description : declaration of the interface of a videoinput core.
33
* A videoinput core manages VideoInputManagers.
42
#include "videoinput-core.h"
43
#include "videoinput-manager.h"
45
using namespace Ekiga;
47
VideoInputCore::VideoPreviewManager::VideoPreviewManager (VideoInputCore& _videoinput_core, VideoOutputCore& _videooutput_core)
48
: PThread (1000, NoAutoDeleteThread, HighestPriority, "VideoPreviewManager"),
49
videoinput_core (_videoinput_core),
50
videooutput_core (_videooutput_core)
55
// Since windows does not like to restart a thread that
56
// was never started, we do so here
61
VideoInputCore::VideoPreviewManager::~VideoPreviewManager ()
70
void VideoInputCore::VideoPreviewManager::start (unsigned width, unsigned height)
72
PTRACE(4, "PreviewManager\tStarting Preview");
74
frame = (char*) malloc (unsigned (width * height * 3 / 2));
76
videooutput_core.start();
81
void VideoInputCore::VideoPreviewManager::stop ()
83
PTRACE(4, "PreviewManager\tStopping Preview");
91
videooutput_core.stop();
94
void VideoInputCore::VideoPreviewManager::Main ()
96
PWaitAndSignal m(thread_ended);
99
unsigned height = 144;;
100
while (!end_thread) {
102
thread_paused.Signal ();
105
while (!pause_thread) {
107
videoinput_core.get_frame_data(frame, width, height);
108
videooutput_core.set_frame_data(frame, width, height, true, 1);
110
// We have to sleep some time outside the mutex lock
111
// to give other threads time to get the mutex
112
// It will be taken into account by PAdaptiveDelay
113
Current()->Sleep (5);
118
VideoInputCore::VideoInputCore (Ekiga::Runtime & _runtime, VideoOutputCore& _videooutput_core)
119
: runtime (_runtime),
120
preview_manager(*this, _videooutput_core)
122
PWaitAndSignal m_var(core_mutex);
123
PWaitAndSignal m_set(settings_mutex);
125
preview_config.active = false;
126
preview_config.width = 176;
127
preview_config.height = 144;
128
preview_config.fps = 30;
130
stream_config.active = false;
131
stream_config.width = 176;
132
stream_config.height = 144;
133
stream_config.fps = 30;
135
current_settings.brightness = 0;
136
current_settings.whiteness = 0;
137
current_settings.colour = 0;
138
current_settings.contrast = 0;
140
desired_settings.brightness = 0;
141
desired_settings.whiteness = 0;
142
desired_settings.colour = 0;
143
desired_settings.contrast = 0;
145
current_manager = NULL;
146
videoinput_core_conf_bridge = NULL;
149
VideoInputCore::~VideoInputCore ()
151
PWaitAndSignal m(core_mutex);
153
if (videoinput_core_conf_bridge)
154
delete videoinput_core_conf_bridge;
156
for (std::set<VideoInputManager *>::iterator iter = managers.begin ();
157
iter != managers.end ();
164
void VideoInputCore::setup_conf_bridge ()
166
PWaitAndSignal m(core_mutex);
168
videoinput_core_conf_bridge = new VideoInputCoreConfBridge (*this);
171
void VideoInputCore::add_manager (VideoInputManager &manager)
173
managers.insert (&manager);
174
manager_added.emit (manager);
176
manager.device_opened.connect (sigc::bind (sigc::mem_fun (this, &VideoInputCore::on_device_opened), &manager));
177
manager.device_closed.connect (sigc::bind (sigc::mem_fun (this, &VideoInputCore::on_device_closed), &manager));
178
manager.device_error.connect (sigc::bind (sigc::mem_fun (this, &VideoInputCore::on_device_error), &manager));
182
void VideoInputCore::visit_managers (sigc::slot<bool, VideoInputManager &> visitor)
184
PWaitAndSignal m(core_mutex);
187
for (std::set<VideoInputManager *>::iterator iter = managers.begin ();
188
iter != managers.end () && go_on;
190
go_on = visitor (*(*iter));
193
void VideoInputCore::get_devices (std::vector <VideoInputDevice> & devices)
195
PWaitAndSignal m(core_mutex);
199
for (std::set<VideoInputManager *>::iterator iter = managers.begin ();
200
iter != managers.end ();
202
(*iter)->get_devices (devices);
204
if (PTrace::CanTrace(4)) {
205
for (std::vector<VideoInputDevice>::iterator iter = devices.begin ();
206
iter != devices.end ();
208
PTRACE(4, "VidInputCore\tDetected Device: " << *iter);
213
void VideoInputCore::set_device(const VideoInputDevice & device, int channel, VideoInputFormat format)
215
PWaitAndSignal m(core_mutex);
216
internal_set_device(device, channel, format);
217
desired_device = device;
220
void VideoInputCore::add_device (const std::string & source, const std::string & device_name, unsigned capabilities, HalManager* /*manager*/)
222
PTRACE(4, "VidInputCore\tAdding Device " << device_name);
223
PWaitAndSignal m(core_mutex);
225
VideoInputDevice device;
226
for (std::set<VideoInputManager *>::iterator iter = managers.begin ();
227
iter != managers.end ();
229
if ((*iter)->has_device (source, device_name, capabilities, device)) {
231
if ( desired_device == device )
232
internal_set_device(device, current_channel, current_format);
234
device_added.emit(device, desired_device == device);
239
void VideoInputCore::remove_device (const std::string & source, const std::string & device_name, unsigned capabilities, HalManager* /*manager*/)
241
PTRACE(4, "VidInputCore\tRemoving Device " << device_name);
242
PWaitAndSignal m(core_mutex);
244
VideoInputDevice device;
245
for (std::set<VideoInputManager *>::iterator iter = managers.begin ();
246
iter != managers.end ();
248
if ((*iter)->has_device (source, device_name, capabilities, device)) {
249
if ( (current_device == device) && (preview_config.active || stream_config.active) ) {
251
VideoInputDevice new_device;
252
new_device.type = VIDEO_INPUT_FALLBACK_DEVICE_TYPE;
253
new_device.source = VIDEO_INPUT_FALLBACK_DEVICE_SOURCE;
254
new_device.name = VIDEO_INPUT_FALLBACK_DEVICE_NAME;
255
internal_set_device(new_device, current_channel, current_format);
258
device_removed.emit(device, current_device == device);
263
void VideoInputCore::set_preview_config (unsigned width, unsigned height, unsigned fps)
265
PWaitAndSignal m(core_mutex);
267
VideoDeviceConfig new_preview_config(width, height, fps);
269
PTRACE(4, "VidInputCore\tSetting new preview config: " << new_preview_config);
270
// There is only one state where we have to reopen the preview device:
271
// we have preview enabled, no stream is active and some value has changed
272
if ( ( preview_config.active && !stream_config.active) &&
273
( preview_config != new_preview_config) )
275
preview_manager.stop();
278
internal_open(new_preview_config.width, new_preview_config.height, new_preview_config.fps);
279
preview_manager.start(new_preview_config.width, new_preview_config.height);
282
preview_config = new_preview_config;
286
void VideoInputCore::start_preview ()
288
PWaitAndSignal m(core_mutex);
290
PTRACE(4, "VidInputCore\tStarting preview " << preview_config);
291
if (!preview_config.active && !stream_config.active) {
292
internal_open(preview_config.width, preview_config.height, preview_config.fps);
293
preview_manager.start(preview_config.width, preview_config.height);
296
preview_config.active = true;
299
void VideoInputCore::stop_preview ()
301
PWaitAndSignal m(core_mutex);
303
PTRACE(4, "VidInputCore\tStopping Preview");
304
if (preview_config.active && !stream_config.active) {
305
preview_manager.stop();
307
internal_set_manager(desired_device, current_channel, current_format);
310
preview_config.active = false;
313
void VideoInputCore::set_stream_config (unsigned width, unsigned height, unsigned fps)
315
PWaitAndSignal m(core_mutex);
317
VideoDeviceConfig new_stream_config(width, height, fps);
318
PTRACE(4, "VidInputCore\tSetting new stream config: " << new_stream_config);
320
// We do not support switching of framerate or resolution within a stream
321
// since many endpoints will probably have problems with that. Also, it would add
322
// a lot of complexity due to the capabilities exchange. Thus these values will
323
// not be used until the next start_stream.
325
if (!stream_config.active)
326
stream_config = new_stream_config;
329
void VideoInputCore::start_stream ()
331
PWaitAndSignal m(core_mutex);
333
PTRACE(4, "VidInputCore\tStarting stream " << stream_config);
334
if (preview_config.active && !stream_config.active) {
335
preview_manager.stop();
336
if ( preview_config != stream_config )
339
internal_open(stream_config.width, stream_config.height, stream_config.fps);
343
if (!preview_config.active && !stream_config.active) {
344
internal_open(stream_config.width, stream_config.height, stream_config.fps);
347
stream_config.active = true;
350
void VideoInputCore::stop_stream ()
352
PWaitAndSignal m(core_mutex);
354
PTRACE(4, "VidInputCore\tStopping Stream");
355
if (preview_config.active && stream_config.active) {
356
if ( preview_config != stream_config )
359
internal_set_manager(desired_device, current_channel, current_format);
360
internal_open(preview_config.width, preview_config.height, preview_config.fps);
362
preview_manager.start(preview_config.width, preview_config.height);
365
if (!preview_config.active && stream_config.active) {
367
internal_set_manager(desired_device, current_channel, current_format);
370
stream_config.active = false;
373
void VideoInputCore::get_frame_data (char *data,
377
PWaitAndSignal m(core_mutex);
379
if (current_manager) {
380
if (!current_manager->get_frame_data(data, width, height)) {
384
internal_set_fallback();
386
if (preview_config.active && !stream_config.active)
387
internal_open(preview_config.width, preview_config.height, preview_config.fps);
389
if (stream_config.active)
390
internal_open(stream_config.width, stream_config.height, stream_config.fps);
393
current_manager->get_frame_data(data, width, height); // the default device must always return true
395
internal_apply_settings();
399
void VideoInputCore::set_colour (unsigned colour)
401
PWaitAndSignal m(settings_mutex);
402
desired_settings.colour = colour;
405
void VideoInputCore::set_brightness (unsigned brightness)
407
PWaitAndSignal m(settings_mutex);
408
desired_settings.brightness = brightness;
411
void VideoInputCore::set_whiteness (unsigned whiteness)
413
PWaitAndSignal m(settings_mutex);
414
desired_settings.whiteness = whiteness;
417
void VideoInputCore::set_contrast (unsigned contrast)
419
PWaitAndSignal m(settings_mutex);
420
desired_settings.contrast = contrast;
423
void VideoInputCore::on_device_opened (VideoInputDevice device,
424
VideoInputSettings settings,
425
VideoInputManager *manager)
427
device_opened.emit (*manager, device, settings);
430
void VideoInputCore::on_device_closed (VideoInputDevice device, VideoInputManager *manager)
432
device_closed.emit (*manager, device);
435
void VideoInputCore::on_device_error (VideoInputDevice device, VideoInputErrorCodes error_code, VideoInputManager *manager)
437
device_error.emit (*manager, device, error_code);
440
void VideoInputCore::internal_set_device(const VideoInputDevice & device, int channel, VideoInputFormat format)
442
PTRACE(4, "VidInputCore\tSetting device: " << device);
444
if (preview_config.active && !stream_config.active)
445
preview_manager.stop();
447
if (preview_config.active || stream_config.active)
450
internal_set_manager (device, channel, format);
452
if (preview_config.active && !stream_config.active) {
453
internal_open(preview_config.width, preview_config.height, preview_config.fps);
454
preview_manager.start(preview_config.width,preview_config.height);
457
if (stream_config.active)
458
internal_open(stream_config.width, stream_config.height, stream_config.fps);
461
void VideoInputCore::internal_set_manager (const VideoInputDevice & device, int channel, VideoInputFormat format)
463
current_manager = NULL;
464
for (std::set<VideoInputManager *>::iterator iter = managers.begin ();
465
iter != managers.end ();
467
if ((*iter)->set_device (device, channel, format)) {
468
current_manager = (*iter);
472
// If the desired manager could not be found,
473
// we se the default device. The default device
474
// MUST ALWAYS be loaded and openable
475
if (current_manager) {
476
current_device = device;
479
PTRACE(1, "VidInputCore\tTried to set unexisting device " << device);
480
internal_set_fallback();
483
current_channel = channel;
484
current_format = format;
488
void VideoInputCore::internal_set_fallback ()
490
current_device.type = VIDEO_INPUT_FALLBACK_DEVICE_TYPE;
491
current_device.source = VIDEO_INPUT_FALLBACK_DEVICE_SOURCE;
492
current_device.name = VIDEO_INPUT_FALLBACK_DEVICE_NAME;
493
PTRACE(3, "VidInputCore\tFalling back to " << current_device);
495
internal_set_manager(current_device, current_channel, current_format);
498
void VideoInputCore::internal_open (unsigned width, unsigned height, unsigned fps)
500
PTRACE(4, "VidInputCore\tOpening device with " << width << "x" << height << "/" << fps );
502
if (current_manager && !current_manager->open(width, height, fps)) {
504
internal_set_fallback();
506
current_manager->open(width, height, fps);
510
void VideoInputCore::internal_close()
512
PTRACE(4, "VidInputCore\tClosing current device");
514
current_manager->close();
517
void VideoInputCore::internal_apply_settings()
519
PWaitAndSignal m_set(settings_mutex);
521
if (desired_settings.colour != current_settings.colour) {
522
current_manager->set_colour (desired_settings.colour);
523
current_settings.colour = desired_settings.colour;
526
if (desired_settings.brightness != current_settings.brightness) {
527
current_manager->set_brightness (desired_settings.brightness);
528
current_settings.brightness = desired_settings.brightness;
531
if (desired_settings.whiteness != current_settings.whiteness) {
532
current_manager->set_whiteness (desired_settings.whiteness);
533
current_settings.whiteness = desired_settings.whiteness;
536
if (desired_settings.contrast != current_settings.contrast) {
537
current_manager->set_contrast (desired_settings.contrast);
538
current_settings.contrast = desired_settings.contrast;