Merge lp:~fboucault/camera-app/video_quality into lp:camera-app
- video_quality
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Bill Filler |
Approved revision: | 445 |
Merged at revision: | 458 |
Proposed branch: | lp:~fboucault/camera-app/video_quality |
Merge into: | lp:camera-app |
Diff against target: |
531 lines (+281/-19) 9 files modified
CameraApp/advancedcamerasettings.cpp (+39/-1) CameraApp/advancedcamerasettings.h (+6/-0) ViewFinderOverlay.qml (+66/-0) debian/changelog (+7/-0) debian/control (+1/-0) po/camera-app.pot (+17/-17) tests/autopilot/camera_app/emulators/main_window.py (+4/-0) tests/autopilot/camera_app/emulators/panel.py (+1/-1) tests/autopilot/camera_app/tests/test_capture.py (+140/-0) |
To merge this branch: | bzr merge lp:~fboucault/camera-app/video_quality |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bill Filler (community) | Approve | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Arthur Mello (community) | Approve | ||
Review via email: mp+244042@code.launchpad.net |
Commit message
New option to select recording resolution in video mode.
Description of the change
- 438. By Florian Boucault
-
Fix naming.
- 439. By Florian Boucault
-
Added autopilot tests.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:439
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 440. By Florian Boucault
-
Merged from trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:440
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
ABORTED: http://
UNSTABLE: http://
ABORTED: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 441. By Florian Boucault
-
Merged from trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:441
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 442. By Florian Boucault
-
Added failing autopilot test
- 443. By Florian Boucault
-
Set video resolution when switching cameras. Fixes failing AP test.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:443
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Bill Filler (bfiller) wrote : | # |
working pretty well, only found 2 issues:
1) when recording at 480p with front camera on krillin, the resulting video aspect ratio seems incorrect. The video looks squashed. Using the back camera at this resolution doesn't have the same issue.
2) Not specific to this MR but perhaps we should fix in this MR: the bottom edge should be disabled when recording in progress to ensure no changes are made to the video quality, etc.
- 444. By Florian Boucault
-
Disable bottom edge while recording.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:444
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 445. By Florian Boucault
-
Workaround for stretched videos: do not allow recording at 640x480 with the front camera. Ref.: https:/
/bugs.launchpad .net/ubuntu/ +source/ libhybris/ +bug/1408650
Florian Boucault (fboucault) wrote : | # |
> working pretty well, only found 2 issues:
>
> 1) when recording at 480p with front camera on krillin, the resulting video
> aspect ratio seems incorrect. The video looks squashed. Using the back camera
> at this resolution doesn't have the same issue.
>
Workarounded in this MR. Bug reported: https:/
> 2) Not specific to this MR but perhaps we should fix in this MR: the bottom
> edge should be disabled when recording in progress to ensure no changes are
> made to the video quality, etc.
Fixed in this MR.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:445
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CameraApp/advancedcamerasettings.cpp' |
2 | --- CameraApp/advancedcamerasettings.cpp 2014-12-03 19:33:49 +0000 |
3 | +++ CameraApp/advancedcamerasettings.cpp 2015-01-08 13:44:43 +0000 |
4 | @@ -39,7 +39,8 @@ |
5 | m_viewFinderControl(0), |
6 | m_cameraFlashControl(0), |
7 | m_cameraExposureControl(0), |
8 | - m_imageEncoderControl(0) |
9 | + m_imageEncoderControl(0), |
10 | + m_videoEncoderControl(0) |
11 | { |
12 | } |
13 | |
14 | @@ -164,6 +165,17 @@ |
15 | return imageEncoderControl; |
16 | } |
17 | |
18 | +QVideoEncoderSettingsControl* AdvancedCameraSettings::videoEncoderControlFromCamera(QCamera *camera) const |
19 | +{ |
20 | + QMediaControl *control = mediaControlFromCamera(camera, QVideoEncoderSettingsControl_iid); |
21 | + QVideoEncoderSettingsControl *videoEncoderControl = qobject_cast<QVideoEncoderSettingsControl*>(control); |
22 | + |
23 | + if (videoEncoderControl == 0) { |
24 | + qWarning() << "No video encoder settings control support"; |
25 | + } |
26 | + |
27 | + return videoEncoderControl; |
28 | +} |
29 | |
30 | QObject* AdvancedCameraSettings::camera() const |
31 | { |
32 | @@ -221,12 +233,14 @@ |
33 | } |
34 | |
35 | m_imageEncoderControl = imageEncoderControlFromCamera(m_camera); |
36 | + m_videoEncoderControl = videoEncoderControlFromCamera(m_camera); |
37 | |
38 | Q_EMIT resolutionChanged(); |
39 | Q_EMIT hasFlashChanged(); |
40 | Q_EMIT hasHdrChanged(); |
41 | Q_EMIT hdrEnabledChanged(); |
42 | Q_EMIT encodingQualityChanged(); |
43 | + Q_EMIT videoSupportedResolutionsChanged(); |
44 | } |
45 | |
46 | void AdvancedCameraSettings::onCameraStateChanged() |
47 | @@ -246,6 +260,7 @@ |
48 | Q_EMIT activeCameraIndexChanged(); |
49 | Q_EMIT resolutionChanged(); |
50 | Q_EMIT hasFlashChanged(); |
51 | + Q_EMIT videoSupportedResolutionsChanged(); |
52 | } |
53 | } |
54 | |
55 | @@ -261,6 +276,29 @@ |
56 | return QSize(); |
57 | } |
58 | |
59 | +QStringList AdvancedCameraSettings::videoSupportedResolutions() const |
60 | +{ |
61 | + if (m_videoEncoderControl) { |
62 | + QList<QSize> sizes = m_videoEncoderControl->supportedResolutions( |
63 | + m_videoEncoderControl->videoSettings()); |
64 | + QStringList sizesAsStrings; |
65 | + Q_FOREACH(QSize size, sizes) { |
66 | + // Workaround for bug https://bugs.launchpad.net/ubuntu/+source/libhybris/+bug/1408650 |
67 | + // When using the front camera on krillin, using resolution 640x480 does |
68 | + // not work properly and results in stretched videos. Remove it from |
69 | + // the list of supported resolutions. |
70 | + if (activeCameraIndex() == 1 && size.width() == 640 && size.height() == 480) { |
71 | + continue; |
72 | + } |
73 | + sizesAsStrings.append(QString("%1x%2").arg(size.width()).arg(size.height())); |
74 | + } |
75 | + return sizesAsStrings; |
76 | + } else { |
77 | + return QStringList(); |
78 | + } |
79 | +} |
80 | + |
81 | + |
82 | bool AdvancedCameraSettings::hasFlash() const |
83 | { |
84 | if (m_cameraFlashControl) { |
85 | |
86 | === modified file 'CameraApp/advancedcamerasettings.h' |
87 | --- CameraApp/advancedcamerasettings.h 2014-12-03 19:33:49 +0000 |
88 | +++ CameraApp/advancedcamerasettings.h 2015-01-08 13:44:43 +0000 |
89 | @@ -28,6 +28,7 @@ |
90 | #include <QtMultimedia/QCameraExposureControl> |
91 | #include <QtMultimedia/QMediaControl> |
92 | #include <QtMultimedia/QImageEncoderControl> |
93 | +#include <QtMultimedia/QVideoEncoderSettingsControl> |
94 | |
95 | class QCameraControl; |
96 | class QCameraFlashControl; |
97 | @@ -39,6 +40,7 @@ |
98 | Q_PROPERTY (int activeCameraIndex READ activeCameraIndex WRITE setActiveCameraIndex |
99 | NOTIFY activeCameraIndexChanged) |
100 | Q_PROPERTY (QSize resolution READ resolution NOTIFY resolutionChanged) |
101 | + Q_PROPERTY (QStringList videoSupportedResolutions READ videoSupportedResolutions NOTIFY videoSupportedResolutionsChanged) |
102 | Q_PROPERTY (bool hasFlash READ hasFlash NOTIFY hasFlashChanged) |
103 | Q_PROPERTY (bool hdrEnabled READ hdrEnabled WRITE setHdrEnabled NOTIFY hdrEnabledChanged) |
104 | Q_PROPERTY (bool hasHdr READ hasHdr NOTIFY hasHdrChanged) |
105 | @@ -51,6 +53,7 @@ |
106 | void setCamera(QObject* camera); |
107 | void setActiveCameraIndex(int index); |
108 | QSize resolution() const; |
109 | + QStringList videoSupportedResolutions() const; |
110 | bool hasFlash() const; |
111 | bool hasHdr() const; |
112 | bool hdrEnabled() const; |
113 | @@ -67,6 +70,7 @@ |
114 | void hasHdrChanged(); |
115 | void hdrEnabledChanged(); |
116 | void encodingQualityChanged(); |
117 | + void videoSupportedResolutionsChanged(); |
118 | |
119 | private Q_SLOTS: |
120 | void onCameraStateChanged(); |
121 | @@ -81,6 +85,7 @@ |
122 | QCamera* cameraFromCameraObject(QObject* cameraObject) const; |
123 | QMediaControl* mediaControlFromCamera(QCamera *camera, const char* iid) const; |
124 | QImageEncoderControl* imageEncoderControlFromCamera(QCamera *camera) const; |
125 | + QVideoEncoderSettingsControl* videoEncoderControlFromCamera(QCamera *camera) const; |
126 | |
127 | QObject* m_cameraObject; |
128 | QCamera* m_camera; |
129 | @@ -91,6 +96,7 @@ |
130 | QCameraFlashControl* m_cameraFlashControl; |
131 | QCameraExposureControl* m_cameraExposureControl; |
132 | QImageEncoderControl* m_imageEncoderControl; |
133 | + QVideoEncoderSettingsControl* m_videoEncoderControl; |
134 | }; |
135 | |
136 | #endif // ADVANCEDCAMERASETTINGS_H |
137 | |
138 | === modified file 'ViewFinderOverlay.qml' |
139 | --- ViewFinderOverlay.qml 2014-12-11 12:24:25 +0000 |
140 | +++ ViewFinderOverlay.qml 2015-01-08 13:44:43 +0000 |
141 | @@ -47,6 +47,7 @@ |
142 | property int encodingQuality: 2 // QMultimedia.NormalQuality |
143 | property bool gridEnabled: false |
144 | property bool preferRemovableStorage: false |
145 | + property string videoResolution: "1920x1080" |
146 | } |
147 | |
148 | Binding { |
149 | @@ -75,6 +76,57 @@ |
150 | value: settings.encodingQuality |
151 | } |
152 | |
153 | + Binding { |
154 | + target: camera.videoRecorder |
155 | + property: "resolution" |
156 | + value: settings.videoResolution |
157 | + } |
158 | + |
159 | + function resolutionToLabel(resolution) { |
160 | + // takes in a resolution string (e.g. "1920x1080") and returns a nicer |
161 | + // form of it for display in the UI: "1080p" |
162 | + return resolution.split("x").pop() + "p"; |
163 | + } |
164 | + |
165 | + function updateVideoResolutionOptions() { |
166 | + // Clear and refill videoResolutionOptionsModel with available resolutions |
167 | + // Try to only display well known resolutions: 1080p, 720p and 480p |
168 | + videoResolutionOptionsModel.clear(); |
169 | + var supported = camera.advanced.videoSupportedResolutions; |
170 | + var wellKnown = ["1920x1080", "1280x720", "640x480"]; |
171 | + for (var i=0; i<supported.length; i++) { |
172 | + var resolution = supported[i]; |
173 | + if (wellKnown.indexOf(resolution) !== -1) { |
174 | + var option = {"icon": "", |
175 | + "label": resolutionToLabel(resolution), |
176 | + "value": resolution}; |
177 | + videoResolutionOptionsModel.insert(0, option); |
178 | + } |
179 | + } |
180 | + |
181 | + // If resolution setting chosen is not supported select the highest available resolution |
182 | + if (supported.indexOf(settings.videoResolution) == -1) { |
183 | + settings.videoResolution = supported[supported.length - 1]; |
184 | + } |
185 | + } |
186 | + |
187 | + Component.onCompleted: { |
188 | + updateVideoResolutionOptions(); |
189 | + } |
190 | + |
191 | + Connections { |
192 | + target: camera.advanced |
193 | + onVideoSupportedResolutionsChanged: updateVideoResolutionOptions(); |
194 | + } |
195 | + |
196 | + Connections { |
197 | + target: camera.advanced |
198 | + onActiveCameraIndexChanged: { |
199 | + updateVideoResolutionOptions(); |
200 | + camera.videoRecorder.resolution = settings.videoResolution; |
201 | + } |
202 | + } |
203 | + |
204 | Connections { |
205 | target: camera.imageCapture |
206 | onReadyChanged: { |
207 | @@ -111,6 +163,8 @@ |
208 | } |
209 | height: optionsOverlayLoader.height |
210 | onOpenedChanged: optionsOverlayLoader.item.closeValueSelector() |
211 | + enabled: camera.videoRecorder.recorderState == CameraRecorder.StoppedState |
212 | + opacity: enabled ? 1.0 : 0.3 |
213 | |
214 | Item { |
215 | /* Use the 'trigger' feature of Panel so that tapping on the Panel |
216 | @@ -319,6 +373,18 @@ |
217 | label: QT_TR_NOOP("Save internally") |
218 | value: false |
219 | } |
220 | + }, |
221 | + ListModel { |
222 | + id: videoResolutionOptionsModel |
223 | + |
224 | + property string settingsProperty: "videoResolution" |
225 | + property string icon: "" |
226 | + property string label: "HD" |
227 | + property bool isToggle: false |
228 | + property int selectedIndex: bottomEdge.indexForValue(videoResolutionOptionsModel, settings.videoResolution) |
229 | + property bool available: true |
230 | + property bool visible: camera.captureMode == Camera.CaptureVideo |
231 | + property bool showInIndicators: false |
232 | } |
233 | ] |
234 | |
235 | |
236 | === modified file 'debian/changelog' |
237 | --- debian/changelog 2014-12-11 16:24:50 +0000 |
238 | +++ debian/changelog 2015-01-08 13:44:43 +0000 |
239 | @@ -30,6 +30,13 @@ |
240 | |
241 | -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 09 Dec 2014 21:48:24 +0000 |
242 | |
243 | +camera-app (3.0.0+15.04.20141205-0ubuntu2) UNRELEASED; urgency=medium |
244 | + |
245 | + [ Florian Boucault ] |
246 | + * Add dependency on python3-mediainfodll to camera-app-autopilot |
247 | + |
248 | + -- Florian Boucault <florian.boucault@canonical.com> Wed, 10 Dec 2014 15:16:28 -0200 |
249 | + |
250 | camera-app (3.0.0+15.04.20141205-0ubuntu1) vivid; urgency=low |
251 | |
252 | [ Ubuntu daily release ] |
253 | |
254 | === modified file 'debian/control' |
255 | --- debian/control 2014-12-03 18:18:05 +0000 |
256 | +++ debian/control 2015-01-08 13:44:43 +0000 |
257 | @@ -58,5 +58,6 @@ |
258 | ${shlibs:Depends}, |
259 | python3-autopilot, |
260 | python3-wand, |
261 | + python3-mediainfodll, |
262 | Description: Test package for the camera app |
263 | Autopilot tests for the camera-app package |
264 | |
265 | === modified file 'po/camera-app.pot' |
266 | --- po/camera-app.pot 2014-12-11 12:24:25 +0000 |
267 | +++ po/camera-app.pot 2015-01-08 13:44:43 +0000 |
268 | @@ -8,7 +8,7 @@ |
269 | msgstr "" |
270 | "Project-Id-Version: camera-app\n" |
271 | "Report-Msgid-Bugs-To: \n" |
272 | -"POT-Creation-Date: 2014-12-11 10:23-0200\n" |
273 | +"POT-Creation-Date: 2014-12-15 08:50-0200\n" |
274 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
275 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
276 | "Language-Team: LANGUAGE <LL@li.org>\n" |
277 | @@ -49,55 +49,55 @@ |
278 | msgid "Share" |
279 | msgstr "" |
280 | |
281 | -#: ../ViewFinderOverlay.qml:141 ../ViewFinderOverlay.qml:164 |
282 | -#: ../ViewFinderOverlay.qml:192 ../ViewFinderOverlay.qml:215 |
283 | -#: ../ViewFinderOverlay.qml:292 |
284 | +#: ../ViewFinderOverlay.qml:185 ../ViewFinderOverlay.qml:208 |
285 | +#: ../ViewFinderOverlay.qml:236 ../ViewFinderOverlay.qml:259 |
286 | +#: ../ViewFinderOverlay.qml:336 |
287 | msgid "On" |
288 | msgstr "" |
289 | |
290 | -#: ../ViewFinderOverlay.qml:146 ../ViewFinderOverlay.qml:174 |
291 | -#: ../ViewFinderOverlay.qml:197 ../ViewFinderOverlay.qml:220 |
292 | -#: ../ViewFinderOverlay.qml:239 ../ViewFinderOverlay.qml:297 |
293 | +#: ../ViewFinderOverlay.qml:190 ../ViewFinderOverlay.qml:218 |
294 | +#: ../ViewFinderOverlay.qml:241 ../ViewFinderOverlay.qml:264 |
295 | +#: ../ViewFinderOverlay.qml:283 ../ViewFinderOverlay.qml:341 |
296 | msgid "Off" |
297 | msgstr "" |
298 | |
299 | -#: ../ViewFinderOverlay.qml:169 |
300 | +#: ../ViewFinderOverlay.qml:213 |
301 | msgid "Auto" |
302 | msgstr "" |
303 | |
304 | -#: ../ViewFinderOverlay.qml:206 |
305 | +#: ../ViewFinderOverlay.qml:250 |
306 | msgid "HDR" |
307 | msgstr "" |
308 | |
309 | -#: ../ViewFinderOverlay.qml:244 |
310 | +#: ../ViewFinderOverlay.qml:288 |
311 | msgid "5 seconds" |
312 | msgstr "" |
313 | |
314 | -#: ../ViewFinderOverlay.qml:249 |
315 | +#: ../ViewFinderOverlay.qml:293 |
316 | msgid "15 seconds" |
317 | msgstr "" |
318 | |
319 | -#: ../ViewFinderOverlay.qml:266 |
320 | +#: ../ViewFinderOverlay.qml:310 |
321 | msgid "Fine Quality" |
322 | msgstr "" |
323 | |
324 | -#: ../ViewFinderOverlay.qml:270 |
325 | +#: ../ViewFinderOverlay.qml:314 |
326 | msgid "Normal Quality" |
327 | msgstr "" |
328 | |
329 | -#: ../ViewFinderOverlay.qml:274 |
330 | +#: ../ViewFinderOverlay.qml:318 |
331 | msgid "Basic Quality" |
332 | msgstr "" |
333 | |
334 | -#: ../ViewFinderOverlay.qml:306 |
335 | +#: ../ViewFinderOverlay.qml:350 |
336 | msgid "SD" |
337 | msgstr "" |
338 | |
339 | -#: ../ViewFinderOverlay.qml:314 |
340 | +#: ../ViewFinderOverlay.qml:358 |
341 | msgid "Save to SD Card" |
342 | msgstr "" |
343 | |
344 | -#: ../ViewFinderOverlay.qml:319 |
345 | +#: ../ViewFinderOverlay.qml:363 |
346 | msgid "Save internally" |
347 | msgstr "" |
348 | |
349 | |
350 | === modified file 'tests/autopilot/camera_app/emulators/main_window.py' |
351 | --- tests/autopilot/camera_app/emulators/main_window.py 2014-12-08 12:04:21 +0000 |
352 | +++ tests/autopilot/camera_app/emulators/main_window.py 2015-01-08 13:44:43 +0000 |
353 | @@ -77,6 +77,10 @@ |
354 | """Returns the grid lines toggle button of the camera""" |
355 | return self.get_option_button("gridEnabled") |
356 | |
357 | + def get_video_resolution_button(self): |
358 | + """Returns the video resolution button of the camera""" |
359 | + return self.get_option_button("videoResolution") |
360 | + |
361 | def get_stop_watch(self): |
362 | """Returns the stop watch when using the record button of the camera""" |
363 | return self.app.wait_select_single("StopWatch") |
364 | |
365 | === modified file 'tests/autopilot/camera_app/emulators/panel.py' |
366 | --- tests/autopilot/camera_app/emulators/panel.py 2014-06-26 11:49:31 +0000 |
367 | +++ tests/autopilot/camera_app/emulators/panel.py 2015-01-08 13:44:43 +0000 |
368 | @@ -51,7 +51,7 @@ |
369 | |
370 | def _drag_to_close(self): |
371 | x, y, _, _ = self.globalRect |
372 | - line_x = x + self.width * 0.50 |
373 | + line_x = x |
374 | start_y = y |
375 | stop_y = y + self.height - 1 |
376 | |
377 | |
378 | === modified file 'tests/autopilot/camera_app/tests/test_capture.py' |
379 | --- tests/autopilot/camera_app/tests/test_capture.py 2014-12-03 18:18:05 +0000 |
380 | +++ tests/autopilot/camera_app/tests/test_capture.py 2015-01-08 13:44:43 +0000 |
381 | @@ -11,6 +11,7 @@ |
382 | from autopilot.platform import model |
383 | from testtools.matchers import Equals, NotEquals |
384 | from wand.image import Image |
385 | +from MediaInfoDLL3 import MediaInfo, Stream |
386 | |
387 | from camera_app.tests import CameraAppTestCase |
388 | |
389 | @@ -253,3 +254,142 @@ |
390 | self.pointing_device.click() |
391 | |
392 | bottom_edge.close() |
393 | + |
394 | + """Test recording videos at a set resolution and switching cameras""" |
395 | + def test_video_resolution_setting_switching_cameras(self): |
396 | + # switch to video recording and empty video folder |
397 | + self.switch_to_video_recording() |
398 | + self.delete_all_videos() |
399 | + |
400 | + # select the first resolution for the current camera |
401 | + resolutions = self.get_available_video_resolutions() |
402 | + initial_resolution = resolutions[0] |
403 | + self.set_video_resolution(initial_resolution) |
404 | + |
405 | + # switch cameras and select the last resolution for the current camera |
406 | + self.switch_cameras() |
407 | + resolutions = self.get_available_video_resolutions() |
408 | + expected_resolution = resolutions[-1] |
409 | + self.assertThat(expected_resolution, NotEquals(initial_resolution)) |
410 | + self.set_video_resolution(expected_resolution) |
411 | + |
412 | + # switch back to the initial camera and record a video |
413 | + self.switch_cameras() |
414 | + self.record_video(2) |
415 | + video_file = self.get_first_video() |
416 | + height = self.read_video_height(video_file) |
417 | + expected_height = self.height_from_resolution_label(expected_resolution) |
418 | + self.assertThat(height, Equals(expected_height)) |
419 | + |
420 | + def switch_cameras(self): |
421 | + # Swap cameras and wait for camera to settle |
422 | + shoot_button = self.main_window.get_exposure_button() |
423 | + swap_camera_button = self.main_window.get_swap_camera_button() |
424 | + self.pointing_device.move_to_object(swap_camera_button) |
425 | + self.pointing_device.click() |
426 | + self.assertThat(shoot_button.enabled, Eventually(Equals(True))) |
427 | + |
428 | + """Test recording videos at various resolutions""" |
429 | + def test_video_resolution_setting(self): |
430 | + self.switch_to_video_recording() |
431 | + resolutions = self.get_available_video_resolutions() |
432 | + |
433 | + for resolution_label in resolutions: |
434 | + self.delete_all_videos() |
435 | + self.set_video_resolution(resolution_label) |
436 | + self.record_video(2) |
437 | + video_file = self.get_first_video() |
438 | + height = self.read_video_height(video_file) |
439 | + expected_height = self.height_from_resolution_label(resolution_label) |
440 | + self.assertThat(height, Equals(expected_height)) |
441 | + self.dismiss_first_photo_hint() |
442 | + |
443 | + def switch_to_video_recording(self): |
444 | + record_control = self.main_window.get_record_control() |
445 | + # Wait for the camera overlay to be loaded |
446 | + self.assertThat(record_control.enabled, Eventually(Equals(True))) |
447 | + self.assertThat(record_control.width, Eventually(NotEquals(0))) |
448 | + self.assertThat(record_control.height, Eventually(NotEquals(0))) |
449 | + |
450 | + self.pointing_device.move_to_object(record_control) |
451 | + self.pointing_device.click() |
452 | + |
453 | + def get_available_video_resolutions(self): |
454 | + # open bottom edge |
455 | + bottom_edge = self.main_window.get_bottom_edge() |
456 | + bottom_edge.open() |
457 | + |
458 | + # open video resolution option value selector showing the possible values |
459 | + video_resolution_button = self.main_window.get_video_resolution_button() |
460 | + self.pointing_device.move_to_object(video_resolution_button) |
461 | + self.pointing_device.click() |
462 | + option_value_selector = self.main_window.get_option_value_selector() |
463 | + self.assertThat(option_value_selector.visible, Eventually(Equals(True))) |
464 | + optionButtons = option_value_selector.select_many("OptionValueButton") |
465 | + resolutions = [button.label for button in optionButtons] |
466 | + |
467 | + bottom_edge.close() |
468 | + return resolutions |
469 | + |
470 | + def delete_all_videos(self): |
471 | + video_files = os.listdir(self.videos_dir) |
472 | + for f in video_files: |
473 | + os.remove(os.path.join(self.videos_dir, f)) |
474 | + |
475 | + def set_video_resolution(self, resolution_label="720p"): |
476 | + # open bottom edge |
477 | + bottom_edge = self.main_window.get_bottom_edge() |
478 | + bottom_edge.open() |
479 | + |
480 | + # open video resolution option value selector showing the possible values |
481 | + video_resolution_button = self.main_window.get_video_resolution_button() |
482 | + self.pointing_device.move_to_object(video_resolution_button) |
483 | + self.pointing_device.click() |
484 | + option_value_selector = self.main_window.get_option_value_selector() |
485 | + self.assertThat(option_value_selector.visible, Eventually(Equals(True))) |
486 | + |
487 | + # tap on chosen video resolution option |
488 | + option = self.main_window.get_option_value_button(resolution_label) |
489 | + self.pointing_device.move_to_object(option) |
490 | + self.pointing_device.click() |
491 | + |
492 | + bottom_edge.close() |
493 | + |
494 | + def record_video(self, duration): |
495 | + exposure_button = self.main_window.get_exposure_button() |
496 | + |
497 | + # Click the exposure button to start recording |
498 | + self.pointing_device.move_to_object(exposure_button) |
499 | + self.assertThat(exposure_button.enabled, Eventually(Equals(True))) |
500 | + self.assertThat(exposure_button.width, Eventually(NotEquals(0))) |
501 | + self.assertThat(exposure_button.height, Eventually(NotEquals(0))) |
502 | + self.pointing_device.click() |
503 | + |
504 | + # Record video for duration seconds |
505 | + time.sleep(duration) |
506 | + self.pointing_device.click() |
507 | + |
508 | + stop_watch = self.main_window.get_stop_watch() |
509 | + self.assertThat(stop_watch.opacity, Eventually(Equals(0.0))) |
510 | + |
511 | + def get_first_video(self, timeout=10): |
512 | + videos = [] |
513 | + for i in range(0, timeout): |
514 | + videos = os.listdir(self.videos_dir) |
515 | + if len(videos) != 0: |
516 | + break |
517 | + time.sleep(1) |
518 | + |
519 | + video_file = os.path.join(self.videos_dir, videos[0]) |
520 | + return video_file |
521 | + |
522 | + def read_video_height(self, video_file): |
523 | + MI = MediaInfo() |
524 | + MI.Open(video_file) |
525 | + height = MI.Get(Stream.Video, 0, "Height") |
526 | + MI.Close() |
527 | + return height |
528 | + |
529 | + def height_from_resolution_label(self, resolution_label): |
530 | + # remove last character from label (always 'p') |
531 | + return resolution_label[:-1] |
lgtm