mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	citra_qt: camera integration (#3566)
* Implement camera feature * Make OpenCVCamera optional * Fix styling problems * CI configuration * Fix CI * Hopefully final fix * Hopefully final fix * Fix all the problems * Oops.. * Add Qt Multimedia Camera * Another oops * Try to fix broken linux CI * Try to fix broken linux CI * Fix problems * Improve UI * Fix problems * camera: Add support for Qt <5.10 and fix preview error * CI: try to fix linux-frozen travis build * camera: fix problems and add multiple handlers support * fix CI * remove most ServiceFramework changes * Fix format * Remove last ServiceFramework change * camera: remove unused interfaces; revert submodule change * camera: fix CI error * ci: use ccache for opencv build * citra_qt: fix configuration error; CI: add mediaservice plugin * citra_qt: fix clang-format * citra_qt: fix documentation error * citra_qt: fix configuration page; camera: fix pausing crash * citra_qt: fix preview not stopping * camera: extend handlers length * camera: fix camera resume error * camera: fix clang-format * camera: remove all OpenCV; citra_qt: rewrite configuration * camera: remove all OpenCV; citra_qt: rewrite configuration * camera: remove all OpenCV; citra_qt: rewrite configuration * CI: fix linux ci * camera: check settings update; citra_qt: fix configuration error * service_cam: use a better way to apply configuration * Service_CAM: rewrite camera reload * cam: fix clang format * citra_qt: fix argument load issue; camera: base of system camera selection * citra_qt: Add system camera selection * camera: fix image upside down, Implement SetFrameRate in Qt Multimedia Camera * camera: Add missing <array> include, update SetFrameRate and add settings in Qt Multimedia Camera header * camera: move started in Qt Multimedia Camera header * QtMultimediaCamera: Move frame rates to SetFrameRate; Set minimum and maximum frame rate * Update appveyor.yml
This commit is contained in:
		
							parent
							
								
									bcecfac0ef
								
							
						
					
					
						commit
						57827de38b
					
				
					 28 changed files with 1531 additions and 18 deletions
				
			
		
							
								
								
									
										228
									
								
								src/citra_qt/camera/camera_util.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/citra_qt/camera/camera_util.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,228 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cstring> | ||||
| #include <QImage> | ||||
| #include "citra_qt/camera/camera_util.h" | ||||
| #include "common/math_util.h" | ||||
| #include "core/frontend/camera/factory.h" | ||||
| #include "core/frontend/camera/interface.h" | ||||
| 
 | ||||
| namespace CameraUtil { | ||||
| 
 | ||||
| // The following are data tables for RGB -> YUV conversions.
 | ||||
| namespace YuvTable { | ||||
| 
 | ||||
| constexpr std::array<int, 256> Y_R = { | ||||
|     53,  53,  53,  54,  54,  54,  55,  55,  55,  56,  56,  56,  56,  57,  57,  57,  58,  58,  58, | ||||
|     59,  59,  59,  59,  60,  60,  60,  61,  61,  61,  62,  62,  62,  62,  63,  63,  63,  64,  64, | ||||
|     64,  65,  65,  65,  65,  66,  66,  66,  67,  67,  67,  67,  68,  68,  68,  69,  69,  69,  70, | ||||
|     70,  70,  70,  71,  71,  71,  72,  72,  72,  73,  73,  73,  73,  74,  74,  74,  75,  75,  75, | ||||
|     76,  76,  76,  76,  77,  77,  77,  78,  78,  78,  79,  79,  79,  79,  80,  80,  80,  81,  81, | ||||
|     81,  82,  82,  82,  82,  83,  83,  83,  84,  84,  84,  85,  85,  85,  85,  86,  86,  86,  87, | ||||
|     87,  87,  87,  88,  88,  88,  89,  89,  89,  90,  90,  90,  90,  91,  91,  91,  92,  92,  92, | ||||
|     93,  93,  93,  93,  94,  94,  94,  95,  95,  95,  96,  96,  96,  96,  97,  97,  97,  98,  98, | ||||
|     98,  99,  99,  99,  99,  100, 100, 100, 101, 101, 101, 102, 102, 102, 102, 103, 103, 103, 104, | ||||
|     104, 104, 105, 105, 105, 105, 106, 106, 106, 107, 107, 107, 108, 108, 108, 108, 109, 109, 109, | ||||
|     110, 110, 110, 110, 111, 111, 111, 112, 112, 112, 113, 113, 113, 113, 114, 114, 114, 115, 115, | ||||
|     115, 116, 116, 116, 116, 117, 117, 117, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 121, | ||||
|     121, 121, 122, 122, 122, 122, 123, 123, 123, 124, 124, 124, 125, 125, 125, 125, 126, 126, 126, | ||||
|     127, 127, 127, 128, 128, 128, 128, 129, 129, | ||||
| }; | ||||
| 
 | ||||
| constexpr std::array<int, 256> Y_G = { | ||||
|     -79, -79, -78, -78, -77, -77, -76, -75, -75, -74, -74, -73, -72, -72, -71, -71, -70, -70, -69, | ||||
|     -68, -68, -67, -67, -66, -65, -65, -64, -64, -63, -62, -62, -61, -61, -60, -60, -59, -58, -58, | ||||
|     -57, -57, -56, -55, -55, -54, -54, -53, -52, -52, -51, -51, -50, -50, -49, -48, -48, -47, -47, | ||||
|     -46, -45, -45, -44, -44, -43, -42, -42, -41, -41, -40, -40, -39, -38, -38, -37, -37, -36, -35, | ||||
|     -35, -34, -34, -33, -33, -32, -31, -31, -30, -30, -29, -28, -28, -27, -27, -26, -25, -25, -24, | ||||
|     -24, -23, -23, -22, -21, -21, -20, -20, -19, -18, -18, -17, -17, -16, -15, -15, -14, -14, -13, | ||||
|     -13, -12, -11, -11, -10, -10, -9,  -8,  -8,  -7,  -7,  -6,  -5,  -5,  -4,  -4,  -3,  -3,  -2, | ||||
|     -1,  -1,  0,   0,   0,   1,   1,   2,   2,   3,   4,   4,   5,   5,   6,   6,   7,   8,   8, | ||||
|     9,   9,   10,  11,  11,  12,  12,  13,  13,  14,  15,  15,  16,  16,  17,  18,  18,  19,  19, | ||||
|     20,  21,  21,  22,  22,  23,  23,  24,  25,  25,  26,  26,  27,  28,  28,  29,  29,  30,  31, | ||||
|     31,  32,  32,  33,  33,  34,  35,  35,  36,  36,  37,  38,  38,  39,  39,  40,  41,  41,  42, | ||||
|     42,  43,  43,  44,  45,  45,  46,  46,  47,  48,  48,  49,  49,  50,  50,  51,  52,  52,  53, | ||||
|     53,  54,  55,  55,  56,  56,  57,  58,  58,  59,  59,  60,  60,  61,  62,  62,  63,  63,  64, | ||||
|     65,  65,  66,  66,  67,  68,  68,  69,  69, | ||||
| }; | ||||
| 
 | ||||
| constexpr std::array<int, 256> Y_B = { | ||||
|     25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, | ||||
|     28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, | ||||
|     31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, | ||||
|     34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, | ||||
|     36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, | ||||
|     39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, | ||||
|     42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, | ||||
|     44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, | ||||
|     47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, | ||||
|     50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, | ||||
|     53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, | ||||
| }; | ||||
| 
 | ||||
| static constexpr int Y(int r, int g, int b) { | ||||
|     return Y_R[r] + Y_G[g] + Y_B[b]; | ||||
| } | ||||
| 
 | ||||
| constexpr std::array<int, 256> U_R = { | ||||
|     30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 34, | ||||
|     34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 38, | ||||
|     38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 42, | ||||
|     42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 46, 46, | ||||
|     46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 50, 50, | ||||
|     50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 54, | ||||
|     54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 58, 58, | ||||
|     58, 58, 58, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 61, 62, 62, 62, | ||||
|     62, 62, 62, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 66, 66, 66, | ||||
|     66, 66, 66, 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 70, 70, 70, | ||||
|     70, 70, 70, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 73, 73, | ||||
| }; | ||||
| 
 | ||||
| constexpr std::array<int, 256> U_G = { | ||||
|     -45, -44, -44, -44, -43, -43, -43, -42, -42, -42, -41, -41, -41, -40, -40, -40, -39, -39, -39, | ||||
|     -38, -38, -38, -37, -37, -37, -36, -36, -36, -35, -35, -35, -34, -34, -34, -33, -33, -33, -32, | ||||
|     -32, -32, -31, -31, -31, -30, -30, -30, -29, -29, -29, -28, -28, -28, -27, -27, -27, -26, -26, | ||||
|     -26, -25, -25, -25, -24, -24, -24, -23, -23, -23, -22, -22, -22, -21, -21, -21, -20, -20, -20, | ||||
|     -19, -19, -19, -18, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, -14, -14, | ||||
|     -13, -13, -13, -12, -12, -12, -11, -11, -11, -10, -10, -10, -9,  -9,  -9,  -8,  -8,  -8,  -7, | ||||
|     -7,  -7,  -6,  -6,  -6,  -5,  -5,  -5,  -4,  -4,  -4,  -3,  -3,  -3,  -2,  -2,  -2,  -1,  -1, | ||||
|     -1,  0,   0,   0,   0,   0,   0,   1,   1,   1,   2,   2,   2,   3,   3,   3,   4,   4,   4, | ||||
|     5,   5,   5,   6,   6,   6,   7,   7,   7,   8,   8,   8,   9,   9,   9,   10,  10,  10,  11, | ||||
|     11,  11,  12,  12,  12,  13,  13,  13,  14,  14,  14,  15,  15,  15,  16,  16,  16,  17,  17, | ||||
|     17,  18,  18,  18,  19,  19,  19,  20,  20,  20,  21,  21,  21,  22,  22,  22,  23,  23,  23, | ||||
|     24,  24,  24,  25,  25,  25,  26,  26,  26,  27,  27,  27,  28,  28,  28,  29,  29,  29,  30, | ||||
|     30,  30,  31,  31,  31,  32,  32,  32,  33,  33,  33,  34,  34,  34,  35,  35,  35,  36,  36, | ||||
|     36,  37,  37,  37,  38,  38,  38,  39,  39, | ||||
| }; | ||||
| 
 | ||||
| constexpr std::array<int, 256> U_B = { | ||||
|     113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, | ||||
|     122, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, | ||||
|     132, 132, 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, | ||||
|     141, 142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, 150, 150, | ||||
|     151, 151, 152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 159, 160, | ||||
|     160, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 166, 167, 167, 168, 168, 169, 169, | ||||
|     170, 170, 171, 171, 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 177, 178, 178, 179, | ||||
|     179, 180, 180, 181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, | ||||
|     189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 194, 194, 195, 195, 196, 196, 197, 197, 198, | ||||
|     198, 199, 199, 200, 200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 206, 206, 207, 207, | ||||
|     208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, | ||||
|     217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 225, 226, 226, | ||||
|     227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, | ||||
|     236, 237, 237, 238, 238, 239, 239, 240, 240, | ||||
| }; | ||||
| 
 | ||||
| static constexpr int U(int r, int g, int b) { | ||||
|     return -U_R[r] - U_G[g] + U_B[b]; | ||||
| } | ||||
| 
 | ||||
| constexpr std::array<int, 256> V_R = { | ||||
|     89,  90,  90,  91,  91,  92,  92,  93,  93,  94,  94,  95,  95,  96,  96,  97,  97,  98,  98, | ||||
|     99,  99,  100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, | ||||
|     108, 109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, | ||||
|     118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127, | ||||
|     127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, 136, 136, | ||||
|     137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143, 144, 144, 145, 145, 146, | ||||
|     146, 147, 147, 148, 148, 149, 149, 150, 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, 155, | ||||
|     156, 156, 157, 157, 158, 158, 159, 159, 160, 160, 161, 161, 162, 162, 163, 163, 164, 164, 165, | ||||
|     165, 166, 166, 167, 167, 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 173, 173, 174, 174, | ||||
|     175, 175, 176, 176, 177, 177, 178, 178, 179, 179, 180, 180, 181, 181, 182, 182, 183, 183, 184, | ||||
|     184, 185, 185, 186, 186, 187, 187, 188, 188, 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, | ||||
|     194, 194, 195, 195, 196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 201, 201, 202, 202, 203, | ||||
|     203, 204, 205, 205, 206, 206, 207, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, | ||||
|     213, 214, 214, 215, 215, 216, 216, 217, 217, | ||||
| }; | ||||
| 
 | ||||
| constexpr std::array<int, 256> V_G = { | ||||
|     -57, -56, -56, -55, -55, -55, -54, -54, -53, -53, -52, -52, -52, -51, -51, -50, -50, -50, -49, | ||||
|     -49, -48, -48, -47, -47, -47, -46, -46, -45, -45, -45, -44, -44, -43, -43, -42, -42, -42, -41, | ||||
|     -41, -40, -40, -39, -39, -39, -38, -38, -37, -37, -37, -36, -36, -35, -35, -34, -34, -34, -33, | ||||
|     -33, -32, -32, -31, -31, -31, -30, -30, -29, -29, -29, -28, -28, -27, -27, -26, -26, -26, -25, | ||||
|     -25, -24, -24, -24, -23, -23, -22, -22, -21, -21, -21, -20, -20, -19, -19, -18, -18, -18, -17, | ||||
|     -17, -16, -16, -16, -15, -15, -14, -14, -13, -13, -13, -12, -12, -11, -11, -10, -10, -10, -9, | ||||
|     -9,  -8,  -8,  -8,  -7,  -7,  -6,  -6,  -5,  -5,  -5,  -4,  -4,  -3,  -3,  -3,  -2,  -2,  -1, | ||||
|     -1,  0,   0,   0,   0,   0,   1,   1,   2,   2,   2,   3,   3,   4,   4,   4,   5,   5,   6, | ||||
|     6,   7,   7,   7,   8,   8,   9,   9,   10,  10,  10,  11,  11,  12,  12,  12,  13,  13,  14, | ||||
|     14,  15,  15,  15,  16,  16,  17,  17,  17,  18,  18,  19,  19,  20,  20,  20,  21,  21,  22, | ||||
|     22,  23,  23,  23,  24,  24,  25,  25,  25,  26,  26,  27,  27,  28,  28,  28,  29,  29,  30, | ||||
|     30,  31,  31,  31,  32,  32,  33,  33,  33,  34,  34,  35,  35,  36,  36,  36,  37,  37,  38, | ||||
|     38,  38,  39,  39,  40,  40,  41,  41,  41,  42,  42,  43,  43,  44,  44,  44,  45,  45,  46, | ||||
|     46,  46,  47,  47,  48,  48,  49,  49,  49, | ||||
| }; | ||||
| 
 | ||||
| constexpr std::array<int, 256> V_B = { | ||||
|     18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, | ||||
|     20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, | ||||
|     22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, | ||||
|     24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, | ||||
|     26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, | ||||
|     28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, | ||||
|     30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, | ||||
|     32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, | ||||
|     34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, | ||||
|     36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, | ||||
|     38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, | ||||
| }; | ||||
| 
 | ||||
| static constexpr int V(int r, int g, int b) { | ||||
|     return V_R[r] - V_G[g] - V_B[b]; | ||||
| } | ||||
| } // namespace YuvTable
 | ||||
| 
 | ||||
| std::vector<u16> Rgb2Yuv(const QImage& source, int width, int height) { | ||||
|     auto buffer = std::vector<u16>(width * height); | ||||
|     auto dest = buffer.begin(); | ||||
|     bool write = false; | ||||
|     int py, pu, pv; | ||||
|     for (int y = 0; y < height; ++y) { | ||||
|         for (int x = 0; x < width; ++x) { | ||||
|             QRgb rgb = source.pixel(x, y); | ||||
|             int r = qRed(rgb); | ||||
|             int g = qGreen(rgb); | ||||
|             int b = qBlue(rgb); | ||||
| 
 | ||||
|             // The following transformation is a reverse of the one in Y2R using ITU_Rec601
 | ||||
|             int y = YuvTable::Y(r, g, b); | ||||
|             int u = YuvTable::U(r, g, b); | ||||
|             int v = YuvTable::V(r, g, b); | ||||
| 
 | ||||
|             if (write) { | ||||
|                 pu = (pu + u) / 2; | ||||
|                 pv = (pv + v) / 2; | ||||
|                 using MathUtil::Clamp; | ||||
|                 *(dest++) = static_cast<u16>(Clamp(py, 0, 0xFF) | (Clamp(pu, 0, 0xFF) << 8)); | ||||
|                 *(dest++) = static_cast<u16>(Clamp(y, 0, 0xFF) | (Clamp(pv, 0, 0xFF) << 8)); | ||||
|             } else { | ||||
|                 py = y; | ||||
|                 pu = u; | ||||
|                 pv = v; | ||||
|             } | ||||
|             write = !write; | ||||
|         } | ||||
|     } | ||||
|     return buffer; | ||||
| } | ||||
| 
 | ||||
| std::vector<u16> ProcessImage(const QImage& image, int width, int height, bool output_rgb = false, | ||||
|                               bool flip_horizontal = false, bool flip_vertical = false) { | ||||
|     std::vector<u16> buffer(width * height); | ||||
|     if (image.isNull()) { | ||||
|         return buffer; | ||||
|     } | ||||
|     QImage scaled = | ||||
|         image.scaled(width, height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); | ||||
|     QImage transformed = | ||||
|         scaled.copy((scaled.width() - width) / 2, (scaled.height() - height) / 2, width, height) | ||||
|             .mirrored(flip_horizontal, flip_vertical); | ||||
|     if (output_rgb) { | ||||
|         QImage converted = transformed.convertToFormat(QImage::Format_RGB16); | ||||
|         std::memcpy(buffer.data(), converted.bits(), width * height * sizeof(u16)); | ||||
|     } else { | ||||
|         return CameraUtil::Rgb2Yuv(transformed, width, height); | ||||
|     } | ||||
|     return buffer; | ||||
| } | ||||
| 
 | ||||
| } // namespace CameraUtil
 | ||||
							
								
								
									
										21
									
								
								src/citra_qt/camera/camera_util.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/citra_qt/camera/camera_util.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| class QImage; | ||||
| 
 | ||||
| namespace CameraUtil { | ||||
| 
 | ||||
| /// Converts QImage to a yuv formatted std::vector
 | ||||
| std::vector<u16> Rgb2Yuv(const QImage& source, int width, int height); | ||||
| 
 | ||||
| /// Processes the QImage (resizing, flipping ...) and converts it to a std::vector
 | ||||
| std::vector<u16> ProcessImage(const QImage& source, int width, int height, bool output_rgb, | ||||
|                               bool flip_horizontal, bool flip_vertical); | ||||
| 
 | ||||
| } // namespace CameraUtil
 | ||||
							
								
								
									
										24
									
								
								src/citra_qt/camera/qt_camera_factory.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/citra_qt/camera/qt_camera_factory.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <QMessageBox> | ||||
| #include "citra_qt/camera/qt_camera_factory.h" | ||||
| 
 | ||||
| namespace Camera { | ||||
| 
 | ||||
| std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(const std::string& config, | ||||
|                                                                 int width, int height) const { | ||||
|     std::unique_ptr<CameraInterface> camera = Create(config); | ||||
| 
 | ||||
|     if (camera->IsPreviewAvailable()) { | ||||
|         return camera; | ||||
|     } | ||||
|     QMessageBox::critical(nullptr, QObject::tr("Error"), | ||||
|                           QObject::tr("Couldn't load ") + | ||||
|                               (config.empty() ? QObject::tr("the camera") : "") + | ||||
|                               QString::fromStdString(config)); | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| } // namespace Camera
 | ||||
							
								
								
									
										18
									
								
								src/citra_qt/camera/qt_camera_factory.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/citra_qt/camera/qt_camera_factory.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| #include "core/frontend/camera/factory.h" | ||||
| 
 | ||||
| namespace Camera { | ||||
| 
 | ||||
| // Base class for camera factories of citra_qt
 | ||||
| class QtCameraFactory : public CameraFactory { | ||||
|     std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, | ||||
|                                                    int height) const override; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Camera
 | ||||
							
								
								
									
										224
									
								
								src/citra_qt/camera/qt_multimedia_camera.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								src/citra_qt/camera/qt_multimedia_camera.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,224 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <QCamera> | ||||
| #include <QCameraInfo> | ||||
| #include <QImageReader> | ||||
| #include <QMessageBox> | ||||
| #include <QThread> | ||||
| #include "citra_qt/camera/qt_multimedia_camera.h" | ||||
| #include "citra_qt/main.h" | ||||
| 
 | ||||
| namespace Camera { | ||||
| 
 | ||||
| QList<QVideoFrame::PixelFormat> QtCameraSurface::supportedPixelFormats( | ||||
|     QAbstractVideoBuffer::HandleType handleType) const { | ||||
|     Q_UNUSED(handleType); | ||||
|     return QList<QVideoFrame::PixelFormat>() | ||||
|            << QVideoFrame::Format_ARGB32 << QVideoFrame::Format_ARGB32_Premultiplied | ||||
|            << QVideoFrame::Format_RGB32 << QVideoFrame::Format_RGB24 << QVideoFrame::Format_RGB565 | ||||
|            << QVideoFrame::Format_RGB555 << QVideoFrame::Format_ARGB8565_Premultiplied | ||||
|            << QVideoFrame::Format_BGRA32 << QVideoFrame::Format_BGRA32_Premultiplied | ||||
|            << QVideoFrame::Format_BGR32 << QVideoFrame::Format_BGR24 << QVideoFrame::Format_BGR565 | ||||
|            << QVideoFrame::Format_BGR555 << QVideoFrame::Format_BGRA5658_Premultiplied | ||||
|            << QVideoFrame::Format_AYUV444 << QVideoFrame::Format_AYUV444_Premultiplied | ||||
|            << QVideoFrame::Format_YUV444 << QVideoFrame::Format_YUV420P << QVideoFrame::Format_YV12 | ||||
|            << QVideoFrame::Format_UYVY << QVideoFrame::Format_YUYV << QVideoFrame::Format_NV12 | ||||
|            << QVideoFrame::Format_NV21 << QVideoFrame::Format_IMC1 << QVideoFrame::Format_IMC2 | ||||
|            << QVideoFrame::Format_IMC3 << QVideoFrame::Format_IMC4 << QVideoFrame::Format_Y8 | ||||
|            << QVideoFrame::Format_Y16 << QVideoFrame::Format_Jpeg << QVideoFrame::Format_CameraRaw | ||||
|            << QVideoFrame::Format_AdobeDng; // Supporting all the formats
 | ||||
| } | ||||
| 
 | ||||
| bool QtCameraSurface::present(const QVideoFrame& frame) { | ||||
|     if (!frame.isValid()) { | ||||
|         return false; | ||||
|     } | ||||
|     QVideoFrame cloneFrame(frame); | ||||
|     cloneFrame.map(QAbstractVideoBuffer::ReadOnly); | ||||
|     const QImage image(cloneFrame.bits(), cloneFrame.width(), cloneFrame.height(), | ||||
|                        QVideoFrame::imageFormatFromPixelFormat(cloneFrame.pixelFormat())); | ||||
|     QMutexLocker locker(&mutex); | ||||
|     current_frame = image.mirrored(true, true); | ||||
|     locker.unlock(); | ||||
|     cloneFrame.unmap(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name) | ||||
|     : handler(QtMultimediaCameraHandler::GetHandler()) { | ||||
|     if (handler->thread() == QThread::currentThread()) { | ||||
|         handler->CreateCamera(camera_name); | ||||
|     } else { | ||||
|         QMetaObject::invokeMethod(handler.get(), "CreateCamera", Qt::BlockingQueuedConnection, | ||||
|                                   Q_ARG(const std::string&, camera_name)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| QtMultimediaCamera::~QtMultimediaCamera() { | ||||
|     handler->StopCamera(); | ||||
|     QtMultimediaCameraHandler::ReleaseHandler(handler); | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCamera::StartCapture() { | ||||
|     if (handler->thread() == QThread::currentThread()) { | ||||
|         handler->StartCamera(); | ||||
|     } else { | ||||
|         QMetaObject::invokeMethod(handler.get(), "StartCamera", Qt::BlockingQueuedConnection); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCamera::StopCapture() { | ||||
|     handler->StopCamera(); | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCamera::SetFormat(Service::CAM::OutputFormat output_format) { | ||||
|     output_rgb = output_format == Service::CAM::OutputFormat::RGB565; | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) { | ||||
|     const std::array<QCamera::FrameRateRange, 13> FrameRateList = { | ||||
|         /* Rate_15 */ QCamera::FrameRateRange(15, 15), | ||||
|         /* Rate_15_To_5 */ QCamera::FrameRateRange(5, 15), | ||||
|         /* Rate_15_To_2 */ QCamera::FrameRateRange(2, 15), | ||||
|         /* Rate_10 */ QCamera::FrameRateRange(10, 10), | ||||
|         /* Rate_8_5 */ QCamera::FrameRateRange(8.5, 8.5), | ||||
|         /* Rate_5 */ QCamera::FrameRateRange(5, 5), | ||||
|         /* Rate_20 */ QCamera::FrameRateRange(20, 20), | ||||
|         /* Rate_20_To_5 */ QCamera::FrameRateRange(5, 20), | ||||
|         /* Rate_30 */ QCamera::FrameRateRange(30, 30), | ||||
|         /* Rate_30_To_5 */ QCamera::FrameRateRange(5, 30), | ||||
|         /* Rate_15_To_10 */ QCamera::FrameRateRange(10, 15), | ||||
|         /* Rate_20_To_10 */ QCamera::FrameRateRange(10, 20), | ||||
|         /* Rate_30_To_10 */ QCamera::FrameRateRange(10, 30), | ||||
|     }; | ||||
| 
 | ||||
|     auto framerate = FrameRateList[static_cast<int>(frame_rate)]; | ||||
| 
 | ||||
|     handler->settings.setMinimumFrameRate(framerate.minimumFrameRate); | ||||
|     handler->settings.setMinimumFrameRate(framerate.maximumFrameRate); | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCamera::SetResolution(const Service::CAM::Resolution& resolution) { | ||||
|     width = resolution.width; | ||||
|     height = resolution.height; | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCamera::SetFlip(Service::CAM::Flip flip) { | ||||
|     using namespace Service::CAM; | ||||
|     flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse); | ||||
|     flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse); | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCamera::SetEffect(Service::CAM::Effect effect) { | ||||
|     if (effect != Service::CAM::Effect::None) { | ||||
|         NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::vector<u16> QtMultimediaCamera::ReceiveFrame() { | ||||
|     QMutexLocker locker(&handler->camera_surface.mutex); | ||||
|     return CameraUtil::ProcessImage(handler->camera_surface.current_frame, width, height, | ||||
|                                     output_rgb, flip_horizontal, flip_vertical); | ||||
| } | ||||
| 
 | ||||
| bool QtMultimediaCamera::IsPreviewAvailable() { | ||||
|     return handler->CameraAvailable(); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create( | ||||
|     const std::string& config) const { | ||||
|     return std::make_unique<QtMultimediaCamera>(config); | ||||
| } | ||||
| 
 | ||||
| std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> QtMultimediaCameraHandler::handlers; | ||||
| 
 | ||||
| std::array<bool, 3> QtMultimediaCameraHandler::status; | ||||
| 
 | ||||
| void QtMultimediaCameraHandler::Init() { | ||||
|     for (auto& handler : handlers) { | ||||
|         handler = std::make_shared<QtMultimediaCameraHandler>(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<QtMultimediaCameraHandler> QtMultimediaCameraHandler::GetHandler() { | ||||
|     for (int i = 0; i < handlers.size(); i++) { | ||||
|         if (!status[i]) { | ||||
|             NGLOG_INFO(Service_CAM, "Successfully got handler {}", i); | ||||
|             status[i] = true; | ||||
|             return handlers[i]; | ||||
|         } | ||||
|     } | ||||
|     NGLOG_CRITICAL(Service_CAM, "All handlers taken up"); | ||||
|     return nullptr; | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCameraHandler::ReleaseHandler( | ||||
|     const std::shared_ptr<Camera::QtMultimediaCameraHandler>& handler) { | ||||
|     for (int i = 0; i < handlers.size(); i++) { | ||||
|         if (handlers[i] == handler) { | ||||
|             NGLOG_INFO(Service_CAM, "Successfully released handler {}", i); | ||||
|             status[i] = false; | ||||
|             handlers[i]->started = false; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCameraHandler::CreateCamera(const std::string& camera_name) { | ||||
|     QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); | ||||
|     for (const QCameraInfo& cameraInfo : cameras) { | ||||
|         if (cameraInfo.deviceName().toStdString() == camera_name) | ||||
|             camera = std::make_unique<QCamera>(cameraInfo); | ||||
|     } | ||||
|     if (!camera) { // no cameras found, using default camera
 | ||||
|         camera = std::make_unique<QCamera>(); | ||||
|     } | ||||
|     settings.setMinimumFrameRate(30); | ||||
|     settings.setMaximumFrameRate(30); | ||||
|     camera->setViewfinder(&camera_surface); | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCameraHandler::StopCamera() { | ||||
|     camera->stop(); | ||||
|     started = false; | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCameraHandler::StartCamera() { | ||||
|     camera->setViewfinderSettings(settings); | ||||
|     camera->start(); | ||||
|     started = true; | ||||
| } | ||||
| 
 | ||||
| bool QtMultimediaCameraHandler::CameraAvailable() const { | ||||
|     return camera && camera->isAvailable(); | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCameraHandler::StopCameras() { | ||||
|     NGLOG_INFO(Service_CAM, "Stopping all cameras"); | ||||
|     for (auto& handler : handlers) { | ||||
|         if (handler && handler->started) { | ||||
|             handler->StopCamera(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCameraHandler::ResumeCameras() { | ||||
|     for (auto& handler : handlers) { | ||||
|         if (handler && handler->started) { | ||||
|             handler->StartCamera(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void QtMultimediaCameraHandler::ReleaseHandlers() { | ||||
|     StopCameras(); | ||||
|     NGLOG_INFO(Service_CAM, "Releasing all handlers"); | ||||
|     for (int i = 0; i < handlers.size(); i++) { | ||||
|         status[i] = false; | ||||
|         handlers[i]->started = false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace Camera
 | ||||
							
								
								
									
										105
									
								
								src/citra_qt/camera/qt_multimedia_camera.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/citra_qt/camera/qt_multimedia_camera.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,105 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <QAbstractVideoSurface> | ||||
| #include <QCamera> | ||||
| #include <QCameraViewfinderSettings> | ||||
| #include <QImage> | ||||
| #include <QMutex> | ||||
| #include "citra_qt/camera/camera_util.h" | ||||
| #include "citra_qt/camera/qt_camera_factory.h" | ||||
| #include "core/frontend/camera/interface.h" | ||||
| 
 | ||||
| class GMainWindow; | ||||
| 
 | ||||
| namespace Camera { | ||||
| 
 | ||||
| class QtCameraSurface final : public QAbstractVideoSurface { | ||||
| public: | ||||
|     QList<QVideoFrame::PixelFormat> supportedPixelFormats( | ||||
|         QAbstractVideoBuffer::HandleType) const override; | ||||
|     bool present(const QVideoFrame&) override; | ||||
| 
 | ||||
| private: | ||||
|     QMutex mutex; | ||||
|     QImage current_frame; | ||||
| 
 | ||||
|     friend class QtMultimediaCamera; // For access to current_frame
 | ||||
| }; | ||||
| 
 | ||||
| class QtMultimediaCameraHandler; | ||||
| 
 | ||||
| /// This class is only an interface. It just calls QtMultimediaCameraHandler.
 | ||||
| class QtMultimediaCamera final : public CameraInterface { | ||||
| public: | ||||
|     QtMultimediaCamera(const std::string& camera_name); | ||||
|     ~QtMultimediaCamera(); | ||||
|     void StartCapture() override; | ||||
|     void StopCapture() override; | ||||
|     void SetResolution(const Service::CAM::Resolution&) override; | ||||
|     void SetFlip(Service::CAM::Flip) override; | ||||
|     void SetEffect(Service::CAM::Effect) override; | ||||
|     void SetFormat(Service::CAM::OutputFormat) override; | ||||
|     void SetFrameRate(Service::CAM::FrameRate frame_rate) override; | ||||
|     std::vector<u16> ReceiveFrame() override; | ||||
|     bool IsPreviewAvailable() override; | ||||
| 
 | ||||
| private: | ||||
|     std::shared_ptr<QtMultimediaCameraHandler> handler; | ||||
|     int width, height; | ||||
|     bool output_rgb; | ||||
|     bool flip_horizontal, flip_vertical; | ||||
| }; | ||||
| 
 | ||||
| class QtMultimediaCameraFactory final : public QtCameraFactory { | ||||
| public: | ||||
|     std::unique_ptr<CameraInterface> Create(const std::string& config) const override; | ||||
| }; | ||||
| 
 | ||||
| class QtMultimediaCameraHandler final : public QObject { | ||||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     /// Creates the global handler. Must be called in UI thread.
 | ||||
|     static void Init(); | ||||
|     static std::shared_ptr<QtMultimediaCameraHandler> GetHandler(); | ||||
|     static void ReleaseHandler(const std::shared_ptr<QtMultimediaCameraHandler>& handler); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Creates the camera. | ||||
|      * Note: This function must be called via QMetaObject::invokeMethod in UI thread. | ||||
|      */ | ||||
|     Q_INVOKABLE void CreateCamera(const std::string& camera_name); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Starts the camera. | ||||
|      * Note: This function must be called via QMetaObject::invokeMethod in UI thread when | ||||
|      *       starting the camera for the first time. 'Resume' calls can be in other threads. | ||||
|      */ | ||||
|     Q_INVOKABLE void StartCamera(); | ||||
| 
 | ||||
|     void StopCamera(); | ||||
|     bool CameraAvailable() const; | ||||
|     static void StopCameras(); | ||||
|     static void ResumeCameras(); | ||||
|     static void ReleaseHandlers(); | ||||
| 
 | ||||
| private: | ||||
|     std::unique_ptr<QCamera> camera; | ||||
|     QtCameraSurface camera_surface{}; | ||||
|     QCameraViewfinderSettings settings; | ||||
|     bool started = false; | ||||
| 
 | ||||
|     static std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> handlers; | ||||
|     static std::array<bool, 3> status; | ||||
| 
 | ||||
|     friend class QtMultimediaCamera; // For access to camera_surface (and camera)
 | ||||
| }; | ||||
| 
 | ||||
| } // namespace Camera
 | ||||
							
								
								
									
										73
									
								
								src/citra_qt/camera/still_image_camera.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/citra_qt/camera/still_image_camera.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <QFileDialog> | ||||
| #include <QImageReader> | ||||
| #include <QMessageBox> | ||||
| #include "citra_qt/camera/still_image_camera.h" | ||||
| 
 | ||||
| namespace Camera { | ||||
| 
 | ||||
| StillImageCamera::StillImageCamera(QImage image_) : image(std::move(image_)) {} | ||||
| 
 | ||||
| void StillImageCamera::StartCapture() {} | ||||
| 
 | ||||
| void StillImageCamera::StopCapture() {} | ||||
| 
 | ||||
| void StillImageCamera::SetFormat(Service::CAM::OutputFormat output_format) { | ||||
|     output_rgb = output_format == Service::CAM::OutputFormat::RGB565; | ||||
| } | ||||
| 
 | ||||
| void StillImageCamera::SetResolution(const Service::CAM::Resolution& resolution) { | ||||
|     width = resolution.width; | ||||
|     height = resolution.height; | ||||
| } | ||||
| 
 | ||||
| void StillImageCamera::SetFlip(Service::CAM::Flip flip) { | ||||
|     using namespace Service::CAM; | ||||
|     flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse); | ||||
|     flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse); | ||||
| } | ||||
| 
 | ||||
| void StillImageCamera::SetEffect(Service::CAM::Effect effect) { | ||||
|     if (effect != Service::CAM::Effect::None) { | ||||
|         NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| std::vector<u16> StillImageCamera::ReceiveFrame() { | ||||
|     return CameraUtil::ProcessImage(image, width, height, output_rgb, flip_horizontal, | ||||
|                                     flip_vertical); | ||||
| } | ||||
| 
 | ||||
| bool StillImageCamera::IsPreviewAvailable() { | ||||
|     return !image.isNull(); | ||||
| } | ||||
| 
 | ||||
| const std::string StillImageCameraFactory::getFilePath() { | ||||
|     QList<QByteArray> types = QImageReader::supportedImageFormats(); | ||||
|     QList<QString> temp_filters; | ||||
|     for (QByteArray type : types) { | ||||
|         temp_filters << QString("*." + QString(type)); | ||||
|     } | ||||
| 
 | ||||
|     QString filter = QObject::tr("Supported image files (") + temp_filters.join(" ") + ")"; | ||||
| 
 | ||||
|     return QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter) | ||||
|         .toStdString(); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config) const { | ||||
|     std::string real_config = config; | ||||
|     if (config.empty()) { | ||||
|         real_config = getFilePath(); | ||||
|     } | ||||
|     QImage image(QString::fromStdString(real_config)); | ||||
|     if (image.isNull()) { | ||||
|         NGLOG_ERROR(Service_CAM, "Couldn't load image \"{}\"", real_config.c_str()); | ||||
|     } | ||||
|     return std::make_unique<StillImageCamera>(image); | ||||
| } | ||||
| 
 | ||||
| } // namespace Camera
 | ||||
							
								
								
									
										43
									
								
								src/citra_qt/camera/still_image_camera.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/citra_qt/camera/still_image_camera.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| // Copyright 2018 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <QImage> | ||||
| #include "citra_qt/camera/camera_util.h" | ||||
| #include "citra_qt/camera/qt_camera_factory.h" | ||||
| #include "core/frontend/camera/interface.h" | ||||
| 
 | ||||
| namespace Camera { | ||||
| 
 | ||||
| class StillImageCamera final : public CameraInterface { | ||||
| public: | ||||
|     StillImageCamera(QImage image); | ||||
|     void StartCapture() override; | ||||
|     void StopCapture() override; | ||||
|     void SetResolution(const Service::CAM::Resolution&) override; | ||||
|     void SetFlip(Service::CAM::Flip) override; | ||||
|     void SetEffect(Service::CAM::Effect) override; | ||||
|     void SetFormat(Service::CAM::OutputFormat) override; | ||||
|     void SetFrameRate(Service::CAM::FrameRate frame_rate) override {} | ||||
|     std::vector<u16> ReceiveFrame() override; | ||||
|     bool IsPreviewAvailable() override; | ||||
| 
 | ||||
| private: | ||||
|     QImage image; | ||||
|     int width, height; | ||||
|     bool output_rgb; | ||||
|     bool flip_horizontal, flip_vertical; | ||||
| }; | ||||
| 
 | ||||
| class StillImageCameraFactory final : public QtCameraFactory { | ||||
| public: | ||||
|     std::unique_ptr<CameraInterface> Create(const std::string& config) const override; | ||||
| 
 | ||||
| private: | ||||
|     static const std::string getFilePath(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace Camera
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue