summaryrefslogtreecommitdiffstats
path: root/src/plugins/android/src
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/android/src')
-rw-r--r--src/plugins/android/src/common/common.pri3
-rw-r--r--src/plugins/android/src/common/qandroidmultimediautils.cpp586
-rw-r--r--src/plugins/android/src/common/qandroidmultimediautils.h4
-rw-r--r--src/plugins/android/src/common/qandroidvideooutput.cpp (renamed from src/plugins/android/src/common/qandroidvideorendercontrol.cpp)83
-rw-r--r--src/plugins/android/src/common/qandroidvideooutput.h64
-rw-r--r--src/plugins/android/src/mediacapture/mediacapture.pri6
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.cpp143
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.h20
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.cpp275
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.h (renamed from src/plugins/android/src/common/qandroidvideorendercontrol.h)78
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp6
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcaptureservice.h4
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.cpp27
-rw-r--r--src/plugins/android/src/mediaplayer/mediaplayer.pri6
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp4
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h2
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp70
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.h62
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp10
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaservice.h3
-rw-r--r--src/plugins/android/src/qandroidmediaserviceplugin.cpp4
-rw-r--r--src/plugins/android/src/wrappers/jni/androidcamera.cpp168
-rw-r--r--src/plugins/android/src/wrappers/jni/androidcamera.h12
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp37
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediarecorder.h5
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp20
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfacetexture.h4
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfaceview.cpp204
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfaceview.h101
-rw-r--r--src/plugins/android/src/wrappers/jni/jni.pri8
30 files changed, 1188 insertions, 831 deletions
diff --git a/src/plugins/android/src/common/common.pri b/src/plugins/android/src/common/common.pri
index f99dad507..9c741bd94 100644
--- a/src/plugins/android/src/common/common.pri
+++ b/src/plugins/android/src/common/common.pri
@@ -2,9 +2,8 @@ INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/qandroidvideooutput.h \
- $$PWD/qandroidvideorendercontrol.h \
$$PWD/qandroidmultimediautils.h
SOURCES += \
- $$PWD/qandroidvideorendercontrol.cpp \
+ $$PWD/qandroidvideooutput.cpp \
$$PWD/qandroidmultimediautils.cpp
diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp
index a41cc0e1b..6b6ca3255 100644
--- a/src/plugins/android/src/common/qandroidmultimediautils.cpp
+++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp
@@ -68,563 +68,39 @@ bool qt_sizeLessThan(const QSize &s1, const QSize &s2)
return s1.width() * s1.height() < s2.width() * s2.height();
}
-// Pre-computed Y coefficients for all possible y values (0-255). Stored as fixed-point (16:16)
-// Y = 1.164 * (y - 16)
-static const int coefficientsY[256] = {
- -593888, -555746, -517604, -479462, -441320, -403178, -365036, -326894, -288752, -250610,
- -212468, -174326, -136184, -98042, -59900, -21758, 16384, 54526, 92668, 130810,
- 168952, 207094, 245236, 283378, 321520, 359662, 397804, 435946, 474088, 512230,
- 550372, 588514, 626656, 664798, 702940, 741082, 779224, 817366, 855508, 893650,
- 931792, 969934, 1008076, 1046218, 1084360, 1122502, 1160644, 1198786, 1236928, 1275070,
- 1313212, 1351354, 1389496, 1427638, 1465780, 1503922, 1542064, 1580206, 1618348, 1656490,
- 1694632, 1732774, 1770916, 1809058, 1847200, 1885342, 1923484, 1961626, 1999768, 2037910,
- 2076052, 2114194, 2152336, 2190478, 2228620, 2266762, 2304904, 2343046, 2381188, 2419330,
- 2457472, 2495614, 2533756, 2571898, 2610040, 2648182, 2686324, 2724466, 2762608, 2800750,
- 2838892, 2877034, 2915176, 2953318, 2991460, 3029602, 3067744, 3105886, 3144028, 3182170,
- 3220312, 3258454, 3296596, 3334738, 3372880, 3411022, 3449164, 3487306, 3525448, 3563590,
- 3601732, 3639874, 3678016, 3716158, 3754300, 3792442, 3830584, 3868726, 3906868, 3945010,
- 3983152, 4021294, 4059436, 4097578, 4135720, 4173862, 4212004, 4250146, 4288288, 4326430,
- 4364572, 4402714, 4440856, 4478998, 4517140, 4555282, 4593424, 4631566, 4669708, 4707850,
- 4745992, 4784134, 4822276, 4860418, 4898560, 4936702, 4974844, 5012986, 5051128, 5089270,
- 5127412, 5165554, 5203696, 5241838, 5279980, 5318122, 5356264, 5394406, 5432548, 5470690,
- 5508832, 5546974, 5585116, 5623258, 5661400, 5699542, 5737684, 5775826, 5813968, 5852110,
- 5890252, 5928394, 5966536, 6004678, 6042820, 6080962, 6119104, 6157246, 6195388, 6233530,
- 6271672, 6309814, 6347956, 6386098, 6424240, 6462382, 6500524, 6538666, 6576808, 6614950,
- 6653092, 6691234, 6729376, 6767518, 6805660, 6843802, 6881944, 6920086, 6958228, 6996370,
- 7034512, 7072654, 7110796, 7148938, 7187080, 7225222, 7263364, 7301506, 7339648, 7377790,
- 7415932, 7454074, 7492216, 7530358, 7568500, 7606642, 7644784, 7682926, 7721068, 7759210,
- 7797352, 7835494, 7873636, 7911778, 7949920, 7988062, 8026204, 8064346, 8102488, 8140630,
- 8178772, 8216914, 8255056, 8293198, 8331340, 8369482, 8407624, 8445766, 8483908, 8522050,
- 8560192, 8598334, 8636476, 8674618, 8712760, 8750902, 8789044, 8827186, 8865328, 8903470,
- 8941612, 8979754, 9017896, 9056038, 9094180, 9132322
-};
-
-// V lookup table for the Red component. Stored as fixed-point (16:16).
-// V = 1.596 * (v - 128)
-static const int coefficientsRV[256] = {
- -6694144, -6641846, -6589548, -6537250, -6484952, -6432654, -6380356, -6328058, -6275760,
- -6223462, -6171164, -6118866, -6066568, -6014270, -5961972, -5909674, -5857376, -5805078,
- -5752780, -5700482, -5648184, -5595886, -5543588, -5491290, -5438992, -5386694, -5334396,
- -5282098, -5229800, -5177502, -5125204, -5072906, -5020608, -4968310, -4916012, -4863714,
- -4811416, -4759118, -4706820, -4654522, -4602224, -4549926, -4497628, -4445330, -4393032,
- -4340734, -4288436, -4236138, -4183840, -4131542, -4079244, -4026946, -3974648, -3922350,
- -3870052, -3817754, -3765456, -3713158, -3660860, -3608562, -3556264, -3503966, -3451668,
- -3399370, -3347072, -3294774, -3242476, -3190178, -3137880, -3085582, -3033284, -2980986,
- -2928688, -2876390, -2824092, -2771794, -2719496, -2667198, -2614900, -2562602, -2510304,
- -2458006, -2405708, -2353410, -2301112, -2248814, -2196516, -2144218, -2091920, -2039622,
- -1987324, -1935026, -1882728, -1830430, -1778132, -1725834, -1673536, -1621238, -1568940,
- -1516642, -1464344, -1412046, -1359748, -1307450, -1255152, -1202854, -1150556, -1098258,
- -1045960, -993662, -941364, -889066, -836768, -784470, -732172, -679874, -627576,
- -575278, -522980, -470682, -418384, -366086, -313788, -261490, -209192, -156894,
- -104596, -52298, 0, 52298, 104596, 156894, 209192, 261490, 313788,
- 366086, 418384, 470682, 522980, 575278, 627576, 679874, 732172, 784470,
- 836768, 889066, 941364, 993662, 1045960, 1098258, 1150556, 1202854, 1255152,
- 1307450, 1359748, 1412046, 1464344, 1516642, 1568940, 1621238, 1673536, 1725834,
- 1778132, 1830430, 1882728, 1935026, 1987324, 2039622, 2091920, 2144218, 2196516,
- 2248814, 2301112, 2353410, 2405708, 2458006, 2510304, 2562602, 2614900, 2667198,
- 2719496, 2771794, 2824092, 2876390, 2928688, 2980986, 3033284, 3085582, 3137880,
- 3190178, 3242476, 3294774, 3347072, 3399370, 3451668, 3503966, 3556264, 3608562,
- 3660860, 3713158, 3765456, 3817754, 3870052, 3922350, 3974648, 4026946, 4079244,
- 4131542, 4183840, 4236138, 4288436, 4340734, 4393032, 4445330, 4497628, 4549926,
- 4602224, 4654522, 4706820, 4759118, 4811416, 4863714, 4916012, 4968310, 5020608,
- 5072906, 5125204, 5177502, 5229800, 5282098, 5334396, 5386694, 5438992, 5491290,
- 5543588, 5595886, 5648184, 5700482, 5752780, 5805078, 5857376, 5909674, 5961972,
- 6014270, 6066568, 6118866, 6171164, 6223462, 6275760, 6328058, 6380356, 6432654,
- 6484952, 6537250, 6589548, 6641846
-};
-
-// U lookup table for the Green component. Stored as fixed-point (16:16).
-// U = 0.391 * (u - 128)
-static const int coefficientsGU[256] = {
- 1639936, 1627124, 1614312, 1601500, 1588688, 1575876, 1563064, 1550252, 1537440,
- 1524628, 1511816, 1499004, 1486192, 1473380, 1460568, 1447756, 1434944, 1422132,
- 1409320, 1396508, 1383696, 1370884, 1358072, 1345260, 1332448, 1319636, 1306824,
- 1294012, 1281200, 1268388, 1255576, 1242764, 1229952, 1217140, 1204328, 1191516,
- 1178704, 1165892, 1153080, 1140268, 1127456, 1114644, 1101832, 1089020, 1076208,
- 1063396, 1050584, 1037772, 1024960, 1012148, 999336, 986524, 973712, 960900,
- 948088, 935276, 922464, 909652, 896840, 884028, 871216, 858404, 845592,
- 832780, 819968, 807156, 794344, 781532, 768720, 755908, 743096, 730284,
- 717472, 704660, 691848, 679036, 666224, 653412, 640600, 627788, 614976,
- 602164, 589352, 576540, 563728, 550916, 538104, 525292, 512480, 499668,
- 486856, 474044, 461232, 448420, 435608, 422796, 409984, 397172, 384360,
- 371548, 358736, 345924, 333112, 320300, 307488, 294676, 281864, 269052,
- 256240, 243428, 230616, 217804, 204992, 192180, 179368, 166556, 153744,
- 140932, 128120, 115308, 102496, 89684, 76872, 64060, 51248, 38436,
- 25624, 12812, 0, -12812, -25624, -38436, -51248, -64060, -76872,
- -89684, -102496, -115308, -128120, -140932, -153744, -166556, -179368, -192180,
- -204992, -217804, -230616, -243428, -256240, -269052, -281864, -294676, -307488,
- -320300, -333112, -345924, -358736, -371548, -384360, -397172, -409984, -422796,
- -435608, -448420, -461232, -474044, -486856, -499668, -512480, -525292, -538104,
- -550916, -563728, -576540, -589352, -602164, -614976, -627788, -640600, -653412,
- -666224, -679036, -691848, -704660, -717472, -730284, -743096, -755908, -768720,
- -781532, -794344, -807156, -819968, -832780, -845592, -858404, -871216, -884028,
- -896840, -909652, -922464, -935276, -948088, -960900, -973712, -986524, -999336,
- -1012148, -1024960, -1037772, -1050584, -1063396, -1076208, -1089020, -1101832, -1114644,
- -1127456, -1140268, -1153080, -1165892, -1178704, -1191516, -1204328, -1217140, -1229952,
- -1242764, -1255576, -1268388, -1281200, -1294012, -1306824, -1319636, -1332448, -1345260,
- -1358072, -1370884, -1383696, -1396508, -1409320, -1422132, -1434944, -1447756, -1460568,
- -1473380, -1486192, -1499004, -1511816, -1524628, -1537440, -1550252, -1563064, -1575876,
- -1588688, -1601500, -1614312, -1627124
-};
-
-// V lookup table for the Green component. Stored as fixed-point (16:16).
-// V = 0.813 * (v - 128)
-static const int coefficientsGV[256] = {
- 3409920, 3383280, 3356640, 3330000, 3303360, 3276720, 3250080, 3223440, 3196800,
- 3170160, 3143520, 3116880, 3090240, 3063600, 3036960, 3010320, 2983680, 2957040,
- 2930400, 2903760, 2877120, 2850480, 2823840, 2797200, 2770560, 2743920, 2717280,
- 2690640, 2664000, 2637360, 2610720, 2584080, 2557440, 2530800, 2504160, 2477520,
- 2450880, 2424240, 2397600, 2370960, 2344320, 2317680, 2291040, 2264400, 2237760,
- 2211120, 2184480, 2157840, 2131200, 2104560, 2077920, 2051280, 2024640, 1998000,
- 1971360, 1944720, 1918080, 1891440, 1864800, 1838160, 1811520, 1784880, 1758240,
- 1731600, 1704960, 1678320, 1651680, 1625040, 1598400, 1571760, 1545120, 1518480,
- 1491840, 1465200, 1438560, 1411920, 1385280, 1358640, 1332000, 1305360, 1278720,
- 1252080, 1225440, 1198800, 1172160, 1145520, 1118880, 1092240, 1065600, 1038960,
- 1012320, 985680, 959040, 932400, 905760, 879120, 852480, 825840, 799200,
- 772560, 745920, 719280, 692640, 666000, 639360, 612720, 586080, 559440,
- 532800, 506160, 479520, 452880, 426240, 399600, 372960, 346320, 319680,
- 293040, 266400, 239760, 213120, 186480, 159840, 133200, 106560, 79920,
- 53280, 26640, 0, -26640, -53280, -79920, -106560, -133200, -159840,
- -186480, -213120, -239760, -266400, -293040, -319680, -346320, -372960, -399600,
- -426240, -452880, -479520, -506160, -532800, -559440, -586080, -612720, -639360,
- -666000, -692640, -719280, -745920, -772560, -799200, -825840, -852480, -879120,
- -905760, -932400, -959040, -985680, -1012320, -1038960, -1065600, -1092240, -1118880,
- -1145520, -1172160, -1198800, -1225440, -1252080, -1278720, -1305360, -1332000, -1358640,
- -1385280, -1411920, -1438560, -1465200, -1491840, -1518480, -1545120, -1571760, -1598400,
- -1625040, -1651680, -1678320, -1704960, -1731600, -1758240, -1784880, -1811520, -1838160,
- -1864800, -1891440, -1918080, -1944720, -1971360, -1998000, -2024640, -2051280, -2077920,
- -2104560, -2131200, -2157840, -2184480, -2211120, -2237760, -2264400, -2291040, -2317680,
- -2344320, -2370960, -2397600, -2424240, -2450880, -2477520, -2504160, -2530800, -2557440,
- -2584080, -2610720, -2637360, -2664000, -2690640, -2717280, -2743920, -2770560, -2797200,
- -2823840, -2850480, -2877120, -2903760, -2930400, -2957040, -2983680, -3010320, -3036960,
- -3063600, -3090240, -3116880, -3143520, -3170160, -3196800, -3223440, -3250080, -3276720,
- -3303360, -3330000, -3356640, -3383280
-};
-
-// U lookup table for the Blue component. Stored as fixed-point (16:16).
-// U = 2.018 * (u - 128)
-static const int coefficientsBU[256] = {
- -8464128, -8398002, -8331876, -8265750, -8199624, -8133498, -8067372, -8001246, -7935120,
- -7868994, -7802868, -7736742, -7670616, -7604490, -7538364, -7472238, -7406112, -7339986,
- -7273860, -7207734, -7141608, -7075482, -7009356, -6943230, -6877104, -6810978, -6744852,
- -6678726, -6612600, -6546474, -6480348, -6414222, -6348096, -6281970, -6215844, -6149718,
- -6083592, -6017466, -5951340, -5885214, -5819088, -5752962, -5686836, -5620710, -5554584,
- -5488458, -5422332, -5356206, -5290080, -5223954, -5157828, -5091702, -5025576, -4959450,
- -4893324, -4827198, -4761072, -4694946, -4628820, -4562694, -4496568, -4430442, -4364316,
- -4298190, -4232064, -4165938, -4099812, -4033686, -3967560, -3901434, -3835308, -3769182,
- -3703056, -3636930, -3570804, -3504678, -3438552, -3372426, -3306300, -3240174, -3174048,
- -3107922, -3041796, -2975670, -2909544, -2843418, -2777292, -2711166, -2645040, -2578914,
- -2512788, -2446662, -2380536, -2314410, -2248284, -2182158, -2116032, -2049906, -1983780,
- -1917654, -1851528, -1785402, -1719276, -1653150, -1587024, -1520898, -1454772, -1388646,
- -1322520, -1256394, -1190268, -1124142, -1058016, -991890, -925764, -859638, -793512,
- -727386, -661260, -595134, -529008, -462882, -396756, -330630, -264504, -198378,
- -132252, -66126, 0, 66126, 132252, 198378, 264504, 330630, 396756,
- 462882, 529008, 595134, 661260, 727386, 793512, 859638, 925764, 991890,
- 1058016, 1124142, 1190268, 1256394, 1322520, 1388646, 1454772, 1520898, 1587024,
- 1653150, 1719276, 1785402, 1851528, 1917654, 1983780, 2049906, 2116032, 2182158,
- 2248284, 2314410, 2380536, 2446662, 2512788, 2578914, 2645040, 2711166, 2777292,
- 2843418, 2909544, 2975670, 3041796, 3107922, 3174048, 3240174, 3306300, 3372426,
- 3438552, 3504678, 3570804, 3636930, 3703056, 3769182, 3835308, 3901434, 3967560,
- 4033686, 4099812, 4165938, 4232064, 4298190, 4364316, 4430442, 4496568, 4562694,
- 4628820, 4694946, 4761072, 4827198, 4893324, 4959450, 5025576, 5091702, 5157828,
- 5223954, 5290080, 5356206, 5422332, 5488458, 5554584, 5620710, 5686836, 5752962,
- 5819088, 5885214, 5951340, 6017466, 6083592, 6149718, 6215844, 6281970, 6348096,
- 6414222, 6480348, 6546474, 6612600, 6678726, 6744852, 6810978, 6877104, 6943230,
- 7009356, 7075482, 7141608, 7207734, 7273860, 7339986, 7406112, 7472238, 7538364,
- 7604490, 7670616, 7736742, 7802868, 7868994, 7935120, 8001246, 8067372, 8133498,
- 8199624, 8265750, 8331876, 8398002
-};
-
-// R = min(max(r, 0), 255) << 16
-// where 'r' is the converted red component from YUV, which is always in the range -320 <= r < 704
-// and needs to be clamped to 0-255. It also precomputes the bitshift needed to create an RGB value.
-static const quint32 _clampedR[1024] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 65536, 131072, 196608, 262144, 327680, 393216, 458752,
- 524288, 589824, 655360, 720896, 786432, 851968, 917504, 983040,
- 1048576, 1114112, 1179648, 1245184, 1310720, 1376256, 1441792, 1507328,
- 1572864, 1638400, 1703936, 1769472, 1835008, 1900544, 1966080, 2031616,
- 2097152, 2162688, 2228224, 2293760, 2359296, 2424832, 2490368, 2555904,
- 2621440, 2686976, 2752512, 2818048, 2883584, 2949120, 3014656, 3080192,
- 3145728, 3211264, 3276800, 3342336, 3407872, 3473408, 3538944, 3604480,
- 3670016, 3735552, 3801088, 3866624, 3932160, 3997696, 4063232, 4128768,
- 4194304, 4259840, 4325376, 4390912, 4456448, 4521984, 4587520, 4653056,
- 4718592, 4784128, 4849664, 4915200, 4980736, 5046272, 5111808, 5177344,
- 5242880, 5308416, 5373952, 5439488, 5505024, 5570560, 5636096, 5701632,
- 5767168, 5832704, 5898240, 5963776, 6029312, 6094848, 6160384, 6225920,
- 6291456, 6356992, 6422528, 6488064, 6553600, 6619136, 6684672, 6750208,
- 6815744, 6881280, 6946816, 7012352, 7077888, 7143424, 7208960, 7274496,
- 7340032, 7405568, 7471104, 7536640, 7602176, 7667712, 7733248, 7798784,
- 7864320, 7929856, 7995392, 8060928, 8126464, 8192000, 8257536, 8323072,
- 8388608, 8454144, 8519680, 8585216, 8650752, 8716288, 8781824, 8847360,
- 8912896, 8978432, 9043968, 9109504, 9175040, 9240576, 9306112, 9371648,
- 9437184, 9502720, 9568256, 9633792, 9699328, 9764864, 9830400, 9895936,
- 9961472, 10027008, 10092544, 10158080, 10223616, 10289152, 10354688, 10420224,
- 10485760, 10551296, 10616832, 10682368, 10747904, 10813440, 10878976, 10944512,
- 11010048, 11075584, 11141120, 11206656, 11272192, 11337728, 11403264, 11468800,
- 11534336, 11599872, 11665408, 11730944, 11796480, 11862016, 11927552, 11993088,
- 12058624, 12124160, 12189696, 12255232, 12320768, 12386304, 12451840, 12517376,
- 12582912, 12648448, 12713984, 12779520, 12845056, 12910592, 12976128, 13041664,
- 13107200, 13172736, 13238272, 13303808, 13369344, 13434880, 13500416, 13565952,
- 13631488, 13697024, 13762560, 13828096, 13893632, 13959168, 14024704, 14090240,
- 14155776, 14221312, 14286848, 14352384, 14417920, 14483456, 14548992, 14614528,
- 14680064, 14745600, 14811136, 14876672, 14942208, 15007744, 15073280, 15138816,
- 15204352, 15269888, 15335424, 15400960, 15466496, 15532032, 15597568, 15663104,
- 15728640, 15794176, 15859712, 15925248, 15990784, 16056320, 16121856, 16187392,
- 16252928, 16318464, 16384000, 16449536, 16515072, 16580608, 16646144, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680,
- 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680, 16711680
-};
-
-// G = min(max(g, 0), 255) << 8
-// where 'g' is the converted green component from YUV, which is always in the range -320 <= r < 704
-// and needs to be clamped to 0-255. It also precomputes the bitshift needed to create an RGB value.
-static const quint32 _clampedG[1024] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 256, 512, 768, 1024, 1280, 1536, 1792,
- 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840,
- 4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888,
- 6144, 6400, 6656, 6912, 7168, 7424, 7680, 7936,
- 8192, 8448, 8704, 8960, 9216, 9472, 9728, 9984,
- 10240, 10496, 10752, 11008, 11264, 11520, 11776, 12032,
- 12288, 12544, 12800, 13056, 13312, 13568, 13824, 14080,
- 14336, 14592, 14848, 15104, 15360, 15616, 15872, 16128,
- 16384, 16640, 16896, 17152, 17408, 17664, 17920, 18176,
- 18432, 18688, 18944, 19200, 19456, 19712, 19968, 20224,
- 20480, 20736, 20992, 21248, 21504, 21760, 22016, 22272,
- 22528, 22784, 23040, 23296, 23552, 23808, 24064, 24320,
- 24576, 24832, 25088, 25344, 25600, 25856, 26112, 26368,
- 26624, 26880, 27136, 27392, 27648, 27904, 28160, 28416,
- 28672, 28928, 29184, 29440, 29696, 29952, 30208, 30464,
- 30720, 30976, 31232, 31488, 31744, 32000, 32256, 32512,
- 32768, 33024, 33280, 33536, 33792, 34048, 34304, 34560,
- 34816, 35072, 35328, 35584, 35840, 36096, 36352, 36608,
- 36864, 37120, 37376, 37632, 37888, 38144, 38400, 38656,
- 38912, 39168, 39424, 39680, 39936, 40192, 40448, 40704,
- 40960, 41216, 41472, 41728, 41984, 42240, 42496, 42752,
- 43008, 43264, 43520, 43776, 44032, 44288, 44544, 44800,
- 45056, 45312, 45568, 45824, 46080, 46336, 46592, 46848,
- 47104, 47360, 47616, 47872, 48128, 48384, 48640, 48896,
- 49152, 49408, 49664, 49920, 50176, 50432, 50688, 50944,
- 51200, 51456, 51712, 51968, 52224, 52480, 52736, 52992,
- 53248, 53504, 53760, 54016, 54272, 54528, 54784, 55040,
- 55296, 55552, 55808, 56064, 56320, 56576, 56832, 57088,
- 57344, 57600, 57856, 58112, 58368, 58624, 58880, 59136,
- 59392, 59648, 59904, 60160, 60416, 60672, 60928, 61184,
- 61440, 61696, 61952, 62208, 62464, 62720, 62976, 63232,
- 63488, 63744, 64000, 64256, 64512, 64768, 65024, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280,
- 65280, 65280, 65280, 65280, 65280, 65280, 65280, 65280
-};
-
-// B = min(max(b, 0), 255)
-// where 'b' is the converted blue component from YUV, which is always in the range -320 <= r < 704
-static const quint32 _clampedB[1024] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
- 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
- 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
- 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
- 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
- 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
- 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
- 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
- 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
- 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
- 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
-};
-
-static const quint32 *clampedR = _clampedR + 320;
-static const quint32 *clampedG = _clampedG + 320;
-static const quint32 *clampedB = _clampedB + 320;
-
-#define MAKE_RGB(r, g, b) 0xff000000 | clampedR[r] | clampedG[g] | clampedB[b]
-
-void qt_convert_NV21_to_ARGB32(const uchar *yuv, quint32 *rgb, int width, int height)
+QVideoFrame::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat f)
{
- const uchar *y0 = yuv;
- const uchar *y1 = yuv + width;
- const uchar *vu = yuv + width * height;
-
- quint32 *rgb0 = rgb;
- quint32 *rgb1 = rgb + width;
-
- for (int i = 0; i < height; i += 2) {
- for (int j = 0; j < width; j += 2) {
- int v = *vu++;
- int u = *vu++;
-
- int ruv = coefficientsRV[v] >> 15;
- int guv = (coefficientsGU[u] + coefficientsGV[v]) >> 15;
- int buv = coefficientsBU[u] >> 15;
-
- int y = coefficientsY[*y0++] >> 15;
- int r = y + ruv;
- int g = y + guv;
- int b = y + buv;
- *rgb0++ = MAKE_RGB(r, g, b);
-
- y = coefficientsY[*y0++] >> 15;
- r = y + ruv;
- g = y + guv;
- b = y + buv;
- *rgb0++ = MAKE_RGB(r, g, b);
-
- y = coefficientsY[*y1++] >> 15;
- r = y + ruv;
- g = y + guv;
- b = y + buv;
- *rgb1++ = MAKE_RGB(r, g, b);
-
- y = coefficientsY[*y1++] >> 15;
- r = y + ruv;
- g = y + guv;
- b = y + buv;
- *rgb1++ = MAKE_RGB(r, g, b);
- }
+ switch (f) {
+ case AndroidCamera::NV21:
+ return QVideoFrame::Format_NV21;
+ case AndroidCamera::YV12:
+ return QVideoFrame::Format_YV12;
+ case AndroidCamera::RGB565:
+ return QVideoFrame::Format_RGB565;
+ case AndroidCamera::YUY2:
+ return QVideoFrame::Format_YUYV;
+ case AndroidCamera::JPEG:
+ return QVideoFrame::Format_Jpeg;
+ default:
+ return QVideoFrame::Format_Invalid;
+ }
+}
- rgb0 += width;
- rgb1 += width;
- y0 += width;
- y1 += width;
+AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::PixelFormat f)
+{
+ switch (f) {
+ case QVideoFrame::Format_NV21:
+ return AndroidCamera::NV21;
+ case QVideoFrame::Format_YV12:
+ return AndroidCamera::YV12;
+ case QVideoFrame::Format_RGB565:
+ return AndroidCamera::RGB565;
+ case QVideoFrame::Format_YUYV:
+ return AndroidCamera::YUY2;
+ case QVideoFrame::Format_Jpeg:
+ return AndroidCamera::JPEG;
+ default:
+ return AndroidCamera::UnknownImageFormat;
}
}
diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h
index ea6a322e7..622f343f5 100644
--- a/src/plugins/android/src/common/qandroidmultimediautils.h
+++ b/src/plugins/android/src/common/qandroidmultimediautils.h
@@ -36,6 +36,7 @@
#include <qglobal.h>
#include <qsize.h>
+#include "androidcamera.h"
QT_BEGIN_NAMESPACE
@@ -45,7 +46,8 @@ int qt_findClosestValue(const QList<int> &list, int value);
bool qt_sizeLessThan(const QSize &s1, const QSize &s2);
-void qt_convert_NV21_to_ARGB32(const uchar *yuv, quint32 *rgb, int width, int height);
+QVideoFrame::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat f);
+AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::PixelFormat f);
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/common/qandroidvideorendercontrol.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp
index cd9c9d1d6..82c27035d 100644
--- a/src/plugins/android/src/common/qandroidvideorendercontrol.cpp
+++ b/src/plugins/android/src/common/qandroidvideooutput.cpp
@@ -31,9 +31,9 @@
**
****************************************************************************/
-#include "qandroidvideorendercontrol.h"
-#include "androidsurfacetexture.h"
+#include "qandroidvideooutput.h"
+#include "androidsurfacetexture.h"
#include <QAbstractVideoSurface>
#include <QVideoSurfaceFormat>
#include <qevent.h>
@@ -59,19 +59,13 @@ static const GLfloat g_texture_data[] = {
0.f, 1.f
};
-OpenGLResourcesDeleter::~OpenGLResourcesDeleter()
-{
- glDeleteTextures(1, &m_textureID);
- delete m_fbo;
- delete m_program;
-}
class AndroidTextureVideoBuffer : public QAbstractVideoBuffer
{
public:
- AndroidTextureVideoBuffer(QAndroidVideoRendererControl *control)
+ AndroidTextureVideoBuffer(QAndroidTextureVideoOutput *output)
: QAbstractVideoBuffer(GLTextureHandle)
- , m_control(control)
+ , m_output(output)
, m_textureUpdated(false)
, m_mapMode(NotMapped)
{
@@ -86,7 +80,7 @@ public:
if (m_mapMode == NotMapped && mode == ReadOnly) {
updateFrame();
m_mapMode = mode;
- m_image = m_control->m_fbo->toImage();
+ m_image = m_output->m_fbo->toImage();
if (numBytes)
*numBytes = m_image.byteCount();
@@ -110,7 +104,7 @@ public:
{
AndroidTextureVideoBuffer *that = const_cast<AndroidTextureVideoBuffer*>(this);
that->updateFrame();
- return m_control->m_fbo->texture();
+ return m_output->m_fbo->texture();
}
private:
@@ -118,19 +112,47 @@ private:
{
if (!m_textureUpdated) {
// update the video texture (called from the render thread)
- m_control->renderFrameToFbo();
+ m_output->renderFrameToFbo();
m_textureUpdated = true;
}
}
- QAndroidVideoRendererControl *m_control;
+ QAndroidTextureVideoOutput *m_output;
bool m_textureUpdated;
MapMode m_mapMode;
QImage m_image;
};
-QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
- : QVideoRendererControl(parent)
+
+class OpenGLResourcesDeleter : public QObject
+{
+public:
+ OpenGLResourcesDeleter()
+ : m_textureID(0)
+ , m_fbo(0)
+ , m_program(0)
+ { }
+
+ ~OpenGLResourcesDeleter()
+ {
+ glDeleteTextures(1, &m_textureID);
+ delete m_fbo;
+ delete m_program;
+ }
+
+ void setTexture(quint32 id) { m_textureID = id; }
+ void setFbo(QOpenGLFramebufferObject *fbo) { m_fbo = fbo; }
+ void setShaderProgram(QOpenGLShaderProgram *prog) { m_program = prog; }
+
+private:
+ quint32 m_textureID;
+ QOpenGLFramebufferObject *m_fbo;
+ QOpenGLShaderProgram *m_program;
+};
+
+
+QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent)
+ : QAndroidVideoOutput(parent)
, m_surface(0)
, m_surfaceTexture(0)
, m_externalTex(0)
@@ -138,9 +160,10 @@ QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
, m_program(0)
, m_glDeleter(0)
{
+
}
-QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
+QAndroidTextureVideoOutput::~QAndroidTextureVideoOutput()
{
clearSurfaceTexture();
@@ -148,12 +171,12 @@ QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
m_glDeleter->deleteLater();
}
-QAbstractVideoSurface *QAndroidVideoRendererControl::surface() const
+QAbstractVideoSurface *QAndroidTextureVideoOutput::surface() const
{
return m_surface;
}
-void QAndroidVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+void QAndroidTextureVideoOutput::setSurface(QAbstractVideoSurface *surface)
{
if (surface == m_surface)
return;
@@ -172,12 +195,12 @@ void QAndroidVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
}
}
-bool QAndroidVideoRendererControl::isReady()
+bool QAndroidTextureVideoOutput::isReady()
{
return QOpenGLContext::currentContext() || m_externalTex;
}
-bool QAndroidVideoRendererControl::initSurfaceTexture()
+bool QAndroidTextureVideoOutput::initSurfaceTexture()
{
if (m_surfaceTexture)
return true;
@@ -210,7 +233,7 @@ bool QAndroidVideoRendererControl::initSurfaceTexture()
return m_surfaceTexture != 0;
}
-void QAndroidVideoRendererControl::clearSurfaceTexture()
+void QAndroidTextureVideoOutput::clearSurfaceTexture()
{
if (m_surfaceTexture) {
delete m_surfaceTexture;
@@ -218,7 +241,7 @@ void QAndroidVideoRendererControl::clearSurfaceTexture()
}
}
-AndroidSurfaceTexture *QAndroidVideoRendererControl::surfaceTexture()
+AndroidSurfaceTexture *QAndroidTextureVideoOutput::surfaceTexture()
{
if (!initSurfaceTexture())
return 0;
@@ -226,7 +249,7 @@ AndroidSurfaceTexture *QAndroidVideoRendererControl::surfaceTexture()
return m_surfaceTexture;
}
-void QAndroidVideoRendererControl::setVideoSize(const QSize &size)
+void QAndroidTextureVideoOutput::setVideoSize(const QSize &size)
{
QMutexLocker locker(&m_mutex);
@@ -238,19 +261,19 @@ void QAndroidVideoRendererControl::setVideoSize(const QSize &size)
m_nativeSize = size;
}
-void QAndroidVideoRendererControl::stop()
+void QAndroidTextureVideoOutput::stop()
{
if (m_surface && m_surface->isActive())
m_surface->stop();
m_nativeSize = QSize();
}
-void QAndroidVideoRendererControl::reset()
+void QAndroidTextureVideoOutput::reset()
{
clearSurfaceTexture();
}
-void QAndroidVideoRendererControl::onFrameAvailable()
+void QAndroidTextureVideoOutput::onFrameAvailable()
{
if (!m_nativeSize.isValid() || !m_surface)
return;
@@ -274,7 +297,7 @@ void QAndroidVideoRendererControl::onFrameAvailable()
m_surface->present(frame);
}
-void QAndroidVideoRendererControl::renderFrameToFbo()
+void QAndroidTextureVideoOutput::renderFrameToFbo()
{
QMutexLocker locker(&m_mutex);
@@ -333,7 +356,7 @@ void QAndroidVideoRendererControl::renderFrameToFbo()
glEnable(GL_BLEND);
}
-void QAndroidVideoRendererControl::createGLResources()
+void QAndroidTextureVideoOutput::createGLResources()
{
if (!m_fbo || m_fbo->size() != m_nativeSize) {
delete m_fbo;
@@ -374,7 +397,7 @@ void QAndroidVideoRendererControl::createGLResources()
}
}
-void QAndroidVideoRendererControl::customEvent(QEvent *e)
+void QAndroidTextureVideoOutput::customEvent(QEvent *e)
{
if (e->type() == QEvent::User) {
// This is running in the render thread (OpenGL enabled)
diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h
index d45779d12..f4401fa1d 100644
--- a/src/plugins/android/src/common/qandroidvideooutput.h
+++ b/src/plugins/android/src/common/qandroidvideooutput.h
@@ -34,19 +34,27 @@
#ifndef QANDROIDVIDEOOUTPUT_H
#define QANDROIDVIDEOOUTPUT_H
-#include <qglobal.h>
+#include <qobject.h>
#include <qsize.h>
+#include <qmutex.h>
QT_BEGIN_NAMESPACE
class AndroidSurfaceTexture;
+class AndroidSurfaceHolder;
+class QOpenGLFramebufferObject;
+class QOpenGLShaderProgram;
+class OpenGLResourcesDeleter;
+class QAbstractVideoSurface;
-class QAndroidVideoOutput
+class QAndroidVideoOutput : public QObject
{
+ Q_OBJECT
public:
virtual ~QAndroidVideoOutput() { }
virtual AndroidSurfaceTexture *surfaceTexture() { return 0; }
+ virtual AndroidSurfaceHolder *surfaceHolder() { return 0; }
virtual bool isReady() { return true; }
@@ -54,12 +62,56 @@ public:
virtual void stop() { }
virtual void reset() { }
- // signals:
- // void readyChanged(bool);
+Q_SIGNALS:
+ void readyChanged(bool);
+
+protected:
+ QAndroidVideoOutput(QObject *parent) : QObject(parent) { }
};
-#define QAndroidVideoOutput_iid "org.qt-project.qt.qandroidvideooutput/5.0"
-Q_DECLARE_INTERFACE(QAndroidVideoOutput, QAndroidVideoOutput_iid)
+
+class QAndroidTextureVideoOutput : public QAndroidVideoOutput
+{
+ Q_OBJECT
+public:
+ explicit QAndroidTextureVideoOutput(QObject *parent = 0);
+ ~QAndroidTextureVideoOutput() Q_DECL_OVERRIDE;
+
+ QAbstractVideoSurface *surface() const;
+ void setSurface(QAbstractVideoSurface *surface);
+
+ AndroidSurfaceTexture *surfaceTexture() Q_DECL_OVERRIDE;
+
+ bool isReady() Q_DECL_OVERRIDE;
+ void setVideoSize(const QSize &) Q_DECL_OVERRIDE;
+ void stop() Q_DECL_OVERRIDE;
+ void reset() Q_DECL_OVERRIDE;
+
+ void customEvent(QEvent *) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void onFrameAvailable();
+
+private:
+ bool initSurfaceTexture();
+ void renderFrameToFbo();
+ void createGLResources();
+
+ QMutex m_mutex;
+ void clearSurfaceTexture();
+
+ QAbstractVideoSurface *m_surface;
+ QSize m_nativeSize;
+
+ AndroidSurfaceTexture *m_surfaceTexture;
+
+ quint32 m_externalTex;
+ QOpenGLFramebufferObject *m_fbo;
+ QOpenGLShaderProgram *m_program;
+ OpenGLResourcesDeleter *m_glDeleter;
+
+ friend class AndroidTextureVideoBuffer;
+};
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/mediacapture.pri b/src/plugins/android/src/mediacapture/mediacapture.pri
index fde0e3d6f..2811f0371 100644
--- a/src/plugins/android/src/mediacapture/mediacapture.pri
+++ b/src/plugins/android/src/mediacapture/mediacapture.pri
@@ -22,7 +22,8 @@ SOURCES += \
$$PWD/qandroidvideoencodersettingscontrol.cpp \
$$PWD/qandroidaudioinputselectorcontrol.cpp \
$$PWD/qandroidmediavideoprobecontrol.cpp \
- $$PWD/qandroidcamerainfocontrol.cpp
+ $$PWD/qandroidcamerainfocontrol.cpp \
+ $$PWD/qandroidcameravideorenderercontrol.cpp
HEADERS += \
$$PWD/qandroidcaptureservice.h \
@@ -46,4 +47,5 @@ HEADERS += \
$$PWD/qandroidvideoencodersettingscontrol.h \
$$PWD/qandroidaudioinputselectorcontrol.h \
$$PWD/qandroidmediavideoprobecontrol.h \
- $$PWD/qandroidcamerainfocontrol.h
+ $$PWD/qandroidcamerainfocontrol.h \
+ $$PWD/qandroidcameravideorenderercontrol.h
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
index 743764cb0..7b065c8c4 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
@@ -43,45 +43,11 @@
#include <qguiapplication.h>
#include <qdebug.h>
#include <qvideoframe.h>
+#include <private/qmemoryvideobuffer_p.h>
+#include <private/qvideoframe_p.h>
QT_BEGIN_NAMESPACE
-class DataVideoBuffer : public QAbstractVideoBuffer
-{
-public:
- DataVideoBuffer(const QByteArray &d, int bpl = -1)
- : QAbstractVideoBuffer(NoHandle)
- , data(d)
- , mode(NotMapped)
- , bytesPerLine(bpl)
- { }
-
- MapMode mapMode() const { return mode; }
-
- uchar *map(MapMode m, int *numBytes, int *bpl)
- {
- if (mode != NotMapped || m == NotMapped)
- return 0;
-
- mode = m;
-
- if (numBytes)
- *numBytes = data.size();
-
- if (bpl)
- *bpl = bytesPerLine;
-
- return reinterpret_cast<uchar *>(data.data());
- }
-
- void unmap() { mode = NotMapped; }
-
-private:
- QByteArray data;
- MapMode mode;
- int bytesPerLine;
-};
-
Q_GLOBAL_STATIC(QList<AndroidCameraInfo>, g_availableCameras)
QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
@@ -102,6 +68,7 @@ QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
, m_readyForCapture(false)
, m_captureCanceled(false)
, m_currentImageCaptureId(-1)
+ , m_previewCallback(0)
{
m_mediaStorageLocation.addStorageLocation(
QMediaStorageLocation::Pictures,
@@ -206,10 +173,11 @@ bool QAndroidCameraSession::open()
if (m_camera) {
connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed()));
- connect(m_camera, SIGNAL(lastPreviewFrameFetched(QByteArray,int,int)),
- this, SLOT(onLastPreviewFrameFetched(QByteArray,int,int)));
- connect(m_camera, SIGNAL(newPreviewFrame(QByteArray,int,int)),
- this, SLOT(onNewPreviewFrame(QByteArray,int,int)),
+ connect(m_camera, SIGNAL(lastPreviewFrameFetched(QVideoFrame)),
+ this, SLOT(onLastPreviewFrameFetched(QVideoFrame)),
+ Qt::DirectConnection);
+ connect(m_camera, SIGNAL(newPreviewFrame(QVideoFrame)),
+ this, SLOT(onNewPreviewFrame(QVideoFrame)),
Qt::DirectConnection);
connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray)));
connect(m_camera, SIGNAL(previewStarted()), this, SLOT(onCameraPreviewStarted()));
@@ -224,7 +192,7 @@ bool QAndroidCameraSession::open()
if (m_camera->getPreviewFormat() != AndroidCamera::NV21)
m_camera->setPreviewFormat(AndroidCamera::NV21);
- m_camera->notifyNewFrames(m_videoProbes.count());
+ m_camera->notifyNewFrames(m_videoProbes.count() || m_previewCallback);
emit opened();
} else {
@@ -259,16 +227,19 @@ void QAndroidCameraSession::close()
emit statusChanged(m_status);
}
-void QAndroidCameraSession::setVideoPreview(QObject *videoOutput)
+void QAndroidCameraSession::setVideoOutput(QAndroidVideoOutput *output)
{
if (m_videoOutput) {
m_videoOutput->stop();
m_videoOutput->reset();
}
- if (videoOutput) {
- connect(videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(onVideoOutputReady(bool)));
- m_videoOutput = qobject_cast<QAndroidVideoOutput *>(videoOutput);
+ if (output) {
+ m_videoOutput = output;
+ if (m_videoOutput->isReady())
+ onVideoOutputReady(true);
+ else
+ connect(m_videoOutput, SIGNAL(readyChanged(bool)), this, SLOT(onVideoOutputReady(bool)));
} else {
m_videoOutput = 0;
}
@@ -336,7 +307,10 @@ bool QAndroidCameraSession::startPreview()
if (!m_videoOutput->isReady())
return true; // delay starting until the video output is ready
- if (!m_camera->setPreviewTexture(m_videoOutput->surfaceTexture()))
+ Q_ASSERT(m_videoOutput->surfaceTexture() || m_videoOutput->surfaceHolder());
+
+ if ((m_videoOutput->surfaceTexture() && !m_camera->setPreviewTexture(m_videoOutput->surfaceTexture()))
+ || (m_videoOutput->surfaceHolder() && !m_camera->setPreviewDisplay(m_videoOutput->surfaceHolder())))
return false;
m_status = QCamera::StartingStatus;
@@ -366,6 +340,7 @@ void QAndroidCameraSession::stopPreview()
m_camera->stopPreview();
m_camera->setPreviewSize(QSize());
m_camera->setPreviewTexture(0);
+ m_camera->setPreviewDisplay(0);
if (m_videoOutput) {
m_videoOutput->stop();
@@ -413,7 +388,7 @@ void QAndroidCameraSession::addProbe(QAndroidMediaVideoProbeControl *probe)
if (probe)
m_videoProbes << probe;
if (m_camera)
- m_camera->notifyNewFrames(m_videoProbes.count());
+ m_camera->notifyNewFrames(m_videoProbes.count() || m_previewCallback);
m_videoProbesMutex.unlock();
}
@@ -422,7 +397,24 @@ void QAndroidCameraSession::removeProbe(QAndroidMediaVideoProbeControl *probe)
m_videoProbesMutex.lock();
m_videoProbes.remove(probe);
if (m_camera)
- m_camera->notifyNewFrames(m_videoProbes.count());
+ m_camera->notifyNewFrames(m_videoProbes.count() || m_previewCallback);
+ m_videoProbesMutex.unlock();
+}
+
+void QAndroidCameraSession::setPreviewFormat(AndroidCamera::ImageFormat format)
+{
+ if (format == AndroidCamera::UnknownImageFormat)
+ return;
+
+ m_camera->setPreviewFormat(format);
+}
+
+void QAndroidCameraSession::setPreviewCallback(PreviewCallback *callback)
+{
+ m_videoProbesMutex.lock();
+ m_previewCallback = callback;
+ if (m_camera)
+ m_camera->notifyNewFrames(m_videoProbes.count() || m_previewCallback);
m_videoProbesMutex.unlock();
}
@@ -571,58 +563,37 @@ void QAndroidCameraSession::onCameraPictureExposed()
m_camera->fetchLastPreviewFrame();
}
-void QAndroidCameraSession::onLastPreviewFrameFetched(const QByteArray &preview, int width, int height)
-{
- if (preview.size()) {
- QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
- m_currentImageCaptureId,
- preview,
- width,
- height,
- m_camera->getRotation());
- }
-}
-
-void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data, int width, int height, int rotation)
+void QAndroidCameraSession::onLastPreviewFrameFetched(const QVideoFrame &frame)
{
- emit imageCaptured(id, prepareImageFromPreviewData(data, width, height, rotation));
+ QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
+ m_currentImageCaptureId,
+ frame,
+ m_camera->getRotation());
}
-QImage QAndroidCameraSession::prepareImageFromPreviewData(const QByteArray &data, int width, int height, int rotation)
+void QAndroidCameraSession::processPreviewImage(int id, const QVideoFrame &frame, int rotation)
{
- QImage result(width, height, QImage::Format_ARGB32);
- qt_convert_NV21_to_ARGB32((const uchar *)data.constData(),
- (quint32 *)result.bits(),
- width,
- height);
-
- QTransform transform;
-
// Preview display of front-facing cameras is flipped horizontally, but the frame data
// we get here is not. Flip it ourselves if the camera is front-facing to match what the user
// sees on the viewfinder.
+ QTransform transform;
if (m_camera->getFacing() == AndroidCamera::CameraFacingFront)
transform.scale(-1, 1);
-
transform.rotate(rotation);
- result = result.transformed(transform);
-
- return result;
+ emit imageCaptured(id, qt_imageFromVideoFrame(frame).transformed(transform));
}
-void QAndroidCameraSession::onNewPreviewFrame(const QByteArray &frame, int width, int height)
+void QAndroidCameraSession::onNewPreviewFrame(const QVideoFrame &frame)
{
m_videoProbesMutex.lock();
- if (frame.size() && m_videoProbes.count()) {
- // Bytes per line should be only for the first plane. For NV21, the Y plane has 8 bits
- // per sample, so bpl == width
- QVideoFrame videoFrame(new DataVideoBuffer(frame, width),
- QSize(width, height),
- QVideoFrame::Format_NV21);
- foreach (QAndroidMediaVideoProbeControl *probe, m_videoProbes)
- probe->newFrameProbed(videoFrame);
- }
+
+ foreach (QAndroidMediaVideoProbeControl *probe, m_videoProbes)
+ probe->newFrameProbed(frame);
+
+ if (m_previewCallback)
+ m_previewCallback->onFrameAvailable(frame);
+
m_videoProbesMutex.unlock();
}
@@ -720,7 +691,7 @@ void QAndroidCameraSession::processCapturedImage(int id,
}
if (dest & QCameraImageCapture::CaptureToBuffer) {
- QVideoFrame frame(new DataVideoBuffer(data), resolution, QVideoFrame::Format_Jpeg);
+ QVideoFrame frame(new QMemoryVideoBuffer(data, -1), resolution, QVideoFrame::Format_Jpeg);
emit imageAvailable(id, frame);
}
}
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
index c1772053d..d15509fe8 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
@@ -68,7 +68,8 @@ public:
void setCaptureMode(QCamera::CaptureModes mode);
bool isCaptureModeSupported(QCamera::CaptureModes mode) const;
- void setVideoPreview(QObject *videoOutput);
+ QAndroidVideoOutput *videoOutput() const { return m_videoOutput; }
+ void setVideoOutput(QAndroidVideoOutput *output);
void adjustViewfinderSize(const QSize &captureSize, bool restartPreview = true);
QImageEncoderSettings imageSettings() const { return m_imageSettings; }
@@ -90,6 +91,14 @@ public:
void addProbe(QAndroidMediaVideoProbeControl *probe);
void removeProbe(QAndroidMediaVideoProbeControl *probe);
+ void setPreviewFormat(AndroidCamera::ImageFormat format);
+
+ struct PreviewCallback
+ {
+ virtual void onFrameAvailable(const QVideoFrame &frame) = 0;
+ };
+ void setPreviewCallback(PreviewCallback *callback);
+
Q_SIGNALS:
void statusChanged(QCamera::Status status);
void stateChanged(QCamera::State);
@@ -115,8 +124,8 @@ private Q_SLOTS:
void onCameraTakePictureFailed();
void onCameraPictureExposed();
void onCameraPictureCaptured(const QByteArray &data);
- void onLastPreviewFrameFetched(const QByteArray &preview, int width, int height);
- void onNewPreviewFrame(const QByteArray &frame, int width, int height);
+ void onLastPreviewFrameFetched(const QVideoFrame &frame);
+ void onNewPreviewFrame(const QVideoFrame &frame);
void onCameraPreviewStarted();
void onCameraPreviewFailedToStart();
void onCameraPreviewStopped();
@@ -131,8 +140,8 @@ private:
void stopPreview();
void applyImageSettings();
- void processPreviewImage(int id, const QByteArray &data, int width, int height, int rotation);
- QImage prepareImageFromPreviewData(const QByteArray &data, int width, int height, int rotation);
+
+ void processPreviewImage(int id, const QVideoFrame &frame, int rotation);
void processCapturedImage(int id,
const QByteArray &data,
const QSize &resolution,
@@ -164,6 +173,7 @@ private:
QSet<QAndroidMediaVideoProbeControl *> m_videoProbes;
QMutex m_videoProbesMutex;
+ PreviewCallback *m_previewCallback;
};
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.cpp
new file mode 100644
index 000000000..1d5b521b8
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameravideorenderercontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "qandroidvideooutput.h"
+#include "androidsurfaceview.h"
+#include "qandroidmultimediautils.h"
+#include <qabstractvideosurface.h>
+#include <qvideosurfaceformat.h>
+#include <qcoreapplication.h>
+#include <qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraDataVideoOutput : public QAndroidVideoOutput
+ , public QAndroidCameraSession::PreviewCallback
+{
+ Q_OBJECT
+public:
+ explicit QAndroidCameraDataVideoOutput(QAndroidCameraVideoRendererControl *control);
+ ~QAndroidCameraDataVideoOutput() Q_DECL_OVERRIDE;
+
+ AndroidSurfaceHolder *surfaceHolder() Q_DECL_OVERRIDE;
+
+ bool isReady() Q_DECL_OVERRIDE;
+
+ void stop() Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void onSurfaceCreated();
+ void configureFormat();
+
+private:
+ void onFrameAvailable(const QVideoFrame &frame);
+ void presentFrame();
+ bool event(QEvent *);
+
+ QAndroidCameraVideoRendererControl *m_control;
+ AndroidSurfaceView *m_surfaceView;
+ QMutex m_mutex;
+ QVideoFrame::PixelFormat m_pixelFormat;
+ QVideoFrame m_lastFrame;
+};
+
+QAndroidCameraDataVideoOutput::QAndroidCameraDataVideoOutput(QAndroidCameraVideoRendererControl *control)
+ : QAndroidVideoOutput(control)
+ , m_control(control)
+ , m_pixelFormat(QVideoFrame::Format_Invalid)
+{
+ // The camera preview cannot be started unless we set a SurfaceTexture or a
+ // SurfaceHolder. In this case we don't actually care about either of these, but since
+ // we need to, we setup an offscreen dummy SurfaceView in order to be able to start
+ // the camera preview. We'll then be able to use setPreviewCallbackWithBuffer() to
+ // get the raw data.
+
+ m_surfaceView = new AndroidSurfaceView;
+
+ connect(m_surfaceView, &AndroidSurfaceView::surfaceCreated,
+ this, &QAndroidCameraDataVideoOutput::onSurfaceCreated);
+
+ m_surfaceView->setGeometry(-1, -1, 1, 1);
+ m_surfaceView->setVisible(true);
+
+ connect(m_control->cameraSession(), &QAndroidCameraSession::opened,
+ this, &QAndroidCameraDataVideoOutput::configureFormat);
+ connect(m_control->surface(), &QAbstractVideoSurface::supportedFormatsChanged,
+ this, &QAndroidCameraDataVideoOutput::configureFormat);
+ configureFormat();
+}
+
+QAndroidCameraDataVideoOutput::~QAndroidCameraDataVideoOutput()
+{
+ m_control->cameraSession()->setPreviewCallback(Q_NULLPTR);
+ delete m_surfaceView;
+}
+
+AndroidSurfaceHolder *QAndroidCameraDataVideoOutput::surfaceHolder()
+{
+ return m_surfaceView->holder();
+}
+
+bool QAndroidCameraDataVideoOutput::isReady()
+{
+ return m_surfaceView->holder() && m_surfaceView->holder()->isSurfaceCreated();
+}
+
+void QAndroidCameraDataVideoOutput::onSurfaceCreated()
+{
+ emit readyChanged(true);
+}
+
+void QAndroidCameraDataVideoOutput::configureFormat()
+{
+ m_pixelFormat = QVideoFrame::Format_Invalid;
+
+ if (!m_control->cameraSession()->camera())
+ return;
+
+ QList<QVideoFrame::PixelFormat> surfaceFormats = m_control->surface()->supportedPixelFormats();
+ QList<AndroidCamera::ImageFormat> previewFormats = m_control->cameraSession()->camera()->getSupportedPreviewFormats();
+ for (int i = 0; i < surfaceFormats.size(); ++i) {
+ QVideoFrame::PixelFormat pixFormat = surfaceFormats.at(i);
+ AndroidCamera::ImageFormat f = qt_androidImageFormatFromPixelFormat(pixFormat);
+ if (previewFormats.contains(f)) {
+ m_pixelFormat = pixFormat;
+ break;
+ }
+ }
+
+ if (m_pixelFormat == QVideoFrame::Format_Invalid) {
+ m_control->cameraSession()->setPreviewCallback(Q_NULLPTR);
+ qWarning("The video surface is not compatible with any format supported by the camera");
+ } else {
+ m_control->cameraSession()->setPreviewCallback(this);
+
+ if (m_control->cameraSession()->status() > QCamera::LoadedStatus)
+ m_control->cameraSession()->camera()->stopPreview();
+
+ m_control->cameraSession()->setPreviewFormat(qt_androidImageFormatFromPixelFormat(m_pixelFormat));
+
+ if (m_control->cameraSession()->status() > QCamera::LoadedStatus)
+ m_control->cameraSession()->camera()->startPreview();
+ }
+}
+
+void QAndroidCameraDataVideoOutput::stop()
+{
+ m_mutex.lock();
+ m_lastFrame = QVideoFrame();
+ m_mutex.unlock();
+
+ if (m_control->surface() && m_control->surface()->isActive())
+ m_control->surface()->stop();
+}
+
+void QAndroidCameraDataVideoOutput::onFrameAvailable(const QVideoFrame &frame)
+{
+ m_mutex.lock();
+ m_lastFrame = frame;
+ m_mutex.unlock();
+
+ if (thread() == QThread::currentThread())
+ presentFrame();
+ else
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority);
+}
+
+bool QAndroidCameraDataVideoOutput::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ presentFrame();
+ return true;
+ }
+
+ return QObject::event(e);
+}
+
+void QAndroidCameraDataVideoOutput::presentFrame()
+{
+ Q_ASSERT(thread() == QThread::currentThread());
+
+ QMutexLocker locker(&m_mutex);
+
+ if (m_control->surface() && m_lastFrame.isValid() && m_lastFrame.pixelFormat() == m_pixelFormat) {
+
+ if (m_control->surface()->isActive() && (m_control->surface()->surfaceFormat().pixelFormat() != m_lastFrame.pixelFormat()
+ || m_control->surface()->surfaceFormat().frameSize() != m_lastFrame.size())) {
+ m_control->surface()->stop();
+ }
+
+ if (!m_control->surface()->isActive()) {
+ QVideoSurfaceFormat format(m_lastFrame.size(), m_lastFrame.pixelFormat(), m_lastFrame.handleType());
+ // Front camera frames are automatically mirrored when using SurfaceTexture or SurfaceView,
+ // but the buffers we get from the data callback are not. Tell the QAbstractVideoSurface
+ // that it needs to mirror the frames.
+ if (m_control->cameraSession()->camera()->getFacing() == AndroidCamera::CameraFacingFront)
+ format.setProperty("mirrored", true);
+
+ m_control->surface()->start(format);
+ }
+
+ if (m_control->surface()->isActive())
+ m_control->surface()->present(m_lastFrame);
+ }
+
+ m_lastFrame = QVideoFrame();
+}
+
+
+QAndroidCameraVideoRendererControl::QAndroidCameraVideoRendererControl(QAndroidCameraSession *session, QObject *parent)
+ : QVideoRendererControl(parent)
+ , m_cameraSession(session)
+ , m_surface(0)
+ , m_textureOutput(0)
+ , m_dataOutput(0)
+{
+}
+
+QAndroidCameraVideoRendererControl::~QAndroidCameraVideoRendererControl()
+{
+ m_cameraSession->setVideoOutput(0);
+}
+
+QAbstractVideoSurface *QAndroidCameraVideoRendererControl::surface() const
+{
+ return m_surface;
+}
+
+void QAndroidCameraVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+ if (m_surface == surface)
+ return;
+
+ m_surface = surface;
+ QAndroidVideoOutput *oldOutput = m_textureOutput ? static_cast<QAndroidVideoOutput*>(m_textureOutput)
+ : static_cast<QAndroidVideoOutput*>(m_dataOutput);
+ QAndroidVideoOutput *newOutput = 0;
+
+ if (m_surface) {
+ if (!m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty()) {
+ if (!m_textureOutput) {
+ m_dataOutput = 0;
+ newOutput = m_textureOutput = new QAndroidTextureVideoOutput(this);
+ }
+ } else if (!m_dataOutput) {
+ m_textureOutput = 0;
+ newOutput = m_dataOutput = new QAndroidCameraDataVideoOutput(this);
+ }
+
+ if (m_textureOutput)
+ m_textureOutput->setSurface(m_surface);
+ }
+
+ if (newOutput != oldOutput) {
+ m_cameraSession->setVideoOutput(newOutput);
+ delete oldOutput;
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "qandroidcameravideorenderercontrol.moc"
+
diff --git a/src/plugins/android/src/common/qandroidvideorendercontrol.h b/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.h
index c660758fb..4b6428ba0 100644
--- a/src/plugins/android/src/common/qandroidvideorendercontrol.h
+++ b/src/plugins/android/src/mediacapture/qandroidcameravideorenderercontrol.h
@@ -31,88 +31,36 @@
**
****************************************************************************/
-#ifndef QANDROIDVIDEORENDERCONTROL_H
-#define QANDROIDVIDEORENDERCONTROL_H
+#ifndef QANDROIDCAMERAVIDEORENDERERCONTROL_H
+#define QANDROIDCAMERAVIDEORENDERERCONTROL_H
#include <qvideorenderercontrol.h>
-#include <qmutex.h>
-#include "qandroidvideooutput.h"
QT_BEGIN_NAMESPACE
-class QOpenGLTexture;
-class QOpenGLFramebufferObject;
-class QOpenGLShaderProgram;
-class AndroidSurfaceTexture;
+class QAndroidCameraSession;
+class QAndroidTextureVideoOutput;
+class QAndroidCameraDataVideoOutput;
-class OpenGLResourcesDeleter : public QObject
+class QAndroidCameraVideoRendererControl : public QVideoRendererControl
{
Q_OBJECT
public:
- OpenGLResourcesDeleter()
- : m_textureID(0)
- , m_fbo(0)
- , m_program(0)
- { }
-
- ~OpenGLResourcesDeleter();
-
- void setTexture(quint32 id) { m_textureID = id; }
- void setFbo(QOpenGLFramebufferObject *fbo) { m_fbo = fbo; }
- void setShaderProgram(QOpenGLShaderProgram *prog) { m_program = prog; }
-
-private:
- quint32 m_textureID;
- QOpenGLFramebufferObject *m_fbo;
- QOpenGLShaderProgram *m_program;
-};
-
-class QAndroidVideoRendererControl : public QVideoRendererControl, public QAndroidVideoOutput
-{
- Q_OBJECT
- Q_INTERFACES(QAndroidVideoOutput)
-public:
- explicit QAndroidVideoRendererControl(QObject *parent = 0);
- ~QAndroidVideoRendererControl() Q_DECL_OVERRIDE;
+ QAndroidCameraVideoRendererControl(QAndroidCameraSession *session, QObject *parent = 0);
+ ~QAndroidCameraVideoRendererControl() Q_DECL_OVERRIDE;
QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE;
void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE;
- AndroidSurfaceTexture *surfaceTexture() Q_DECL_OVERRIDE;
- bool isReady() Q_DECL_OVERRIDE;
- void setVideoSize(const QSize &size) Q_DECL_OVERRIDE;
- void stop() Q_DECL_OVERRIDE;
- void reset() Q_DECL_OVERRIDE;
-
- void customEvent(QEvent *) Q_DECL_OVERRIDE;
-
-Q_SIGNALS:
- void readyChanged(bool);
-
-private Q_SLOTS:
- void onFrameAvailable();
+ QAndroidCameraSession *cameraSession() const { return m_cameraSession; }
private:
- bool initSurfaceTexture();
- void renderFrameToFbo();
- void createGLResources();
-
- QMutex m_mutex;
- void clearSurfaceTexture();
-
+ QAndroidCameraSession *m_cameraSession;
QAbstractVideoSurface *m_surface;
- QSize m_nativeSize;
-
- AndroidSurfaceTexture *m_surfaceTexture;
-
- quint32 m_externalTex;
- QOpenGLFramebufferObject *m_fbo;
- QOpenGLShaderProgram *m_program;
- OpenGLResourcesDeleter *m_glDeleter;
-
- friend class AndroidTextureVideoBuffer;
+ QAndroidTextureVideoOutput *m_textureOutput;
+ QAndroidCameraDataVideoOutput *m_dataOutput;
};
QT_END_NAMESPACE
-#endif // QANDROIDVIDEORENDERCONTROL_H
+#endif // QANDROIDCAMERAVIDEORENDERERCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp b/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp
index e9cdb1e78..d2107e8a5 100644
--- a/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp
@@ -40,7 +40,7 @@
#include "qandroidvideodeviceselectorcontrol.h"
#include "qandroidaudioinputselectorcontrol.h"
#include "qandroidcamerasession.h"
-#include "qandroidvideorendercontrol.h"
+#include "qandroidcameravideorenderercontrol.h"
#include "qandroidcamerazoomcontrol.h"
#include "qandroidcameraexposurecontrol.h"
#include "qandroidcameraflashcontrol.h"
@@ -196,8 +196,7 @@ QMediaControl *QAndroidCaptureService::requestControl(const char *name)
if (qstrcmp(name, QVideoRendererControl_iid) == 0
&& m_service == QLatin1String(Q_MEDIASERVICE_CAMERA)
&& !m_videoRendererControl) {
- m_videoRendererControl = new QAndroidVideoRendererControl;
- m_cameraSession->setVideoPreview(m_videoRendererControl);
+ m_videoRendererControl = new QAndroidCameraVideoRendererControl(m_cameraSession);
return m_videoRendererControl;
}
@@ -217,7 +216,6 @@ void QAndroidCaptureService::releaseControl(QMediaControl *control)
{
if (control) {
if (control == m_videoRendererControl) {
- m_cameraSession->setVideoPreview(0);
delete m_videoRendererControl;
m_videoRendererControl = 0;
return;
diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
index fc84ac124..02f063444 100644
--- a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
+++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
@@ -46,7 +46,7 @@ class QAndroidCameraInfoControl;
class QAndroidVideoDeviceSelectorControl;
class QAndroidAudioInputSelectorControl;
class QAndroidCameraSession;
-class QAndroidVideoRendererControl;
+class QAndroidCameraVideoRendererControl;
class QAndroidCameraZoomControl;
class QAndroidCameraExposureControl;
class QAndroidCameraFlashControl;
@@ -82,7 +82,7 @@ private:
QAndroidVideoDeviceSelectorControl *m_videoInputControl;
QAndroidAudioInputSelectorControl *m_audioInputControl;
QAndroidCameraSession *m_cameraSession;
- QMediaControl *m_videoRendererControl;
+ QAndroidCameraVideoRendererControl *m_videoRendererControl;
QAndroidCameraZoomControl *m_cameraZoomControl;
QAndroidCameraExposureControl *m_cameraExposureControl;
QAndroidCameraFlashControl *m_cameraFlashControl;
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
index f2ea1b9d7..d25438ec7 100644
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
@@ -37,6 +37,7 @@
#include "qandroidcamerasession.h"
#include "androidmultimediautils.h"
#include "qandroidmultimediautils.h"
+#include "qandroidvideooutput.h"
QT_BEGIN_NAMESPACE
@@ -217,6 +218,20 @@ void QAndroidCaptureSession::start()
m_usedOutputLocation = QUrl::fromLocalFile(filePath);
m_mediaRecorder->setOutputFile(filePath);
+ // Even though the Android doc explicitly says that calling MediaRecorder.setPreviewDisplay()
+ // is not necessary when the Camera already has a Surface, it doesn't actually work on some
+ // devices. For example on the Samsung Galaxy Tab 2, the camera server dies after prepare()
+ // and start() if MediaRecorder.setPreviewDispaly() is not called.
+ if (m_cameraSession) {
+ // When using a SurfaceTexture, we need to pass a new one to the MediaRecorder, not the same
+ // one that is set on the Camera or it will crash, hence the reset().
+ m_cameraSession->videoOutput()->reset();
+ if (m_cameraSession->videoOutput()->surfaceTexture())
+ m_mediaRecorder->setSurfaceTexture(m_cameraSession->videoOutput()->surfaceTexture());
+ else if (m_cameraSession->videoOutput()->surfaceHolder())
+ m_mediaRecorder->setSurfaceHolder(m_cameraSession->videoOutput()->surfaceHolder());
+ }
+
if (!m_mediaRecorder->prepare()) {
emit error(QMediaRecorder::FormatError, QLatin1String("Unable to prepare the media recorder."));
restartViewfinder();
@@ -412,13 +427,23 @@ void QAndroidCaptureSession::applySettings()
void QAndroidCaptureSession::updateViewfinder()
{
- m_cameraSession->camera()->stopPreview();
+ m_cameraSession->camera()->stopPreviewSynchronous();
m_cameraSession->adjustViewfinderSize(m_videoSettings.resolution(), false);
}
void QAndroidCaptureSession::restartViewfinder()
{
m_cameraSession->camera()->reconnect();
+
+ // This is not necessary on most devices, but it crashes on some if we don't stop the
+ // preview and reset the preview display on the camera when recording is over.
+ m_cameraSession->camera()->stopPreviewSynchronous();
+ m_cameraSession->videoOutput()->reset();
+ if (m_cameraSession->videoOutput()->surfaceTexture())
+ m_cameraSession->camera()->setPreviewTexture(m_cameraSession->videoOutput()->surfaceTexture());
+ else if (m_cameraSession->videoOutput()->surfaceHolder())
+ m_cameraSession->camera()->setPreviewDisplay(m_cameraSession->videoOutput()->surfaceHolder());
+
m_cameraSession->camera()->startPreview();
m_cameraSession->setReadyForCapture(true);
}
diff --git a/src/plugins/android/src/mediaplayer/mediaplayer.pri b/src/plugins/android/src/mediaplayer/mediaplayer.pri
index c386d996b..9f758a993 100644
--- a/src/plugins/android/src/mediaplayer/mediaplayer.pri
+++ b/src/plugins/android/src/mediaplayer/mediaplayer.pri
@@ -3,9 +3,11 @@ INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/qandroidmediaplayercontrol.h \
$$PWD/qandroidmediaservice.h \
- $$PWD/qandroidmetadatareadercontrol.h
+ $$PWD/qandroidmetadatareadercontrol.h \
+ $$PWD/qandroidmediaplayervideorenderercontrol.h
SOURCES += \
$$PWD/qandroidmediaplayercontrol.cpp \
$$PWD/qandroidmediaservice.cpp \
- $$PWD/qandroidmetadatareadercontrol.cpp
+ $$PWD/qandroidmetadatareadercontrol.cpp \
+ $$PWD/qandroidmediaplayervideorenderercontrol.cpp
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
index 9a050e7ad..90beeabe7 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
@@ -345,7 +345,7 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
mReloadingMedia = false;
}
-void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
+void QAndroidMediaPlayerControl::setVideoOutput(QAndroidVideoOutput *videoOutput)
{
if (mVideoOutput) {
mMediaPlayer->setDisplay(0);
@@ -353,7 +353,7 @@ void QAndroidMediaPlayerControl::setVideoOutput(QObject *videoOutput)
mVideoOutput->reset();
}
- mVideoOutput = qobject_cast<QAndroidVideoOutput *>(videoOutput);
+ mVideoOutput = videoOutput;
if (!mVideoOutput)
return;
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
index 3f92d809c..a015a6809 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
@@ -67,7 +67,7 @@ public:
const QIODevice *mediaStream() const Q_DECL_OVERRIDE;
void setMedia(const QMediaContent &mediaContent, QIODevice *stream) Q_DECL_OVERRIDE;
- void setVideoOutput(QObject *videoOutput);
+ void setVideoOutput(QAndroidVideoOutput *videoOutput);
Q_SIGNALS:
void metaDataUpdated();
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp
new file mode 100644
index 000000000..5dd51c395
--- /dev/null
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmediaplayervideorenderercontrol.h"
+
+#include "qandroidmediaplayercontrol.h"
+#include "qandroidvideooutput.h"
+#include <qabstractvideosurface.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidMediaPlayerVideoRendererControl::QAndroidMediaPlayerVideoRendererControl(QAndroidMediaPlayerControl *mediaPlayer, QObject *parent)
+ : QVideoRendererControl(parent)
+ , m_mediaPlayerControl(mediaPlayer)
+ , m_surface(0)
+ , m_textureOutput(new QAndroidTextureVideoOutput(this))
+{
+ m_mediaPlayerControl->setVideoOutput(m_textureOutput);
+}
+
+QAndroidMediaPlayerVideoRendererControl::~QAndroidMediaPlayerVideoRendererControl()
+{
+ m_mediaPlayerControl->setVideoOutput(0);
+}
+
+QAbstractVideoSurface *QAndroidMediaPlayerVideoRendererControl::surface() const
+{
+ return m_surface;
+}
+
+void QAndroidMediaPlayerVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+ if (m_surface == surface)
+ return;
+
+ m_surface = surface;
+ m_textureOutput->setSurface(m_surface);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.h
new file mode 100644
index 000000000..cfa41980d
--- /dev/null
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayervideorenderercontrol.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIAPLAYERVIDEORENDERERCONTROL_H
+#define QANDROIDMEDIAPLAYERVIDEORENDERERCONTROL_H
+
+#include <qvideorenderercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidMediaPlayerControl;
+class QAndroidTextureVideoOutput;
+
+class QAndroidMediaPlayerVideoRendererControl : public QVideoRendererControl
+{
+ Q_OBJECT
+public:
+ QAndroidMediaPlayerVideoRendererControl(QAndroidMediaPlayerControl *mediaPlayer, QObject *parent = 0);
+ ~QAndroidMediaPlayerVideoRendererControl() Q_DECL_OVERRIDE;
+
+ QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE;
+ void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE;
+
+private:
+ QAndroidMediaPlayerControl *m_mediaPlayerControl;
+ QAbstractVideoSurface *m_surface;
+ QAndroidTextureVideoOutput *m_textureOutput;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIAPLAYERVIDEORENDERERCONTROL_H
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp
index 74943ca64..992bcead2 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp
@@ -35,7 +35,7 @@
#include "qandroidmediaplayercontrol.h"
#include "qandroidmetadatareadercontrol.h"
-#include "qandroidvideorendercontrol.h"
+#include "qandroidmediaplayervideorenderercontrol.h"
QT_BEGIN_NAMESPACE
@@ -53,9 +53,9 @@ QAndroidMediaService::QAndroidMediaService(QObject *parent)
QAndroidMediaService::~QAndroidMediaService()
{
- delete mMediaControl;
- delete mMetadataControl;
delete mVideoRendererControl;
+ delete mMetadataControl;
+ delete mMediaControl;
}
QMediaControl *QAndroidMediaService::requestControl(const char *name)
@@ -68,8 +68,7 @@ QMediaControl *QAndroidMediaService::requestControl(const char *name)
if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
if (!mVideoRendererControl) {
- mVideoRendererControl = new QAndroidVideoRendererControl;
- mMediaControl->setVideoOutput(mVideoRendererControl);
+ mVideoRendererControl = new QAndroidMediaPlayerVideoRendererControl(mMediaControl);
return mVideoRendererControl;
}
}
@@ -80,7 +79,6 @@ QMediaControl *QAndroidMediaService::requestControl(const char *name)
void QAndroidMediaService::releaseControl(QMediaControl *control)
{
if (control == mVideoRendererControl) {
- mMediaControl->setVideoOutput(0);
delete mVideoRendererControl;
mVideoRendererControl = 0;
}
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaservice.h b/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
index 6babbb15f..798d6ef39 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
@@ -40,6 +40,7 @@ QT_BEGIN_NAMESPACE
class QAndroidMediaPlayerControl;
class QAndroidMetaDataReaderControl;
+class QAndroidMediaPlayerVideoRendererControl;
class QAndroidMediaService : public QMediaService
{
@@ -54,7 +55,7 @@ public:
private:
QAndroidMediaPlayerControl *mMediaControl;
QAndroidMetaDataReaderControl *mMetadataControl;
- QMediaControl *mVideoRendererControl;
+ QAndroidMediaPlayerVideoRendererControl *mVideoRendererControl;
};
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/qandroidmediaserviceplugin.cpp b/src/plugins/android/src/qandroidmediaserviceplugin.cpp
index 5d35ddf51..bf89badb3 100644
--- a/src/plugins/android/src/qandroidmediaserviceplugin.cpp
+++ b/src/plugins/android/src/qandroidmediaserviceplugin.cpp
@@ -43,6 +43,7 @@
#include "androidcamera.h"
#include "androidmultimediautils.h"
#include "androidmediarecorder.h"
+#include "androidsurfaceview.h"
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@@ -160,7 +161,8 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
if (!AndroidMediaPlayer::initJNI(jniEnv) ||
!AndroidCamera::initJNI(jniEnv) ||
- !AndroidMediaRecorder::initJNI(jniEnv)) {
+ !AndroidMediaRecorder::initJNI(jniEnv) ||
+ !AndroidSurfaceHolder::initJNI(jniEnv)) {
return JNI_ERR;
}
diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp
index 7d8e4532d..23200462e 100644
--- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp
@@ -33,20 +33,24 @@
#include "androidcamera.h"
#include "androidsurfacetexture.h"
+#include "androidsurfaceview.h"
#include "qandroidmultimediautils.h"
#include <qstringlist.h>
#include <qdebug.h>
-#include <qmutex.h>
#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/qthread.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qmutex.h>
+#include <QtMultimedia/private/qmemoryvideobuffer_p.h>
QT_BEGIN_NAMESPACE
static const char QtCameraListenerClassName[] = "org/qtproject/qt5/android/multimedia/QtCameraListener";
-static QMutex g_cameraMapMutex;
-typedef QMap<int, AndroidCamera *> CameraMap;
-Q_GLOBAL_STATIC(CameraMap, g_cameraMap)
+
+typedef QHash<int, AndroidCamera *> CameraMap;
+Q_GLOBAL_STATIC(CameraMap, cameras)
+Q_GLOBAL_STATIC(QReadWriteLock, rwLock)
static inline bool exceptionCheckAndClear(JNIEnv *env)
{
@@ -88,43 +92,57 @@ static QJNIObjectPrivate rectToArea(const QRect &rect)
// native method for QtCameraLisener.java
static void notifyAutoFocusComplete(JNIEnv* , jobject, int id, jboolean success)
{
- QMutexLocker locker(&g_cameraMapMutex);
- AndroidCamera *obj = g_cameraMap->value(id, 0);
- if (obj)
- Q_EMIT obj->autoFocusComplete(success);
+ QReadLocker locker(rwLock);
+ const auto it = cameras->constFind(id);
+ if (Q_UNLIKELY(it == cameras->cend()))
+ return;
+
+ Q_EMIT (*it)->autoFocusComplete(success);
}
static void notifyPictureExposed(JNIEnv* , jobject, int id)
{
- QMutexLocker locker(&g_cameraMapMutex);
- AndroidCamera *obj = g_cameraMap->value(id, 0);
- if (obj)
- Q_EMIT obj->pictureExposed();
+ QReadLocker locker(rwLock);
+ const auto it = cameras->constFind(id);
+ if (Q_UNLIKELY(it == cameras->cend()))
+ return;
+
+ Q_EMIT (*it)->pictureExposed();
}
static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
{
- QMutexLocker locker(&g_cameraMapMutex);
- AndroidCamera *obj = g_cameraMap->value(id, 0);
- if (obj) {
- const int arrayLength = env->GetArrayLength(data);
- QByteArray bytes(arrayLength, Qt::Uninitialized);
- env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
- Q_EMIT obj->pictureCaptured(bytes);
- }
+ QReadLocker locker(rwLock);
+ const auto it = cameras->constFind(id);
+ if (Q_UNLIKELY(it == cameras->cend()))
+ return;
+
+ const int arrayLength = env->GetArrayLength(data);
+ QByteArray bytes(arrayLength, Qt::Uninitialized);
+ env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+ Q_EMIT (*it)->pictureCaptured(bytes);
}
-static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data, int width, int height)
+static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data,
+ int width, int height, int format, int bpl)
{
- QMutexLocker locker(&g_cameraMapMutex);
- AndroidCamera *obj = g_cameraMap->value(id, 0);
- if (obj) {
- const int arrayLength = env->GetArrayLength(data);
- QByteArray bytes(arrayLength, Qt::Uninitialized);
- env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+ QReadLocker locker(rwLock);
+ const auto it = cameras->constFind(id);
+ if (Q_UNLIKELY(it == cameras->cend()))
+ return;
- Q_EMIT obj->newPreviewFrame(bytes, width, height);
- }
+ const int arrayLength = env->GetArrayLength(data);
+ if (arrayLength == 0)
+ return;
+
+ QByteArray bytes(arrayLength, Qt::Uninitialized);
+ env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+
+ QVideoFrame frame(new QMemoryVideoBuffer(bytes, bpl),
+ QSize(width, height),
+ qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format)));
+
+ Q_EMIT (*it)->newPreviewFrame(frame);
}
class AndroidCameraPrivate : public QObject
@@ -149,10 +167,12 @@ public:
Q_INVOKABLE AndroidCamera::ImageFormat getPreviewFormat();
Q_INVOKABLE void setPreviewFormat(AndroidCamera::ImageFormat fmt);
+ Q_INVOKABLE QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats();
Q_INVOKABLE QSize previewSize() const { return m_previewSize; }
Q_INVOKABLE void updatePreviewSize();
Q_INVOKABLE bool setPreviewTexture(void *surfaceTexture);
+ Q_INVOKABLE bool setPreviewDisplay(void *surfaceHolder);
Q_INVOKABLE bool isZoomSupported();
Q_INVOKABLE int getMaxZoom();
@@ -233,7 +253,7 @@ Q_SIGNALS:
void takePictureFailed();
- void lastPreviewFrameFetched(const QByteArray &preview, int width, int height);
+ void lastPreviewFrameFetched(const QVideoFrame &frame);
};
AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker)
@@ -245,6 +265,7 @@ AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker)
qRegisterMetaType<QList<int> >();
qRegisterMetaType<QList<QSize> >();
qRegisterMetaType<QList<QRect> >();
+ qRegisterMetaType<ImageFormat>();
connect(d, &AndroidCameraPrivate::previewSizeChanged, this, &AndroidCamera::previewSizeChanged);
connect(d, &AndroidCameraPrivate::previewStarted, this, &AndroidCamera::previewStarted);
@@ -260,12 +281,11 @@ AndroidCamera::~AndroidCamera()
{
Q_D(AndroidCamera);
if (d->m_camera.isValid()) {
- g_cameraMapMutex.lock();
- g_cameraMap->remove(d->m_cameraId);
- g_cameraMapMutex.unlock();
+ release();
+ QWriteLocker locker(rwLock);
+ cameras->remove(cameraId());
}
- release();
m_worker->exit();
m_worker->wait(5000);
}
@@ -288,9 +308,9 @@ AndroidCamera *AndroidCamera::open(int cameraId)
}
AndroidCamera *q = new AndroidCamera(d, worker);
- g_cameraMapMutex.lock();
- g_cameraMap->insert(cameraId, q);
- g_cameraMapMutex.unlock();
+ QWriteLocker locker(rwLock);
+ cameras->insert(cameraId, q);
+
return q;
}
@@ -366,6 +386,12 @@ void AndroidCamera::setPreviewFormat(ImageFormat fmt)
QMetaObject::invokeMethod(d, "setPreviewFormat", Q_ARG(AndroidCamera::ImageFormat, fmt));
}
+QList<AndroidCamera::ImageFormat> AndroidCamera::getSupportedPreviewFormats()
+{
+ Q_D(AndroidCamera);
+ return d->getSupportedPreviewFormats();
+}
+
QSize AndroidCamera::previewSize() const
{
Q_D(const AndroidCamera);
@@ -397,6 +423,18 @@ bool AndroidCamera::setPreviewTexture(AndroidSurfaceTexture *surfaceTexture)
return ok;
}
+bool AndroidCamera::setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder)
+{
+ Q_D(AndroidCamera);
+ bool ok = true;
+ QMetaObject::invokeMethod(d,
+ "setPreviewDisplay",
+ Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(bool, ok),
+ Q_ARG(void *, surfaceHolder ? surfaceHolder->surfaceHolder() : 0));
+ return ok;
+}
+
bool AndroidCamera::isZoomSupported()
{
Q_D(AndroidCamera);
@@ -711,6 +749,12 @@ void AndroidCamera::stopPreview()
QMetaObject::invokeMethod(d, "stopPreview");
}
+void AndroidCamera::stopPreviewSynchronous()
+{
+ Q_D(AndroidCamera);
+ QMetaObject::invokeMethod(d, "stopPreview", Qt::BlockingQueuedConnection);
+}
+
AndroidCameraPrivate::AndroidCameraPrivate()
: QObject(),
m_parametersMutex(QMutex::Recursive)
@@ -832,7 +876,7 @@ AndroidCamera::ImageFormat AndroidCameraPrivate::getPreviewFormat()
QMutexLocker parametersLocker(&m_parametersMutex);
if (!m_parameters.isValid())
- return AndroidCamera::Unknown;
+ return AndroidCamera::UnknownImageFormat;
return AndroidCamera::ImageFormat(m_parameters.callMethod<jint>("getPreviewFormat"));
}
@@ -848,6 +892,27 @@ void AndroidCameraPrivate::setPreviewFormat(AndroidCamera::ImageFormat fmt)
applyParameters();
}
+QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewFormats()
+{
+ QList<AndroidCamera::ImageFormat> list;
+
+ QMutexLocker parametersLocker(&m_parametersMutex);
+
+ if (m_parameters.isValid()) {
+ QJNIObjectPrivate formatList = m_parameters.callObjectMethod("getSupportedPreviewFormats",
+ "()Ljava/util/List;");
+ int count = formatList.callMethod<jint>("size");
+ for (int i = 0; i < count; ++i) {
+ QJNIObjectPrivate format = formatList.callObjectMethod("get",
+ "(I)Ljava/lang/Object;",
+ i);
+ list.append(AndroidCamera::ImageFormat(format.callMethod<jint>("intValue")));
+ }
+ }
+
+ return list;
+}
+
void AndroidCameraPrivate::updatePreviewSize()
{
QMutexLocker parametersLocker(&m_parametersMutex);
@@ -869,6 +934,15 @@ bool AndroidCameraPrivate::setPreviewTexture(void *surfaceTexture)
return !exceptionCheckAndClear(env);
}
+bool AndroidCameraPrivate::setPreviewDisplay(void *surfaceHolder)
+{
+ QJNIEnvironmentPrivate env;
+ m_camera.callMethod<void>("setPreviewDisplay",
+ "(Landroid/view/SurfaceHolder;)V",
+ static_cast<jobject>(surfaceHolder));
+ return !exceptionCheckAndClear(env);
+}
+
bool AndroidCameraPrivate::isZoomSupported()
{
QMutexLocker parametersLocker(&m_parametersMutex);
@@ -1380,15 +1454,25 @@ void AndroidCameraPrivate::fetchLastPreviewFrame()
return;
const int arrayLength = env->GetArrayLength(static_cast<jbyteArray>(data.object()));
+ if (arrayLength == 0)
+ return;
+
QByteArray bytes(arrayLength, Qt::Uninitialized);
env->GetByteArrayRegion(static_cast<jbyteArray>(data.object()),
0,
arrayLength,
reinterpret_cast<jbyte *>(bytes.data()));
- emit lastPreviewFrameFetched(bytes,
- m_cameraListener.callMethod<jint>("previewWidth"),
- m_cameraListener.callMethod<jint>("previewHeight"));
+ const int width = m_cameraListener.callMethod<jint>("previewWidth");
+ const int height = m_cameraListener.callMethod<jint>("previewHeight");
+ const int format = m_cameraListener.callMethod<jint>("previewFormat");
+ const int bpl = m_cameraListener.callMethod<jint>("previewBytesPerLine");
+
+ QVideoFrame frame(new QMemoryVideoBuffer(bytes, bpl),
+ QSize(width, height),
+ qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat(format)));
+
+ emit lastPreviewFrameFetched(frame);
}
void AndroidCameraPrivate::applyParameters()
@@ -1433,7 +1517,7 @@ bool AndroidCamera::initJNI(JNIEnv *env)
{"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
{"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
{"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured},
- {"notifyNewPreviewFrame", "(I[BII)V", (void *)notifyNewPreviewFrame}
+ {"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame}
};
if (clazz && env->RegisterNatives(clazz,
diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.h b/src/plugins/android/src/wrappers/jni/androidcamera.h
index b5903688d..a5e0294c0 100644
--- a/src/plugins/android/src/wrappers/jni/androidcamera.h
+++ b/src/plugins/android/src/wrappers/jni/androidcamera.h
@@ -46,6 +46,7 @@ class QThread;
class AndroidCameraPrivate;
class AndroidSurfaceTexture;
+class AndroidSurfaceHolder;
struct AndroidCameraInfo
{
@@ -67,7 +68,7 @@ public:
};
enum ImageFormat { // same values as in android.graphics.ImageFormat Java class
- Unknown = 0,
+ UnknownImageFormat = 0,
RGB565 = 4,
NV16 = 16,
NV21 = 17,
@@ -95,10 +96,12 @@ public:
ImageFormat getPreviewFormat();
void setPreviewFormat(ImageFormat fmt);
+ QList<ImageFormat> getSupportedPreviewFormats();
QSize previewSize() const;
void setPreviewSize(const QSize &size);
bool setPreviewTexture(AndroidSurfaceTexture *surfaceTexture);
+ bool setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder);
bool isZoomSupported();
int getMaxZoom();
@@ -152,6 +155,7 @@ public:
void startPreview();
void stopPreview();
+ void stopPreviewSynchronous();
void takePicture();
@@ -179,8 +183,8 @@ Q_SIGNALS:
void takePictureFailed();
void pictureExposed();
void pictureCaptured(const QByteArray &data);
- void lastPreviewFrameFetched(const QByteArray &preview, int width, int height);
- void newPreviewFrame(const QByteArray &frame, int width, int height);
+ void lastPreviewFrameFetched(const QVideoFrame &frame);
+ void newPreviewFrame(const QVideoFrame &frame);
private:
AndroidCamera(AndroidCameraPrivate *d, QThread *worker);
@@ -190,6 +194,8 @@ private:
QScopedPointer<QThread> m_worker;
};
+Q_DECLARE_METATYPE(AndroidCamera::ImageFormat)
+
QT_END_NAMESPACE
#endif // ANDROIDCAMERA_H
diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
index fa32f31ef..34063056f 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
@@ -34,6 +34,8 @@
#include "androidmediarecorder.h"
#include "androidcamera.h"
+#include "androidsurfacetexture.h"
+#include "androidsurfaceview.h"
#include <QtCore/private/qjni_p.h>
#include <qmap.h>
@@ -339,6 +341,41 @@ void AndroidMediaRecorder::setOutputFile(const QString &path)
}
}
+void AndroidMediaRecorder::setSurfaceTexture(AndroidSurfaceTexture *texture)
+{
+ QJNIEnvironmentPrivate env;
+ m_mediaRecorder.callMethod<void>("setPreviewDisplay",
+ "(Landroid/view/Surface;)V",
+ texture->surface());
+ if (env->ExceptionCheck()) {
+#ifdef QT_DEBUG
+ env->ExceptionDescribe();
+#endif
+ env->ExceptionClear();
+ }
+}
+
+void AndroidMediaRecorder::setSurfaceHolder(AndroidSurfaceHolder *holder)
+{
+ QJNIEnvironmentPrivate env;
+ QJNIObjectPrivate surfaceHolder(holder->surfaceHolder());
+ QJNIObjectPrivate surface = surfaceHolder.callObjectMethod("getSurface",
+ "()Landroid/view/Surface;");
+ if (!surface.isValid())
+ return;
+
+ m_mediaRecorder.callMethod<void>("setPreviewDisplay",
+ "(Landroid/view/Surface;)V",
+ surface.object());
+ if (env->ExceptionCheck()) {
+#ifdef QT_DEBUG
+ env->ExceptionDescribe();
+#endif
+ env->ExceptionClear();
+ }
+}
+
+
bool AndroidMediaRecorder::initJNI(JNIEnv *env)
{
jclass clazz = QJNIEnvironmentPrivate::findClass(QtMediaRecorderListenerClassName,
diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
index 1aa83a201..95b48ed47 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
+++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
@@ -41,6 +41,8 @@
QT_BEGIN_NAMESPACE
class AndroidCamera;
+class AndroidSurfaceTexture;
+class AndroidSurfaceHolder;
class AndroidCamcorderProfile
{
@@ -149,6 +151,9 @@ public:
void setOutputFormat(OutputFormat format);
void setOutputFile(const QString &path);
+ void setSurfaceTexture(AndroidSurfaceTexture *texture);
+ void setSurfaceHolder(AndroidSurfaceHolder *holder);
+
static bool initJNI(JNIEnv *env);
Q_SIGNALS:
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
index ffa37d7d4..9a25b7e28 100644
--- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
@@ -78,8 +78,8 @@ AndroidSurfaceTexture::AndroidSurfaceTexture(unsigned int texName)
AndroidSurfaceTexture::~AndroidSurfaceTexture()
{
- if (QtAndroidPrivate::androidSdkVersion() > 13 && m_surfaceView.isValid())
- m_surfaceView.callMethod<void>("release");
+ if (QtAndroidPrivate::androidSdkVersion() > 13 && m_surface.isValid())
+ m_surface.callMethod<void>("release");
if (m_surfaceTexture.isValid()) {
release();
@@ -124,21 +124,23 @@ jobject AndroidSurfaceTexture::surfaceTexture()
return m_surfaceTexture.object();
}
-jobject AndroidSurfaceTexture::surfaceView()
+jobject AndroidSurfaceTexture::surface()
{
- return m_surfaceView.object();
+ if (!m_surface.isValid()) {
+ m_surface = QJNIObjectPrivate("android/view/Surface",
+ "(Landroid/graphics/SurfaceTexture;)V",
+ m_surfaceTexture.object());
+ }
+
+ return m_surface.object();
}
jobject AndroidSurfaceTexture::surfaceHolder()
{
if (!m_surfaceHolder.isValid()) {
- m_surfaceView = QJNIObjectPrivate("android/view/Surface",
- "(Landroid/graphics/SurfaceTexture;)V",
- m_surfaceTexture.object());
-
m_surfaceHolder = QJNIObjectPrivate("org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder",
"(Landroid/view/Surface;)V",
- m_surfaceView.object());
+ surface());
}
return m_surfaceHolder.object();
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
index 2618ed6c9..ac2af694e 100644
--- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
+++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
@@ -50,7 +50,7 @@ public:
int textureID() const { return m_texID; }
jobject surfaceTexture();
- jobject surfaceView();
+ jobject surface();
jobject surfaceHolder();
inline bool isValid() const { return m_surfaceTexture.isValid(); }
@@ -66,7 +66,7 @@ Q_SIGNALS:
private:
int m_texID;
QJNIObjectPrivate m_surfaceTexture;
- QJNIObjectPrivate m_surfaceView;
+ QJNIObjectPrivate m_surface;
QJNIObjectPrivate m_surfaceHolder;
};
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfaceview.cpp b/src/plugins/android/src/wrappers/jni/androidsurfaceview.cpp
new file mode 100644
index 000000000..67560baf4
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jni/androidsurfaceview.cpp
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidsurfaceview.h"
+
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmutex.h>
+#include <QtGui/qwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+static const char QtSurfaceHolderCallbackClassName[] = "org/qtproject/qt5/android/multimedia/QtSurfaceHolderCallback";
+typedef QVector<AndroidSurfaceHolder *> SurfaceHolders;
+Q_GLOBAL_STATIC(SurfaceHolders, surfaceHolders)
+Q_GLOBAL_STATIC(QMutex, shLock)
+
+AndroidSurfaceHolder::AndroidSurfaceHolder(QJNIObjectPrivate object)
+ : m_surfaceHolder(object)
+ , m_surfaceCreated(false)
+{
+ if (!m_surfaceHolder.isValid())
+ return;
+
+ {
+ QMutexLocker locker(shLock);
+ surfaceHolders->append(this);
+ }
+
+ QJNIObjectPrivate callback(QtSurfaceHolderCallbackClassName, "(J)V", reinterpret_cast<jlong>(this));
+ m_surfaceHolder.callMethod<void>("addCallback",
+ "(Landroid/view/SurfaceHolder$Callback;)V",
+ callback.object());
+}
+
+AndroidSurfaceHolder::~AndroidSurfaceHolder()
+{
+ QMutexLocker locker(shLock);
+ const int i = surfaceHolders->indexOf(this);
+ if (Q_UNLIKELY(i == -1))
+ return;
+
+ surfaceHolders->remove(i);
+}
+
+jobject AndroidSurfaceHolder::surfaceHolder() const
+{
+ return m_surfaceHolder.object();
+}
+
+bool AndroidSurfaceHolder::isSurfaceCreated() const
+{
+ QMutexLocker locker(shLock);
+ return m_surfaceCreated;
+}
+
+void AndroidSurfaceHolder::handleSurfaceCreated(JNIEnv*, jobject, jlong id)
+{
+ QMutexLocker locker(shLock);
+ const int i = surfaceHolders->indexOf(reinterpret_cast<AndroidSurfaceHolder *>(id));
+ if (Q_UNLIKELY(i == -1))
+ return;
+
+ (*surfaceHolders)[i]->m_surfaceCreated = true;
+ Q_EMIT (*surfaceHolders)[i]->surfaceCreated();
+}
+
+void AndroidSurfaceHolder::handleSurfaceDestroyed(JNIEnv*, jobject, jlong id)
+{
+ QMutexLocker locker(shLock);
+ const int i = surfaceHolders->indexOf(reinterpret_cast<AndroidSurfaceHolder *>(id));
+ if (Q_UNLIKELY(i == -1))
+ return;
+
+ (*surfaceHolders)[i]->m_surfaceCreated = false;
+}
+
+bool AndroidSurfaceHolder::initJNI(JNIEnv *env)
+{
+ jclass clazz = QJNIEnvironmentPrivate::findClass(QtSurfaceHolderCallbackClassName,
+ env);
+
+ static const JNINativeMethod methods[] = {
+ {"notifySurfaceCreated", "(J)V", (void *)AndroidSurfaceHolder::handleSurfaceCreated},
+ {"notifySurfaceDestroyed", "(J)V", (void *)AndroidSurfaceHolder::handleSurfaceDestroyed}
+ };
+
+ if (clazz && env->RegisterNatives(clazz,
+ methods,
+ sizeof(methods) / sizeof(methods[0])) != JNI_OK) {
+ return false;
+ }
+
+ return true;
+}
+
+AndroidSurfaceView::AndroidSurfaceView()
+ : m_window(0)
+ , m_surfaceHolder(0)
+ , m_pendingVisible(-1)
+{
+ setAutoDelete(false);
+ QtAndroidPrivate::runOnUiThread(this, QJNIEnvironmentPrivate());
+}
+
+AndroidSurfaceView::~AndroidSurfaceView()
+{
+ delete m_surfaceHolder;
+ delete m_window;
+}
+
+AndroidSurfaceHolder *AndroidSurfaceView::holder() const
+{
+ return m_surfaceHolder;
+}
+
+void AndroidSurfaceView::setVisible(bool v)
+{
+ if (m_window)
+ m_window->setVisible(v);
+ else
+ m_pendingVisible = int(v);
+}
+
+void AndroidSurfaceView::setGeometry(int x, int y, int width, int height)
+{
+ if (m_window)
+ m_window->setGeometry(x, y, width, height);
+ else
+ m_pendingGeometry = QRect(x, y, width, height);
+}
+
+bool AndroidSurfaceView::event(QEvent *e)
+{
+ if (e->type() == QEvent::User) {
+ Q_ASSERT(m_surfaceView.isValid());
+
+ QJNIObjectPrivate holder = m_surfaceView.callObjectMethod("getHolder",
+ "()Landroid/view/SurfaceHolder;");
+ if (!holder.isValid()) {
+ m_surfaceView = QJNIObjectPrivate();
+ } else {
+ m_surfaceHolder = new AndroidSurfaceHolder(holder);
+ connect(m_surfaceHolder, &AndroidSurfaceHolder::surfaceCreated,
+ this, &AndroidSurfaceView::surfaceCreated);
+ { // Lock now to avoid a race with handleSurfaceCreated()
+ QMutexLocker locker(shLock);
+ m_window = QWindow::fromWinId(WId(m_surfaceView.object()));
+
+ if (m_pendingVisible != -1)
+ m_window->setVisible(m_pendingVisible);
+ if (m_pendingGeometry.isValid())
+ m_window->setGeometry(m_pendingGeometry);
+ }
+ }
+
+ return true;
+ }
+
+ return QObject::event(e);
+}
+
+// Called on the Android UI thread.
+void AndroidSurfaceView::run()
+{
+ m_surfaceView = QJNIObjectPrivate("android/view/SurfaceView",
+ "(Landroid/content/Context;)V",
+ QtAndroidPrivate::activity());
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfaceview.h b/src/plugins/android/src/wrappers/jni/androidsurfaceview.h
new file mode 100644
index 000000000..661a5959f
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jni/androidsurfaceview.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDSURFACEVIEW_H
+#define ANDROIDSURFACEVIEW_H
+
+#include <QtCore/private/qjni_p.h>
+#include <qrect.h>
+#include <QtCore/qrunnable.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+
+class AndroidSurfaceHolder : public QObject
+{
+ Q_OBJECT
+public:
+ ~AndroidSurfaceHolder();
+
+ jobject surfaceHolder() const;
+ bool isSurfaceCreated() const;
+
+ static bool initJNI(JNIEnv *env);
+
+Q_SIGNALS:
+ void surfaceCreated();
+
+private:
+ AndroidSurfaceHolder(QJNIObjectPrivate object);
+
+ static void handleSurfaceCreated(JNIEnv*, jobject, jlong id);
+ static void handleSurfaceDestroyed(JNIEnv*, jobject, jlong id);
+
+ QJNIObjectPrivate m_surfaceHolder;
+ bool m_surfaceCreated;
+
+ friend class AndroidSurfaceView;
+};
+
+class AndroidSurfaceView : public QObject, public QRunnable
+{
+ Q_OBJECT
+public:
+ AndroidSurfaceView();
+ ~AndroidSurfaceView();
+
+ AndroidSurfaceHolder *holder() const;
+
+ void setVisible(bool v);
+ void setGeometry(int x, int y, int width, int height);
+
+ bool event(QEvent *);
+
+Q_SIGNALS:
+ void surfaceCreated();
+
+protected:
+ void run() override;
+
+private:
+ QJNIObjectPrivate m_surfaceView;
+ QWindow *m_window;
+ AndroidSurfaceHolder *m_surfaceHolder;
+ int m_pendingVisible;
+ QRect m_pendingGeometry;
+};
+
+QT_END_NAMESPACE
+
+#endif // ANDROIDSURFACEVIEW_H
diff --git a/src/plugins/android/src/wrappers/jni/jni.pri b/src/plugins/android/src/wrappers/jni/jni.pri
index ba2ad0801..930d7e922 100644
--- a/src/plugins/android/src/wrappers/jni/jni.pri
+++ b/src/plugins/android/src/wrappers/jni/jni.pri
@@ -1,4 +1,4 @@
-QT += platformsupport-private
+QT += core-private
INCLUDEPATH += $$PWD
@@ -8,7 +8,8 @@ HEADERS += \
$$PWD/androidmediametadataretriever.h \
$$PWD/androidcamera.h \
$$PWD/androidmultimediautils.h \
- $$PWD/androidmediarecorder.h
+ $$PWD/androidmediarecorder.h \
+ $$PWD/androidsurfaceview.h
SOURCES += \
$$PWD/androidmediaplayer.cpp \
@@ -16,4 +17,5 @@ SOURCES += \
$$PWD/androidmediametadataretriever.cpp \
$$PWD/androidcamera.cpp \
$$PWD/androidmultimediautils.cpp \
- $$PWD/androidmediarecorder.cpp
+ $$PWD/androidmediarecorder.cpp \
+ $$PWD/androidsurfaceview.cpp