blob: 5b971830c0471d19d4597980ea62df5d6fe6374d [file] [log] [blame]
Alexandre Lision8521baa2015-03-13 11:08:00 -04001/*
Alexandre Lision9fe374b2016-01-06 10:17:31 -05002 * Copyright (C) 2015-2016 Savoir-faire Linux Inc.
Alexandre Lision8521baa2015-03-13 11:08:00 -04003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lision8521baa2015-03-13 11:08:00 -040018 */
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050019#import "VideoPrefsVC.h"
20
Alexandre Lisionb8a81162015-03-20 18:08:01 -040021#import <QuartzCore/QuartzCore.h>
22
23#import <QItemSelectionModel>
24#import <QAbstractProxyModel>
25
26#import <video/configurationproxy.h>
27#import <video/sourcemodel.h>
28#import <video/previewmanager.h>
29#import <video/renderer.h>
30#import <video/device.h>
31#import <video/devicemodel.h>
32
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050033@interface VideoPrefsVC ()
34
Alexandre Lision861d0102016-02-09 17:19:27 -050035@property (assign) IBOutlet NSView* previewView;
36@property (assign) IBOutlet NSPopUpButton* videoDevicesList;
37@property (assign) IBOutlet NSPopUpButton* sizesList;
38@property (assign) IBOutlet NSPopUpButton* ratesList;
Alexandre Lisionb8a81162015-03-20 18:08:01 -040039
Alexandre Lisione0c7e332015-07-30 11:11:33 -040040@property BOOL shouldHandlePreview;
41
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050042@end
43
44@implementation VideoPrefsVC
Alexandre Lisionb8a81162015-03-20 18:08:01 -040045@synthesize previewView;
46@synthesize videoDevicesList;
47@synthesize sizesList;
48@synthesize ratesList;
Alexandre Lision4a7b95e2015-02-20 10:06:43 -050049
Alexandre Lisionb8a81162015-03-20 18:08:01 -040050QMetaObject::Connection frameUpdated;
51QMetaObject::Connection previewStarted;
52QMetaObject::Connection previewStopped;
53
54- (void)loadView
55{
56 [super loadView];
57
Alexandre Lision861d0102016-02-09 17:19:27 -050058 // Make sure models are loaded
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040059 Video::ConfigurationProxy::deviceModel().rowCount();
60 Video::ConfigurationProxy::resolutionModel().rowCount();
61 Video::ConfigurationProxy::rateModel().rowCount();
Alexandre Lisionb8a81162015-03-20 18:08:01 -040062
Alexandre Lision861d0102016-02-09 17:19:27 -050063 // Prepopulate values
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040064 QModelIndex qDeviceIdx = Video::ConfigurationProxy::deviceSelectionModel().currentIndex();
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040065 [videoDevicesList addItemWithTitle:Video::ConfigurationProxy::deviceModel().data(qDeviceIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lisionb8a81162015-03-20 18:08:01 -040066
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040067 QModelIndex qSizeIdx = Video::ConfigurationProxy::resolutionSelectionModel().currentIndex();
68 [sizesList addItemWithTitle:Video::ConfigurationProxy::resolutionModel().data(qSizeIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lisionb8a81162015-03-20 18:08:01 -040069
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -040070 QModelIndex qRate = Video::ConfigurationProxy::rateSelectionModel().currentIndex();
71 [ratesList addItemWithTitle:Video::ConfigurationProxy::rateModel().data(qDeviceIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lisionb8a81162015-03-20 18:08:01 -040072
Alexandre Lision861d0102016-02-09 17:19:27 -050073 // connect to model reset (device may have changed) and selection changed signals
74 QObject::connect(qobject_cast<QAbstractProxyModel*>(&Video::ConfigurationProxy::resolutionModel()),
75 &QAbstractProxyModel::modelReset,
76 [=]() {
77 [sizesList removeAllItems];
78 });
Alexandre Lisionb8a81162015-03-20 18:08:01 -040079
Alexandre Lision861d0102016-02-09 17:19:27 -050080 QObject::connect(&Video::ConfigurationProxy::resolutionSelectionModel(),
81 &QItemSelectionModel::currentChanged,
82 [=](const QModelIndex &current, const QModelIndex &previous) {
83 if (!current.isValid()) {
84 return;
85 }
86 [sizesList removeAllItems];
87 [sizesList addItemWithTitle:Video::ConfigurationProxy::resolutionSelectionModel().currentIndex().data(Qt::DisplayRole).toString().toNSString()];
88
89 });
90
91 QObject::connect(qobject_cast<QAbstractProxyModel*>(&Video::ConfigurationProxy::rateModel()),
92 &QAbstractProxyModel::modelReset,
93 [=]() {
94 [ratesList removeAllItems];
95 });
96
97 QObject::connect(&Video::ConfigurationProxy::rateSelectionModel(),
98 &QItemSelectionModel::currentChanged,
99 [=](const QModelIndex &current, const QModelIndex &previous) {
100 if (!current.isValid()) {
101 return;
102 }
103 [ratesList removeAllItems];
104 [ratesList addItemWithTitle:Video::ConfigurationProxy::rateSelectionModel().currentIndex().data(Qt::DisplayRole).toString().toNSString()];
105
106 });
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400107
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400108 [previewView setWantsLayer:YES];
109 [previewView setLayer:[CALayer layer]];
110 [previewView.layer setBackgroundColor:[NSColor blackColor].CGColor];
111 [previewView.layer setContentsGravity:kCAGravityResizeAspect];
112 [previewView.layer setFrame:previewView.frame];
113 [previewView.layer setBounds:previewView.frame];
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400114}
115
116- (IBAction)chooseDevice:(id)sender {
117 int index = [sender indexOfSelectedItem];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400118 QModelIndex qIdx = Video::ConfigurationProxy::deviceModel().index(index, 0);
119 Video::ConfigurationProxy::deviceSelectionModel().setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400120}
121
122- (IBAction)chooseSize:(id)sender {
123 int index = [sender indexOfSelectedItem];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400124 QModelIndex qIdx = Video::ConfigurationProxy::resolutionModel().index(index, 0);
125 Video::ConfigurationProxy::resolutionSelectionModel().setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400126}
127
128- (IBAction)chooseRate:(id)sender {
129 int index = [sender indexOfSelectedItem];
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400130 QModelIndex qIdx = Video::ConfigurationProxy::rateModel().index(index, 0);
131 Video::ConfigurationProxy::rateSelectionModel().setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400132}
133
134- (void) connectPreviewSignals
135{
136 QObject::disconnect(frameUpdated);
137 QObject::disconnect(previewStopped);
138 QObject::disconnect(previewStarted);
Alexandre Lisiond7b85462015-11-10 17:14:29 -0500139
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400140 previewStarted = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisiond7b85462015-11-10 17:14:29 -0500141 &Video::PreviewManager::previewStarted,
142 [=](Video::Renderer* renderer) {
143 NSLog(@"Preview started");
144 QObject::disconnect(frameUpdated);
145 frameUpdated = QObject::connect(renderer,
146 &Video::Renderer::frameUpdated,
147 [=]() {
148 [self renderer:Video::PreviewManager::instance().previewRenderer() renderFrameForView:previewView];
149 });
150 });
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400151
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400152 previewStopped = QObject::connect(&Video::PreviewManager::instance(),
Alexandre Lisiond7b85462015-11-10 17:14:29 -0500153 &Video::PreviewManager::previewStopped,
154 [=](Video::Renderer* renderer) {
155 NSLog(@"Preview stopped");
156 QObject::disconnect(frameUpdated);
157 [previewView.layer setContents:nil];
158 });
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400159
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400160 frameUpdated = QObject::connect(Video::PreviewManager::instance().previewRenderer(),
Alexandre Lisiond7b85462015-11-10 17:14:29 -0500161 &Video::Renderer::frameUpdated,
162 [=]() {
163 [self renderer:Video::PreviewManager::instance().previewRenderer()
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400164 renderFrameForView:previewView];
Alexandre Lisiond7b85462015-11-10 17:14:29 -0500165 });
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400166}
167
168-(void) renderer: (Video::Renderer*)renderer renderFrameForView:(NSView*) view
169{
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400170 QSize res = renderer->size();
171
Alexandre Lision6731e132015-10-14 14:29:06 -0400172 auto frame_ptr = renderer->currentFrame();
173 auto frame_data = frame_ptr.ptr;
174 if (!frame_data)
175 return;
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400176
177 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
Alexandre Lision6731e132015-10-14 14:29:06 -0400178 CGContextRef newContext = CGBitmapContextCreate(frame_data,
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400179 res.width(),
180 res.height(),
181 8,
182 4*res.width(),
183 colorSpace,
184 kCGImageAlphaPremultipliedLast);
185
186
187 CGImageRef newImage = CGBitmapContextCreateImage(newContext);
188
189 /*We release some components*/
190 CGContextRelease(newContext);
191 CGColorSpaceRelease(colorSpace);
192
193 [CATransaction begin];
194 view.layer.contents = (__bridge id)newImage;
195 [CATransaction commit];
196
197 CFRelease(newImage);
198}
199
Alexandre Lisione78a09b2015-07-03 15:52:23 -0400200- (void) viewWillAppear
201{
Alexandre Lisiond7b85462015-11-10 17:14:29 -0500202 // check if preview has to be started/stopped by this controller
203 self.shouldHandlePreview = !Video::PreviewManager::instance().previewRenderer()->isRendering();
204
205 [self connectPreviewSignals];
Alexandre Lisione0c7e332015-07-30 11:11:33 -0400206 if (self.shouldHandlePreview) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400207 Video::PreviewManager::instance().startPreview();
Alexandre Lisione0c7e332015-07-30 11:11:33 -0400208 }
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400209}
210
211- (void)viewWillDisappear
212{
Alexandre Lisiond7b85462015-11-10 17:14:29 -0500213 QObject::disconnect(frameUpdated);
214 QObject::disconnect(previewStopped);
215 QObject::disconnect(previewStarted);
Alexandre Lisione0c7e332015-07-30 11:11:33 -0400216 if (self.shouldHandlePreview) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400217 Video::PreviewManager::instance().stopPreview();
Alexandre Lisione0c7e332015-07-30 11:11:33 -0400218 }
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400219}
220
221#pragma mark - NSMenuDelegate methods
222
223- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
224{
225 QModelIndex qIdx;
Alexandre Lisione1cf4462015-10-08 15:44:38 -0400226 if(self.videoDevicesList.menu == menu) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400227 qIdx = Video::ConfigurationProxy::deviceModel().index(index, 0);
228 [item setTitle:Video::ConfigurationProxy::deviceModel().data(qIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lision861d0102016-02-09 17:19:27 -0500229 if (qIdx == Video::ConfigurationProxy::deviceSelectionModel().currentIndex()) {
230 [videoDevicesList selectItem:item];
231 }
Alexandre Lisione1cf4462015-10-08 15:44:38 -0400232 } else if(self.sizesList.menu == menu) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400233 qIdx = Video::ConfigurationProxy::resolutionModel().index(index, 0);
234 [item setTitle:Video::ConfigurationProxy::resolutionModel().data(qIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lision861d0102016-02-09 17:19:27 -0500235 if (qIdx == Video::ConfigurationProxy::resolutionSelectionModel().currentIndex()) {
236 [sizesList selectItem:item];
237 }
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400238
Alexandre Lisione1cf4462015-10-08 15:44:38 -0400239 } else if(self.ratesList.menu == menu) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400240 qIdx = Video::ConfigurationProxy::rateModel().index(index, 0);
241 [item setTitle:Video::ConfigurationProxy::rateModel().data(qIdx, Qt::DisplayRole).toString().toNSString()];
Alexandre Lision861d0102016-02-09 17:19:27 -0500242 if (qIdx == Video::ConfigurationProxy::rateSelectionModel().currentIndex()) {
243 [ratesList selectItem:item];
244 }
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400245 }
246 return YES;
247}
248
249- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
250{
Alexandre Lisione1cf4462015-10-08 15:44:38 -0400251 if(self.videoDevicesList.menu == menu) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400252 return Video::ConfigurationProxy::deviceModel().rowCount();
Alexandre Lisione1cf4462015-10-08 15:44:38 -0400253 } else if(self.sizesList.menu == menu) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400254 return Video::ConfigurationProxy::resolutionModel().rowCount();
Alexandre Lisione1cf4462015-10-08 15:44:38 -0400255 } else if(self.ratesList.menu == menu) {
Alexandre Lisiond3aa3ad2015-10-23 14:28:41 -0400256 return Video::ConfigurationProxy::rateModel().rowCount();
Alexandre Lisionb8a81162015-03-20 18:08:01 -0400257 }
Alexandre Lisione1cf4462015-10-08 15:44:38 -0400258 return 0;
Alexandre Lision4a7b95e2015-02-20 10:06:43 -0500259}
260
261@end