Compare commits
1140 Commits
TempBranch
...
main
Author | SHA1 | Date |
---|---|---|
|
dcd1d20a75 | 2 days ago |
|
f9b79e67fd | 5 days ago |
|
024d7f73b8 | 5 days ago |
|
476fa0ab7c | 5 days ago |
|
9ea9043a0e | 5 days ago |
|
8acd884797 | 5 days ago |
|
bbcd2691ed | 6 days ago |
|
c65ffab9dd | 6 days ago |
|
99d08c30ef | 6 days ago |
|
a38e3801ae | 6 days ago |
|
a9ac0743f7 | 6 days ago |
|
a7c4356d93 | 6 days ago |
|
2baf96fe67 | 6 days ago |
|
913747e6c3 | 6 days ago |
|
0b1aa8a13a | 1 week ago |
|
b5aec7ae17 | 1 week ago |
|
6f3cae9d02 | 1 week ago |
|
7a67a142cb | 1 week ago |
|
0a6850d92b | 1 week ago |
|
42dab55bc4 | 1 week ago |
|
662d3307b0 | 1 week ago |
|
2b9c1feae5 | 1 week ago |
|
aa04fca845 | 1 week ago |
|
a72118a5a6 | 1 week ago |
|
d50b21d0d6 | 1 week ago |
|
6255fa932c | 1 week ago |
|
8aec5f30ef | 2 weeks ago |
|
c23f30ce71 | 2 weeks ago |
|
118ffdc638 | 2 weeks ago |
|
058e4b2f46 | 2 weeks ago |
|
48d61baf6f | 2 weeks ago |
|
9ff07b8c12 | 2 weeks ago |
|
69958ba1d2 | 2 weeks ago |
|
3979e03882 | 2 weeks ago |
|
b96fe6bbfd | 3 weeks ago |
|
94edf1324f | 3 weeks ago |
|
18efb1e439 | 3 weeks ago |
|
b2a1a5cde3 | 3 weeks ago |
|
cdf664b448 | 3 weeks ago |
|
e549126563 | 3 weeks ago |
|
1322ddd8b2 | 3 weeks ago |
|
139a6a5fde | 3 weeks ago |
|
9721eced21 | 3 weeks ago |
|
b425713f63 | 3 weeks ago |
|
7e3ff1b741 | 3 weeks ago |
|
284f61a86e | 3 weeks ago |
|
aa4ca70d07 | 3 weeks ago |
|
6e1655813d | 3 weeks ago |
|
8468978f19 | 3 weeks ago |
|
ce2b36422c | 3 weeks ago |
|
38bfd44bcd | 3 weeks ago |
|
5ac7838839 | 3 weeks ago |
|
86b7e63849 | 3 weeks ago |
|
adb24119ef | 3 weeks ago |
|
436058fefa | 3 weeks ago |
|
7a6497ee40 | 3 weeks ago |
|
03110ac486 | 3 weeks ago |
|
8612c66ed3 | 3 weeks ago |
|
60989b5c40 | 4 weeks ago |
|
4df8d72c42 | 4 weeks ago |
|
f3e5cda1da | 4 weeks ago |
|
6d68a33224 | 4 weeks ago |
|
9d0f93b6ff | 4 weeks ago |
|
789547b503 | 4 weeks ago |
|
514fc054a7 | 4 weeks ago |
|
afc69b9dff | 4 weeks ago |
|
d29fb0280c | 4 weeks ago |
|
eca28cd6f7 | 4 weeks ago |
|
9efab780cf | 4 weeks ago |
|
c60587661b | 4 weeks ago |
|
1b40738b71 | 4 weeks ago |
|
8bff5f0741 | 4 weeks ago |
|
3c58e63c6a | 4 weeks ago |
|
450556375e | 4 weeks ago |
|
4cb359d0fd | 4 weeks ago |
|
a39614c581 | 4 weeks ago |
|
8c702f86c6 | 4 weeks ago |
|
81d4cd700c | 4 weeks ago |
|
15873ca510 | 4 weeks ago |
|
f06a7dfcff | 4 weeks ago |
|
1fbb9ffe51 | 4 weeks ago |
|
1772027e9e | 4 weeks ago |
|
8ff8a4bb1e | 4 weeks ago |
|
c071d8ec71 | 4 weeks ago |
|
e47acced9b | 4 weeks ago |
|
4bc9005ebb | 4 weeks ago |
|
5eb8e630c6 | 4 weeks ago |
|
02e66332ea | 4 weeks ago |
|
bd3451f47c | 4 weeks ago |
|
812688ae68 | 4 weeks ago |
|
5de3b6e73e | 4 weeks ago |
|
c34a649fa5 | 4 weeks ago |
|
cf557a599a | 4 weeks ago |
|
fd15553e70 | 4 weeks ago |
|
deb8b06820 | 4 weeks ago |
|
740dc120f6 | 4 weeks ago |
|
f66955ba99 | 4 weeks ago |
|
fed87bc421 | 4 weeks ago |
|
3bec3c924b | 4 weeks ago |
|
0d97a04da0 | 4 weeks ago |
|
0a88e9b918 | 4 weeks ago |
|
e5fd96efce | 4 weeks ago |
|
621bbb9c78 | 1 month ago |
|
c7351b8000 | 1 month ago |
|
d27321974f | 1 month ago |
|
75864122c5 | 1 month ago |
|
4eb14e755c | 1 month ago |
|
a22f41d537 | 1 month ago |
|
a58544eab1 | 1 month ago |
|
ebf8312f6f | 1 month ago |
|
46ec0a4f39 | 1 month ago |
|
189ebe3f41 | 1 month ago |
|
ba42b72744 | 1 month ago |
|
92ce03d2e8 | 1 month ago |
|
553bae38d9 | 1 month ago |
|
d3b493efbc | 1 month ago |
|
90df33d1f7 | 1 month ago |
|
38edbefcda | 1 month ago |
|
707aa9bd94 | 1 month ago |
|
6239916828 | 1 month ago |
|
3f4531ecd6 | 1 month ago |
|
5945fc1d1c | 1 month ago |
|
0f54876da8 | 1 month ago |
|
f433903745 | 1 month ago |
|
f216640381 | 1 month ago |
|
afae4794d3 | 1 month ago |
|
d96f337162 | 1 month ago |
|
ba500120b4 | 1 month ago |
|
6b8e477ed1 | 1 month ago |
|
f7ae9d42d2 | 1 month ago |
|
31d65ea586 | 1 month ago |
|
911a39a22f | 1 month ago |
|
1f07b07004 | 1 month ago |
|
6bc8849d3c | 1 month ago |
|
c67bebed88 | 1 month ago |
|
f7912c8882 | 1 month ago |
|
35b31577b2 | 1 month ago |
|
f8e627abc5 | 1 month ago |
|
92412cf7d7 | 1 month ago |
|
4222c6ff8a | 1 month ago |
|
2bba3867e9 | 1 month ago |
|
5df43d28d6 | 1 month ago |
|
724db375ca | 1 month ago |
|
2b416c3f0d | 1 month ago |
|
713f69048f | 1 month ago |
|
c85a5b9371 | 1 month ago |
|
031dc97548 | 1 month ago |
|
456268c682 | 1 month ago |
|
cc55b5aa4d | 1 month ago |
|
7558b79c5e | 1 month ago |
|
0d2090153f | 1 month ago |
|
024cca3104 | 1 month ago |
|
be9f65d3a3 | 1 month ago |
|
792a694f66 | 1 month ago |
|
b916e63a00 | 1 month ago |
|
eb5af62ad3 | 1 month ago |
|
67479e0acc | 1 month ago |
|
05b9a7a5e5 | 1 month ago |
|
c1a06203e3 | 1 month ago |
|
02fc11fc22 | 1 month ago |
|
026bd1a022 | 1 month ago |
|
200131ec67 | 1 month ago |
|
0b08c08d81 | 1 month ago |
|
75f0fdc73c | 1 month ago |
|
a7f4866ac8 | 1 month ago |
|
bc823212aa | 1 month ago |
|
7e23d09814 | 1 month ago |
|
5e869d0f92 | 1 month ago |
|
c6dbc278da | 1 month ago |
|
a248c9e297 | 1 month ago |
|
185ed0abff | 1 month ago |
|
3a0ae0ab75 | 1 month ago |
|
69bc6dced9 | 1 month ago |
|
6e1625b58d | 1 month ago |
|
115a22dd47 | 1 month ago |
|
c104f26f7d | 1 month ago |
|
d36d0d916d | 1 month ago |
|
0c57bca352 | 1 month ago |
|
8abeaf9e04 | 1 month ago |
|
f0b82e235e | 1 month ago |
|
3db1ae1c08 | 1 month ago |
|
43148b5962 | 1 month ago |
|
a58e86b519 | 1 month ago |
|
a6bfbdcea2 | 1 month ago |
|
752b5fe318 | 1 month ago |
|
4ca40f0424 | 1 month ago |
|
d75ad0949e | 1 month ago |
|
e3388d77c3 | 1 month ago |
|
4067f2d6ed | 1 month ago |
|
aeb8e49b81 | 1 month ago |
|
3bc6775f84 | 1 month ago |
|
dc17a15210 | 1 month ago |
|
e4e174a083 | 1 month ago |
|
44d780a0ce | 1 month ago |
|
0097f11b69 | 1 month ago |
|
b533cd645f | 1 month ago |
|
e0063691f0 | 1 month ago |
|
31039c213d | 1 month ago |
|
86f22853ca | 1 month ago |
|
b3024a934b | 1 month ago |
|
b1b2b0d550 | 1 month ago |
|
0c1143d0d0 | 1 month ago |
|
362a23f58d | 1 month ago |
|
ce762add59 | 1 month ago |
|
8e44768f7e | 1 month ago |
|
fc7fc294eb | 1 month ago |
|
ee0a2b632e | 1 month ago |
|
d94124aa3c | 1 month ago |
|
22b81f8c46 | 1 month ago |
|
2811c694b7 | 1 month ago |
|
06f38f3ff0 | 1 month ago |
|
f8ccfbba76 | 1 month ago |
|
96b07fa223 | 1 month ago |
|
ae6d49ed99 | 1 month ago |
|
5d57a099cd | 1 month ago |
|
c8f34e9319 | 1 month ago |
|
e01b32e166 | 1 month ago |
|
db2ff686c6 | 1 month ago |
|
e022748f71 | 1 month ago |
|
c6405cf287 | 1 month ago |
|
38fe69d93b | 1 month ago |
|
e75fe1648c | 1 month ago |
|
ab438f68b8 | 1 month ago |
|
ba37692f73 | 1 month ago |
|
97c8cc3038 | 2 months ago |
|
5872857f8d | 2 months ago |
|
9c7be4fe96 | 2 months ago |
|
4e5b1b7b2a | 2 months ago |
|
cbf60b12f6 | 2 months ago |
|
9a88a2dcd2 | 2 months ago |
|
00a8de5e54 | 2 months ago |
|
1fcc231ac1 | 2 months ago |
|
667ebb60c8 | 2 months ago |
|
dcf3dffe02 | 2 months ago |
|
20c5eebd20 | 2 months ago |
|
eeabd15b87 | 2 months ago |
|
d930f65393 | 2 months ago |
|
3974564746 | 2 months ago |
|
3c5f49a563 | 2 months ago |
|
b1b70395c7 | 2 months ago |
|
21aac05206 | 2 months ago |
|
e2c4e51550 | 2 months ago |
|
75a7c17d62 | 2 months ago |
|
d9b75e2c2f | 2 months ago |
|
f90cbd0446 | 2 months ago |
|
a90617698b | 2 months ago |
|
738f4f230a | 2 months ago |
|
55bda9770e | 2 months ago |
|
e580737761 | 2 months ago |
|
c0e0b3874f | 2 months ago |
|
31391c2bab | 2 months ago |
|
025c9fb07f | 2 months ago |
|
07f7744ad8 | 2 months ago |
|
58d8c614ab | 2 months ago |
|
82e8212027 | 2 months ago |
|
32a1fbbeb1 | 2 months ago |
|
2dd6cb8f31 | 2 months ago |
|
0d8bb73f17 | 2 months ago |
|
89b263e4de | 2 months ago |
|
2d600c18e4 | 2 months ago |
|
424bd6ee88 | 2 months ago |
|
987d2e8053 | 2 months ago |
|
387673bf99 | 2 months ago |
|
8bb1c53bc2 | 2 months ago |
|
7ae8505809 | 2 months ago |
|
d2881112f2 | 2 months ago |
|
40d36e1577 | 2 months ago |
|
47ff714ae5 | 2 months ago |
|
f8784c5b26 | 2 months ago |
|
ee492d0e60 | 2 months ago |
|
8fd275a6e7 | 2 months ago |
|
a9fd536a8a | 2 months ago |
|
142fca3dd0 | 2 months ago |
|
ed35d74c94 | 2 months ago |
|
cd520ebefe | 2 months ago |
|
9ff79bbe1b | 2 months ago |
|
6598b45d3e | 2 months ago |
|
62de685e4e | 2 months ago |
|
a0c4651e97 | 2 months ago |
|
883e9f94e4 | 2 months ago |
|
44a5a32741 | 2 months ago |
|
31e33b065b | 2 months ago |
|
5a8be5883b | 2 months ago |
|
b734a9cc2a | 2 months ago |
|
be7b992bdd | 2 months ago |
|
2b06803252 | 2 months ago |
|
396d20ea3f | 2 months ago |
|
fde6514d16 | 2 months ago |
|
f6d3ccbfa1 | 2 months ago |
|
754d3bebb7 | 2 months ago |
|
a04db636c6 | 2 months ago |
|
6e379548e6 | 2 months ago |
|
38a8498dbc | 2 months ago |
|
5dae67b03b | 2 months ago |
|
b821156ca1 | 2 months ago |
|
870cffab5c | 2 months ago |
|
55c3776ac8 | 2 months ago |
|
126c1f5e1b | 2 months ago |
|
28be0c4c80 | 2 months ago |
|
8c3103eef6 | 2 months ago |
|
e59f6fbbea | 2 months ago |
|
b216ad7546 | 2 months ago |
|
c3e4ef0847 | 2 months ago |
|
101d2b945a | 2 months ago |
|
7ea3b47abb | 2 months ago |
|
cf6c5c8158 | 2 months ago |
|
b9fe6ce048 | 2 months ago |
|
138040baa8 | 2 months ago |
|
e21e409712 | 2 months ago |
|
b3f3703c74 | 2 months ago |
|
f445f5f6c8 | 2 months ago |
|
cafa30c728 | 2 months ago |
|
167878de1a | 2 months ago |
|
c51fb6924b | 2 months ago |
|
ec6a27df28 | 2 months ago |
|
11e5b98a90 | 2 months ago |
|
d4c5986943 | 2 months ago |
|
5a91bd8dcb | 2 months ago |
|
4c42820cea | 2 months ago |
|
db78ce7728 | 2 months ago |
|
b5a188a5b4 | 2 months ago |
|
90465c4ac1 | 2 months ago |
|
7ef6086f50 | 2 months ago |
|
5151f9291a | 2 months ago |
|
7037eab930 | 2 months ago |
|
2d67c94bc9 | 2 months ago |
|
39b94cee90 | 2 months ago |
|
801a9e98ba | 2 months ago |
|
868fbebb6b | 2 months ago |
|
1806c36148 | 2 months ago |
|
f2f29482a0 | 2 months ago |
|
a52255e9d9 | 2 months ago |
|
2cc92025fc | 2 months ago |
|
744057c407 | 2 months ago |
|
d23116aa57 | 2 months ago |
|
3fab6d4542 | 2 months ago |
|
21c789155c | 2 months ago |
|
11dbea7170 | 2 months ago |
|
17ae352c31 | 2 months ago |
|
31c0d81e13 | 2 months ago |
|
18ecc420ed | 2 months ago |
|
b58969cc5e | 2 months ago |
|
9bb9b6848c | 2 months ago |
|
7a557ac8fd | 2 months ago |
|
e0a23a6c3b | 2 months ago |
|
2d0fe6609b | 2 months ago |
|
7e57c3cc08 | 2 months ago |
|
0fc7ff436e | 2 months ago |
|
2009c6d472 | 2 months ago |
|
24333d1882 | 2 months ago |
|
04abdbeb61 | 2 months ago |
|
4106ce8cb3 | 2 months ago |
|
7ad52b042c | 2 months ago |
|
6925da78b1 | 2 months ago |
|
9f00a81b8e | 2 months ago |
|
1c8372d5a2 | 2 months ago |
|
1782269938 | 2 months ago |
|
8398ae8246 | 2 months ago |
|
49aff958d0 | 2 months ago |
|
b6932b116e | 2 months ago |
|
4976337878 | 2 months ago |
|
897b53e44e | 2 months ago |
|
621cf4f3ba | 2 months ago |
|
476ebbd5e0 | 2 months ago |
|
c54cecacf0 | 2 months ago |
|
9fedc2532c | 2 months ago |
|
8e9597eaf4 | 2 months ago |
|
b94039cbd6 | 2 months ago |
|
6d2f4c7535 | 2 months ago |
|
252e2575f5 | 2 months ago |
|
6587298604 | 2 months ago |
|
eb96c9c6c7 | 2 months ago |
|
d1d34ebcfc | 2 months ago |
|
3a0a8b71a0 | 2 months ago |
|
030ca9c7d7 | 2 months ago |
|
a9535f2df7 | 2 months ago |
|
1ba1b9d56a | 2 months ago |
|
7a51b96100 | 2 months ago |
|
8a7d571e0e | 2 months ago |
|
2336758523 | 2 months ago |
|
95213a4ecd | 2 months ago |
|
8f49d82dec | 2 months ago |
|
0170e21b1d | 2 months ago |
|
94ca4f77a4 | 2 months ago |
|
2af459d57a | 2 months ago |
|
1f3943b34b | 2 months ago |
|
ec5799f167 | 2 months ago |
|
9f23994521 | 2 months ago |
|
e3aa7d04eb | 2 months ago |
|
5049677133 | 2 months ago |
|
eb5aa8396a | 2 months ago |
|
d35bf3d71c | 2 months ago |
|
17e2ae7fd9 | 2 months ago |
|
8108bf4c7c | 2 months ago |
|
996cb9109f | 2 months ago |
|
164b14697c | 2 months ago |
|
74f42bcfd3 | 2 months ago |
|
3ea1fbde25 | 2 months ago |
|
2c53f2fc0a | 2 months ago |
|
a74db09f67 | 2 months ago |
|
ae213c7a9b | 2 months ago |
|
13cb6722f3 | 2 months ago |
|
820158e650 | 2 months ago |
|
78cacaeba1 | 2 months ago |
|
40e9533d31 | 2 months ago |
|
357c58112f | 2 months ago |
|
4afdbdae62 | 2 months ago |
|
79dc4e8ec7 | 2 months ago |
|
6388002df2 | 2 months ago |
|
ebe52ca252 | 2 months ago |
|
ce81c8dd4f | 2 months ago |
|
7033ad7e0b | 2 months ago |
|
9397d53107 | 2 months ago |
|
48856f0c0b | 2 months ago |
|
2d5cc27c0e | 2 months ago |
|
e3c74db577 | 2 months ago |
|
dada0e876f | 2 months ago |
|
9170d2bec0 | 2 months ago |
|
06842bca13 | 2 months ago |
|
410ded43f1 | 2 months ago |
|
1d92d624f8 | 2 months ago |
|
5a26bd6353 | 2 months ago |
|
f247a6f4e0 | 2 months ago |
|
991fc0a449 | 3 months ago |
|
ac357883ac | 3 months ago |
|
604819a8a1 | 3 months ago |
|
95c0fb4415 | 3 months ago |
|
4e10f77ce3 | 3 months ago |
|
3575377767 | 3 months ago |
|
f577a1be3d | 3 months ago |
|
0b8c29eb91 | 3 months ago |
|
4b09ea6428 | 3 months ago |
|
2b5916c9ce | 3 months ago |
|
0b5e19541e | 3 months ago |
|
bae16b9427 | 3 months ago |
|
22bc6af87c | 3 months ago |
|
8951b8cdaf | 3 months ago |
|
ae9ea20948 | 3 months ago |
|
963ac6bdaf | 3 months ago |
|
a2aef51df6 | 3 months ago |
|
182c592f98 | 3 months ago |
|
c09ed76819 | 3 months ago |
|
3b492e7ea3 | 3 months ago |
|
bd7d4132e2 | 3 months ago |
|
9c2346befd | 3 months ago |
|
385c456401 | 3 months ago |
|
c5d9e19aff | 3 months ago |
|
9a227b149e | 3 months ago |
|
49b614b7b9 | 3 months ago |
|
4033f978a5 | 3 months ago |
|
3c7e35b5ee | 3 months ago |
|
e6228f7dfa | 3 months ago |
|
8381d6a0b9 | 3 months ago |
|
a42bf5390c | 3 months ago |
|
44aeadbe2d | 3 months ago |
|
d7a9212d90 | 3 months ago |
|
c106ae42fd | 3 months ago |
|
5f4af242be | 3 months ago |
|
7212994a5f | 3 months ago |
|
09dae14725 | 3 months ago |
|
7b0c32e7b9 | 3 months ago |
|
b0c9e5f412 | 3 months ago |
|
180b2efe0b | 3 months ago |
|
bd81fd52d0 | 3 months ago |
|
eaf7bfb875 | 3 months ago |
|
82ebd92ad2 | 3 months ago |
|
ae3f25b14a | 3 months ago |
|
9017c2bd7d | 3 months ago |
|
b1071b52c5 | 3 months ago |
|
89443efa26 | 3 months ago |
|
d8defe3b63 | 3 months ago |
|
496a6fbdce | 3 months ago |
|
3a9b85c868 | 3 months ago |
|
e280e76015 | 3 months ago |
|
41208a587c | 3 months ago |
|
b381fa562f | 3 months ago |
|
0375b13c67 | 3 months ago |
|
864a8dc0dd | 3 months ago |
|
a506598b42 | 3 months ago |
|
441cdc40b1 | 3 months ago |
|
ab91aa6cef | 3 months ago |
|
b40f77076d | 3 months ago |
|
3fdf189af5 | 3 months ago |
|
447f9999eb | 3 months ago |
|
0c33cc68c4 | 3 months ago |
|
e999149187 | 3 months ago |
|
0aabc2af52 | 3 months ago |
|
c17dc6a83e | 3 months ago |
|
026508615d | 3 months ago |
|
deaf5ec7e1 | 3 months ago |
|
c8610406ef | 3 months ago |
|
3902d69997 | 3 months ago |
|
22e81844ac | 3 months ago |
|
4c426cf5ff | 3 months ago |
|
8f9fa84028 | 3 months ago |
|
1925e923e2 | 3 months ago |
|
9aa25b6d66 | 3 months ago |
|
0cb2927b13 | 3 months ago |
|
5578b2e40f | 3 months ago |
|
f0c6738887 | 3 months ago |
|
9f8e92030a | 3 months ago |
|
f5c38b5127 | 3 months ago |
|
b18b9f54e4 | 3 months ago |
|
808271c7f1 | 3 months ago |
|
21fd57061c | 3 months ago |
|
32698886d0 | 3 months ago |
|
3dbb79e94c | 3 months ago |
|
ca7e8e5acf | 3 months ago |
|
c8966009b8 | 3 months ago |
|
ccc0e0e334 | 3 months ago |
|
5d312ed1f0 | 3 months ago |
|
120d7fdde7 | 3 months ago |
|
238f0aeb4f | 3 months ago |
|
69a3997805 | 3 months ago |
|
ebcd0c4dca | 3 months ago |
|
e74c0185a5 | 3 months ago |
|
b08adad0a4 | 3 months ago |
|
955efa5389 | 3 months ago |
|
2c0b32fe64 | 3 months ago |
|
28315925ee | 3 months ago |
|
1fd8c79f58 | 3 months ago |
|
b4e7cf8fab | 3 months ago |
|
56d42d8774 | 3 months ago |
|
fe97b3c5bc | 3 months ago |
|
1583dc6a46 | 3 months ago |
|
44dc885717 | 3 months ago |
|
fb42203056 | 3 months ago |
|
5cf252b12f | 3 months ago |
|
6a80e97a43 | 3 months ago |
|
4d5020803c | 3 months ago |
|
e05bcedb6e | 3 months ago |
|
296858be26 | 3 months ago |
|
34a1c4377b | 3 months ago |
|
620af9bb26 | 3 months ago |
|
7624c2b249 | 3 months ago |
|
d939b8089e | 3 months ago |
|
99784847e3 | 3 months ago |
|
eba500f734 | 3 months ago |
|
454c5d6cc6 | 3 months ago |
|
c07508a711 | 3 months ago |
|
d51ff00473 | 3 months ago |
|
b23224415e | 3 months ago |
|
4e80dced8b | 3 months ago |
|
b579a0062d | 3 months ago |
|
2ae0368468 | 3 months ago |
|
9ad980f666 | 3 months ago |
|
0cfd48ff92 | 3 months ago |
|
0957cc3a12 | 3 months ago |
|
6dee0b0ad4 | 3 months ago |
|
d37d4e0c13 | 3 months ago |
|
c308feff90 | 3 months ago |
|
0f50e62000 | 3 months ago |
|
24321ae011 | 3 months ago |
|
bdfe3e2bd7 | 3 months ago |
|
485301e714 | 3 months ago |
|
64316cedf3 | 3 months ago |
|
b5eb21d063 | 3 months ago |
|
feb4981377 | 3 months ago |
|
4109741628 | 3 months ago |
|
fedae228b1 | 3 months ago |
|
0d92c10c60 | 3 months ago |
|
8b51cfdefb | 3 months ago |
|
a7d3266624 | 3 months ago |
|
b8416b8e1b | 3 months ago |
|
2e12a1ac84 | 3 months ago |
|
3453e2d221 | 3 months ago |
|
12197fa28d | 3 months ago |
|
a1601cd71c | 3 months ago |
|
a14c76c4ed | 3 months ago |
|
4cae89014d | 3 months ago |
|
89fe772caa | 3 months ago |
|
216a053086 | 3 months ago |
|
52608b8324 | 3 months ago |
|
5734762c07 | 3 months ago |
|
3a8ef64e2f | 3 months ago |
|
4ba4be427e | 3 months ago |
|
5c7f6abb71 | 3 months ago |
|
02663dd08b | 3 months ago |
|
fd84d84157 | 3 months ago |
|
70b795fe27 | 3 months ago |
|
d206a59d9a | 3 months ago |
|
ee93791683 | 3 months ago |
|
53578065f1 | 3 months ago |
|
6f56bf0fe3 | 3 months ago |
|
d1298663f3 | 3 months ago |
|
b82fe124d8 | 3 months ago |
|
83d9e4e6c9 | 3 months ago |
|
79e8a8ff71 | 3 months ago |
|
d9f6c6e8ac | 3 months ago |
|
c912c70572 | 3 months ago |
|
bbb78f44b9 | 3 months ago |
|
df1fc220d1 | 3 months ago |
|
4de7693aaa | 3 months ago |
|
79c828324d | 3 months ago |
|
a34e66c7ff | 3 months ago |
|
f2a965caf0 | 3 months ago |
|
1bdc190a1b | 3 months ago |
|
127b06de77 | 3 months ago |
|
d908a36d3b | 3 months ago |
|
9eafc3d2f3 | 3 months ago |
|
2167afa1d8 | 3 months ago |
|
341045651c | 3 months ago |
|
b6e58239d3 | 3 months ago |
|
b996c663a9 | 3 months ago |
|
55a01c47b6 | 3 months ago |
|
87f9559cfd | 3 months ago |
|
cdd0fcc361 | 3 months ago |
|
6d84ed0ab7 | 3 months ago |
|
ed08d8099c | 3 months ago |
|
8ddc778cc4 | 3 months ago |
|
63339c199d | 3 months ago |
|
b15f12bf5f | 3 months ago |
|
f08871da64 | 3 months ago |
|
691acaf67e | 3 months ago |
|
964fa2a91b | 3 months ago |
|
aa434414ed | 3 months ago |
|
e1721d52d7 | 3 months ago |
|
7376d4cb0f | 3 months ago |
|
614b0d4500 | 3 months ago |
|
ba223f90bd | 3 months ago |
|
0d7d3a69b6 | 3 months ago |
|
4c03d73752 | 3 months ago |
|
e88c2ddfcf | 3 months ago |
|
a6bf1e117c | 3 months ago |
|
1f6276860e | 3 months ago |
|
15fd93a73a | 3 months ago |
|
ce96fcb46c | 3 months ago |
|
995d9cc127 | 3 months ago |
|
6d1f0832c6 | 3 months ago |
|
3033c8a68d | 3 months ago |
|
cd0a6befd6 | 3 months ago |
|
d9c1cbac2f | 3 months ago |
|
f8bbdc58cf | 3 months ago |
|
05048bbf53 | 3 months ago |
|
a17f6a4278 | 3 months ago |
|
a9145e8871 | 3 months ago |
|
295aadfc16 | 3 months ago |
|
9a89445183 | 3 months ago |
|
8f595e415e | 3 months ago |
|
22741fe3e2 | 3 months ago |
|
567a4b81fd | 3 months ago |
|
c97342abc7 | 3 months ago |
|
6db86856e7 | 3 months ago |
|
d841200500 | 3 months ago |
|
fd88feeacd | 3 months ago |
|
d0288551fc | 3 months ago |
|
b1d1e3f65c | 3 months ago |
|
f3bd23680d | 3 months ago |
|
2b818f920c | 3 months ago |
|
3d6a3b6559 | 3 months ago |
|
878bae9961 | 3 months ago |
|
a6e928c2d2 | 3 months ago |
|
03a2888369 | 3 months ago |
|
fc39cd0eb1 | 3 months ago |
|
fa6d7929ff | 3 months ago |
|
9e76c216f7 | 3 months ago |
|
b8dad4ed13 | 3 months ago |
|
06843dff13 | 3 months ago |
|
9b0f50c8b3 | 3 months ago |
|
3ec9d6e711 | 3 months ago |
|
2baecd5289 | 3 months ago |
|
05d265d559 | 3 months ago |
|
369f4d7c87 | 3 months ago |
|
f2023d130d | 3 months ago |
|
293431c608 | 3 months ago |
|
65e56000cb | 3 months ago |
|
5001581438 | 3 months ago |
|
0f2b29a61e | 3 months ago |
|
f9ca260bcc | 3 months ago |
|
3633fda081 | 3 months ago |
|
4de735fb19 | 3 months ago |
|
e5c25f084e | 3 months ago |
|
8fc0354f0c | 3 months ago |
|
20aaed0bb2 | 4 months ago |
|
12035d2990 | 4 months ago |
|
ee68539dde | 4 months ago |
|
8d31b18917 | 4 months ago |
|
92e5dabee8 | 4 months ago |
|
a38f473ce8 | 4 months ago |
|
1b6c7ef372 | 4 months ago |
|
04b8ce7796 | 4 months ago |
|
8a14578952 | 4 months ago |
|
e01c19e9f8 | 4 months ago |
|
ace0d5babb | 4 months ago |
|
003193d95a | 4 months ago |
|
853e556d8a | 4 months ago |
|
2c46504b36 | 4 months ago |
|
515864c93d | 4 months ago |
|
148ce5cb57 | 4 months ago |
|
e66667eb11 | 4 months ago |
|
3db0d0387b | 4 months ago |
|
876ab5ab05 | 4 months ago |
|
d8ab5050b3 | 4 months ago |
|
78101816a4 | 4 months ago |
|
291d72b135 | 4 months ago |
|
1a36d83b29 | 4 months ago |
|
9ae985965c | 4 months ago |
|
226932ae02 | 4 months ago |
|
4e16d4ff74 | 4 months ago |
|
20736f0c56 | 4 months ago |
|
8f45e88547 | 4 months ago |
|
160dffd274 | 4 months ago |
|
2d6db87e11 | 4 months ago |
|
54e35bce2c | 4 months ago |
|
2898295236 | 4 months ago |
|
8a3da517b4 | 4 months ago |
|
bba91ff3a6 | 4 months ago |
|
1801ceb965 | 4 months ago |
|
4371f39872 | 4 months ago |
|
a8c945be2b | 4 months ago |
|
4d39dda520 | 4 months ago |
|
d69c7d257a | 4 months ago |
|
bf91569905 | 4 months ago |
|
5e93009f25 | 4 months ago |
|
95bd8ff7b3 | 4 months ago |
|
84597d0108 | 4 months ago |
|
3d4aa720d9 | 4 months ago |
|
238d572f1e | 4 months ago |
|
80e8c5e7c7 | 4 months ago |
|
63259f11c8 | 4 months ago |
|
6fdfe988a7 | 4 months ago |
|
97eb35e169 | 4 months ago |
|
cff24f65ae | 4 months ago |
|
856c1a8b10 | 4 months ago |
|
a98dc5126c | 4 months ago |
|
5a4840dcbf | 4 months ago |
|
3234185c8b | 4 months ago |
|
486805b469 | 4 months ago |
|
70ff5e7ea2 | 4 months ago |
|
e0d1cbb60a | 4 months ago |
|
a205ee22f9 | 4 months ago |
|
c64cc8ef44 | 4 months ago |
|
d8ecf26722 | 4 months ago |
|
522d0b96e3 | 4 months ago |
|
ef8efd48b0 | 4 months ago |
|
4ca8e83188 | 4 months ago |
|
52e2b5f064 | 4 months ago |
|
7fbffb2930 | 4 months ago |
|
033e632e3b | 4 months ago |
|
dabff33bbc | 4 months ago |
|
fa3bb289bf | 4 months ago |
|
cae5b6996b | 4 months ago |
|
e39f42c28a | 4 months ago |
|
6129d10749 | 4 months ago |
|
2be8a53a67 | 4 months ago |
|
76e63a8808 | 4 months ago |
|
c186ab9098 | 4 months ago |
|
ac43db4e4a | 4 months ago |
|
600c46f024 | 4 months ago |
|
46bc13a608 | 4 months ago |
|
b91432cc4d | 4 months ago |
|
e27cd3e5fe | 4 months ago |
|
d6dc5729fe | 4 months ago |
|
2d90f18220 | 4 months ago |
|
5a74b57eb1 | 4 months ago |
|
cb36acfbd6 | 4 months ago |
|
dc448adc34 | 4 months ago |
|
79aa0134a5 | 4 months ago |
|
0001c9dc5a | 4 months ago |
|
6162c220b4 | 4 months ago |
|
5275d0c272 | 4 months ago |
|
4686003763 | 4 months ago |
|
a81dfe5bcf | 4 months ago |
|
50ee50f3d9 | 4 months ago |
|
e20f442512 | 4 months ago |
|
1e71375144 | 4 months ago |
|
e1c99fa228 | 4 months ago |
|
b751429199 | 4 months ago |
|
99b0d9ef70 | 4 months ago |
|
50adc38110 | 4 months ago |
|
2fe94152e5 | 4 months ago |
|
46b1c48c5c | 4 months ago |
|
28d58199bf | 4 months ago |
|
09cd545777 | 4 months ago |
|
dc692d05b1 | 4 months ago |
|
6be75f4a8e | 4 months ago |
|
9b59489969 | 4 months ago |
|
31954a3f17 | 4 months ago |
|
b7f6631672 | 4 months ago |
|
c4d8bd7f92 | 4 months ago |
|
672159ddc5 | 4 months ago |
|
727e397efe | 4 months ago |
|
9fa531b98d | 4 months ago |
|
3c3cb9b130 | 4 months ago |
|
bcda473b40 | 4 months ago |
|
011bd762ab | 4 months ago |
|
fe174f800d | 4 months ago |
|
101c8f41a4 | 4 months ago |
|
49cdb9d3ab | 4 months ago |
|
53df77733d | 4 months ago |
|
3d3a02158e | 4 months ago |
|
e0ed5615c3 | 4 months ago |
|
85a3d99f21 | 4 months ago |
|
018ccea1f8 | 4 months ago |
|
4f1b8c3b49 | 4 months ago |
|
db208237d6 | 4 months ago |
|
7adebb3019 | 4 months ago |
|
b7bfefe3e6 | 4 months ago |
|
af9ace5183 | 4 months ago |
|
87e8853737 | 4 months ago |
|
384d999ead | 4 months ago |
|
fc3f5fafa1 | 4 months ago |
|
b597e1f4eb | 4 months ago |
|
b9ba8135cd | 4 months ago |
|
63264f8e1c | 4 months ago |
|
2ba7429b56 | 4 months ago |
|
ae75a59f51 | 4 months ago |
|
de466ba891 | 4 months ago |
|
874f7db0cd | 4 months ago |
|
30e4562f1d | 4 months ago |
|
04504794a0 | 4 months ago |
|
7d7234037f | 4 months ago |
|
f2db516071 | 4 months ago |
|
becda30777 | 4 months ago |
|
6915001d02 | 4 months ago |
|
c680c83015 | 4 months ago |
|
c08b8a03b1 | 4 months ago |
|
5bfd1f58ea | 4 months ago |
|
772690d57e | 4 months ago |
|
5000fdecef | 4 months ago |
|
c91c97e5d0 | 4 months ago |
|
30360e9a05 | 4 months ago |
|
511852597c | 4 months ago |
|
2b0f921157 | 4 months ago |
|
650765e87d | 4 months ago |
|
345f9cc09d | 4 months ago |
|
055cd6cc7f | 4 months ago |
|
a8c97d93e2 | 4 months ago |
|
b5684256fe | 4 months ago |
|
e762e2b53c | 4 months ago |
|
a716856a4f | 4 months ago |
|
0bfbe32077 | 4 months ago |
|
72c936c3dd | 4 months ago |
|
278703deed | 5 months ago |
|
eba83ab37d | 5 months ago |
|
da75bd8519 | 5 months ago |
|
c307b7e56e | 5 months ago |
|
51a744cc51 | 5 months ago |
|
72c2ebebc6 | 5 months ago |
|
378bc2d0fb | 5 months ago |
|
5a8d4fdf9e | 5 months ago |
|
bbb4d8b4a3 | 5 months ago |
|
6a7295d9c3 | 5 months ago |
|
f1c6153852 | 5 months ago |
|
26725d8bdc | 5 months ago |
|
dfac4eeba6 | 5 months ago |
|
ac3e4627e9 | 5 months ago |
|
697fe83f5e | 5 months ago |
|
cdfb158437 | 5 months ago |
|
f3b2f01f8b | 5 months ago |
|
d4a561f3c2 | 5 months ago |
|
417d5c5083 | 5 months ago |
|
2c35ca4b3d | 5 months ago |
|
c408fa2e68 | 5 months ago |
|
34f0c173cb | 5 months ago |
|
5a8b7427c4 | 5 months ago |
|
a76b654593 | 5 months ago |
|
35ad7d8d25 | 5 months ago |
|
950e520fb2 | 5 months ago |
|
5cc05c373d | 5 months ago |
|
de288c860f | 5 months ago |
|
7b240fd01b | 5 months ago |
|
dc2b8c1504 | 5 months ago |
|
4e4904241c | 5 months ago |
|
b71fcebdf2 | 5 months ago |
|
7baaae19d8 | 5 months ago |
|
128a0a0003 | 5 months ago |
|
26144c195b | 5 months ago |
|
dfd970d1a9 | 5 months ago |
|
5d318b62c8 | 5 months ago |
|
9417980864 | 5 months ago |
|
a29b471633 | 5 months ago |
|
680b763ff6 | 5 months ago |
|
eb26477067 | 5 months ago |
|
8dbe00c8f9 | 5 months ago |
|
6e337a986f | 5 months ago |
|
25e465df3b | 6 months ago |
|
a423c07820 | 6 months ago |
|
e4b9245bed | 6 months ago |
|
0d9b6a1736 | 6 months ago |
|
5007405469 | 6 months ago |
|
f910187a48 | 6 months ago |
|
8b79de9208 | 6 months ago |
|
7eac44e6ce | 6 months ago |
|
c7c91af66d | 6 months ago |
|
a3599ccfc1 | 6 months ago |
|
dd35758e59 | 6 months ago |
|
ac5905f9fc | 6 months ago |
|
9231d205ca | 6 months ago |
|
0243d9b7d4 | 6 months ago |
|
a59144c97b | 6 months ago |
|
69a634edab | 6 months ago |
|
03628c4a70 | 6 months ago |
|
65f9e617e8 | 6 months ago |
|
25ae7ec464 | 6 months ago |
|
fa7b1d2bfa | 6 months ago |
|
2b6db343be | 6 months ago |
|
d5b46fb343 | 6 months ago |
|
8c1492052d | 6 months ago |
|
8dabf9aecc | 6 months ago |
|
43fde7df76 | 6 months ago |
|
2354403941 | 6 months ago |
|
3b03dce9e4 | 6 months ago |
|
4967f47036 | 6 months ago |
|
b482a184a0 | 6 months ago |
|
ef1a061fad | 6 months ago |
|
b73e58bfe7 | 6 months ago |
|
09073b86b0 | 6 months ago |
|
c2d4c3d296 | 6 months ago |
|
a6d4e065b3 | 6 months ago |
|
4cca774a09 | 6 months ago |
|
2f176a0a33 | 6 months ago |
|
e07de45f59 | 6 months ago |
|
a6134b860d | 6 months ago |
|
ebe573f0f3 | 6 months ago |
|
d4e64008bc | 6 months ago |
|
af0de16a67 | 6 months ago |
|
b5413de417 | 6 months ago |
|
a24345e01f | 6 months ago |
|
816881fd89 | 6 months ago |
|
ce4f7358b4 | 6 months ago |
|
c410e1e6a9 | 6 months ago |
|
bf9ee3aea8 | 6 months ago |
|
f0ed4adea3 | 6 months ago |
|
e0d926efb1 | 6 months ago |
|
92781524d7 | 6 months ago |
|
907836d3d6 | 6 months ago |
|
23877165ab | 6 months ago |
|
470d2be42a | 6 months ago |
|
61402ee8cb | 6 months ago |
|
23f2ab7527 | 6 months ago |
|
56ceb40f6d | 6 months ago |
|
eebf9b5a03 | 6 months ago |
|
9facbf3c55 | 6 months ago |
|
c501b689de | 6 months ago |
|
162d7624af | 6 months ago |
|
99efe9c91f | 6 months ago |
|
a3291e2dd2 | 6 months ago |
|
ddff8bdaca | 6 months ago |
|
1195bb01a1 | 6 months ago |
|
cd1e7b8a8c | 6 months ago |
|
ebe0def611 | 6 months ago |
|
a10f029175 | 6 months ago |
|
6940c89caf | 6 months ago |
|
7cc3de572b | 6 months ago |
|
48d37afa1e | 6 months ago |
|
2b26a090a0 | 6 months ago |
|
c3f7d99a0b | 6 months ago |
|
d671565f0b | 6 months ago |
|
a4deb30423 | 6 months ago |
|
7a2acd5f97 | 6 months ago |
|
3a98b0a451 | 6 months ago |
|
4af9c92440 | 6 months ago |
|
7aa553b1fa | 6 months ago |
|
fd8b9c093e | 6 months ago |
|
77aa962521 | 6 months ago |
|
7ae11e40fe | 6 months ago |
|
2ddb82a345 | 6 months ago |
|
8311ad8ba9 | 6 months ago |
|
b73c395357 | 6 months ago |
|
fc7a00d10c | 6 months ago |
|
d80ae9c119 | 6 months ago |
|
d92bc67606 | 6 months ago |
|
7d8c5d2342 | 6 months ago |
|
e2455cfd5a | 6 months ago |
|
bc01722f5d | 6 months ago |
|
feadee8ae4 | 6 months ago |
|
224659c163 | 6 months ago |
|
fa08064340 | 6 months ago |
|
6f8772d6a3 | 6 months ago |
|
09c7af6947 | 6 months ago |
|
bf3cb6416f | 6 months ago |
|
d6392eb1d3 | 6 months ago |
|
b2d2100dfc | 6 months ago |
|
ab9ba337dc | 6 months ago |
|
0b69dc75bc | 6 months ago |
|
653812fa56 | 6 months ago |
|
c2687cc87e | 6 months ago |
|
fcd78f02a6 | 6 months ago |
|
99c8e158c2 | 6 months ago |
|
56c1394bce | 6 months ago |
|
bec5b74a4f | 6 months ago |
|
dc69600477 | 6 months ago |
|
20f93c20bf | 6 months ago |
|
467d042a7b | 6 months ago |
|
99ee66139b | 6 months ago |
|
b24798af08 | 6 months ago |
|
8d05947395 | 6 months ago |
|
93864e30b9 | 6 months ago |
|
1633412d17 | 6 months ago |
|
30d69e378a | 6 months ago |
|
d435bab3c2 | 6 months ago |
|
2445315c5d | 6 months ago |
|
da14135af3 | 6 months ago |
|
06b8185a0a | 6 months ago |
|
5f48449da6 | 6 months ago |
|
6908711c3a | 6 months ago |
|
0fef92ddaf | 6 months ago |
|
4ba68b4d82 | 6 months ago |
|
f4a93cae9a | 6 months ago |
|
96a1221a53 | 6 months ago |
|
76e6b91e7e | 6 months ago |
|
e664a5f766 | 6 months ago |
|
a07e656a56 | 6 months ago |
|
66a4fa7f00 | 6 months ago |
|
77184e796d | 6 months ago |
|
6bd0ebf5b1 | 6 months ago |
|
ae02d3b366 | 6 months ago |
|
e943c79efc | 6 months ago |
|
dc4b2fbeed | 6 months ago |
|
bccff01bbd | 6 months ago |
|
8332dd98ef | 6 months ago |
|
fed405d585 | 6 months ago |
|
601c47b11b | 6 months ago |
|
7a35404099 | 6 months ago |
|
24856c5fb4 | 6 months ago |
|
a5603100f8 | 6 months ago |
|
3ccd293f4a | 6 months ago |
|
973000aa6b | 6 months ago |
|
af475d2795 | 6 months ago |
|
70f6f69fc3 | 6 months ago |
|
bca5c93430 | 6 months ago |
|
ce5e543f6b | 6 months ago |
|
a282111810 | 6 months ago |
|
9767036d54 | 6 months ago |
|
30b57fcce5 | 6 months ago |
|
8122341f79 | 6 months ago |
|
a43965639a | 6 months ago |
|
30a1706af5 | 6 months ago |
|
821dd34c18 | 6 months ago |
|
c2aa754b4b | 6 months ago |
|
915259ba2f | 6 months ago |
|
dfcb3623a9 | 6 months ago |
|
78ceadc24e | 6 months ago |
|
a7b7623c93 | 6 months ago |
|
d3a6903f5e | 6 months ago |
|
101f136036 | 6 months ago |
|
517323a28e | 6 months ago |
|
c2c6a2a10f | 6 months ago |
|
5f1f788694 | 6 months ago |
|
2e3cd76f01 | 6 months ago |
|
bd125e73fb | 6 months ago |
|
c98472d1fb | 6 months ago |
|
9cb881ce0a | 6 months ago |
|
856dc1c239 | 6 months ago |
|
76e6770cac | 6 months ago |
|
cf9e7b8264 | 6 months ago |
|
1fe9648704 | 6 months ago |
|
7a784a89e0 | 6 months ago |
|
1b96064578 | 6 months ago |
|
b236eb40d2 | 6 months ago |
|
58b01573ad | 6 months ago |
|
e59497e159 | 6 months ago |
|
187d715cd5 | 6 months ago |
|
e7a0a3b290 | 6 months ago |
|
11bab5a631 | 6 months ago |
|
87eac6bd08 | 6 months ago |
|
dbbfd96de2 | 6 months ago |
|
4f77f847b1 | 6 months ago |
|
3e26f35c65 | 6 months ago |
|
98c99e016c | 6 months ago |
|
ceb89a0c70 | 6 months ago |
|
bd706d1cf4 | 6 months ago |
|
385ae48185 | 6 months ago |
|
f1cfe67f72 | 6 months ago |
|
2fead34087 | 7 months ago |
|
7e48c76d33 | 7 months ago |
|
8c9ff7f2ba | 7 months ago |
|
ef3cc6d726 | 7 months ago |
|
da6074e2ec | 7 months ago |
|
01a056da4b | 7 months ago |
|
f10c33a5f9 | 7 months ago |
|
879801088d | 7 months ago |
|
f5590a708a | 7 months ago |
|
2694aec84a | 7 months ago |
|
e90e9a3d4e | 7 months ago |
|
7cf1055452 | 7 months ago |
|
3fa3a53507 | 7 months ago |
|
57c028c877 | 7 months ago |
|
f8b02ee28c | 7 months ago |
|
11f1dcd2f6 | 7 months ago |
|
4bddca2cd2 | 7 months ago |
|
251e120676 | 7 months ago |
|
096c253dbf | 7 months ago |
|
90e11f8763 | 7 months ago |
|
c271753dec | 7 months ago |
|
2a8a9e6074 | 7 months ago |
|
6b4076785f | 7 months ago |
|
25e459faea | 7 months ago |
|
01c8767a29 | 7 months ago |
|
5d844da1c4 | 7 months ago |
|
b7a7221e31 | 7 months ago |
|
7c16733906 | 7 months ago |
|
9ebbe19c4f | 7 months ago |
|
0ba0901619 | 7 months ago |
|
ce39427eda | 7 months ago |
|
05208d202f | 7 months ago |
|
fd2b54aef1 | 7 months ago |
|
39493ec75b | 7 months ago |
|
cd220aa256 | 7 months ago |
|
36750d6e85 | 7 months ago |
|
36d2188ce9 | 7 months ago |
|
eb13dea4fa | 7 months ago |
|
56b53eb8d4 | 7 months ago |
|
0b8fc17c22 | 7 months ago |
|
1728e08f7a | 7 months ago |
|
1e47fe04e6 | 7 months ago |
|
8cdcbc690e | 7 months ago |
|
30e9987c9e | 7 months ago |
|
d1571fad00 | 7 months ago |
|
02037ac34f | 7 months ago |
|
e7da756eec | 7 months ago |
|
fefa90b01f | 7 months ago |
|
c6eee57115 | 7 months ago |
|
80c9ed157a | 7 months ago |
|
64b75e994d | 7 months ago |
|
140726808f | 7 months ago |
|
9617743566 | 7 months ago |
|
1e72f8e4c4 | 7 months ago |
|
e2c0cff2e3 | 7 months ago |
|
e06b9178bf | 7 months ago |
|
83dfd4fb7c | 7 months ago |
|
70075a0ecc | 7 months ago |
|
7bdde7b70d | 7 months ago |
|
69536dc45d | 7 months ago |
|
c098420f1e | 7 months ago |
|
a71841c725 | 7 months ago |
|
53cd58bbe1 | 7 months ago |
|
002cb79223 | 7 months ago |
|
a15a0f6ed6 | 7 months ago |
|
f6d5f38bfc | 7 months ago |
|
2653290682 | 7 months ago |
|
a7e4fabe13 | 7 months ago |
|
9e260d2b93 | 7 months ago |
|
494b26d92d | 7 months ago |
|
1b0d0f421f | 7 months ago |
|
7cfe23f078 | 7 months ago |
|
7cd424953a | 7 months ago |
|
1f18a20b14 | 7 months ago |
|
3c65c5d5a9 | 8 months ago |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,227 @@
|
||||
#!/system/bin/sh
|
||||
|
||||
# ==============================================
|
||||
# Configuration parameters - modify as needed
|
||||
# ==============================================
|
||||
ETH_IP="192.168.68.91" # Ethernet IP address
|
||||
ETH_NETMASK="24" # Subnet mask (CIDR format)
|
||||
ETH_NETWORK="192.168.68.0" # Network address
|
||||
ETH_BROADCAST="192.168.68.255" # Broadcast address
|
||||
ETH_GATEWAY="192.168.68.1" # Default gateway
|
||||
ROUTE_TABLE="20" # Routing table number
|
||||
MAX_INIT_WAIT=150 # Maximum seconds to wait for ethernet interface
|
||||
MAX_UP_WAIT=10 # Maximum seconds to wait for interface to come UP
|
||||
MAX_ROUTE_WAIT=5 # Maximum seconds to wait for routing rules
|
||||
|
||||
# For debugging only - comment out in production
|
||||
# set -x
|
||||
|
||||
ANDROID_VERSION=$(getprop ro.build.version.release 2>/dev/null | cut -d '.' -f1)
|
||||
|
||||
# Record script start time
|
||||
SCRIPT_START=$(date +%s)
|
||||
|
||||
# Cleanup function - handles unexpected interruptions
|
||||
cleanup() {
|
||||
echo "Script interrupted, cleaning up..." >&2
|
||||
# Add additional cleanup code here if needed
|
||||
exit 1
|
||||
}
|
||||
trap cleanup INT TERM
|
||||
|
||||
# Get script directory for finding tools like ethtool
|
||||
SCRIPT_PATH="$0"
|
||||
# Ensure path is absolute
|
||||
case "$SCRIPT_PATH" in
|
||||
/*) ;; # Already absolute path
|
||||
*) SCRIPT_PATH="$PWD/$SCRIPT_PATH" ;;
|
||||
esac
|
||||
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
|
||||
echo "Script directory detected as: $SCRIPT_DIR"
|
||||
|
||||
# Only configure rp_filter for eth0 interface
|
||||
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter 2>/dev/null || true
|
||||
|
||||
# Wait for eth0 interface to appear
|
||||
WAITED=0
|
||||
while [ $WAITED -lt $MAX_INIT_WAIT ]; do
|
||||
if [ -d "/sys/class/net/eth0" ]; then
|
||||
echo "eth0 found after $WAITED seconds"
|
||||
break
|
||||
fi
|
||||
echo "Wait eth0... ($WAITED/$MAX_INIT_WAIT)"
|
||||
sleep 0.1
|
||||
WAITED=$((WAITED+1))
|
||||
done
|
||||
|
||||
# Check if eth0 exists
|
||||
if ! [ -d "/sys/class/net/eth0" ]; then
|
||||
echo "Error: eth0 not exists" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check physical connection status
|
||||
if [ -f "/sys/class/net/eth0/carrier" ]; then
|
||||
CARRIER=$(cat /sys/class/net/eth0/carrier)
|
||||
echo "Physical connection status: $CARRIER (1=connected, 0=disconnected)"
|
||||
if [ "$CARRIER" != "1" ]; then
|
||||
echo "Warning: Ethernet physical connection may have issues, please check the cable" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clear previous configuration
|
||||
/system/bin/ip link set eth0 down
|
||||
/system/bin/ip addr flush dev eth0
|
||||
/system/bin/ip route flush dev eth0
|
||||
/system/bin/ip route flush table $ROUTE_TABLE
|
||||
/system/bin/ip rule del to $ETH_NETWORK/$ETH_NETMASK 2>/dev/null || true
|
||||
|
||||
# Configure physical layer with ethtool (while interface is DOWN)
|
||||
if [ -x "$SCRIPT_DIR/ethtool" ]; then
|
||||
echo "Using ethtool from script directory: $SCRIPT_DIR/ethtool"
|
||||
"$SCRIPT_DIR/ethtool" -s eth0 speed 10 duplex full autoneg off
|
||||
# Try alternative path next
|
||||
elif [ -x "/data/data/com.xypower.mpapp/files/ethtool" ]; then
|
||||
echo "Configuring eth0 to 10Mbps full duplex..."
|
||||
/data/data/com.xypower.mpapp/files/ethtool -s eth0 speed 10 duplex full autoneg off
|
||||
else
|
||||
echo "Warning: ethtool not found, falling back to sysfs configuration" >&2
|
||||
# Try sysfs configuration as fallback
|
||||
if [ -f "/sys/class/net/eth0/speed" ]; then
|
||||
echo "off" > /sys/class/net/eth0/autoneg 2>/dev/null || true
|
||||
echo "10" > /sys/class/net/eth0/speed 2>/dev/null || true
|
||||
echo "full" > /sys/class/net/eth0/duplex 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# ====================================================
|
||||
# MTK Android 9 IP configuration with loss prevention
|
||||
# ====================================================
|
||||
|
||||
# Configure IP address first while interface is DOWN
|
||||
echo "Setting IP address while interface is DOWN..."
|
||||
/system/bin/ip addr add $ETH_IP/$ETH_NETMASK broadcast $ETH_BROADCAST dev eth0
|
||||
PRE_UP_IP=$(/system/bin/ip addr show eth0 | grep -c "inet $ETH_IP")
|
||||
echo "IP configuration before UP: $PRE_UP_IP (1=configured, 0=missing)"
|
||||
|
||||
# Enable interface and wait for UP
|
||||
echo "Bringing up interface..."
|
||||
/system/bin/ip link set eth0 up
|
||||
if [ "$ANDROID_VERSION" = "9" ]; then
|
||||
sleep 3
|
||||
else
|
||||
# Use standard configuration for other devices
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Check if IP was lost after interface UP (common issue on MTK devices)
|
||||
POST_UP_IP=$(/system/bin/ip addr show eth0 | grep -c "inet $ETH_IP")
|
||||
echo "IP configuration after UP: $POST_UP_IP (1=retained, 0=lost)"
|
||||
|
||||
# IP address lost detection and recovery
|
||||
if [ "$PRE_UP_IP" = "1" ] && [ "$POST_UP_IP" = "0" ]; then
|
||||
echo "Warning: IP address was lost after bringing interface up - MTK issue detected"
|
||||
echo "Reapplying IP configuration..."
|
||||
/system/bin/ip addr add $ETH_IP/$ETH_NETMASK broadcast $ETH_BROADCAST dev eth0
|
||||
|
||||
# Check if reapplied configuration worked
|
||||
FIXED_IP=$(/system/bin/ip addr show eth0 | grep -c "inet $ETH_IP")
|
||||
echo "IP reapplication result: $FIXED_IP (1=success, 0=still missing)"
|
||||
|
||||
# If standard method fails, try MTK-specific approaches
|
||||
if [ "$FIXED_IP" = "0" ]; then
|
||||
echo "Standard IP configuration failed, trying MTK-specific methods"
|
||||
|
||||
# Try ifconfig if available (works better on some MTK devices)
|
||||
if command -v ifconfig >/dev/null 2>&1; then
|
||||
echo "Using ifconfig method..."
|
||||
ifconfig eth0 $ETH_IP netmask 255.255.255.0 up
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Try Android's netd service if available
|
||||
if [ -x "/system/bin/ndc" ]; then
|
||||
echo "Using MTK netd service..."
|
||||
/system/bin/ndc network interface setcfg eth0 $ETH_IP 255.255.255.0 up
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use loop to wait for interface UP instead of fixed sleep
|
||||
WAITED=0
|
||||
while [ $WAITED -lt $MAX_UP_WAIT ]; do
|
||||
# Check both link status and IP configuration
|
||||
IF_STATUS=$(/system/bin/ip link show eth0 | grep -c ",UP")
|
||||
IP_STATUS=$(/system/bin/ip addr show eth0 | grep -c "inet $ETH_IP")
|
||||
|
||||
if [ "$IF_STATUS" = "1" ] && [ "$IP_STATUS" = "1" ]; then
|
||||
echo "Interface is UP with correct IP after $WAITED seconds"
|
||||
break
|
||||
fi
|
||||
|
||||
echo "Waiting for interface UP with IP... ($WAITED/$MAX_UP_WAIT)"
|
||||
|
||||
# If interface is UP but IP is missing, reapply IP
|
||||
if [ "$IF_STATUS" = "1" ] && [ "$IP_STATUS" = "0" ]; then
|
||||
echo "Interface UP but IP missing, reapplying IP..."
|
||||
/system/bin/ip addr add $ETH_IP/$ETH_NETMASK broadcast $ETH_BROADCAST dev eth0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
WAITED=$((WAITED+1))
|
||||
done
|
||||
|
||||
# Final status check
|
||||
FINAL_IF_STATUS=$(/system/bin/ip link show eth0 | grep -c ",UP")
|
||||
FINAL_IP_STATUS=$(/system/bin/ip addr show eth0 | grep -c "inet $ETH_IP")
|
||||
|
||||
if [ "$FINAL_IF_STATUS" != "1" ] || [ "$FINAL_IP_STATUS" != "1" ]; then
|
||||
echo "Warning: Failed to achieve stable interface state with IP" >&2
|
||||
echo "Final interface status: $FINAL_IF_STATUS (1=UP, 0=DOWN)"
|
||||
echo "Final IP status: $FINAL_IP_STATUS (1=configured, 0=missing)"
|
||||
/system/bin/ip addr show eth0
|
||||
else
|
||||
echo "Successfully configured eth0 with IP $ETH_IP"
|
||||
fi
|
||||
|
||||
# First add to main routing table
|
||||
/system/bin/ip route add $ETH_NETWORK/$ETH_NETMASK dev eth0 proto static scope link
|
||||
|
||||
# Then add to specified routing table
|
||||
/system/bin/ip route add $ETH_NETWORK/$ETH_NETMASK dev eth0 proto static scope link table $ROUTE_TABLE
|
||||
ADD_ROUTE_STATUS=$?
|
||||
|
||||
if [ $ADD_ROUTE_STATUS -eq 0 ]; then
|
||||
echo "Add route successfully"
|
||||
else
|
||||
echo "Failed to add route: $ADD_ROUTE_STATUS" >&2
|
||||
fi
|
||||
|
||||
# Only clear ARP and neighbor cache for eth0
|
||||
/system/bin/ip neigh flush dev eth0
|
||||
|
||||
# Add routing rules - only flush cache once after rule is added
|
||||
/system/bin/ip rule add from all to $ETH_NETWORK/$ETH_NETMASK lookup $ROUTE_TABLE prio 1000
|
||||
/system/bin/ip route flush cache dev eth0
|
||||
|
||||
# Only enable forwarding for eth0 interface
|
||||
echo 1 > /proc/sys/net/ipv4/conf/eth0/forwarding 2>/dev/null || true
|
||||
|
||||
# Wait for routing rules to take effect - using loop check instead of fixed wait
|
||||
WAITED=0
|
||||
while [ $WAITED -lt $MAX_ROUTE_WAIT ]; do
|
||||
if /system/bin/ip rule | grep -q "$ETH_NETWORK/$ETH_NETMASK"; then
|
||||
echo "Routing rules are now effective after $WAITED seconds"
|
||||
break
|
||||
fi
|
||||
echo "Waiting for routing rules to take effect... ($WAITED/$MAX_ROUTE_WAIT)"
|
||||
sleep 0.5
|
||||
WAITED=$((WAITED+1))
|
||||
done
|
||||
|
||||
# Display execution time
|
||||
SCRIPT_END=$(date +%s)
|
||||
TOTAL_TIME=$((SCRIPT_END - SCRIPT_START))
|
||||
echo "Total script execution time: $TOTAL_TIME seconds"
|
||||
exit 0
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,912 +0,0 @@
|
||||
#include "TerminalDevice.h"
|
||||
/*
|
||||
* Copyright 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#define LOG_TAG "CameraTestHelpers"
|
||||
|
||||
#include "PhoneDevice2.h"
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
// #include <opencv2/objdetect.hpp>
|
||||
// #include <opencv2/features2d.hpp>
|
||||
|
||||
// #include <opencv2/core/types.hpp>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <AndroidHelper.h>
|
||||
|
||||
extern bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread);
|
||||
|
||||
|
||||
// This value is 2 ^ 18 - 1, and is used to clamp the RGB values before their
|
||||
// ranges
|
||||
// are normalized to eight bits.
|
||||
static const int kMaxChannelValue = 262143;
|
||||
|
||||
static inline uint32_t YUV2RGB(int nY, int nU, int nV) {
|
||||
nY -= 16;
|
||||
nU -= 128;
|
||||
nV -= 128;
|
||||
if (nY < 0) nY = 0;
|
||||
|
||||
// This is the floating point equivalent. We do the conversion in integer
|
||||
// because some Android devices do not have floating point in hardware.
|
||||
// nR = (int)(1.164 * nY + 1.596 * nV);
|
||||
// nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
|
||||
// nB = (int)(1.164 * nY + 2.018 * nU);
|
||||
|
||||
int nR = (int)(1192 * nY + 1634 * nV);
|
||||
int nG = (int)(1192 * nY - 833 * nV - 400 * nU);
|
||||
int nB = (int)(1192 * nY + 2066 * nU);
|
||||
|
||||
nR = std::min(kMaxChannelValue, std::max(0, nR));
|
||||
nG = std::min(kMaxChannelValue, std::max(0, nG));
|
||||
nB = std::min(kMaxChannelValue, std::max(0, nB));
|
||||
|
||||
nR = (nR >> 10) & 0xff;
|
||||
nG = (nG >> 10) & 0xff;
|
||||
nB = (nB >> 10) & 0xff;
|
||||
|
||||
return 0xff000000 | (nR << 16) | (nG << 8) | nB;
|
||||
}
|
||||
|
||||
CPhoneDevice2::CPhoneDevice2(JavaVM* vm, jobject service)
|
||||
{
|
||||
m_vm = vm;
|
||||
JNIEnv* env = NULL;
|
||||
bool attached = false;
|
||||
bool res = GetJniEnv(m_vm, &env, attached);
|
||||
if (!res)
|
||||
{
|
||||
ALOGE("Failed to get JNI Env");
|
||||
}
|
||||
m_javaService = env->NewGlobalRef(service);
|
||||
|
||||
jclass classService = env->GetObjectClass(m_javaService);
|
||||
mRegisterTimerMid = env->GetMethodID(classService, "registerTimer", "(JI)Z");
|
||||
mRegisterHeartbeatMid = env->GetMethodID(classService, "registerHeartbeatTimer", "(I)V");
|
||||
mUnregisterTimerMid = env->GetMethodID(classService, "unregisterTimer", "(J)Z");
|
||||
mUpdateTimeMid = env->GetMethodID(classService, "updateTime", "(J)Z");
|
||||
|
||||
env->DeleteLocalRef(classService);
|
||||
|
||||
if (attached)
|
||||
{
|
||||
vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
m_timerUidFeed = time(NULL);
|
||||
presentRotation_ = 0;
|
||||
}
|
||||
|
||||
CPhoneDevice2::~CPhoneDevice2()
|
||||
{
|
||||
JNIEnv* env = NULL;
|
||||
bool attached = false;
|
||||
bool res = GetJniEnv(m_vm, &env, attached);
|
||||
if (!res)
|
||||
{
|
||||
ALOGE("Failed to get JNI Env");
|
||||
}
|
||||
env->DeleteGlobalRef(m_javaService);
|
||||
if (attached)
|
||||
{
|
||||
m_vm->DetachCurrentThread();
|
||||
}
|
||||
m_javaService = NULL;
|
||||
}
|
||||
|
||||
void CPhoneDevice2::SetListener(IListener* listener)
|
||||
{
|
||||
m_listener = listener;
|
||||
}
|
||||
|
||||
bool CPhoneDevice2::UpdateTime(time_t ts)
|
||||
{
|
||||
JNIEnv* env = NULL;
|
||||
jboolean ret = JNI_FALSE;
|
||||
bool attached = false;
|
||||
bool res = GetJniEnv(m_vm, &env, attached);
|
||||
if (!res)
|
||||
{
|
||||
ALOGE("Failed to get JNI Env");
|
||||
return false;
|
||||
}
|
||||
jlong timeInMillis = ((jlong)ts) * 1000;
|
||||
ret = env->CallBooleanMethod(m_javaService, mUpdateTimeMid, timeInMillis);
|
||||
if (attached)
|
||||
{
|
||||
m_vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
return (ret == JNI_TRUE);
|
||||
}
|
||||
|
||||
bool CPhoneDevice2::Reboot()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IDevice::timer_uid_t CPhoneDevice2::RegisterTimer(unsigned int timerType, unsigned int timeout)
|
||||
{
|
||||
IDevice::timer_uid_t uid = m_timerUidFeed.fetch_add(1);
|
||||
|
||||
ALOGI("NDK RegTimer: uid=%lld Type=%u timeout=%u", uid, timerType, timeout);
|
||||
|
||||
JNIEnv* env = NULL;
|
||||
jboolean ret = JNI_FALSE;
|
||||
bool attached = false;
|
||||
bool res = GetJniEnv(m_vm, &env, attached);
|
||||
if (!res)
|
||||
{
|
||||
ALOGE("Failed to get JNI Env");
|
||||
return 0;
|
||||
}
|
||||
ret = env->CallBooleanMethod(m_javaService, mRegisterTimerMid, (jlong)uid, (jint)timeout);
|
||||
|
||||
if (attached)
|
||||
{
|
||||
m_vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
if (ret == JNI_TRUE)
|
||||
{
|
||||
unsigned long val = timerType;
|
||||
mTimers.insert(mTimers.end(), std::pair<IDevice::timer_uid_t, unsigned long>(uid, val));
|
||||
return uid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CPhoneDevice2::UnregisterTimer(IDevice::timer_uid_t uid)
|
||||
{
|
||||
JNIEnv* env = NULL;
|
||||
jboolean ret = JNI_FALSE;
|
||||
bool attached = false;
|
||||
bool res = GetJniEnv(m_vm, &env, attached);
|
||||
if (!res)
|
||||
{
|
||||
ALOGE("Failed to get JNI Env");
|
||||
return false;
|
||||
}
|
||||
ret = env->CallBooleanMethod(m_javaService, mUnregisterTimerMid, (jlong)uid);
|
||||
if (attached)
|
||||
{
|
||||
m_vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
if (ret == JNI_TRUE)
|
||||
{
|
||||
mTimers.erase(uid);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPhoneDevice2::FireTimer(timer_uid_t uid)
|
||||
{
|
||||
std::map<IDevice::timer_uid_t, unsigned long>::iterator it = mTimers.find(uid);
|
||||
if (it == mTimers.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long timerType = it->second & 0xFFFFFFFF;
|
||||
unsigned long times = (it->second & 0xFFFFFFFF00000000) >> 32;
|
||||
times++;
|
||||
|
||||
if (timerType != 100)
|
||||
{
|
||||
int aa = 0;
|
||||
}
|
||||
it->second = timerType | (times << 32);
|
||||
|
||||
if (m_listener == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_listener->OnTimeout(uid, timerType, NULL, times);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IDevice::timer_uid_t CPhoneDevice2::RegisterHeartbeat(unsigned int timerType, unsigned int timeout)
|
||||
{
|
||||
IDevice::timer_uid_t uid = m_timerUidFeed.fetch_add(1);
|
||||
|
||||
JNIEnv* env = NULL;
|
||||
jboolean ret = JNI_FALSE;
|
||||
bool attached = false;
|
||||
bool res = GetJniEnv(m_vm, &env, attached);
|
||||
if (!res)
|
||||
{
|
||||
ALOGE("Failed to get JNI Env");
|
||||
return 0;
|
||||
}
|
||||
env->CallVoidMethod(m_javaService, mRegisterHeartbeatMid, (jint)timeout);
|
||||
if (attached)
|
||||
{
|
||||
m_vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
bool CPhoneDevice2::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<OSD_INFO>& osds, const string& path)
|
||||
{
|
||||
ALOGI("TAKE_PHOTO: CH=%u PR=%u\n", (unsigned int)photoInfo.channel, (unsigned int)photoInfo.preset);
|
||||
mPhotoInfo = photoInfo;
|
||||
mPath = path;
|
||||
|
||||
mDisplayDimension = DisplayDimension(photoInfo.width, photoInfo.height);
|
||||
|
||||
ALOGE("Image Buffer Size: %d", photoInfo.width * photoInfo.height * 4);
|
||||
imageBuffer_ = (uint8_t*)malloc(photoInfo.width * photoInfo.height * 4);
|
||||
AASSERT(imageBuffer_ != nullptr, "Failed to allocate imageBuffer_");
|
||||
|
||||
int cameraId = (int)photoInfo.channel - 1;
|
||||
|
||||
ACameraIdList *cameraIdList = NULL;
|
||||
ACameraMetadata *cameraMetadata = NULL;
|
||||
|
||||
const char *selectedCameraId = NULL;
|
||||
camera_status_t camera_status = ACAMERA_OK;
|
||||
ACameraManager *cameraManager = ACameraManager_create();
|
||||
|
||||
camera_status = ACameraManager_getCameraIdList(cameraManager, &cameraIdList);
|
||||
if (camera_status != ACAMERA_OK) {
|
||||
ALOGI("Failed to get camera id list (reason: %d)\n", camera_status);
|
||||
TakePhotoCb(false, photoInfo, path, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cameraIdList->numCameras < 1 ) {
|
||||
ALOGI("No camera device detected.\n");
|
||||
TakePhotoCb(false, photoInfo, path, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cameraIdList->numCameras <= cameraId ) {
|
||||
ALOGI("No required camera device %d detected.\n", cameraId);
|
||||
TakePhotoCb(false, photoInfo, path, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
selectedCameraId = cameraIdList->cameraIds[cameraId];
|
||||
|
||||
ALOGI("Trying to open Camera2 (id: %s, num of camera : %d)\n", selectedCameraId,
|
||||
cameraIdList->numCameras);
|
||||
|
||||
camera_status = ACameraManager_getCameraCharacteristics(cameraManager, selectedCameraId,
|
||||
&cameraMetadata);
|
||||
|
||||
if (camera_status != ACAMERA_OK) {
|
||||
ALOGI("Failed to get camera meta data of ID:%s\n", selectedCameraId);
|
||||
}
|
||||
|
||||
ACameraMetadata_const_entry face, orientation;
|
||||
camera_status = ACameraMetadata_getConstEntry(cameraMetadata, ACAMERA_LENS_FACING, &face);
|
||||
uint32_t cameraFacing_ = static_cast<int32_t>(face.data.u8[0]);
|
||||
|
||||
if (cameraFacing_ == ACAMERA_LENS_FACING_FRONT)
|
||||
{
|
||||
int aa = 0;
|
||||
}
|
||||
|
||||
camera_status = ACameraMetadata_getConstEntry(cameraMetadata, ACAMERA_SENSOR_ORIENTATION, &orientation);
|
||||
|
||||
ALOGI("====Current SENSOR_ORIENTATION: %8d", orientation.data.i32[0]);
|
||||
uint32_t cameraOrientation_ = orientation.data.i32[0];
|
||||
if (cameraOrientation_ == 90 || cameraOrientation_ == 270)
|
||||
{
|
||||
mDisplayDimension.Flip();
|
||||
}
|
||||
|
||||
ImageFormat resCap = {(int32_t)photoInfo.width, (int32_t)photoInfo.height, AIMAGE_FORMAT_YUV_420_888};
|
||||
MatchCaptureSizeRequest(cameraManager, selectedCameraId, photoInfo.width, photoInfo.height, cameraOrientation_, &resCap);
|
||||
|
||||
deviceStateCallbacks.onDisconnected = camera_device_on_disconnected;
|
||||
deviceStateCallbacks.onError = camera_device_on_error;
|
||||
|
||||
camera_status = ACameraManager_openCamera(cameraManager, selectedCameraId,
|
||||
&deviceStateCallbacks, &cameraDevice);
|
||||
|
||||
if (camera_status != ACAMERA_OK) {
|
||||
ALOGI("Failed to open camera device (id: %s)\n", selectedCameraId);
|
||||
}
|
||||
|
||||
camera_status = ACameraDevice_createCaptureRequest(cameraDevice, TEMPLATE_STILL_CAPTURE/*TEMPLATE_PREVIEW*/,
|
||||
&captureRequest);
|
||||
|
||||
if (camera_status != ACAMERA_OK) {
|
||||
ALOGI("Failed to create preview capture request (id: %s)\n", selectedCameraId);
|
||||
}
|
||||
|
||||
ACaptureSessionOutputContainer_create(&captureSessionOutputContainer);
|
||||
|
||||
captureSessionStateCallbacks.onReady = capture_session_on_ready;
|
||||
captureSessionStateCallbacks.onActive = capture_session_on_active;
|
||||
captureSessionStateCallbacks.onClosed = capture_session_on_closed;
|
||||
|
||||
ACameraMetadata_free(cameraMetadata);
|
||||
ACameraManager_deleteCameraIdList(cameraIdList);
|
||||
ACameraManager_delete(cameraManager);
|
||||
|
||||
media_status_t status;
|
||||
// status = AImageReader_new(1920, 1080, AIMAGE_FORMAT_YUV_420_888, 5, &mAImageReader);
|
||||
status = AImageReader_new(resCap.width, resCap.height, resCap.format, 5, &mAImageReader);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
ALOGI("AImageReader_new error\n");
|
||||
TakePhotoCb(false, photoInfo, path, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
AImageReader_ImageListener listener{
|
||||
.context = this,
|
||||
.onImageAvailable = OnImageCallback,
|
||||
};
|
||||
AImageReader_setImageListener(mAImageReader, &listener);
|
||||
|
||||
//ANativeWindow *mNativeWindow;
|
||||
status = AImageReader_getWindow(mAImageReader, &theNativeWindow);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
ALOGI("AImageReader_getWindow error\n");
|
||||
TakePhotoCb(false, photoInfo, path, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
ALOGI("Surface is prepared in %p.\n", theNativeWindow);
|
||||
// theNativeWindow
|
||||
|
||||
ACameraOutputTarget_create(theNativeWindow, &cameraOutputTarget);
|
||||
ACaptureRequest_addTarget(captureRequest, cameraOutputTarget);
|
||||
|
||||
ACaptureSessionOutput_create(theNativeWindow, &sessionOutput);
|
||||
ACaptureSessionOutputContainer_add(captureSessionOutputContainer, sessionOutput);
|
||||
|
||||
ACameraDevice_createCaptureSession(cameraDevice, captureSessionOutputContainer,
|
||||
&captureSessionStateCallbacks, &captureSession);
|
||||
|
||||
// ACameraCaptureSession_setRepeatingRequest(captureSession, NULL, 1, &captureRequest, NULL);
|
||||
ACameraCaptureSession_capture(captureSession, NULL, 1, &captureRequest, NULL);
|
||||
ALOGI("Surface is prepared in here.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
ACameraCaptureSession_stateCallbacks* CPhoneDevice2::GetSessionListener()
|
||||
{
|
||||
static ACameraCaptureSession_stateCallbacks sessionListener = {
|
||||
.context = this,
|
||||
.onClosed = CPhoneDevice2::capture_session_on_closed,
|
||||
.onReady = CPhoneDevice2::capture_session_on_ready,
|
||||
.onActive = CPhoneDevice2::capture_session_on_active,
|
||||
};
|
||||
return &sessionListener;
|
||||
}
|
||||
|
||||
void CPhoneDevice2::ImageCallback(AImageReader *reader)
|
||||
{
|
||||
bool res = false;
|
||||
AImage *image = nullptr;
|
||||
media_status_t status = AImageReader_acquireNextImage(reader, &image);
|
||||
if (status == AMEDIA_OK && image)
|
||||
{
|
||||
int32_t srcFormat = -1;
|
||||
AImage_getFormat(image, &srcFormat);
|
||||
AASSERT(AIMAGE_FORMAT_YUV_420_888 == srcFormat, "Failed to get format");
|
||||
int32_t srcPlanes = 0;
|
||||
AImage_getNumberOfPlanes(image, &srcPlanes);
|
||||
AASSERT(srcPlanes == 3, "Is not 3 planes");
|
||||
|
||||
AImageCropRect srcRect;
|
||||
AImage_getCropRect(image, &srcRect);
|
||||
int32_t width = srcRect.right - srcRect.left;
|
||||
int32_t height = srcRect.bottom - srcRect.top;
|
||||
|
||||
// int32_t height = srcRect.right - srcRect.left;
|
||||
// int32_t width = srcRect.bottom - srcRect.top;
|
||||
|
||||
uint8_t *yPixel = nullptr;
|
||||
uint8_t *uPixel = nullptr;
|
||||
uint8_t *vPixel = nullptr;
|
||||
|
||||
int32_t yLen = 0;
|
||||
int32_t uLen = 0;
|
||||
int32_t vLen = 0;
|
||||
|
||||
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
||||
AImage_getPlaneData(image, 1, &uPixel, &uLen);
|
||||
AImage_getPlaneData(image, 2, &vPixel, &vLen);
|
||||
|
||||
uint8_t * data = new uint8_t[yLen + vLen + uLen];
|
||||
memcpy(data, yPixel, yLen);
|
||||
memcpy(data+yLen, vPixel, vLen);
|
||||
memcpy(data+yLen+vLen, uPixel, uLen);
|
||||
|
||||
cv::Mat mYUV = cv::Mat(((height * 3) >> 1), width, CV_8UC1, data);
|
||||
|
||||
// cv::cvtColor(mYUV, _yuv_rgb_img, cv::COLOR_YUV2RGB_NV21, 3);
|
||||
|
||||
// cv::Mat mYUV = cv::Mat(height, yStride, CV_8UC4, data);
|
||||
|
||||
cv::Mat _yuv_rgb_img(height, width, CV_8UC4), _yuv_gray_img;
|
||||
cv::cvtColor(mYUV, _yuv_rgb_img, cv::COLOR_YUV2RGB_NV21, 3);
|
||||
|
||||
cv::rotate(_yuv_rgb_img, _yuv_rgb_img, cv::ROTATE_180);
|
||||
|
||||
// cv::Mat rgbMat(height, width, CV_8UC3);
|
||||
// 通过cv::cvtColor将yuv420转换为rgb格式
|
||||
// cvtColor(_yuv_rgb_img, rgbMat, cv::COLOR_YUV2RGB_I420);
|
||||
|
||||
// cv::Mat mat = cv::Mat(buffer.height, buffer.stride, CV_8UC4, buffer.bits);
|
||||
|
||||
const char *str = "OSD";
|
||||
putText(_yuv_rgb_img, str, cv::Point(50, 50), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(0, 0, 0), 4,cv::LINE_AA);
|
||||
putText(_yuv_rgb_img, str, cv::Point(50, 50), cv::FONT_HERSHEY_COMPLEX, 1, cv::Scalar(255, 255, 255), 2,cv::LINE_AA);
|
||||
|
||||
vector <int> compression_params;
|
||||
compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
|
||||
compression_params.push_back(80);
|
||||
|
||||
res = cv::imwrite(mPath.c_str(), _yuv_rgb_img, compression_params);
|
||||
|
||||
// ANativeWindow_unlockAndPost(theNativeWindow);
|
||||
|
||||
if (res)
|
||||
{
|
||||
int aa = 0;
|
||||
}
|
||||
|
||||
// res = WriteFile(image, GetFileName() + ".org.jpg");
|
||||
AImage_delete(image);
|
||||
// delete pThis;
|
||||
|
||||
TakePhotoCb(res, mPhotoInfo, mPath, time(NULL));
|
||||
}
|
||||
}
|
||||
void CPhoneDevice2::OnImageCallback(void *ctx, AImageReader *reader)
|
||||
{
|
||||
CPhoneDevice2* pThis = reinterpret_cast<CPhoneDevice2*>(ctx);
|
||||
if (pThis != NULL)
|
||||
{
|
||||
pThis->ImageCallback(reader);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CPhoneDevice2::WriteFile(AImage *image, const string& path)
|
||||
{
|
||||
int planeCount = 0;
|
||||
media_status_t status = AImage_getNumberOfPlanes(image, &planeCount);
|
||||
|
||||
ALOGI("Info: getNumberOfPlanes() planeCount = %d", planeCount);
|
||||
if (!(status == AMEDIA_OK && planeCount == 1))
|
||||
{
|
||||
ALOGE("Error: getNumberOfPlanes() planeCount = %d", planeCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *data = nullptr;
|
||||
int len = 0;
|
||||
AImage_getPlaneData(image, 0, &data, &len);
|
||||
|
||||
bool res = false;
|
||||
FILE *file = fopen(path.c_str(), "wb");
|
||||
if (file && data && len)
|
||||
{
|
||||
fwrite(data, 1, len, file);
|
||||
fclose(file);
|
||||
|
||||
ALOGI("Capture: %s", path.c_str());
|
||||
|
||||
|
||||
res = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (file)
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CPhoneDevice2::WriteFile(CPhoneDevice2* pThis, AImage *image)
|
||||
{
|
||||
return pThis->WriteFile(image, pThis->GetFileName());
|
||||
}
|
||||
|
||||
std::string CPhoneDevice2::GetFileName() const
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
/*
|
||||
const char *selectedCameraId = NULL;
|
||||
|
||||
ACameraManager *cameraManager = ACameraManager_create();
|
||||
*/
|
||||
|
||||
bool CPhoneDevice2::MatchCaptureSizeRequest(ACameraManager *cameraManager, const char *selectedCameraId, unsigned int width, unsigned int height, uint32_t cameraOrientation_,
|
||||
ImageFormat* resCap) {
|
||||
DisplayDimension disp(resCap->width,resCap->height);
|
||||
if (cameraOrientation_ == 90 || cameraOrientation_ == 270) {
|
||||
disp.Flip();
|
||||
}
|
||||
|
||||
ACameraMetadata* metadata;
|
||||
camera_status_t camera_status = ACAMERA_OK;
|
||||
camera_status = ACameraManager_getCameraCharacteristics(cameraManager, selectedCameraId, &metadata);
|
||||
ACameraMetadata_const_entry entry;
|
||||
camera_status = ACameraMetadata_getConstEntry(metadata, ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
|
||||
// format of the data: format, width, height, input?, type int32
|
||||
bool foundIt = false;
|
||||
DisplayDimension foundRes(16384, 16384);
|
||||
DisplayDimension maxJPG(0, 0);
|
||||
|
||||
for (int i = 0; i < entry.count; i += 4) {
|
||||
int32_t input = entry.data.i32[i + 3];
|
||||
int32_t format = entry.data.i32[i + 0];
|
||||
if (input) continue;
|
||||
|
||||
if (format == AIMAGE_FORMAT_YUV_420_888 || format == AIMAGE_FORMAT_JPEG) {
|
||||
DisplayDimension res(entry.data.i32[i + 1], entry.data.i32[i + 2]);
|
||||
ALOGI("Camera Resolution: %d x %d fmt=%d", res.width(), res.height(), format);
|
||||
if (!disp.IsSameRatio(res)) continue;
|
||||
if (format == AIMAGE_FORMAT_YUV_420_888 && res > disp) {
|
||||
foundIt = true;
|
||||
foundRes = res;
|
||||
} else if (format == AIMAGE_FORMAT_JPEG && res > maxJPG) {
|
||||
maxJPG = res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundIt) {
|
||||
// resView->width = foundRes.org_width();
|
||||
// resView->height = foundRes.org_height();
|
||||
resCap->width = foundRes.org_width();
|
||||
resCap->height = foundRes.org_height();
|
||||
} else {
|
||||
ALOGI("Did not find any compatible camera resolution, taking 640x480");
|
||||
resCap->width = disp.org_width();
|
||||
resCap->height = disp.org_height();
|
||||
// *resCap = *resView;
|
||||
}
|
||||
// resView->format = AIMAGE_FORMAT_YUV_420_888;
|
||||
// resCap->format = AIMAGE_FORMAT_JPEG;
|
||||
return foundIt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert yuv image inside AImage into ANativeWindow_Buffer
|
||||
* ANativeWindow_Buffer format is guaranteed to be
|
||||
* WINDOW_FORMAT_RGBX_8888
|
||||
* WINDOW_FORMAT_RGBA_8888
|
||||
* @param buf a {@link ANativeWindow_Buffer } instance, destination of
|
||||
* image conversion
|
||||
* @param image a {@link AImage} instance, source of image conversion.
|
||||
* it will be deleted via {@link AImage_delete}
|
||||
*/
|
||||
bool CPhoneDevice2::DisplayImage(ANativeWindow_Buffer *buf, AImage *image) {
|
||||
AASSERT(buf->format == WINDOW_FORMAT_RGBX_8888 ||
|
||||
buf->format == WINDOW_FORMAT_RGBA_8888,
|
||||
"Not supported buffer format");
|
||||
|
||||
int32_t srcFormat = -1;
|
||||
AImage_getFormat(image, &srcFormat);
|
||||
AASSERT(AIMAGE_FORMAT_YUV_420_888 == srcFormat, "Failed to get format");
|
||||
int32_t srcPlanes = 0;
|
||||
AImage_getNumberOfPlanes(image, &srcPlanes);
|
||||
AASSERT(srcPlanes == 3, "Is not 3 planes");
|
||||
|
||||
switch (presentRotation_) {
|
||||
case 0:
|
||||
PresentImage(buf, image);
|
||||
break;
|
||||
case 90:
|
||||
PresentImage90(buf, image);
|
||||
break;
|
||||
case 180:
|
||||
PresentImage180(buf, image);
|
||||
break;
|
||||
case 270:
|
||||
PresentImage270(buf, image);
|
||||
break;
|
||||
default:
|
||||
AASSERT(0, "NOT recognized display rotation: %d", presentRotation_);
|
||||
}
|
||||
|
||||
AImage_delete(image);
|
||||
image = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PresentImage()
|
||||
* Converting yuv to RGB
|
||||
* No rotation: (x,y) --> (x, y)
|
||||
* Refer to:
|
||||
* https://mathbits.com/MathBits/TISection/Geometry/Transformations2.htm
|
||||
*/
|
||||
void CPhoneDevice2::PresentImage(ANativeWindow_Buffer *buf, AImage *image) {
|
||||
AImageCropRect srcRect;
|
||||
AImage_getCropRect(image, &srcRect);
|
||||
|
||||
AImage_getPlaneRowStride(image, 0, &yStride);
|
||||
AImage_getPlaneRowStride(image, 1, &uvStride);
|
||||
yPixel = imageBuffer_;
|
||||
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
||||
vPixel = imageBuffer_ + yLen;
|
||||
AImage_getPlaneData(image, 1, &vPixel, &vLen);
|
||||
uPixel = imageBuffer_ + yLen + vLen;
|
||||
AImage_getPlaneData(image, 2, &uPixel, &uLen);
|
||||
AImage_getPlanePixelStride(image, 1, &uvPixelStride);
|
||||
|
||||
int32_t rowStride;
|
||||
AImage_getPlaneRowStride(image, 0, &rowStride);
|
||||
|
||||
int32_t height = std::min(buf->height, (srcRect.bottom - srcRect.top));
|
||||
int32_t width = std::min(buf->width, (srcRect.right - srcRect.left));
|
||||
|
||||
uint32_t *out = static_cast<uint32_t *>(buf->bits);
|
||||
|
||||
for (int32_t y = 0; y < height; y++) {
|
||||
const uint8_t *pY = yPixel + yStride * (y + srcRect.top) + srcRect.left;
|
||||
|
||||
int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1);
|
||||
const uint8_t *pU = uPixel + uv_row_start + (srcRect.left >> 1);
|
||||
const uint8_t *pV = vPixel + uv_row_start + (srcRect.left >> 1);
|
||||
|
||||
for (int32_t x = 0; x < width; x++) {
|
||||
const int32_t uv_offset = (x >> 1) * uvPixelStride;
|
||||
out[x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]);
|
||||
}
|
||||
out += buf->stride;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PresentImage90()
|
||||
* Converting YUV to RGB
|
||||
* Rotation image anti-clockwise 90 degree -- (x, y) --> (-y, x)
|
||||
*/
|
||||
void CPhoneDevice2::PresentImage90(ANativeWindow_Buffer *buf, AImage *image) {
|
||||
AImageCropRect srcRect;
|
||||
AImage_getCropRect(image, &srcRect);
|
||||
|
||||
AImage_getPlaneRowStride(image, 0, &yStride);
|
||||
AImage_getPlaneRowStride(image, 1, &uvStride);
|
||||
yPixel = imageBuffer_;
|
||||
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
||||
vPixel = imageBuffer_ + yLen;
|
||||
AImage_getPlaneData(image, 1, &vPixel, &vLen);
|
||||
uPixel = imageBuffer_ + yLen + vLen;
|
||||
AImage_getPlaneData(image, 2, &uPixel, &uLen);
|
||||
AImage_getPlanePixelStride(image, 1, &uvPixelStride);
|
||||
|
||||
int32_t height = std::min(buf->width, (srcRect.bottom - srcRect.top));
|
||||
int32_t width = std::min(buf->height, (srcRect.right - srcRect.left));
|
||||
|
||||
uint32_t *out = static_cast<uint32_t *>(buf->bits);
|
||||
out += height - 1;
|
||||
for (int32_t y = 0; y < height; y++) {
|
||||
const uint8_t *pY = yPixel + yStride * (y + srcRect.top) + srcRect.left;
|
||||
|
||||
int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1);
|
||||
const uint8_t *pU = uPixel + uv_row_start + (srcRect.left >> 1);
|
||||
const uint8_t *pV = vPixel + uv_row_start + (srcRect.left >> 1);
|
||||
|
||||
for (int32_t x = 0; x < width; x++) {
|
||||
const int32_t uv_offset = (x >> 1) * uvPixelStride;
|
||||
// [x, y]--> [-y, x]
|
||||
int testb = pU[uv_offset];
|
||||
int testc = pV[uv_offset];
|
||||
int testA = pY[x];
|
||||
out[x * buf->stride] = YUV2RGB(testA, testb, testc);
|
||||
}
|
||||
out -= 1; // move to the next column
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PresentImage180()
|
||||
* Converting yuv to RGB
|
||||
* Rotate image 180 degree: (x, y) --> (-x, -y)
|
||||
*/
|
||||
void CPhoneDevice2::PresentImage180(ANativeWindow_Buffer *buf, AImage *image) {
|
||||
AImageCropRect srcRect;
|
||||
AImage_getCropRect(image, &srcRect);
|
||||
|
||||
AImage_getPlaneRowStride(image, 0, &yStride);
|
||||
AImage_getPlaneRowStride(image, 1, &uvStride);
|
||||
yPixel = imageBuffer_;
|
||||
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
||||
vPixel = imageBuffer_ + yLen;
|
||||
AImage_getPlaneData(image, 1, &vPixel, &vLen);
|
||||
uPixel = imageBuffer_ + yLen + vLen;
|
||||
AImage_getPlaneData(image, 2, &uPixel, &uLen);
|
||||
AImage_getPlanePixelStride(image, 1, &uvPixelStride);
|
||||
|
||||
int32_t height = std::min(buf->height, (srcRect.bottom - srcRect.top));
|
||||
int32_t width = std::min(buf->width, (srcRect.right - srcRect.left));
|
||||
|
||||
uint32_t *out = static_cast<uint32_t *>(buf->bits);
|
||||
out += (height - 1) * buf->stride;
|
||||
for (int32_t y = 0; y < height; y++) {
|
||||
const uint8_t *pY = yPixel + yStride * (y + srcRect.top) + srcRect.left;
|
||||
|
||||
int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1);
|
||||
const uint8_t *pU = uPixel + uv_row_start + (srcRect.left >> 1);
|
||||
const uint8_t *pV = vPixel + uv_row_start + (srcRect.left >> 1);
|
||||
|
||||
for (int32_t x = 0; x < width; x++) {
|
||||
const int32_t uv_offset = (x >> 1) * uvPixelStride;
|
||||
// mirror image since we are using front camera
|
||||
out[width - 1 - x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]);
|
||||
// out[x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]);
|
||||
}
|
||||
out -= buf->stride;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PresentImage270()
|
||||
* Converting image from YUV to RGB
|
||||
* Rotate Image counter-clockwise 270 degree: (x, y) --> (y, x)
|
||||
*/
|
||||
void CPhoneDevice2::PresentImage270(ANativeWindow_Buffer *buf, AImage *image) {
|
||||
AImageCropRect srcRect;
|
||||
AImage_getCropRect(image, &srcRect);
|
||||
|
||||
AImage_getPlaneRowStride(image, 0, &yStride);
|
||||
AImage_getPlaneRowStride(image, 1, &uvStride);
|
||||
yPixel = imageBuffer_;
|
||||
AImage_getPlaneData(image, 0, &yPixel, &yLen);
|
||||
vPixel = imageBuffer_ + yLen;
|
||||
AImage_getPlaneData(image, 1, &vPixel, &vLen);
|
||||
uPixel = imageBuffer_ + yLen + vLen;
|
||||
AImage_getPlaneData(image, 2, &uPixel, &uLen);
|
||||
AImage_getPlanePixelStride(image, 1, &uvPixelStride);
|
||||
|
||||
int32_t height = std::min(buf->width, (srcRect.bottom - srcRect.top));
|
||||
int32_t width = std::min(buf->height, (srcRect.right - srcRect.left));
|
||||
|
||||
uint32_t *out = static_cast<uint32_t *>(buf->bits);
|
||||
for (int32_t y = 0; y < height; y++) {
|
||||
const uint8_t *pY = yPixel + yStride * (y + srcRect.top) + srcRect.left;
|
||||
|
||||
int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1);
|
||||
const uint8_t *pU = uPixel + uv_row_start + (srcRect.left >> 1);
|
||||
const uint8_t *pV = vPixel + uv_row_start + (srcRect.left >> 1);
|
||||
|
||||
for (int32_t x = 0; x < width; x++) {
|
||||
const int32_t uv_offset = (x >> 1) * uvPixelStride;
|
||||
int testb = pU[uv_offset];
|
||||
int testc = pV[uv_offset];
|
||||
int testA = pY[x];
|
||||
out[(width - 1 - x) * buf->stride] =
|
||||
YUV2RGB(testA, testb, testc);
|
||||
}
|
||||
out += 1; // move to the next column
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool CPhoneDevice2::SendBroadcastMessage(String16 action, int value)
|
||||
{
|
||||
TM_INFO_LOG("sendBroadcastMessage(): Action: %s, Value: %d ", action.string(), value);
|
||||
sp <IServiceManager> sm = defaultServiceManager();
|
||||
sp <IBinder> am = sm->getService(String16("activity"));
|
||||
if (am != NULL) {
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(String16("android.app.IActivityManager"));
|
||||
data.writeStrongBinder(NULL);
|
||||
// intent begin
|
||||
data.writeString16(action); // action
|
||||
data.writeInt32(0); // URI data type
|
||||
data.writeString16(NULL, 0); // type
|
||||
data.writeInt32(0); // flags
|
||||
data.writeString16(NULL, 0); // package name
|
||||
data.writeString16(NULL, 0); // component name
|
||||
data.writeInt32(0); // source bound - size
|
||||
data.writeInt32(0); // categories - size
|
||||
data.writeInt32(0); // selector - size
|
||||
data.writeInt32(0); // clipData - size
|
||||
data.writeInt32(-2); // contentUserHint: -2 -> UserHandle.USER_CURRENT
|
||||
data.writeInt32(-1); // bundle extras length
|
||||
data.writeInt32(0x4C444E42); // 'B' 'N' 'D' 'L'
|
||||
int oldPos = data.dataPosition();
|
||||
data.writeInt32(1); // size
|
||||
// data.writeInt32(0); // VAL_STRING, need to remove because of analyze common intent
|
||||
data.writeString16(String16("type"));
|
||||
data.writeInt32(1); // VAL_INTEGER
|
||||
data.writeInt32(value);
|
||||
int newPos = data.dataPosition();
|
||||
data.setDataPosition(oldPos - 8);
|
||||
data.writeInt32(newPos - oldPos); // refill bundle extras length
|
||||
data.setDataPosition(newPos);
|
||||
// intent end
|
||||
data.writeString16(NULL, 0); // resolvedType
|
||||
data.writeStrongBinder(NULL); // resultTo
|
||||
data.writeInt32(0); // resultCode
|
||||
data.writeString16(NULL, 0); // resultData
|
||||
data.writeInt32(-1); // resultExtras
|
||||
data.writeString16(NULL, 0); // permission
|
||||
data.writeInt32(0); // appOp
|
||||
data.writeInt32(-1); // option
|
||||
data.writeInt32(1); // serialized: != 0 -> ordered
|
||||
data.writeInt32(0); // sticky
|
||||
data.writeInt32(-2); // userId: -2 -> UserHandle.USER_CURRENT
|
||||
|
||||
status_t ret = am->transact(IBinder::FIRST_CALL_TRANSACTION + 13, data,
|
||||
&reply); // BROADCAST_INTENT_TRANSACTION
|
||||
if (ret == NO_ERROR) {
|
||||
int exceptionCode = reply.readExceptionCode();
|
||||
if (exceptionCode) {
|
||||
TM_INFO_LOG("sendBroadcastMessage(%s) caught exception %d\n",
|
||||
action.string(), exceptionCode);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
TM_INFO_LOG("getService() couldn't find activity service!\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
void CPhoneDevice2::camera_device_on_disconnected(void *context, ACameraDevice *device)
|
||||
{
|
||||
ALOGI("Camera(id: %s) is diconnected.\n", ACameraDevice_getId(device));
|
||||
CPhoneDevice2* pThis = (CPhoneDevice2*)context;
|
||||
// delete pThis;
|
||||
}
|
||||
|
||||
void CPhoneDevice2::camera_device_on_error(void *context, ACameraDevice *device, int error)
|
||||
{
|
||||
ALOGI("Error(code: %d) on Camera(id: %s).\n", error, ACameraDevice_getId(device));
|
||||
}
|
||||
|
||||
void CPhoneDevice2::capture_session_on_ready(void *context, ACameraCaptureSession *session)
|
||||
{
|
||||
ALOGI("Session is ready. %p\n", session);
|
||||
}
|
||||
|
||||
void CPhoneDevice2::capture_session_on_active(void *context, ACameraCaptureSession *session)
|
||||
{
|
||||
ALOGI("Session is activated. %p\n", session);
|
||||
}
|
||||
|
||||
void CPhoneDevice2::capture_session_on_closed(void *context, ACameraCaptureSession *session)
|
||||
{
|
||||
ALOGI("Session is closed. %p\n", session);
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
#ifndef __PHONE_DEVICE2_H__
|
||||
#define __PHONE_DEVICE2_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <map>
|
||||
#include <atomic>
|
||||
|
||||
#include <camera/NdkCameraManager.h>
|
||||
#include <camera/NdkCameraError.h>
|
||||
#include <camera/NdkCameraDevice.h>
|
||||
#include <camera/NdkCameraMetadataTags.h>
|
||||
#include <media/NdkImageReader.h>
|
||||
#include <Client/Device.h>
|
||||
#include <string>
|
||||
|
||||
#include "camera2/Camera2Helper.h"
|
||||
|
||||
class CPhoneDevice2 : public IDevice
|
||||
{
|
||||
public:
|
||||
CPhoneDevice2(JavaVM* vm, jobject service);
|
||||
virtual ~CPhoneDevice2();
|
||||
|
||||
virtual void SetListener(IListener* listener);
|
||||
virtual bool UpdateTime(time_t ts);
|
||||
virtual bool Reboot();
|
||||
virtual timer_uid_t RegisterHeartbeat(unsigned int timerType, unsigned int timeout);
|
||||
virtual bool TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<OSD_INFO>& osds, const string& path);
|
||||
virtual timer_uid_t RegisterTimer(unsigned int timerType, unsigned int timeout);
|
||||
virtual bool UnregisterTimer(timer_uid_t uid);
|
||||
|
||||
virtual bool FireTimer(timer_uid_t uid);
|
||||
protected:
|
||||
|
||||
ACameraCaptureSession_stateCallbacks *GetSessionListener();
|
||||
std::string GetFileName() const;
|
||||
|
||||
bool SendBroadcastMessage(std::string action, int value);
|
||||
bool MatchCaptureSizeRequest(ACameraManager *cameraManager, const char *selectedCameraId, unsigned int width, unsigned int height, uint32_t cameraOrientation_,
|
||||
ImageFormat* resCap);
|
||||
bool DisplayImage(ANativeWindow_Buffer* buf, AImage* image);
|
||||
|
||||
void PresentImage(ANativeWindow_Buffer* buf, AImage* image);
|
||||
void PresentImage90(ANativeWindow_Buffer* buf, AImage* image);
|
||||
void PresentImage180(ANativeWindow_Buffer* buf, AImage* image);
|
||||
void PresentImage270(ANativeWindow_Buffer* buf, AImage* image);
|
||||
|
||||
static void camera_device_on_disconnected(void *context, ACameraDevice *device);
|
||||
static void camera_device_on_error(void *context, ACameraDevice *device, int error);
|
||||
static void capture_session_on_ready(void *context, ACameraCaptureSession *session);
|
||||
static void capture_session_on_active(void *context, ACameraCaptureSession *session);
|
||||
static void capture_session_on_closed(void *context, ACameraCaptureSession *session);
|
||||
|
||||
void ImageCallback(AImageReader *reader);
|
||||
static void OnImageCallback(void *ctx, AImageReader *reader);
|
||||
bool WriteFile(AImage *image, const string& path);
|
||||
static bool WriteFile(CPhoneDevice2* pThis, AImage *image);
|
||||
|
||||
inline bool TakePhotoCb(bool res, const IDevice::PHOTO_INFO& photoInfo, const string& path, time_t photoTime)
|
||||
{
|
||||
if (m_listener != NULL)
|
||||
{
|
||||
std::vector<IDevice::RECOG_OBJECT> objects;
|
||||
return m_listener->OnPhotoTaken(res, photoInfo, path, photoTime, objects);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
JavaVM* m_vm;
|
||||
jobject m_javaService;
|
||||
|
||||
jmethodID mRegisterTimerMid;
|
||||
jmethodID mRegisterHeartbeatMid;
|
||||
jmethodID mUnregisterTimerMid;
|
||||
jmethodID mUpdateTimeMid;
|
||||
|
||||
std::string mPath;
|
||||
IDevice::PHOTO_INFO mPhotoInfo;
|
||||
IListener* m_listener;
|
||||
|
||||
atomic_ulong m_timerUidFeed;
|
||||
std::map<IDevice::timer_uid_t, unsigned long> mTimers;
|
||||
|
||||
AImageReader *mAImageReader;
|
||||
ANativeWindow *theNativeWindow;
|
||||
ACameraDevice *cameraDevice;
|
||||
ACaptureRequest *captureRequest;
|
||||
ACameraOutputTarget *cameraOutputTarget;
|
||||
ACaptureSessionOutput *sessionOutput;
|
||||
ACaptureSessionOutputContainer *captureSessionOutputContainer;
|
||||
ACameraCaptureSession *captureSession;
|
||||
|
||||
ACameraDevice_StateCallbacks deviceStateCallbacks;
|
||||
ACameraCaptureSession_stateCallbacks captureSessionStateCallbacks;
|
||||
|
||||
DisplayDimension mDisplayDimension;
|
||||
int32_t presentRotation_;
|
||||
|
||||
int32_t imageHeight_;
|
||||
int32_t imageWidth_;
|
||||
|
||||
uint8_t* imageBuffer_;
|
||||
int32_t yStride, uvStride;
|
||||
uint8_t *yPixel, *uPixel, *vPixel;
|
||||
int32_t yLen, uLen, vLen;
|
||||
int32_t uvPixelStride;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // __PHONE_DEVICE2_H__
|
@ -0,0 +1,100 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/5.
|
||||
//
|
||||
|
||||
#ifndef MICROPHOTO_PTZCONTROLLER_H
|
||||
#define MICROPHOTO_PTZCONTROLLER_H
|
||||
|
||||
#include <Buffer.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <SemaphoreEx.h>
|
||||
#include <Client/Device.h>
|
||||
|
||||
enum PROC_PTZ_STATE
|
||||
{
|
||||
PTZS_POWER_OFF = 0,
|
||||
PTZS_IDLE = 1,
|
||||
PTZS_SELF_TESTING = 2,
|
||||
PTZS_MOVING = 3,
|
||||
PTZS_TAKING_PHOTO = 4,
|
||||
PTZS_PHOTO_SELF_TESTING = 5,
|
||||
};
|
||||
|
||||
#define CAMERA_SELF_TEST_TIME 150 /* Camera self-test time (excluding PTZ self-test)*/
|
||||
#define MOVE_PRESET_WAIT_TIME 20 /* Waiting for the maximum time for the PTZ to move to the preset position*/
|
||||
#define CAMERA_CLOSE_DELAYTIME 360 /* Auto Power-Off Timer Setting After Manual Power-On (for Camera)*/
|
||||
#define PHOTO_OPEN_POWER 16000
|
||||
#define WAIT_TIME_AUTO_CLOSE 2 /* In order to automatically capture multiple preset point images at the same time and prevent the camera from self checking every time it takes a picture.*/
|
||||
|
||||
class PtzPhotoParams
|
||||
{
|
||||
public:
|
||||
PtzPhotoParams(const IDevice::PHOTO_INFO& photoInfo, const std::string& path, const std::vector<IDevice::OSD_INFO>& osds) :
|
||||
mPhotoInfo(photoInfo), mPath(path), mOsds(osds)
|
||||
{
|
||||
}
|
||||
|
||||
~PtzPhotoParams()
|
||||
{
|
||||
}
|
||||
|
||||
IDevice::PHOTO_INFO mPhotoInfo;
|
||||
std::string mPath;
|
||||
std::vector<IDevice::OSD_INFO> mOsds;
|
||||
};
|
||||
|
||||
struct SERIAL_CMD
|
||||
{
|
||||
uint8_t channel;
|
||||
uint8_t preset;
|
||||
time_t ts;
|
||||
int cmdidx;
|
||||
uint32_t delayTime;
|
||||
uint8_t bImageSize;
|
||||
char serfile[128];
|
||||
uint32_t baud;
|
||||
int addr;
|
||||
std::shared_ptr<PtzPhotoParams> photoParams;
|
||||
};
|
||||
|
||||
|
||||
class CPhoneDevice;
|
||||
class PtzController
|
||||
{
|
||||
public:
|
||||
PtzController(CPhoneDevice* pPhoneDevice);
|
||||
|
||||
void Startup();
|
||||
// ();
|
||||
void AddCommand(uint8_t channel, int cmdidx, uint8_t bImageSize, uint8_t preset, const char *serfile, uint32_t baud, int addr);
|
||||
void AddPhotoCommand(IDevice::PHOTO_INFO& photoInfo, const std::string& path, const std::vector<IDevice::OSD_INFO>& osds);
|
||||
|
||||
void ExitAndWait();
|
||||
|
||||
protected:
|
||||
static void PtzThreadProc(PtzController* pThis);
|
||||
|
||||
void PtzProc();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
protected:
|
||||
std::mutex m_locker;
|
||||
std::vector<SERIAL_CMD> m_cmds;
|
||||
|
||||
CSemaphore m_sem;
|
||||
bool m_exit;
|
||||
|
||||
std::thread m_thread;
|
||||
|
||||
CPhoneDevice* m_pPhoneDevice;
|
||||
};
|
||||
|
||||
|
||||
#endif //MICROPHOTO_PTZCONTROLLER_H
|
File diff suppressed because it is too large
Load Diff
@ -1,79 +0,0 @@
|
||||
#include "TerminalDevice.h"
|
||||
#include <dlfcn.h>
|
||||
#include "Camera.h"
|
||||
#include <AndroidHelper.h>
|
||||
|
||||
typedef jbyteArray (*TakePhotoFunc)(int, int, int, int);
|
||||
|
||||
extern bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread);
|
||||
|
||||
CTerminalDevice::CTerminalDevice(JavaVM* vm, jobject service)
|
||||
{
|
||||
m_vm = vm;
|
||||
JNIEnv* env = NULL;
|
||||
bool attached = false;
|
||||
bool res = GetJniEnv(m_vm, &env, attached);
|
||||
if (!res)
|
||||
{
|
||||
ALOGE("Failed to get JNI Env");
|
||||
}
|
||||
m_javaService = env->NewGlobalRef(service);
|
||||
if (attached)
|
||||
{
|
||||
vm->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
CTerminalDevice::~CTerminalDevice()
|
||||
{
|
||||
JNIEnv* env = NULL;
|
||||
bool attached = false;
|
||||
bool res = GetJniEnv(m_vm, &env, attached);
|
||||
if (!res)
|
||||
{
|
||||
ALOGE("Failed to get JNI Env");
|
||||
}
|
||||
env->DeleteGlobalRef(m_javaService);
|
||||
if (attached)
|
||||
{
|
||||
m_vm->DetachCurrentThread();
|
||||
}
|
||||
m_javaService = NULL;
|
||||
}
|
||||
|
||||
bool CTerminalDevice::TakePhoto(unsigned char channel, unsigned char preset, const string& path, bool photo)
|
||||
{
|
||||
jboolean res = JNI_FALSE;
|
||||
|
||||
CCamera camera;
|
||||
camera.initCamera(NULL);
|
||||
if (camera.isCameraReady())
|
||||
{
|
||||
camera.takePicture();
|
||||
}
|
||||
|
||||
camera.closeCamera();
|
||||
|
||||
#if 0
|
||||
JNIEnv* env = NULL;
|
||||
bool attached = GetJniEnv(m_vm, &env);
|
||||
jclass serviceClass = env->GetObjectClass(m_javaService);
|
||||
jmethodID mid = env->GetMethodID(serviceClass, "takePhoto", "(SSLjava/lang/String;)Z");
|
||||
jstring str = env->NewStringUTF(path.c_str());
|
||||
res = env->CallBooleanMethod (m_javaService, mid, (jint)channel, (jint)preset, str);
|
||||
env->ReleaseStringUTFChars(str, path.c_str());
|
||||
env->DeleteLocalRef(serviceClass);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
int aa = 1;
|
||||
}
|
||||
if (attached)
|
||||
{
|
||||
m_vm->DetachCurrentThread();
|
||||
}
|
||||
#endif
|
||||
|
||||
return res == JNI_TRUE;
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
#ifndef __TERMINAL_DEVICE_H__
|
||||
#define __TERMINAL_DEVICE_H__
|
||||
|
||||
#include <Client/Device.h>
|
||||
#include <jni.h>
|
||||
|
||||
class CTerminalDevice : public IDevice
|
||||
{
|
||||
public:
|
||||
CTerminalDevice(JavaVM* vm, jobject service);
|
||||
~CTerminalDevice();
|
||||
|
||||
virtual bool TakePhoto(unsigned char channel, unsigned char preset, const string& path, bool photo);
|
||||
|
||||
private:
|
||||
JavaVM* m_vm;
|
||||
jobject m_javaService;
|
||||
};
|
||||
|
||||
|
||||
#endif // __TERMINAL_DEVICE_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,724 @@
|
||||
/* Copyright Statement:
|
||||
*
|
||||
* This software/firmware and related documentation ("MediaTek Software") are
|
||||
* protected under relevant copyright laws. The information contained herein is
|
||||
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
|
||||
* the prior written permission of MediaTek inc. and/or its licensors, any
|
||||
* reproduction, modification, use or disclosure of MediaTek Software, and
|
||||
* information contained herein, in whole or in part, shall be strictly
|
||||
* prohibited.
|
||||
*
|
||||
* MediaTek Inc. (C) 2010. All rights reserved.
|
||||
*
|
||||
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
|
||||
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
|
||||
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
|
||||
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
|
||||
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
|
||||
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
|
||||
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
|
||||
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
|
||||
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
|
||||
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
|
||||
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
|
||||
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
|
||||
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
|
||||
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
|
||||
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
|
||||
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
|
||||
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
|
||||
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
|
||||
*
|
||||
* The following software/firmware and/or related documentation ("MediaTek
|
||||
* Software") have been modified by MediaTek Inc. All revisions are subject to
|
||||
* any receiver's applicable license agreements with MediaTek Inc.
|
||||
*/
|
||||
|
||||
#ifndef _MTK_HARDWARE_MTKCAM_INCLUDE_MTKCAM_UTILS_METADATA_HAL_MTKPLATFORMMETADATATAG_H_
|
||||
#define _MTK_HARDWARE_MTKCAM_INCLUDE_MTKCAM_UTILS_METADATA_HAL_MTKPLATFORMMETADATATAG_H_
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef enum mtk_platform_metadata_section {
|
||||
MTK_HAL_REQUEST = 0xC000, // MTK HAL internal metadata become from 0xC000 0000
|
||||
MTK_P1NODE,
|
||||
MTK_P2NODE,
|
||||
MTK_3A_TUNINING,
|
||||
MTK_3A_EXIF,
|
||||
MTK_MF_EXIF,
|
||||
MTK_EIS,
|
||||
MTK_STEREO,
|
||||
MTK_FRAMESYNC,
|
||||
MTK_VHDR,
|
||||
MTK_PIPELINE,
|
||||
MTK_NR,
|
||||
MTK_PLUGIN,
|
||||
MTK_DUALZOOM,
|
||||
MTK_FEATUREPIPE,
|
||||
MTK_POSTPROC,
|
||||
MTK_FEATURE,
|
||||
MTK_FSC,
|
||||
} mtk_platform_metadata_section_t;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef enum mtk_platform_metadata_section_start {
|
||||
MTK_HAL_REQUEST_START = MTK_HAL_REQUEST << 16,
|
||||
MTK_P1NODE_START = MTK_P1NODE << 16,
|
||||
MTK_P2NODE_START = MTK_P2NODE << 16,
|
||||
MTK_3A_TUNINING_START = MTK_3A_TUNINING << 16,
|
||||
MTK_3A_EXIF_START = MTK_3A_EXIF << 16,
|
||||
MTK_EIS_START = MTK_EIS << 16,
|
||||
MTK_STEREO_START = MTK_STEREO << 16,
|
||||
MTK_FRAMESYNC_START = MTK_FRAMESYNC << 16,
|
||||
MTK_VHDR_START = MTK_VHDR << 16,
|
||||
MTK_PIPELINE_START = MTK_PIPELINE << 16,
|
||||
MTK_NR_START = MTK_NR << 16,
|
||||
MTK_PLUGIN_START = MTK_PLUGIN << 16,
|
||||
MTK_DUALZOOM_START = MTK_DUALZOOM << 16,
|
||||
MTK_FEATUREPIPE_START = MTK_FEATUREPIPE << 16,
|
||||
MTK_POSTPROC_START = MTK_POSTPROC << 16,
|
||||
MTK_FEATURE_START = MTK_FEATURE << 16,
|
||||
MTK_FSC_START = MTK_FSC << 16,
|
||||
} mtk_platform_metadata_section_start_t;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef enum mtk_platform_metadata_tag {
|
||||
MTK_HAL_REQUEST_REQUIRE_EXIF = MTK_HAL_REQUEST_START, //MUINT8
|
||||
MTK_HAL_REQUEST_DUMP_EXIF, //MUINT8
|
||||
MTK_HAL_REQUEST_REPEAT, //MUINT8
|
||||
MTK_HAL_REQUEST_DUMMY, //MUINT8
|
||||
MTK_HAL_REQUEST_SENSOR_SIZE, //MSize
|
||||
MTK_HAL_REQUEST_SENSOR_ID, //MINT32
|
||||
MTK_HAL_REQUEST_DEVICE_ID, //MINT32
|
||||
MTK_HAL_REQUEST_HIGH_QUALITY_CAP, //MUINT8
|
||||
MTK_HAL_REQUEST_ISO_SPEED, //MINT32
|
||||
MTK_HAL_REQUEST_BRIGHTNESS_MODE, //MINT32
|
||||
MTK_HAL_REQUEST_CONTRAST_MODE, //MINT32
|
||||
MTK_HAL_REQUEST_HUE_MODE, //MINT32
|
||||
MTK_HAL_REQUEST_SATURATION_MODE, //MINT32
|
||||
MTK_HAL_REQUEST_EDGE_MODE, //MINT32
|
||||
MTK_HAL_REQUEST_PASS1_DISABLE, //MINT32
|
||||
MTK_HAL_REQUEST_ERROR_FRAME, // used for error handling //MUINT8
|
||||
MTK_HAL_REQUEST_PRECAPTURE_START, // 4cell //MUINT8
|
||||
MTK_HAL_REQUEST_AF_TRIGGER_START, // 4cell //MUINT8
|
||||
MTK_HAL_REQUEST_IMG_IMGO_FORMAT, //MINT32
|
||||
MTK_HAL_REQUEST_IMG_RRZO_FORMAT, //MINT32
|
||||
MTK_HAL_REQUEST_INDEX, //MINT32
|
||||
MTK_HAL_REQUEST_COUNT, //MINT32
|
||||
MTK_HAL_REQUEST_SMVR_FPS, //MUINT8 // 0: NOT batch request
|
||||
MTK_HAL_REQUEST_REMOSAIC_ENABLE, //MUINT8 // 0: preview mode 1: capture mode
|
||||
MTK_HAL_REQUEST_INDEX_BSS, //MINT32
|
||||
MTK_HAL_REQUEST_ZSD_CAPTURE_INTENT, //MUINT8
|
||||
MTK_HAL_REQUEST_REAL_CAPTURE_SIZE, //MSize
|
||||
MTK_HAL_REQUEST_VIDEO_SIZE, //MSize
|
||||
MTK_HAL_REQUEST_RAW_IMAGE_INFO, //MINT32 // index[0]: raw fmt, index[1]: raw stride, index[2]: raw size(width), index[3]: raw size(height)
|
||||
MTK_HAL_REQUEST_ISP_PIPELINE_MODE, //MINT32
|
||||
MTK_P1NODE_SCALAR_CROP_REGION = MTK_P1NODE_START, //MRect
|
||||
MTK_P1NODE_BIN_CROP_REGION, //MRect
|
||||
MTK_P1NODE_DMA_CROP_REGION, //MRect
|
||||
MTK_P1NODE_BIN_SIZE, //MSize
|
||||
MTK_P1NODE_RESIZER_SIZE, //MSize
|
||||
MTK_P1NODE_RESIZER_SET_SIZE, //MSize
|
||||
MTK_P1NODE_CTRL_RESIZE_FLUSH, //MBOOL
|
||||
MTK_P1NODE_CTRL_READOUT_FLUSH, //MBOOL
|
||||
MTK_P1NODE_CTRL_RECONFIG_SENSOR_SETTING, //MBOOL
|
||||
MTK_P1NODE_PROCESSOR_MAGICNUM, //MINT32
|
||||
MTK_P1NODE_MIN_FRM_DURATION, //MINT64
|
||||
MTK_P1NODE_RAW_TYPE, //MINT32
|
||||
MTK_P1NODE_SENSOR_CROP_REGION, //MRect
|
||||
MTK_P1NODE_YUV_RESIZER1_CROP_REGION, //MRect
|
||||
MTK_P1NODE_YUV_RESIZER2_CROP_REGION, //MRect
|
||||
MTK_P1NODE_YUV_RESIZER1_SIZE, //MSize
|
||||
MTK_P1NODE_SENSOR_MODE, //MINT32
|
||||
MTK_P1NODE_SENSOR_VHDR_MODE, //MINT32
|
||||
MTK_P1NODE_METADATA_TAG_INDEX, //MINT32
|
||||
MTK_P1NODE_RSS_SIZE, //MSize
|
||||
MTK_P1NODE_SENSOR_STATUS, //MINT32
|
||||
MTK_P1NODE_SENSOR_RAW_ORDER, //MINT32
|
||||
MTK_P1NODE_TWIN_SWITCH, //MINT32
|
||||
MTK_P1NODE_TWIN_STATUS, //MINT32
|
||||
MTK_P1NODE_RESIZE_QUALITY_SWITCH, //MINT32
|
||||
MTK_P1NODE_RESIZE_QUALITY_STATUS, //MINT32
|
||||
MTK_P1NODE_RESIZE_QUALITY_LEVEL, //MINT32
|
||||
MTK_P1NODE_RESIZE_QUALITY_SWITCHING, //MBOOL
|
||||
MTK_P1NODE_RESUME_SHUTTER_TIME_US, //MINT32
|
||||
MTK_P1NODE_FRAME_START_TIMESTAMP, //MINT64
|
||||
MTK_P1NODE_FRAME_START_TIMESTAMP_BOOT, //MINT64
|
||||
MTK_P1NODE_REQUEST_PROCESSED_WITHOUT_WB, //MBOOL
|
||||
MTK_P1NODE_ISNEED_GMV, //MBOOL
|
||||
MTK_P2NODE_HIGH_SPEED_VDO_FPS = MTK_P2NODE_START, //MINT32
|
||||
MTK_P2NODE_HIGH_SPEED_VDO_SIZE, //MSize
|
||||
MTK_P2NODE_CTRL_CALTM_ENABLE, //MBOOL
|
||||
MTK_P2NODE_FD_CROP_REGION, //MRect
|
||||
MTK_P2NODE_CROP_REGION, //MRect // for removing black edge
|
||||
MTK_P2NODE_DSDN_ENABLE, //MBOOL // for DSDN on/off controled by Policy
|
||||
MTK_P2NODE_SENSOR_CROP_REGION, //MRect
|
||||
MTK_3A_AE_HIGH_ISO_BINNING, //MBOOL // for 3HDR high iso binning mode
|
||||
MTK_SENSOR_SCALER_CROP_REGION, //MRect
|
||||
MTK_PROCESSOR_CAMINFO = MTK_3A_TUNINING_START, //IMemory
|
||||
MTK_ISP_ATMS_MAPPING_INFO, //IMemory
|
||||
MTK_3A_ISP_PROFILE, //MUINT8
|
||||
MTK_3A_ISP_P1_PROFILE, //MUINT8
|
||||
MTK_CAMINFO_LCSOUT_INFO, //IMemory
|
||||
MTK_3A_ISP_BYPASS_LCE, //MBOOL
|
||||
MTK_3A_ISP_DISABLE_NR, //MBOOL
|
||||
MTK_3A_ISP_NR3D_SW_PARAMS, //MINT32[14] //GMVX, GMVY, confX, confY, MAX_GMV, frameReset, GMV_Status,ISO_cutoff
|
||||
MTK_3A_ISP_NR3D_HW_PARAMS, //IMemory
|
||||
MTK_3A_ISP_LCE_GAIN, //MINT32, bits[0:15]: LCE gain, bits[16:31]: LCE gain confidence ratio (0-100)
|
||||
MTK_3A_ISP_FUS_NUM, //MINT32
|
||||
MTK_3A_AE_CAP_PARAM, //IMemory
|
||||
MTK_3A_AE_CAP_SINGLE_FRAME_HDR, //MUINT8
|
||||
MTK_3A_AE_BV_TRIGGER, //MBOOL
|
||||
MTK_3A_AF_LENS_POSITION, //MINT32
|
||||
MTK_3A_FLICKER_RESULT, //MINT32
|
||||
MTK_3A_DUMMY_BEFORE_REQUEST_FRAME, //MBOOL // Dummy frame before capture, only for capture intent, preview don't use
|
||||
MTK_3A_DUMMY_AFTER_REQUEST_FRAME, //MBOOL // Dummy frame after capture, only for capture intent, preview don't use
|
||||
MTK_3A_MANUAL_AWB_COLORTEMPERATURE_MAX, //MINT32
|
||||
MTK_3A_MANUAL_AWB_COLORTEMPERATURE_MIN, //MINT32
|
||||
MTK_3A_MANUAL_AWB_COLORTEMPERATURE, //MINT32
|
||||
MTK_3A_HDR_MODE, //MUINT8
|
||||
MTK_3A_AE_HDR_MIXED_ISO, //MUINT32
|
||||
MTK_3A_AE_ZSL_STABLE, //MINT32 ( MBOOL )
|
||||
MTK_3A_PGN_ENABLE, //MUINT8
|
||||
MTK_3A_SKIP_HIGH_QUALITY_CAPTURE, //MUINT8
|
||||
MTK_3A_AI_SHUTTER, //MBOOL
|
||||
MTK_3A_FEATURE_AE_EXPOSURE_LEVEL, //MINT32
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE, //MINT32
|
||||
MTK_3A_OPEN_ID, //MINT32
|
||||
MTK_LSC_TBL_DATA, //IMemory
|
||||
MTK_LSC_TSF_DATA, //IMemory
|
||||
MTK_LSC_TSF_DUMP_NO, //IMemory
|
||||
MTK_ISP_P2_ORIGINAL_SIZE, //MSize
|
||||
MTK_ISP_P2_CROP_REGION, //MRect
|
||||
MTK_ISP_P2_RESIZER_SIZE, //MSize
|
||||
MTK_ISP_P2_IN_IMG_FMT, //MINT32, 0 or not exist: RAW->YUV, 1: YUV->YUV
|
||||
MTK_ISP_P2_TUNING_UPDATE_MODE, //MUINT8, [0 or not exist]: as default; [1]: keep existed parameters but some parts will be updated; [2]: keep all existed parameters (force mode) [3] LPCNR Pass1 [4] LPCNR Pass2
|
||||
MTK_ISP_P2_IN_IMG_RES_REVISED, //MINT32, describes P2 input image revised resolution. bit[0:15] width in pixel, bit[16:31] height in pixel. May be not exist.
|
||||
MTK_ISP_APP_TARGET_SIZE, //MINT32, describes APP Target resolution. bit[0:15] width in pixel, bit[16:31] height in pixel. May be not exist.
|
||||
MTK_MSF_SCALE_INDEX, //MINT32, which scale stage index, would only exist with scaling flow
|
||||
MTK_MSF_FRAME_NUM, //MINT32, After BSS which frame number is this stage using
|
||||
MTK_TOTAL_MULTI_FRAME_NUM, //MINT32, MSYUV fuction used this input to know frame nunber
|
||||
MTK_TOTAL_MULTI_FRAME_NUM_CAPTURED, //MINT32, MSF function used
|
||||
MTK_SW_DSDN_VERSION, //MINT32, distinguish different dsdn version
|
||||
MTK_ISP_COLOR_SPACE, //MINT32
|
||||
MTK_ISP_DRC_CURVE, //IMemory
|
||||
MTK_ISP_DRC_CURVE_SIZE, //MINT32
|
||||
MTK_ISP_FEO_DATA, //IMemory
|
||||
MTK_ISP_FEO_ENABLE, //MINT32
|
||||
MTK_ISP_FEO_INFO, //IMemory
|
||||
MTK_ISP_HLR_RATIO, //MINT32, which is a HDR ratio applied in HLR
|
||||
MTK_ISP_STAGE, //MINT32
|
||||
MTK_FOCUS_AREA_POSITION, //MINT32
|
||||
MTK_FOCUS_AREA_SIZE, //MSize
|
||||
MTK_FOCUS_AREA_RESULT, //MUINT8
|
||||
MTK_FOCUS_PAUSE, //MUINT8
|
||||
MTK_FOCUS_MZ_ON, //MUINT8
|
||||
MTK_3A_AF_FOCUS_VALUE, //MINT64
|
||||
MTK_3A_PRV_CROP_REGION, //MRect
|
||||
MTK_3A_ISP_MDP_TARGET_SIZE, //MSize
|
||||
MTK_3A_REPEAT_RESULT, //MUINT8
|
||||
MTK_3A_SKIP_PRECAPTURE, //MBOOL //if CUST_ENABLE_FLASH_DURING_TOUCH is true, MW can skip precapture
|
||||
MTK_3A_SKIP_BAD_FRAME, //MBOOL
|
||||
MTK_3A_FLARE_IN_MANUAL_CTRL_ENABLE, //MBOOL
|
||||
MTK_3A_DYNAMIC_SUBSAMPLE_COUNT, //MINT32 30fps = 1, 60fps = 2, ... , 120fps = 4
|
||||
MTK_3A_AE_LV_VALUE, //MINT32
|
||||
MTK_APP_CONTROL, //MINT32
|
||||
MTK_3A_CUST_PARAMS, //IMemory
|
||||
MTK_3A_SETTING_CUST_PARAMS, //IMemory
|
||||
MTK_3A_PERFRAME_INFO, //IMemory
|
||||
MTK_SENSOR_MODE_INFO_ACTIVE_ARRAY_CROP_REGION, //MRect
|
||||
MTK_3A_AE_BV, //MINT32
|
||||
MTK_3A_AE_CWV, //MINT32
|
||||
MTK_ISP_P2_PROCESSED_RAW, //MINT32
|
||||
MTK_3A_EXIF_METADATA = MTK_3A_EXIF_START, //IMetadata
|
||||
MTK_EIS_REGION = MTK_EIS_START, //MINT32
|
||||
MTK_EIS_INFO, //MINT64
|
||||
MTK_EIS_VIDEO_SIZE, //MRect
|
||||
MTK_EIS_NEED_OVERRIDE_TIMESTAMP, //MBOOL
|
||||
MTK_EIS_LMV_DATA, //IMemory
|
||||
MTK_STEREO_JPS_MAIN1_CROP = MTK_STEREO_START, //MRect
|
||||
MTK_STEREO_JPS_MAIN2_CROP, //MRect
|
||||
MTK_STEREO_SYNC2A_MODE, //MINT32
|
||||
MTK_STEREO_SYNCAF_MODE, //MINT32
|
||||
MTK_STEREO_HW_FRM_SYNC_MODE, //MINT32
|
||||
MTK_STEREO_NOTIFY, //MINT32
|
||||
MTK_STEREO_SYNC2A_MASTER_SLAVE, //MINT32[2]
|
||||
MTK_STEREO_SYNC2A_STATUS, //IMemory
|
||||
MTK_JPG_ENCODE_TYPE, //MINT8
|
||||
MTK_CONVERGENCE_DEPTH_OFFSET, //MFLOAT
|
||||
MTK_N3D_WARPING_MATRIX_SIZE, //MUINT32
|
||||
MTK_P1NODE_MAIN2_HAL_META, //IMetadata
|
||||
MTK_P2NODE_BOKEH_ISP_PROFILE, //MUINT8
|
||||
MTK_STEREO_FEATURE_DENOISE_MODE, //MINT32
|
||||
MTK_STEREO_FEATURE_SENSOR_PROFILE, //MINT32
|
||||
MTK_P1NODE_MAIN2_APP_META, //IMetadata
|
||||
MTK_STEREO_FEATURE_OPEN_ID, //MINT32
|
||||
MTK_STEREO_FRAME_PER_CAPTURE, //MINT32
|
||||
MTK_STEREO_ENABLE_MFB, //MINT32
|
||||
MTK_STEREO_BSS_RESULT, //MINT32
|
||||
MTK_STEREO_FEATURE_FOV_CROP_REGION, //MINT32[6] // p.x, p.y, p.w, p.h, srcW, srcH
|
||||
MTK_STEREO_DCMF_FEATURE_MODE, //MINT32 // mtk_platform_metadata_enum_dcmf_feature_mode
|
||||
MTK_STEREO_HDR_EV, //MINT32
|
||||
MTK_STEREO_DELAY_FRAME_COUNT, //MINT32
|
||||
MTK_STEREO_DCMF_DEPTHMAP_SIZE, //MSize
|
||||
MTK_STEREO_WITH_CAMSV, //MBOOL
|
||||
MTK_FRAMESYNC_ID = MTK_FRAMESYNC_START, //MINT32
|
||||
MTK_FRAMESYNC_TOLERANCE, //MINT64
|
||||
MTK_FRAMESYNC_FAILHANDLE, //MINT32
|
||||
MTK_FRAMESYNC_RESULT, //MINT64
|
||||
MTK_FRAMESYNC_TYPE, //MINT32
|
||||
MTK_FRAMESYNC_MODE, //MUINT8
|
||||
MTK_VHDR_LCEI_DATA = MTK_VHDR_START, //Memory
|
||||
MTK_VHDR_IMGO_3A_ISP_PROFILE, //MUINT8
|
||||
MTK_HDR_FEATURE_HDR_HAL_MODE,
|
||||
MTK_3A_FEATURE_AE_VALID_EXPOSURE_NUM,
|
||||
MTK_VHDR_MULTIFRAME_TIMESTAMP, //MINT64
|
||||
MTK_VHDR_MULTIFRAME_EXPOSURE_TIME, //MINT64
|
||||
MTK_PIPELINE_UNIQUE_KEY = MTK_PIPELINE_START, //MINT32
|
||||
MTK_PIPELINE_FRAME_NUMBER, //MINT32
|
||||
MTK_PIPELINE_REQUEST_NUMBER, //MINT32
|
||||
MTK_PIPELINE_EV_VALUE, //MINT32
|
||||
MTK_PIPELINE_DUMP_UNIQUE_KEY, //MINT32
|
||||
MTK_PIPELINE_DUMP_FRAME_NUMBER, //MINT32
|
||||
MTK_PIPELINE_DUMP_REQUEST_NUMBER, //MINT32
|
||||
MTK_PIPELINE_VIDEO_RECORD, //MINT32
|
||||
MTK_NR_MODE = MTK_NR_START, //MINT32
|
||||
MTK_NR_MNR_THRESHOLD_ISO, //MINT32
|
||||
MTK_NR_SWNR_THRESHOLD_ISO, //MINT32
|
||||
MTK_REAL_LV, //MINT32
|
||||
MTK_ANALOG_GAIN, //MUINT32
|
||||
MTK_AWB_RGAIN, //MINT32
|
||||
MTK_AWB_GGAIN, //MINT32
|
||||
MTK_AWB_BGAIN, //MINT32
|
||||
MTK_PLUGIN_MODE = MTK_PLUGIN_START, //MINT64
|
||||
MTK_PLUGIN_COMBINATION_KEY, //MINT64
|
||||
MTK_PLUGIN_P2_COMBINATION, //MINT64
|
||||
MTK_PLUGIN_PROCESSED_FRAME_COUNT, //MINT32
|
||||
MTK_PLUGIN_CUSTOM_HINT, //MINT32
|
||||
MTK_PLUGIN_DETACT_JOB_SYNC_TOKEN, //MINT64, may be not exists.
|
||||
MTK_PLUGIN_UNIQUEKEY,
|
||||
MTK_DUALZOOM_DROP_REQ = MTK_DUALZOOM_START, //MINT32
|
||||
MTK_DUALZOOM_FORCE_ENABLE_P2, //MINT32
|
||||
MTK_DUALZOOM_DO_FRAME_SYNC, //MINT32
|
||||
MTK_DUALZOOM_ZOOM_FACTOR, //MINT32
|
||||
MTK_DUALZOOM_DO_FOV, //MINT32
|
||||
MTK_DUALZOOM_FOV_RECT_INFO, //MINT32
|
||||
MTK_DUALZOOM_FOV_CALB_INFO, //MINT32
|
||||
MTK_DUALZOOM_FOV_MARGIN_PIXEL, //MSize
|
||||
MTK_DUALCAM_AF_STATE, //MUINT8
|
||||
MTK_DUALCAM_LENS_STATE, //MUINT8
|
||||
MTK_DUALCAM_TIMESTAMP, //MINT64
|
||||
MTK_DUALZOOM_3DNR_MODE, //MINT32
|
||||
MTK_DUALZOOM_ZOOMRATIO, //MINT32
|
||||
MTK_DUALZOOM_CENTER_SHIFT, //MINT32
|
||||
MTK_DUALZOOM_FOV_RATIO, //MFLOAT
|
||||
MTK_DUALZOOM_REAL_MASTER, //MINT32
|
||||
MTK_DUALZOOM_FD_TARGET_MASTER, //MINT32
|
||||
MTK_DUALZOOM_FD_REAL_MASTER, //MINT32 // maybe not set
|
||||
MTK_LMV_SEND_SWITCH_OUT, //MINT32
|
||||
MTK_LMV_SWITCH_OUT_RESULT, //MINT32
|
||||
MTK_LMV_VALIDITY, //MINT32
|
||||
MTK_VSDOF_P1_MAIN1_ISO, //MINT32
|
||||
MTK_DUALZOOM_IS_STANDBY, //MBOOL
|
||||
MTK_DUALZOOM_CAP_CROP, //MRect
|
||||
MTK_DUALZOOM_MASTER_UPDATE_MODE, //MBOOL
|
||||
MTK_DUALZOOM_STREAMING_NR, //MINT32
|
||||
MTK_FEATUREPIPE_APP_MODE = MTK_FEATUREPIPE_START, //MINT32
|
||||
MTK_POSTPROC_TYPE = MTK_POSTPROC_START, //MINT32
|
||||
MTK_FEATURE_STREAMING = MTK_FEATURE_START, //MINT64
|
||||
MTK_FEATURE_CAPTURE, //MINT64
|
||||
MTK_FEATURE_CAPTURE_PHYSICAL, //MINT64
|
||||
MTK_FEATURE_FREE_MEMORY_MBYTE, //MINT32
|
||||
MTK_FEATURE_MFNR_NVRAM_QUERY_INDEX, //MINT32
|
||||
MTK_FEATURE_MFNR_NVRAM_DECISION_ISO, //MINT32
|
||||
MTK_FEATURE_MFNR_TUNING_INDEX_HINT, //MINT64
|
||||
MTK_FEATURE_MFNR_FINAL_EXP, //MINT32
|
||||
MTK_FEATURE_MFNR_OPEN_ID, //MINT32
|
||||
MTK_FEATURE_AINR_MDLA_MODE, //MINT32
|
||||
MTK_ISP_AINR_MDLA_MODE, //MINT32
|
||||
MTK_ISP_LTM_BIT_MODE, //MINT32
|
||||
MTK_FEATURE_BSS_SELECTED_FRAME_COUNT, //MINT32
|
||||
MTK_FEATURE_BSS_FORCE_DROP_NUM, //MINT32
|
||||
MTK_FEATURE_BSS_FIXED_LSC_TBL_DATA, //MUINT8
|
||||
MTK_FEATURE_BSS_PROCESS, //MINT32
|
||||
MTK_FEATURE_BSS_ISGOLDEN, //MBOOL
|
||||
MTK_FEATURE_BSS_REORDER, //MBOOL
|
||||
MTK_FEATURE_BSS_MANUAL_ORDER, //MUINT8
|
||||
MTK_FEATURE_BSS_RRZO_DATA, //MUINT8
|
||||
MTK_FEATURE_BSS_DOWNSAMPLE, //MBOOL
|
||||
MTK_FEATURE_PACK_RRZO, //MUINT8
|
||||
MTK_FEATURE_FACE_RECTANGLES, //MRect array
|
||||
MTK_FEATURE_FACE_POSE_ORIENTATIONS, //MINT32[n*3] array, each struct include: xAsix, yAsix, zAsix
|
||||
MTK_FEATURE_CAP_YUV_PROCESSING, //MUINT8
|
||||
MTK_FEATURE_CAP_PIPE_DCE_CONTROL, //MUINT8
|
||||
MTK_FEATURE_MULTIFRAMENODE_BYPASSED, //MUINT8
|
||||
MTK_FEATURE_FACE_APPLIED_GAMMA, //MINT32
|
||||
MTK_FEATURE_CAP_PQ_USERID, //MINT64
|
||||
MTK_FEATURE_FLIP_IN_P2A, //MINT32
|
||||
MTK_FSC_CROP_DATA = MTK_FSC_START, //IMemory
|
||||
MTK_FSC_WARP_DATA, //IMemory
|
||||
MTK_STAGGER_ME_META, //IMetadata
|
||||
MTK_STAGGER_SE_META, //IMetadata
|
||||
MTK_STAGGER_BLOB_IMGO_ORDER //MUINT8
|
||||
} mtk_platform_metadata_tag_t;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef enum mtk_platform_3a_exif_metadata_tag {
|
||||
MTK_3A_EXIF_FNUMBER, //MINT32
|
||||
MTK_3A_EXIF_FOCAL_LENGTH, //MINT32
|
||||
MTK_3A_EXIF_FOCAL_LENGTH_35MM, //MINT32
|
||||
MTK_3A_EXIF_SCENE_MODE, //MINT32
|
||||
MTK_3A_EXIF_AWB_MODE, //MINT32
|
||||
MTK_3A_EXIF_LIGHT_SOURCE, //MINT32
|
||||
MTK_3A_EXIF_EXP_PROGRAM, //MINT32
|
||||
MTK_3A_EXIF_SCENE_CAP_TYPE, //MINT32
|
||||
MTK_3A_EXIF_FLASH_LIGHT_TIME_US, //MINT32
|
||||
MTK_3A_EXIF_AE_METER_MODE, //MINT32
|
||||
MTK_3A_EXIF_AE_EXP_BIAS, //MINT32
|
||||
MTK_3A_EXIF_CAP_EXPOSURE_TIME, //MINT32
|
||||
MTK_3A_EXIF_AE_ISO_SPEED, //MINT32
|
||||
MTK_3A_EXIF_REAL_ISO_VALUE, //MINT32
|
||||
MTK_3A_EXIF_AE_BRIGHTNESS_VALUE, //MINT32
|
||||
MTK_3A_EXIF_FLASH_FIRING_STATUS, //MINT32
|
||||
MTK_3A_EXIF_FLASH_RETURN_DETECTION, //MINT32
|
||||
MTK_3A_EXIF_FLASH_MODE, //MINT32
|
||||
MTK_3A_EXIF_FLASH_FUNCTION, //MINT32
|
||||
MTK_3A_EXIF_FLASH_REDEYE, //MINT32
|
||||
MTK_3A_EXIF_DEBUGINFO_BEGIN, // debug info begin
|
||||
// key: MINT32
|
||||
MTK_3A_EXIF_DBGINFO_AAA_KEY = MTK_3A_EXIF_DEBUGINFO_BEGIN, //MINT32
|
||||
MTK_3A_EXIF_DBGINFO_AAA_DATA,
|
||||
MTK_3A_EXIF_DBGINFO_SDINFO_KEY,
|
||||
MTK_3A_EXIF_DBGINFO_SDINFO_DATA,
|
||||
MTK_3A_EXIF_DBGINFO_ISP_KEY,
|
||||
MTK_3A_EXIF_DBGINFO_ISP_DATA,
|
||||
//
|
||||
MTK_CMN_EXIF_DBGINFO_KEY,
|
||||
MTK_CMN_EXIF_DBGINFO_DATA,
|
||||
//
|
||||
MTK_MF_EXIF_DBGINFO_MF_KEY,
|
||||
MTK_MF_EXIF_DBGINFO_MF_DATA,
|
||||
//
|
||||
MTK_N3D_EXIF_DBGINFO_KEY,
|
||||
MTK_N3D_EXIF_DBGINFO_DATA,
|
||||
//
|
||||
MTK_POSTNR_EXIF_DBGINFO_NR_KEY,
|
||||
MTK_POSTNR_EXIF_DBGINFO_NR_DATA,
|
||||
//
|
||||
MTK_RESVB_EXIF_DBGINFO_KEY,
|
||||
MTK_RESVB_EXIF_DBGINFO_DATA,
|
||||
//
|
||||
MTK_RESVC_EXIF_DBGINFO_KEY,
|
||||
MTK_RESVC_EXIF_DBGINFO_DATA,
|
||||
// data: Memory
|
||||
MTK_3A_EXIF_DEBUGINFO_END, // debug info end
|
||||
} mtk_platform_3a_exif_metadata_tag_t;
|
||||
|
||||
// MTK_3A_FEATURE_AE_EXPOSURE_LEVEL
|
||||
typedef enum mtk_camera_metadata_enum_ae_exposure_level {
|
||||
MTK_3A_FEATURE_AE_EXPOSURE_LEVEL_NONE = 0,
|
||||
MTK_3A_FEATURE_AE_EXPOSURE_LEVEL_SHORT,
|
||||
MTK_3A_FEATURE_AE_EXPOSURE_LEVEL_NORMAL,
|
||||
MTK_3A_FEATURE_AE_EXPOSURE_LEVEL_LONG,
|
||||
} mtk_camera_metadata_enum_ae_exposure_level_t;
|
||||
|
||||
// MTK_3A_FEATURE_AE_TARGET_MODE
|
||||
typedef enum mtk_camera_metadata_enum_ae_target_mode {
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_NORMAL = 0,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_IVHDR,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_MVHDR,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_ZVHDR,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_LE_FIX,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_SE_FIX,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_4CELL_MVHDR,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_MSTREAM_VHDR,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_MSTREAM_VHDR_RTO1X,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_STAGGER_2EXP,
|
||||
MTK_3A_FEATURE_AE_TARGET_MODE_STAGGER_3EXP,
|
||||
} mtk_camera_metadata_enum_ae_target_mode_t;
|
||||
|
||||
//MTK_3A_FEATURE_AE_VALID_EXPOSURE_NUM
|
||||
typedef enum mtk_camera_metadata_enum_stagger_valid_exposure_num {
|
||||
MTK_STAGGER_VALID_EXPOSURE_NON = 0,
|
||||
MTK_STAGGER_VALID_EXPOSURE_1 = 1,
|
||||
MTK_STAGGER_VALID_EXPOSURE_2 = 2,
|
||||
MTK_STAGGER_VALID_EXPOSURE_3 = 3
|
||||
} mtk_camera_metadata_enum_stagger_valid_exposure_num_t;
|
||||
|
||||
//MTK_3A_ISP_FUS_NUM
|
||||
typedef enum mtk_camera_metadata_enum_3a_isp_fus_num {
|
||||
MTK_3A_ISP_FUS_NUM_NON = 0,
|
||||
MTK_3A_ISP_FUS_NUM_1 = 1,
|
||||
MTK_3A_ISP_FUS_NUM_2 = 2,
|
||||
MTK_3A_ISP_FUS_NUM_3 = 3,
|
||||
} mtk_camera_metadata_enum_3a_isp_fus_num_t;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
typedef enum mtk_platform_metadata_enum_nr_mode {
|
||||
MTK_NR_MODE_OFF = 0,
|
||||
MTK_NR_MODE_MNR,
|
||||
MTK_NR_MODE_SWNR,
|
||||
MTK_NR_MODE_AUTO
|
||||
} mtk_platform_metadata_enum_nr_mode_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_mfb_mode {
|
||||
MTK_MFB_MODE_OFF = 0,
|
||||
MTK_MFB_MODE_MFLL,
|
||||
MTK_MFB_MODE_AIS,
|
||||
MTK_MFB_MODE_NUM,
|
||||
} mtk_platform_metadata_enum_mfb_mode_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_custom_hint {
|
||||
MTK_CUSTOM_HINT_0 = 0,
|
||||
MTK_CUSTOM_HINT_1,
|
||||
MTK_CUSTOM_HINT_2,
|
||||
MTK_CUSTOM_HINT_3,
|
||||
MTK_CUSTOM_HINT_4,
|
||||
MTK_CUSTOM_HINT_NUM,
|
||||
} mtk_platform_metadata_enum_custom_hint_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_plugin_mode {
|
||||
MTK_PLUGIN_MODE_COMBINATION = 1 << 0,
|
||||
MTK_PLUGIN_MODE_NR = 1 << 1,
|
||||
MTK_PLUGIN_MODE_HDR = 1 << 2,
|
||||
MTK_PLUGIN_MODE_MFNR = 1 << 3,
|
||||
MTK_PLUGIN_MODE_COPY = 1 << 4,
|
||||
MTK_PLUGIN_MODE_TEST_PRV = 1 << 5,
|
||||
MTK_PLUGIN_MODE_BMDN = 1 << 6,
|
||||
MTK_PLUGIN_MODE_MFHR = 1 << 7,
|
||||
MTK_PLUGIN_MODE_BMDN_3rdParty = 1 << 8,
|
||||
MTK_PLUGIN_MODE_MFHR_3rdParty = 1 << 9,
|
||||
MTK_PLUGIN_MODE_FUSION_3rdParty = 1 << 10,
|
||||
MTK_PLUGIN_MODE_VSDOF_3rdParty = 1 << 11,
|
||||
MTK_PLUGIN_MODE_COLLECT = 1 << 12,
|
||||
MTK_PLUGIN_MODE_HDR_3RD_PARTY = 1 << 13,
|
||||
MTK_PLUGIN_MODE_MFNR_3RD_PARTY = 1 << 14,
|
||||
MTK_PLUGIN_MODE_BOKEH_3RD_PARTY = 1 << 15,
|
||||
MTK_PLUGIN_MODE_DCMF_3RD_PARTY = 1 << 16,
|
||||
} mtk_platform_metadata_enum_plugin_mode_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_p2_plugin_combination {
|
||||
MTK_P2_RAW_PROCESSOR = 1 << 0,
|
||||
MTK_P2_ISP_PROCESSOR = 1 << 1,
|
||||
MTK_P2_YUV_PROCESSOR = 1 << 2,
|
||||
MTK_P2_MDP_PROCESSOR = 1 << 3,
|
||||
MTK_P2_CAPTURE_REQUEST = 1 << 4,
|
||||
MTK_P2_PREVIEW_REQUEST = 1 << 5
|
||||
} mtk_platform_metadata_enum_p2_plugin_combination;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_isp_color_space {
|
||||
MTK_ISP_COLOR_SPACE_SRGB = 0 ,
|
||||
MTK_ISP_COLOR_SPACE_DISPLAY_P3 = 1 ,
|
||||
MTK_ISP_COLOR_SPACE_CUSTOM_1 = 2
|
||||
} mtk_platform_metadata_enum_isp_color_space;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_dualzoom_drop_req {
|
||||
MTK_DUALZOOM_DROP_NEVER_DROP = 0,
|
||||
MTK_DUALZOOM_DROP_NONE = 1,
|
||||
MTK_DUALZOOM_DROP_DIRECTLY = 2,
|
||||
MTK_DUALZOOM_DROP_NEED_P1,
|
||||
MTK_DUALZOOM_DROP_NEED_SYNCMGR,
|
||||
MTK_DUALZOOM_DROP_NEED_SYNCMGR_NEED_STREAM_F_PIPE,
|
||||
} mtk_platform_metadata_enum_dualzoom_drop_req_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_p1_sensor_status {
|
||||
MTK_P1_SENSOR_STATUS_NONE = 0,
|
||||
MTK_P1_SENSOR_STATUS_STREAMING = 1,
|
||||
MTK_P1_SENSOR_STATUS_SW_STANDBY = 2,
|
||||
MTK_P1_SENSOR_STATUS_HW_STANDBY = 3,
|
||||
} mtk_platform_metadata_enum_p1_sensor_status_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_p1_twin_switch {
|
||||
MTK_P1_TWIN_SWITCH_NONE = 0,
|
||||
MTK_P1_TWIN_SWITCH_ONE_TG = 1,
|
||||
MTK_P1_TWIN_SWITCH_TWO_TG = 2
|
||||
} mtk_platform_metadata_enum_p1_twin_switch_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_p1_twin_status {
|
||||
MTK_P1_TWIN_STATUS_NONE = 0,
|
||||
MTK_P1_TWIN_STATUS_TG_MODE_1 = 1,
|
||||
MTK_P1_TWIN_STATUS_TG_MODE_2 = 2,
|
||||
MTK_P1_TWIN_STATUS_TG_MODE_3 = 3,
|
||||
} mtk_platform_metadata_enum_p1_twin_status_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_p1_resize_quality_switch {
|
||||
MTK_P1_RESIZE_QUALITY_SWITCH_NONE = 0,
|
||||
MTK_P1_RESIZE_QUALITY_SWITCH_L_L = 1,
|
||||
MTK_P1_RESIZE_QUALITY_SWITCH_L_H = 2,
|
||||
MTK_P1_RESIZE_QUALITY_SWITCH_H_L = 3,
|
||||
MTK_P1_RESIZE_QUALITY_SWITCH_H_H = 4,
|
||||
} mtk_platform_metadata_enum_p1_resize_quality_switch_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_p1_resize_quality_status {
|
||||
MTK_P1_RESIZE_QUALITY_STATUS_NONE = 0,
|
||||
MTK_P1_RESIZE_QUALITY_STATUS_ACCEPT = 1,
|
||||
MTK_P1_RESIZE_QUALITY_STATUS_IGNORE = 2,
|
||||
MTK_P1_RESIZE_QUALITY_STATUS_REJECT = 3,
|
||||
MTK_P1_RESIZE_QUALITY_STATUS_ILLEGAL = 4,
|
||||
} mtk_platform_metadata_enum_p1_resize_quality_status_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_p1_resize_quality_level {
|
||||
MTK_P1_RESIZE_QUALITY_LEVEL_UNKNOWN = 0,
|
||||
MTK_P1_RESIZE_QUALITY_LEVEL_L = 1,
|
||||
MTK_P1_RESIZE_QUALITY_LEVEL_H = 2,
|
||||
} mtk_platform_metadata_enum_p1_resize_quality_level_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_lmv_result {
|
||||
MTK_LMV_RESULT_OK = 0,
|
||||
MTK_LMV_RESULT_FAILED,
|
||||
MTK_LMV_RESULT_SWITCHING
|
||||
} mtk_platform_metadata_enum_lmv_result_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_featurepipe_app_mode {
|
||||
MTK_FEATUREPIPE_PHOTO_PREVIEW = 0,
|
||||
MTK_FEATUREPIPE_VIDEO_PREVIEW = 1,
|
||||
MTK_FEATUREPIPE_VIDEO_RECORD = 2,
|
||||
MTK_FEATUREPIPE_VIDEO_STOP = 3,
|
||||
} mtk_platform_metadata_enum_featurepipe_app_mode_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_dcmf_feature_mode {
|
||||
MTK_DCMF_FEATURE_BOKEH = 0,
|
||||
MTK_DCMF_FEATURE_MFNR_BOKEH = 1,
|
||||
MTK_DCMF_FEATURE_HDR_BOKEH = 2,
|
||||
} mtk_platform_metadata_enum_dcmf_feature_mode_t;
|
||||
|
||||
typedef enum mtk_platform_metadata_enum_smvr_fps {
|
||||
MTK_SMVR_FPS_30 = 0,
|
||||
MTK_SMVR_FPS_120 = 1,
|
||||
MTK_SMVR_FPS_240 = 2,
|
||||
MTK_SMVR_FPS_480 = 3,
|
||||
MTK_SMVR_FPS_960 = 4,
|
||||
} mtk_platform_metadata_enum_smvr_fps_t;
|
||||
|
||||
//MTK_FRAMESYNC_FAILHANDLE
|
||||
typedef enum mtk_platform_metadata_enum_fremesync_failhandle {
|
||||
MTK_FRAMESYNC_FAILHANDLE_CONTINUE,
|
||||
MTK_FRAMESYNC_FAILHANDLE_DROP,
|
||||
} mtk_platform_metadata_enum_fremesync_failhandle_t;
|
||||
|
||||
//MTK_FRAMESYNC_RESULT
|
||||
typedef enum mtk_platform_metadata_enum_fremesync_result {
|
||||
MTK_FRAMESYNC_RESULT_PASS,
|
||||
MTK_FRAMESYNC_RESULT_FAIL_CONTINUE,
|
||||
MTK_FRAMESYNC_RESULT_FAIL_DROP,
|
||||
} mtk_platform_metadata_enum_fremesync_result_t;
|
||||
|
||||
//MTK_FRAMESYNC_MODE
|
||||
typedef enum mtk_platform_metadata_enum_fremesync_mode {
|
||||
MTK_FRAMESYNC_MODE_VSYNC_ALIGNMENT,
|
||||
MTK_FRAMESYNC_MODE_READOUT_CENTER_ALIGNMENT,
|
||||
} mtk_platform_metadata_enum_fremesync_mode_t;
|
||||
|
||||
//MTK_FEATURE_MULTIFRAMENODE_BYPASSED
|
||||
typedef enum mtk_platform_metadata_enum_multiframenode_bypassed {
|
||||
MTK_FEATURE_MULTIFRAMENODE_NOT_BYPASSED = 0,
|
||||
MTK_FEATURE_MULTIFRAMENODE_TO_BE_BYPASSED = 1
|
||||
} mtk_platform_metadata_enum_mfllnode_bypassed_t;
|
||||
|
||||
//MTK_FEATURE_BSS_PROCESS
|
||||
typedef enum mtk_platform_metadata_enum_bss_processing {
|
||||
MTK_FEATURE_BSS_PROCESS_ENABLE = 0,
|
||||
MTK_FEATURE_BSS_PROCESS_DISABLE = 1
|
||||
} mtk_platform_metadata_enum_bss_processing_t;
|
||||
|
||||
//MTK_FEATURE_BSS_MANUAL_ORDER
|
||||
typedef enum mtk_platform_metadata_enum_bss_manual_order {
|
||||
MTK_FEATURE_BSS_MANUAL_ORDER_OFF = 0,
|
||||
MTK_FEATURE_BSS_MANUAL_ORDER_GOLDEN = 1
|
||||
} mtk_platform_metadata_enum_bss_manual_order_t;
|
||||
|
||||
//MTK_FEATURE_CAP_YUV_PROCESSING
|
||||
typedef enum mtk_platform_metadata_enum_cap_yuv_processing {
|
||||
MTK_FEATURE_CAP_YUV_PROCESSING_NOT_NEEDED = 0,
|
||||
MTK_FEATURE_CAP_YUV_PROCESSING_NEEDED = 1
|
||||
} mtk_platform_metadata_enum_cap_yuv_processing_t;
|
||||
|
||||
//MTK_FEATURE_CAP_PIPE_DCE_CONTROL
|
||||
typedef enum mtk_platform_metadata_enum_cap_pipe_control {
|
||||
MTK_FEATURE_CAP_PIPE_DCE_ENABLE_BUT_NOT_APPLY = 2,
|
||||
MTK_FEATURE_CAP_PIPE_DCE_MANUAL_DISABLE = 1,
|
||||
MTK_FEATURE_CAP_PIPE_DCE_DEFAULT_APPLY = 0
|
||||
} mtk_platform_metadata_enum_cap_pipe_dce_control_t;
|
||||
|
||||
// MTK_FEATURE_AINR_MDLA_MODE, MTK_ISP_AINR_MDLA_MODE
|
||||
typedef enum mtk_platform_metadata_enum_ainr_mdla_mode {
|
||||
MTK_FEATURE_AINR_MDLA_MODE_NONE = 0,
|
||||
MTK_FEATURE_AINR_MDLA_MODE_DRCOUT_16BIT = 1,
|
||||
MTK_FEATURE_AINR_MDLA_MODE_NNOUT_12BIT = 2,
|
||||
MTK_FEATURE_AINR_MDLA_MODE_NNOUT_16BIT = 3,
|
||||
} mtk_platform_metadata_enum_ainr_mdla_mode_t;
|
||||
|
||||
//MTK_ISP_P2_PROCESSED_RAW
|
||||
typedef enum mtk_platform_metadata_enum_p2_processed_raw {
|
||||
MTK_ISP_P2_PROCESSED_RAW_NOT_NEEDED = 0,
|
||||
MTK_ISP_P2_PROCESSED_RAW_NEEDED = 1
|
||||
} mtk_platform_metadata_enum_p2_processed_raw_t;
|
||||
|
||||
//MTK_DUALZOOM_STREAMING_NR
|
||||
typedef enum mtk_platform_metadata_enum_dualzoom_streaming_nr {
|
||||
MTK_DUALZOOM_STREAMING_NR_AUTO = 0,
|
||||
MTK_DUALZOOM_STREAMING_NR_OFF = 1
|
||||
} mtk_platform_metadata_enum_dualzoom_streaming_nr_t;
|
||||
|
||||
//MTK_STAGGER_BLOB_IMGO_ORDER
|
||||
typedef enum mtk_platform_metadata_enum_stagger_blob_imgo_order {
|
||||
MTK_STAGGER_IMGO_NONE = 0,
|
||||
MTK_STAGGER_IMGO_NE = 1,
|
||||
MTK_STAGGER_IMGO_ME = 2,
|
||||
MTK_STAGGER_IMGO_SE = 3
|
||||
} mtk_platform_metadata_enum_stagger_blob_imgo_order_t;
|
||||
|
||||
//MTK_3A_EXIF_FLASH_FIRING_STATUS
|
||||
typedef enum mtk_platform_metadata_enum_3a_exif_flash_firing_status_t {
|
||||
MTK_3A_EXIF_FLASH_FIRING_STATUS_NOT_FIRED = 0,
|
||||
MTK_3A_EXIF_FLASH_FIRING_STATUS_FIRED = 1,
|
||||
} mtk_platform_metadata_enum_3a_exif_flash_firing_status_t;
|
||||
|
||||
//MTK_3A_EXIF_FLASH_RETURN_DETECTION
|
||||
typedef enum mtk_platform_metadata_enum_3a_exif_flash_return_detection_t {
|
||||
MTK_3A_EXIF_FLASH_RETURN_DETECTION_NOT_SUPPORT = 0,
|
||||
MTK_3A_EXIF_FLASH_RETURN_DETECTION_RESERVED = 1,
|
||||
MTK_3A_EXIF_FLASH_RETURN_DETECTION_STROBE_NOT_DETECTED = 2,
|
||||
MTK_3A_EXIF_FLASH_RETURN_DETECTION_STROBE_DETECTED = 3,
|
||||
} mtk_platform_metadata_enum_3a_exif_flash_return_detection_t;
|
||||
|
||||
//MTK_3A_EXIF_FLASH_MODE
|
||||
typedef enum mtk_platform_metadata_enum_3a_exif_flash_mode_t {
|
||||
MTK_3A_EXIF_FLASH_MODE_UNKNOWN = 0,
|
||||
MTK_3A_EXIF_FLASH_MODE_COMPULSORY_FIRING = 1,
|
||||
MTK_3A_EXIF_FLASH_MODE_COMPULSORY_SUPPRESSION = 2,
|
||||
MTK_3A_EXIF_FLASH_MODE_AUTO = 3,
|
||||
} mtk_platform_metadata_enum_3a_exif_flash_mode_t;
|
||||
|
||||
//MTK_3A_EXIF_FLASH_FUNCTION
|
||||
typedef enum mtk_platform_metadata_enum_3a_exif_flash_function_t {
|
||||
MTK_3A_EXIF_FLASH_FUNCTION_SUPPORT = 0,
|
||||
MTK_3A_EXIF_FLASH_FUNCTION_NOT_SUPPORT = 1,
|
||||
} mtk_platform_metadata_enum_3a_exif_flash_function_t;
|
||||
|
||||
//MTK_3A_EXIF_FLASH_REDEYE
|
||||
typedef enum mtk_platform_metadata_enum_3a_exif_flash_redeye_t {
|
||||
MTK_3A_EXIF_FLASH_REDEYE_NOT_SUPPORT = 0,
|
||||
MTK_3A_EXIF_FLASH_REDEYE_SUPPORT = 1,
|
||||
} mtk_platform_metadata_enum_3a_exif_flash_redeye_t;
|
||||
|
||||
//MTK_FEATURE_ABF
|
||||
typedef enum mtk_platform_metadata_enum_abf_mode {
|
||||
MTK_ABF_MODE_OFF = 0,
|
||||
MTK_ABF_MODE_ON,
|
||||
} mtk_platform_metadata_enum_abf_mode_t;
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,428 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/1.
|
||||
//
|
||||
|
||||
#include "RTSPRecorder.h"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <android/log.h>
|
||||
#include <errno.h>
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/time.h>
|
||||
}
|
||||
|
||||
|
||||
#define LOG_TAG "libcurl"
|
||||
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
#include <libavutil/log.h>
|
||||
#include <android/log.h>
|
||||
|
||||
void ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vl) {
|
||||
// Map FFmpeg log levels to Android log levels
|
||||
int android_log_level;
|
||||
switch (level) {
|
||||
case AV_LOG_PANIC:
|
||||
case AV_LOG_FATAL:
|
||||
android_log_level = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
case AV_LOG_ERROR:
|
||||
android_log_level = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
case AV_LOG_WARNING:
|
||||
android_log_level = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case AV_LOG_INFO:
|
||||
android_log_level = ANDROID_LOG_INFO;
|
||||
break;
|
||||
case AV_LOG_VERBOSE:
|
||||
android_log_level = ANDROID_LOG_VERBOSE;
|
||||
break;
|
||||
case AV_LOG_DEBUG:
|
||||
case AV_LOG_TRACE:
|
||||
android_log_level = ANDROID_LOG_DEBUG;
|
||||
break;
|
||||
default:
|
||||
android_log_level = ANDROID_LOG_INFO;
|
||||
break;
|
||||
}
|
||||
|
||||
// Format the log message
|
||||
char log_message[1024];
|
||||
vsnprintf(log_message, sizeof(log_message), fmt, vl);
|
||||
|
||||
// Send the log message to logcat
|
||||
__android_log_print(android_log_level, "FFmpeg", "%s", log_message);
|
||||
}
|
||||
|
||||
|
||||
int setup_output_streams(AVFormatContext *input_ctx, AVFormatContext *output_ctx) {
|
||||
// Copy streams and fix time_base
|
||||
for (unsigned int i = 0; i < input_ctx->nb_streams; i++) {
|
||||
AVStream *in_stream = input_ctx->streams[i];
|
||||
AVStream *out_stream = avformat_new_stream(output_ctx, NULL);
|
||||
if (!out_stream) {
|
||||
return AVERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
// Copy codec parameters
|
||||
int ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Fix time base
|
||||
out_stream->time_base = in_stream->time_base;
|
||||
|
||||
// Clear any existing flags
|
||||
out_stream->codecpar->codec_tag = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_mp4_header(AVFormatContext *output_ctx) {
|
||||
AVDictionary *opts = NULL;
|
||||
|
||||
// MP4 specific options
|
||||
av_dict_set(&opts, "movflags", "faststart+frag_keyframe", 0);
|
||||
av_dict_set(&opts, "brand", "mp42", 0);
|
||||
|
||||
// Write header
|
||||
int ret = avformat_write_header(output_ctx, &opts);
|
||||
if (ret < 0) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
fprintf(stderr, "Header write failed: %s (code: %d)\n", errbuf, ret);
|
||||
}
|
||||
|
||||
av_dict_free(&opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle)
|
||||
{
|
||||
AVFormatContext* inputFormatContext = nullptr;
|
||||
AVFormatContext* outputFormatContext = nullptr;
|
||||
AVPacket packet;
|
||||
|
||||
// Open input RTMP stream
|
||||
if (avformat_open_input(&inputFormatContext, rtmpUrl, nullptr, nullptr) != 0) {
|
||||
fprintf(stderr, "Could not open input file '%s'\n", rtmpUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve input stream information
|
||||
if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) {
|
||||
fprintf(stderr, "Could not find stream information\n");
|
||||
avformat_close_input(&inputFormatContext);
|
||||
return;
|
||||
}
|
||||
|
||||
// Open output MP4 file
|
||||
if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mp4", outputPath) < 0) {
|
||||
fprintf(stderr, "Could not create output context\n");
|
||||
avformat_close_input(&inputFormatContext);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy stream information from input to output
|
||||
for (unsigned int i = 0; i < inputFormatContext->nb_streams; i++) {
|
||||
AVStream* inStream = inputFormatContext->streams[i];
|
||||
AVStream* outStream = avformat_new_stream(outputFormatContext, nullptr);
|
||||
if (!outStream) {
|
||||
fprintf(stderr, "Failed to allocate output stream\n");
|
||||
avformat_close_input(&inputFormatContext);
|
||||
avformat_free_context(outputFormatContext);
|
||||
return;
|
||||
}
|
||||
|
||||
if (avcodec_parameters_copy(outStream->codecpar, inStream->codecpar) < 0) {
|
||||
fprintf(stderr, "Failed to copy codec parameters\n");
|
||||
avformat_close_input(&inputFormatContext);
|
||||
avformat_free_context(outputFormatContext);
|
||||
return;
|
||||
}
|
||||
outStream->codecpar->codec_tag = 0;
|
||||
}
|
||||
|
||||
// Open output file
|
||||
if (!(outputFormatContext->oformat->flags & AVFMT_NOFILE)) {
|
||||
if (avio_open(&outputFormatContext->pb, outputPath, AVIO_FLAG_WRITE) < 0) {
|
||||
fprintf(stderr, "Could not open output file '%s'\n", outputPath);
|
||||
avformat_close_input(&inputFormatContext);
|
||||
avformat_free_context(outputFormatContext);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Write output file header
|
||||
if (avformat_write_header(outputFormatContext, nullptr) < 0) {
|
||||
fprintf(stderr, "Error occurred when writing header to output file\n");
|
||||
avformat_close_input(&inputFormatContext);
|
||||
avformat_free_context(outputFormatContext);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start a thread to stop the streaming after the specified duration
|
||||
std::thread stop_thread([&]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(duration));
|
||||
av_read_pause(inputFormatContext);
|
||||
});
|
||||
|
||||
// Read packets from input and write them to output
|
||||
while (av_read_frame(inputFormatContext, &packet) >= 0) {
|
||||
AVStream* inStream = inputFormatContext->streams[packet.stream_index];
|
||||
AVStream* outStream = outputFormatContext->streams[packet.stream_index];
|
||||
|
||||
packet.pts = av_rescale_q_rnd(packet.pts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
|
||||
packet.dts = av_rescale_q_rnd(packet.dts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
|
||||
packet.duration = av_rescale_q(packet.duration, inStream->time_base, outStream->time_base);
|
||||
packet.pos = -1;
|
||||
|
||||
if (av_interleaved_write_frame(outputFormatContext, &packet) < 0) {
|
||||
fprintf(stderr, "Error muxing packet\n");
|
||||
break;
|
||||
}
|
||||
|
||||
av_packet_unref(&packet);
|
||||
}
|
||||
|
||||
stop_thread.join();
|
||||
|
||||
// Write output file trailer
|
||||
av_write_trailer(outputFormatContext);
|
||||
|
||||
// Clean up
|
||||
avformat_close_input(&inputFormatContext);
|
||||
if (outputFormatContext && !(outputFormatContext->oformat->flags & AVFMT_NOFILE)) {
|
||||
avio_closep(&outputFormatContext->pb);
|
||||
}
|
||||
avformat_free_context(outputFormatContext);
|
||||
}
|
||||
|
||||
|
||||
void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration, const std::string& userName, const std::string& password, net_handle_t netHandle)
|
||||
{
|
||||
AVFormatContext* inputFormatContext = nullptr;
|
||||
AVFormatContext* outputFormatContext = nullptr;
|
||||
AVPacket packet;
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
// Set the custom log callback
|
||||
av_log_set_callback(ffmpeg_log_callback);
|
||||
av_log_set_level(AV_LOG_WARNING);
|
||||
|
||||
#endif
|
||||
|
||||
std::string url = rtspUrl;
|
||||
AVDictionary* options = NULL;
|
||||
av_dict_set(&options, "rtsp_transport", "tcp", 0);
|
||||
av_dict_set(&options, "stimeout", "5000000", 0);
|
||||
if (!userName.empty())
|
||||
{
|
||||
av_dict_set(&options, "username", userName.c_str(), 0); // Replace with actual username
|
||||
av_dict_set(&options, "password", password.c_str(), 0); // Replace with actual password
|
||||
|
||||
char auth[512] = { 0 };
|
||||
snprintf(auth, sizeof(auth), "%s:%s@", userName.c_str(), password.c_str());
|
||||
|
||||
url.insert(url.begin() + 7, auth, auth + strlen(auth));
|
||||
}
|
||||
|
||||
// Open input RTSP stream
|
||||
int res = avformat_open_input(&inputFormatContext, url.c_str(), nullptr, &options);
|
||||
av_dict_free(&options);
|
||||
if (res != 0) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
av_strerror(res, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
fprintf(stderr, "Could not open input: %s (error code: %d)\n", errbuf, res);
|
||||
// fprintf(stderr, "Could not open input file '%s'\n", rtspUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Retrieve input stream information
|
||||
if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) {
|
||||
// fprintf(stderr, "Could not find stream information\n");
|
||||
avformat_close_input(&inputFormatContext);
|
||||
return;
|
||||
}
|
||||
|
||||
// Open output MP4 file
|
||||
if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mp4", outputPath) < 0) {
|
||||
fprintf(stderr, "Could not create output context\n");
|
||||
avformat_close_input(&inputFormatContext);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy stream information from input to output
|
||||
for (unsigned int i = 0; i < inputFormatContext->nb_streams; i++) {
|
||||
AVStream* inStream = inputFormatContext->streams[i];
|
||||
const AVCodecParameters *in_codecpar = inStream->codecpar;
|
||||
|
||||
// Skip audio streams
|
||||
if (inStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
// Copy video stream as-is
|
||||
const AVCodec *codec = avcodec_find_decoder(in_codecpar->codec_id);
|
||||
AVStream *out_stream = avformat_new_stream(outputFormatContext, codec);
|
||||
if (!out_stream) {
|
||||
return;
|
||||
}
|
||||
avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
|
||||
out_stream->codecpar->codec_tag = 0;
|
||||
out_stream->time_base = (AVRational){1, 90000};
|
||||
out_stream->avg_frame_rate = inStream->avg_frame_rate;
|
||||
}
|
||||
else if (in_codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
// Setup AAC audio stream
|
||||
const AVCodec *aac_encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
|
||||
if (!aac_encoder) {
|
||||
fprintf(stderr, "AAC encoder not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
AVStream *out_stream = avformat_new_stream(outputFormatContext, aac_encoder);
|
||||
if (!out_stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set AAC parameters
|
||||
out_stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
out_stream->codecpar->codec_id = AV_CODEC_ID_AAC;
|
||||
out_stream->codecpar->sample_rate = in_codecpar->sample_rate;
|
||||
out_stream->codecpar->format = AV_SAMPLE_FMT_FLTP;
|
||||
out_stream->codecpar->channels = in_codecpar->channels;
|
||||
out_stream->codecpar->channel_layout = av_get_default_channel_layout(in_codecpar->channels);
|
||||
out_stream->codecpar->bit_rate = 128000;
|
||||
out_stream->codecpar->frame_size = 1024; // AAC frame size
|
||||
out_stream->time_base = (AVRational){1, in_codecpar->sample_rate};
|
||||
}
|
||||
}
|
||||
|
||||
// Open output file
|
||||
if (!(outputFormatContext->oformat->flags & AVFMT_NOFILE)) {
|
||||
if (avio_open(&outputFormatContext->pb, outputPath, AVIO_FLAG_WRITE) < 0) {
|
||||
fprintf(stderr, "Could not open output file '%s'\n", outputPath);
|
||||
avformat_close_input(&inputFormatContext);
|
||||
avformat_free_context(outputFormatContext);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AVDictionary *opts = NULL;
|
||||
|
||||
// Set output format options
|
||||
av_dict_set(&opts, "movflags", "faststart+frag_keyframe", 0);
|
||||
av_dict_set(&opts, "brand", "mp42", 0);
|
||||
|
||||
// Write output file header
|
||||
res = avformat_write_header(outputFormatContext, &opts);
|
||||
av_dict_free(&opts);
|
||||
if (res < 0) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
av_strerror(res, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
fprintf(stderr, "Error occurred when writing header to output file: %s (error code: %d)\n", errbuf, res);
|
||||
avformat_close_input(&inputFormatContext);
|
||||
avformat_free_context(outputFormatContext);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Start a thread to stop the streaming after the specified duration
|
||||
std::thread stop_thread([&]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(duration));
|
||||
av_read_pause(inputFormatContext);
|
||||
});
|
||||
#endif
|
||||
|
||||
uint32_t framesToSkip = 16;
|
||||
uint32_t framesSkipped = 0;
|
||||
// Skip initial frames
|
||||
while (framesSkipped < framesToSkip) {
|
||||
if (av_read_frame(inputFormatContext, &packet) < 0)
|
||||
break;
|
||||
|
||||
if (packet.stream_index == 0) { // Video stream
|
||||
framesSkipped++;
|
||||
}
|
||||
av_packet_unref(&packet);
|
||||
}
|
||||
|
||||
auto startTime = av_gettime();
|
||||
// int64_t durationNs = (int64_t)duration * 1000000;
|
||||
int64_t durationNs = (int64_t)(duration + 32) * 1000;
|
||||
// Read packets from input and write them to output
|
||||
while (1) {
|
||||
|
||||
if ((av_gettime() - startTime) >= durationNs) {
|
||||
// printf("Duration limit reached (%d seconds)\n", ctx->duration_secs);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
AVStream* inStream = inputFormatContext->streams[packet.stream_index];
|
||||
AVStream* outStream = outputFormatContext->streams[packet.stream_index];
|
||||
|
||||
packet.pts = av_rescale_q_rnd(packet.pts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
|
||||
packet.dts = av_rescale_q_rnd(packet.dts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
|
||||
packet.duration = av_rescale_q(packet.duration, inStream->time_base, outStream->time_base);
|
||||
packet.pos = -1;
|
||||
|
||||
if (av_interleaved_write_frame(outputFormatContext, &packet) < 0) {
|
||||
fprintf(stderr, "Error muxing packet\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (av_read_frame(inputFormatContext, &packet) < 0) break;
|
||||
|
||||
// Skip audio packets
|
||||
if (inputFormatContext->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
av_packet_unref(&packet);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Adjust packet timebase
|
||||
AVStream *in_stream = inputFormatContext->streams[packet.stream_index];
|
||||
AVStream *out_stream = outputFormatContext->streams[packet.stream_index];
|
||||
av_packet_rescale_ts(&packet, in_stream->time_base, out_stream->time_base);
|
||||
packet.pos = -1;
|
||||
|
||||
res = av_write_frame(outputFormatContext, &packet);
|
||||
|
||||
av_packet_unref(&packet);
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// stop_thread.join();
|
||||
|
||||
// Write output file trailer
|
||||
av_write_trailer(outputFormatContext);
|
||||
|
||||
// Clean up
|
||||
avformat_close_input(&inputFormatContext);
|
||||
if (outputFormatContext && !(outputFormatContext->oformat->flags & AVFMT_NOFILE)) {
|
||||
avio_closep(&outputFormatContext->pb);
|
||||
}
|
||||
avformat_free_context(outputFormatContext);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/1.
|
||||
//
|
||||
|
||||
#ifndef MICROPHOTO_RTSPRECORDER_H
|
||||
#define MICROPHOTO_RTSPRECORDER_H
|
||||
|
||||
#include <string>
|
||||
#include <android/multinetwork.h>
|
||||
|
||||
// void dumpRtspToMp4(const std::string &rtspUrl, const std::string &outputPath, uint32_t durationInMs);
|
||||
void dumpRtmpToMp4(const char* rtmpUrl, const char* outputPath, uint32_t duration, net_handle_t netHandle);
|
||||
void dumpRtspToMp4(const char* rtspUrl, const char* outputPath, uint32_t duration, const std::string& userName, const std::string& password, net_handle_t netHandle);
|
||||
|
||||
class RTSPRecorder {
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //MICROPHOTO_RTSPRECORDER_H
|
@ -0,0 +1,186 @@
|
||||
//
|
||||
// Created by Matthew on 2025/2/28.
|
||||
//
|
||||
|
||||
#include "RTSPToMP4.h"
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <jni.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
int32_t getMaxInputSize(AMediaExtractor* extractor, size_t trackIndex)
|
||||
{
|
||||
AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, trackIndex);
|
||||
int32_t maxInputSize = 0;
|
||||
if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, &maxInputSize)) {
|
||||
// LOGI("Max input size for track %zu: %d", trackIndex, maxInputSize);
|
||||
} else {
|
||||
// LOGE("Failed to get max input size for track %zu", trackIndex);
|
||||
}
|
||||
AMediaFormat_delete(format);
|
||||
return maxInputSize;
|
||||
}
|
||||
|
||||
RTSPToMP4::RTSPToMP4(const char* rtspUrl, const char* outputPath, uint64_t durationInMs/* = 0*/)
|
||||
: fd(-1), codec(nullptr), extractor(nullptr), muxer(nullptr), videoTrackIndex(-1), durationInMs(durationInMs), running(false) {
|
||||
initExtractor(rtspUrl);
|
||||
initCodec("video/avc");
|
||||
initMuxer(outputPath);
|
||||
}
|
||||
|
||||
RTSPToMP4::~RTSPToMP4() {
|
||||
if (codec) AMediaCodec_delete(codec);
|
||||
if (extractor) AMediaExtractor_delete(extractor);
|
||||
if (muxer) AMediaMuxer_delete(muxer);
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
fdatasync(fd);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void RTSPToMP4::initCodec(const char* mime) {
|
||||
codec = AMediaCodec_createDecoderByType(mime);
|
||||
AMediaFormat* format = AMediaFormat_new();
|
||||
AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mime);
|
||||
// Set other format parameters as needed
|
||||
// ...
|
||||
AMediaCodec_configure(codec, format, nullptr, nullptr, 0);
|
||||
AMediaFormat_delete(format);
|
||||
}
|
||||
|
||||
void RTSPToMP4::initExtractor(const char* rtspUrl) {
|
||||
extractor = AMediaExtractor_new();
|
||||
media_status_t status = AMediaExtractor_setDataSource(extractor, rtspUrl);
|
||||
if (status != AMEDIA_OK) {
|
||||
// Handle error
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
void RTSPToMP4::initMuxer(const char* outputPath) {
|
||||
fd = open(outputPath, O_CREAT | O_WRONLY, 0644);
|
||||
muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
|
||||
|
||||
int numTracks = AMediaExtractor_getTrackCount(extractor);
|
||||
if (numTracks <= 0) {
|
||||
// LOGE("No tracks found in RTSP stream");
|
||||
AMediaExtractor_delete(extractor);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numTracks; ++i) {
|
||||
AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, i);
|
||||
const char* mime;
|
||||
if (AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime) && strncmp(mime, "video/", 6) == 0) {
|
||||
videoTrackIndex = AMediaMuxer_addTrack(muxer, format);
|
||||
AMediaExtractor_selectTrack(extractor, i);
|
||||
}
|
||||
AMediaFormat_delete(format);
|
||||
}
|
||||
|
||||
if (videoTrackIndex == -1) {
|
||||
// LOGE("No video track found in RTSP stream");
|
||||
AMediaExtractor_delete(extractor);
|
||||
AMediaMuxer_delete(muxer);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t maxInputSize = getMaxInputSize(extractor, videoTrackIndex);
|
||||
if (maxInputSize <= 0) {
|
||||
// LOGE("Invalid max input size");
|
||||
// releaseMediaExtractor(extractor);
|
||||
sampleData.resize(1920 * 1080 * 4, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
sampleData.resize(maxInputSize, 0);
|
||||
}
|
||||
|
||||
void RTSPToMP4::startDecodingAndMuxing() {
|
||||
AMediaCodec_start(codec);
|
||||
size_t bufferSize = sampleData.size();
|
||||
uint8_t* buffer = &sampleData[0];
|
||||
int64_t sampleTime = 0;
|
||||
int64_t startTime = 0;
|
||||
bool firstSampleData = true;
|
||||
|
||||
int64_t durationTime = (durationInMs == 0) ? std::numeric_limits<int64_t>::max() : (int64_t)durationInMs * 1000;
|
||||
|
||||
|
||||
while (running) {
|
||||
// Extract data from RTSP stream
|
||||
ssize_t sampleSize = AMediaExtractor_readSampleData(extractor, buffer, bufferSize);
|
||||
if (sampleSize < 0) {
|
||||
break; // End of stream
|
||||
}
|
||||
|
||||
sampleTime = AMediaExtractor_getSampleTime(extractor);
|
||||
if (firstSampleData)
|
||||
{
|
||||
startTime = sampleTime;
|
||||
firstSampleData = false;
|
||||
}
|
||||
|
||||
sampleTime -= startTime;
|
||||
|
||||
// Feed data to codec
|
||||
size_t inputBufferIndex;
|
||||
uint8_t* inputBuffer = AMediaCodec_getInputBuffer(codec, inputBufferIndex, &bufferSize);
|
||||
memcpy(inputBuffer, buffer, sampleSize);
|
||||
AMediaCodec_queueInputBuffer(codec, inputBufferIndex, 0, sampleSize, sampleTime, 0);
|
||||
|
||||
// Retrieve decoded frames and write to muxer
|
||||
AMediaCodecBufferInfo bufferInfo;
|
||||
ssize_t outputBufferIndex = AMediaCodec_dequeueOutputBuffer(codec, &bufferInfo, 0);
|
||||
if (outputBufferIndex >= 0) {
|
||||
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.size = sampleSize;
|
||||
bufferInfo.presentationTimeUs = sampleTime;
|
||||
bufferInfo.flags = AMediaExtractor_getSampleFlags(extractor);
|
||||
|
||||
uint8_t* outputBuffer = AMediaCodec_getOutputBuffer(codec, outputBufferIndex, &bufferSize);
|
||||
AMediaMuxer_writeSampleData(muxer, videoTrackIndex, outputBuffer, &bufferInfo);
|
||||
AMediaCodec_releaseOutputBuffer(codec, outputBufferIndex, false);
|
||||
}
|
||||
|
||||
AMediaExtractor_advance(extractor);
|
||||
|
||||
if (sampleTime > durationTime)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AMediaCodec_stop(codec);
|
||||
AMediaMuxer_stop(muxer);
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
fdatasync(fd);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void RTSPToMP4::start() {
|
||||
// Add video track to muxer
|
||||
AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, 0);
|
||||
videoTrackIndex = AMediaMuxer_addTrack(muxer, format);
|
||||
running = true;
|
||||
AMediaMuxer_start(muxer);
|
||||
|
||||
startDecodingAndMuxing();
|
||||
}
|
||||
|
||||
void RTSPToMP4::stop() {
|
||||
running = false;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by Matthew on 2025/2/28.
|
||||
//
|
||||
|
||||
#ifndef MICROPHOTO_RTSPTOMP4_H
|
||||
#define MICROPHOTO_RTSPTOMP4_H
|
||||
|
||||
#include <media/NdkMediaCodec.h>
|
||||
#include <media/NdkMediaExtractor.h>
|
||||
#include <media/NdkMediaMuxer.h>
|
||||
#include <vector>
|
||||
|
||||
class RTSPToMP4 {
|
||||
public:
|
||||
RTSPToMP4(const char* rtspUrl, const char* outputPath, uint64_t durationInMs = 0);
|
||||
~RTSPToMP4();
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
void initCodec(const char* mime);
|
||||
void initExtractor(const char* rtspUrl);
|
||||
void initMuxer(const char* outputPath);
|
||||
void startDecodingAndMuxing();
|
||||
|
||||
int fd;
|
||||
AMediaCodec* codec;
|
||||
AMediaExtractor* extractor;
|
||||
AMediaMuxer* muxer;
|
||||
int videoTrackIndex;
|
||||
uint64_t durationInMs;
|
||||
bool running;
|
||||
|
||||
std::vector<uint8_t> sampleData;
|
||||
};
|
||||
|
||||
|
||||
#endif //MICROPHOTO_RTSPTOMP4_H
|
@ -0,0 +1,547 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/11.
|
||||
//
|
||||
|
||||
#include "Streaming.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include <android/api-level.h>
|
||||
#include <android/log.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/time.h>
|
||||
}
|
||||
|
||||
extern void ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vl);
|
||||
|
||||
#if 0
|
||||
StreamForwarder::~StreamForwarder() {
|
||||
stop();
|
||||
if (inputCtx) {
|
||||
avformat_close_input(&inputCtx);
|
||||
}
|
||||
if (outputCtx) {
|
||||
if (outputCtx->pb) {
|
||||
avio_closep(&outputCtx->pb);
|
||||
}
|
||||
avformat_free_context(outputCtx);
|
||||
}
|
||||
}
|
||||
|
||||
bool StreamForwarder::initialize(const std::string& inputUrl, const std::string& outputUrl) {
|
||||
if (!openInput(inputUrl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!openOutput(outputUrl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StreamForwarder::openInput(const std::string& inputUrl) {
|
||||
inputCtx = avformat_alloc_context();
|
||||
if (!inputCtx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (avformat_open_input(&inputCtx, inputUrl.c_str(), nullptr, nullptr) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (avformat_find_stream_info(inputCtx, nullptr) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StreamForwarder::openOutput(const std::string& outputUrl) {
|
||||
int ret = avformat_alloc_output_context2(&outputCtx, nullptr, "flv", outputUrl.c_str());
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy streams from input to output
|
||||
for (unsigned int i = 0; i < inputCtx->nb_streams; i++) {
|
||||
AVStream* inStream = inputCtx->streams[i];
|
||||
AVStream* outStream = avformat_new_stream(outputCtx, inStream->codec->codec);
|
||||
if (!outStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = avcodec_copy_context(outStream->codec, inStream->codec);
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Open output file
|
||||
if (!(outputCtx->oformat->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&outputCtx->pb, outputUrl.c_str(), AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Write header
|
||||
ret = avformat_write_header(outputCtx, nullptr);
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StreamForwarder::setFrameCallback(std::function<void(uint8_t*, int, int, int)> callback) {
|
||||
frameCallback = callback;
|
||||
}
|
||||
|
||||
void StreamForwarder::start() {
|
||||
isRunning = true;
|
||||
forwardPackets();
|
||||
}
|
||||
|
||||
void StreamForwarder::stop() {
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
void StreamForwarder::forwardPackets() {
|
||||
AVPacket packet;
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
|
||||
while (isRunning) {
|
||||
if (av_read_frame(inputCtx, &packet) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Process video frames if callback is set
|
||||
if (frameCallback && packet.stream_index == 0) { // Assuming video is stream 0
|
||||
AVCodecContext* codecCtx = inputCtx->streams[packet.stream_index]->codec;
|
||||
int ret = avcodec_send_packet(codecCtx, &packet);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (ret >= 0) {
|
||||
ret = avcodec_receive_frame(codecCtx, frame);
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||
break;
|
||||
} else if (ret < 0) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
processFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
// Forward packet
|
||||
av_packet_rescale_ts(&packet,
|
||||
inputCtx->streams[packet.stream_index]->time_base,
|
||||
outputCtx->streams[packet.stream_index]->time_base);
|
||||
|
||||
int ret = av_interleaved_write_frame(outputCtx, &packet);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
av_packet_unref(&packet);
|
||||
}
|
||||
|
||||
end:
|
||||
av_frame_free(&frame);
|
||||
av_write_trailer(outputCtx);
|
||||
}
|
||||
|
||||
void StreamForwarder::processFrame(AVFrame* frame) {
|
||||
if (frameCallback) {
|
||||
frameCallback(frame->data[0], frame->linesize[0],
|
||||
frame->width, frame->height);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
RtspForwarder::RtspForwarder(const std::string& input, const std::string& output)
|
||||
: inputUrl(input), outputUrl(output), isRunning(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool RtspForwarder::isStreaming() const
|
||||
{
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
bool RtspForwarder::start()
|
||||
{
|
||||
run();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RtspForwarder::stop()
|
||||
{
|
||||
isRunning = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int RtspForwarder::run()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
|
||||
// Set the custom log callback
|
||||
av_log_set_callback(ffmpeg_log_callback);
|
||||
av_log_set_level(AV_LOG_DEBUG);
|
||||
|
||||
#endif
|
||||
isRunning = true;
|
||||
AVFormatContext* inputFormatContext = nullptr;
|
||||
AVFormatContext* outputFormatContext = nullptr;
|
||||
int ret;
|
||||
int videoStreamIndex = -1;
|
||||
int64_t startTime = AV_NOPTS_VALUE;
|
||||
AVBSFContext* bsf_ctx = nullptr;
|
||||
|
||||
std::string url = inputUrl;
|
||||
if (!m_userName.empty())
|
||||
{
|
||||
char auth[512] = { 0 };
|
||||
snprintf(auth, sizeof(auth), "%s:%s@", m_userName.c_str(), m_password.c_str());
|
||||
|
||||
url.insert(url.begin() + 7, auth, auth + strlen(auth));
|
||||
}
|
||||
|
||||
// Input options
|
||||
AVDictionary* inputOptions = nullptr;
|
||||
av_dict_set(&inputOptions, "rtsp_transport", "tcp", 0);
|
||||
av_dict_set(&inputOptions, "stimeout", "5000000", 0); // 5 second timeout
|
||||
// av_dict_set(&inputOptions, "buffer_size", "1024000", 0); // 1MB buffer
|
||||
|
||||
std::cout << "Opening input: " << url << std::endl;
|
||||
|
||||
// Open input
|
||||
ret = avformat_open_input(&inputFormatContext, url.c_str(), nullptr, &inputOptions);
|
||||
av_dict_free(&inputOptions);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Could not open input: " << av_err2str(ret) << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get stream info
|
||||
ret = avformat_find_stream_info(inputFormatContext, nullptr);
|
||||
if (ret < 0) {
|
||||
// std::cerr << "Failed to get stream info: " << av_err2str(ret) << std::endl;
|
||||
avformat_close_input(&inputFormatContext);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Find video stream
|
||||
for (unsigned i = 0; i < inputFormatContext->nb_streams; i++) {
|
||||
if (inputFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
videoStreamIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (videoStreamIndex == -1) {
|
||||
// std::cerr << "No video stream found" << std::endl;
|
||||
avformat_close_input(&inputFormatContext);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create stream mapping
|
||||
std::vector<int> streamMapping(inputFormatContext->nb_streams, -1);
|
||||
int outputStreamIdx = 0;
|
||||
|
||||
|
||||
// Allocate output context
|
||||
ret = avformat_alloc_output_context2(&outputFormatContext, nullptr, "rtsp", outputUrl.c_str());
|
||||
if ((ret < 0) || !outputFormatContext) {
|
||||
std::cerr << "Could not create output context" << std::endl;
|
||||
avformat_close_input(&inputFormatContext);
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXED VERSION - remove the redundant stream creation
|
||||
for (unsigned i = 0; i < inputFormatContext->nb_streams; i++) {
|
||||
AVStream* inStream = inputFormatContext->streams[i];
|
||||
const AVCodecParameters *in_codecpar = inStream->codecpar;
|
||||
|
||||
// Skip non-video streams if needed
|
||||
if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
|
||||
streamMapping[i] = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create only ONE stream per input stream
|
||||
const AVCodec *codec = avcodec_find_decoder(in_codecpar->codec_id);
|
||||
AVStream *outStream = avformat_new_stream(outputFormatContext, codec);
|
||||
if (!outStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = avcodec_parameters_copy(outStream->codecpar, in_codecpar);
|
||||
outStream->codecpar->codec_tag = 0;
|
||||
outStream->time_base = (AVRational){1, 90000};
|
||||
outStream->avg_frame_rate = inStream->avg_frame_rate;
|
||||
|
||||
// Map input stream to output stream
|
||||
streamMapping[i] = outputStreamIdx++;
|
||||
}
|
||||
|
||||
const AVBitStreamFilter* filter = av_bsf_get_by_name("h264_mp4toannexb");
|
||||
if (filter)
|
||||
{
|
||||
for (unsigned i = 0; i < outputFormatContext->nb_streams; i++) {
|
||||
AVStream* stream = outputFormatContext->streams[i];
|
||||
if (stream->codecpar->codec_id == AV_CODEC_ID_H264) {
|
||||
ret = av_bsf_alloc(filter, &bsf_ctx);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Failed to allocate bitstream filter context: " << av_err2str(ret) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy parameters from input to bsf
|
||||
ret = avcodec_parameters_copy(bsf_ctx->par_in, stream->codecpar);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Failed to copy parameters to bsf: " << av_err2str(ret) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the bsf context
|
||||
ret = av_bsf_init(bsf_ctx);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Failed to initialize bitstream filter: " << av_err2str(ret) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update output parameters
|
||||
ret = avcodec_parameters_copy(stream->codecpar, bsf_ctx->par_out);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Failed to copy parameters from bsf: " << av_err2str(ret) << std::endl;
|
||||
return false;
|
||||
}
|
||||
break; // Only apply to the first H.264 stream
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AVDictionary* outputOptions = nullptr;
|
||||
av_dict_set(&outputOptions, "rtsp_transport", "tcp", 0);
|
||||
av_dict_set(&outputOptions, "rtsp_flags", "filter_src", 0);
|
||||
av_dict_set(&outputOptions, "timeout", "5000000", 0);
|
||||
av_dict_set(&outputOptions, "allowed_media_types", "video", 0);
|
||||
av_dict_set(&outputOptions, "buffer_size", "1024000", 0); // 1MB buffer
|
||||
av_dict_set(&outputOptions, "fflags", "nobuffer", 0); // Reduce latency
|
||||
av_dict_set(&outputOptions, "muxdelay", "0.1", 0); // Reduce delay
|
||||
av_dict_set(&outputOptions, "max_delay", "500000", 0);
|
||||
av_dict_set(&outputOptions, "preset", "ultrafast", 0);
|
||||
av_dict_set(&outputOptions, "tune", "zerolatency", 0);
|
||||
av_dict_set(&outputOptions, "rtsp_flags", "prefer_tcp", 0);
|
||||
|
||||
// Open output
|
||||
if (!(outputFormatContext->oformat->flags & AVFMT_NOFILE)) {
|
||||
|
||||
// Output options
|
||||
|
||||
// ret = avio_open(&outputFormatContext->pb, outputUrl.c_str(), AVIO_FLAG_WRITE);
|
||||
ret = avio_open2(&outputFormatContext->pb, outputFormatContext->url, AVIO_FLAG_WRITE, NULL, &outputOptions);
|
||||
|
||||
if (ret < 0) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
std::cerr << "Could not open output URL: " << errbuf << std::endl;
|
||||
avformat_close_input(&inputFormatContext);
|
||||
avformat_free_context(outputFormatContext);
|
||||
av_dict_free(&outputOptions);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// Write header
|
||||
ret = avformat_write_header(outputFormatContext, &outputOptions);
|
||||
av_dict_free(&outputOptions);
|
||||
if (ret < 0) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
std::cerr << "Error writing header: " << errbuf << std::endl;
|
||||
avformat_close_input(&inputFormatContext);
|
||||
if (!(outputFormatContext->oformat->flags & AVFMT_NOFILE))
|
||||
avio_closep(&outputFormatContext->pb);
|
||||
avformat_free_context(outputFormatContext);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Main loop - read and write packets
|
||||
AVPacket packet;
|
||||
AVMediaType medaiType;
|
||||
while (isRunning) {
|
||||
ret = av_read_frame(inputFormatContext, &packet);
|
||||
if (ret < 0) {
|
||||
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
|
||||
std::cerr << "End of stream or timeout, reconnecting in "
|
||||
<< reconnectDelayMs << "ms" << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(reconnectDelayMs));
|
||||
avformat_close_input(&inputFormatContext);
|
||||
ret = avformat_open_input(&inputFormatContext, inputUrl.c_str(), nullptr, &inputOptions);
|
||||
if (ret < 0) continue;
|
||||
ret = avformat_find_stream_info(inputFormatContext, nullptr);
|
||||
if (ret < 0) continue;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Later when writing packets:
|
||||
int original_stream_index = packet.stream_index;
|
||||
if (streamMapping[original_stream_index] >= 0) {
|
||||
packet.stream_index = streamMapping[original_stream_index];
|
||||
// Write packet...
|
||||
} else {
|
||||
// Skip this packet
|
||||
av_packet_unref(&packet);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip audio packets
|
||||
medaiType = inputFormatContext->streams[original_stream_index]->codecpar->codec_type;
|
||||
if (medaiType == AVMEDIA_TYPE_AUDIO || medaiType == AVMEDIA_TYPE_DATA)
|
||||
{
|
||||
av_packet_unref(&packet);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
// Fix timestamps if enabled
|
||||
if (fixTimestamps) {
|
||||
// Handle timestamp issues similar to FFmpeg warning
|
||||
AVStream* inStream = inputFormatContext->streams[packet.stream_index];
|
||||
AVStream* outStream = outputFormatContext->streams[packet.stream_index];
|
||||
|
||||
if (packet.pts == AV_NOPTS_VALUE) {
|
||||
// Generate PTS if missing
|
||||
if (startTime == AV_NOPTS_VALUE) {
|
||||
startTime = av_gettime();
|
||||
}
|
||||
packet.pts = av_rescale_q(av_gettime() - startTime,
|
||||
AV_TIME_BASE_Q,
|
||||
inStream->time_base);
|
||||
packet.dts = packet.pts;
|
||||
}
|
||||
|
||||
// Rescale timestamps to output timebase
|
||||
packet.pts = av_rescale_q_rnd(packet.pts,
|
||||
inStream->time_base,
|
||||
outStream->time_base,
|
||||
static_cast<AVRounding>(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
|
||||
packet.dts = av_rescale_q_rnd(packet.dts,
|
||||
inStream->time_base,
|
||||
outStream->time_base,
|
||||
static_cast<AVRounding>(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
|
||||
packet.duration = av_rescale_q(packet.duration,
|
||||
inStream->time_base,
|
||||
outStream->time_base);
|
||||
}
|
||||
|
||||
// Write packet to output
|
||||
ret = av_interleaved_write_frame(outputFormatContext, &packet);
|
||||
av_packet_unref(&packet);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Error writing frame: " << av_err2str(ret) << std::endl;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
AVStream *in_stream = inputFormatContext->streams[original_stream_index];
|
||||
AVStream *out_stream = outputFormatContext->streams[packet.stream_index];
|
||||
av_packet_rescale_ts(&packet, in_stream->time_base, out_stream->time_base);
|
||||
|
||||
// CRITICAL: Fix timestamp issues
|
||||
if (packet.dts != AV_NOPTS_VALUE && packet.pts != AV_NOPTS_VALUE && packet.dts > packet.pts) {
|
||||
packet.dts = packet.pts;
|
||||
}
|
||||
|
||||
// Handle missing timestamps
|
||||
if (packet.pts == AV_NOPTS_VALUE) {
|
||||
if (startTime == AV_NOPTS_VALUE) {
|
||||
startTime = av_gettime();
|
||||
}
|
||||
packet.pts = av_rescale_q(av_gettime() - startTime,
|
||||
AV_TIME_BASE_Q,
|
||||
out_stream->time_base);
|
||||
packet.dts = packet.pts;
|
||||
}
|
||||
|
||||
packet.pos = -1;
|
||||
|
||||
// Apply bitstream filter if it's H.264
|
||||
if (bsf_ctx && out_stream->codecpar->codec_id == AV_CODEC_ID_H264) {
|
||||
ret = av_bsf_send_packet(bsf_ctx, &packet);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Error sending packet to bitstream filter: " << av_err2str(ret) << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
while (ret >= 0) {
|
||||
ret = av_bsf_receive_packet(bsf_ctx, &packet);
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||
// Need more input or end of file
|
||||
break;
|
||||
} else if (ret < 0) {
|
||||
std::cerr << "Error receiving packet from bitstream filter: " << av_err2str(ret) << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Write the filtered packet
|
||||
ret = av_interleaved_write_frame(outputFormatContext, &packet);
|
||||
av_packet_unref(&packet);
|
||||
if (ret < 0) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
std::cerr << "Error writing frame: " << errbuf << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Write the packet without filtering
|
||||
ret = av_interleaved_write_frame(outputFormatContext, &packet);
|
||||
av_packet_unref(&packet);
|
||||
if (ret < 0) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
std::cerr << "Error writing frame: " << errbuf << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cleanup:
|
||||
// Free the bitstream filter context
|
||||
if (bsf_ctx) {
|
||||
av_bsf_free(&bsf_ctx);
|
||||
}
|
||||
|
||||
// Write trailer
|
||||
av_write_trailer(outputFormatContext);
|
||||
|
||||
// Cleanup
|
||||
avformat_close_input(&inputFormatContext);
|
||||
if (outputFormatContext && !(outputFormatContext->oformat->flags & AVFMT_NOFILE))
|
||||
avio_closep(&outputFormatContext->pb);
|
||||
avformat_free_context(outputFormatContext);
|
||||
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/11.
|
||||
//
|
||||
|
||||
#ifndef MICROPHOTO_STREAMING_H
|
||||
#define MICROPHOTO_STREAMING_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
|
||||
#include <android/multinetwork.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
class Streaming
|
||||
{
|
||||
public:
|
||||
virtual ~Streaming() {}
|
||||
virtual bool start() { return false; }
|
||||
virtual bool stop() { return false; }
|
||||
virtual bool isStreaming() const { return false; }
|
||||
|
||||
void setAuth(const std::string& userName, const std::string& password)
|
||||
{
|
||||
m_userName = userName;
|
||||
m_password = password;
|
||||
}
|
||||
protected:
|
||||
std::string m_userName;
|
||||
std::string m_password;
|
||||
};
|
||||
|
||||
|
||||
#if 0
|
||||
class StreamForwarder : public Streaming
|
||||
{
|
||||
private:
|
||||
AVFormatContext* inputCtx = nullptr;
|
||||
AVFormatContext* outputCtx = nullptr;
|
||||
bool isRunning = false;
|
||||
|
||||
public:
|
||||
StreamForwarder() = default;
|
||||
virtual ~StreamForwarder();
|
||||
|
||||
bool initialize(const std::string& inputUrl, const std::string& outputUrl);
|
||||
virtual void start();
|
||||
virtual void stop();
|
||||
|
||||
private:
|
||||
bool openInput(const std::string& inputUrl);
|
||||
bool openOutput(const std::string& outputUrl);
|
||||
void forwardPackets();
|
||||
void setFrameCallback(std::function<void(uint8_t*, int, int, int)> callback);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
class RtspForwarder : public Streaming {
|
||||
private:
|
||||
std::string inputUrl;
|
||||
std::string outputUrl;
|
||||
std::atomic<bool> isRunning;
|
||||
|
||||
// Options
|
||||
int reconnectDelayMs = 5000;
|
||||
bool fixTimestamps = true;
|
||||
|
||||
public:
|
||||
RtspForwarder(const std::string& input, const std::string& output);
|
||||
|
||||
virtual bool start();
|
||||
virtual bool stop();
|
||||
virtual bool isStreaming() const;
|
||||
|
||||
|
||||
int run();
|
||||
};
|
||||
|
||||
#endif //MICROPHOTO_STREAMING_H
|
@ -0,0 +1,330 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/4.
|
||||
//
|
||||
|
||||
#include "HangYuCtrl.h"
|
||||
#include "netcamera.h"
|
||||
#include "httpclient.h"
|
||||
#include <LogThread.h>
|
||||
|
||||
#include <SpecData_JSON.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
HangYuCtrl::~HangYuCtrl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool HangYuCtrl::SetResolution(uint8_t channel, uint8_t streamID, uint32_t resX, uint32_t resY)
|
||||
{
|
||||
//流类型范围1-4,1为主流
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Streams/%u/1", m_ip.c_str(), (uint32_t)channel);
|
||||
|
||||
std::vector<uint8_t> resData;
|
||||
|
||||
int res = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
|
||||
if (res != 0 || resData.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string xmlString(resData.begin(), resData.end());
|
||||
|
||||
size_t widthStart = xmlString.find("<ResolutionWidth>");
|
||||
size_t widthEnd = xmlString.find("</ResolutionWidth>");
|
||||
if (widthStart != std::string::npos && widthEnd != std::string::npos) {
|
||||
widthStart += std::string("<ResolutionWidth>").length();
|
||||
xmlString.replace(widthStart, widthEnd - widthStart, std::to_string(resX));
|
||||
}
|
||||
|
||||
size_t heightStart = xmlString.find("<ResolutionHeigth>");
|
||||
size_t heightEnd = xmlString.find("</ResolutionHeigth>");
|
||||
if (heightStart != std::string::npos && heightEnd != std::string::npos) {
|
||||
heightStart += std::string("<ResolutionHeigth>").length();
|
||||
xmlString.replace(heightStart, heightEnd - heightStart, std::to_string(resY));
|
||||
}
|
||||
|
||||
res = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, xmlString.c_str(), resData);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HangYuCtrl::SetOsd(uint8_t channel, std::string osdstring, uint8_t pos)
|
||||
{
|
||||
// /LAPI/V1.0/Channels/<ID>/Media/OSDs/Contents
|
||||
//左上OSD
|
||||
|
||||
bool hasDateTime = (osdstring.find("$$DATETIME$$") != std::string::npos);
|
||||
size_t posi = osdstring.find("$$DATETIME$$");
|
||||
if (posi != std::string::npos) {
|
||||
size_t endPos = posi + 12;
|
||||
while (endPos < osdstring.size() && (osdstring[endPos] == ' ' || osdstring[endPos] == '\n')) {
|
||||
endPos++;
|
||||
}
|
||||
osdstring.erase(posi, endPos - posi);
|
||||
}
|
||||
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Pictures/%u/MultiOSDV2", m_ip.c_str(), (uint32_t)channel);
|
||||
std::vector<uint8_t> resData;
|
||||
std::replace(osdstring.begin(), osdstring.end(), '\n', '^');
|
||||
string xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><MultiLineOSD><DisplayTime><Enable>" + string(hasDateTime ? "true" : "false") + "</Enable><PosX>8</PosX><PosY>0</PosY></DisplayTime><OSD><ID>1</ID><Enable>false</Enable><Text>"+ osdstring+ "</Text><x>8</x><y>" + string(hasDateTime ? "24" : "0") + "</y></MultiLineOSD>";
|
||||
int res = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, xmlString.c_str(), resData);
|
||||
return res;
|
||||
}
|
||||
|
||||
void HangYuCtrl::EnableOsd(bool enable, uint8_t channel)
|
||||
{
|
||||
//航煜 只能显示时间和一个OSD
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Pictures/%u/MultiOSDV2", m_ip.c_str(), (uint32_t)channel);
|
||||
|
||||
std::vector<uint8_t> resData;
|
||||
|
||||
int res = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
|
||||
if (res != 0 || resData.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string xmlString(resData.begin(), resData.end());
|
||||
|
||||
std::string enableStartTag = "<Enable>";
|
||||
std::string enableEndTag = "</Enable>";
|
||||
|
||||
size_t pos = 0;
|
||||
while ((pos = xmlString.find(enableStartTag, pos)) != std::string::npos) {
|
||||
size_t startPos = pos + enableStartTag.length();
|
||||
size_t endPos = xmlString.find(enableEndTag, startPos);
|
||||
if (endPos == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
std::string newValue = enable ? "true" : "false";
|
||||
xmlString.replace(startPos, endPos - startPos, newValue);
|
||||
pos = endPos + enableEndTag.length();
|
||||
}
|
||||
|
||||
res = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, xmlString.c_str(), resData);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
// return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string HangYuCtrl::GetStreamingUrl(uint8_t channel)
|
||||
{
|
||||
// /LAPI/V1.0/Channels/<ID>/Media/Video/Streams/<ID>/LiveStreamURL?TransType=<Tran
|
||||
// sType>&TransProtocol=<TransProtocol>
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Streams/%u/1/Transport", m_ip.c_str(), (uint32_t)channel);
|
||||
|
||||
std::vector<uint8_t> resData;
|
||||
|
||||
int res = 0;
|
||||
for (int idx = 0; idx < 10; idx++)
|
||||
{
|
||||
res = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
|
||||
if (res == 0 && !resData.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res != 0 || resData.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
resData.push_back(0);
|
||||
const char* start = strstr((const char*)&resData[0], "<RTSPURI>");
|
||||
if (start == NULL)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
start += 9;
|
||||
const char* end = strstr(start, "</RTSPURI>");
|
||||
if (end == NULL)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return std::string(start, end);
|
||||
}
|
||||
|
||||
bool HangYuCtrl::UpdateTime(time_t ts)
|
||||
{
|
||||
// /LAPI/V1.0/System/Time
|
||||
|
||||
// <?xml version="1.0" encoding="utf-8"?>
|
||||
//<Time>
|
||||
//<DateTimeFormat>
|
||||
//<!--req,string,YYYYMMDDWhhmmss,YYYYMMDDhhmmss,MMDDYYYYWhhmmss,MMD
|
||||
// DYYYYhhmmss,DDMMYYYYWhhmmss,DDMMYYYYhhmmss-->
|
||||
//</DateTimeFormat>
|
||||
//<TimeFormat><!--req,xs:string,12hour,24hour--></TimeFormat>
|
||||
//<SystemTime><!--req,xs:datetime,” 20040503T173008+08”--></SystemTime>
|
||||
//<SyncNTPFlag><!--req,xs:string,"Sync,NoSync"--></SyncNTPFlag>
|
||||
//</Time>
|
||||
|
||||
std::string reqData = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Time><SystemTime>"
|
||||
+ FormatLocalDateTime("%d%02d%02dT%02d%02d%02d") + "+08</SystemTime></Time>";
|
||||
|
||||
std::string url = "http://" + m_ip + "/System/Time";
|
||||
std::vector<uint8_t> resData;
|
||||
int res = DoPutRequest(url.c_str(), HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, reqData.c_str(), resData);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HangYuCtrl::TakePhoto(uint8_t streamID, std::vector<uint8_t>& img)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
// /Snapshot/%u/1/RemoteImageCaptureV2?ImageFormat=jpg
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Snapshot/%u/1/RemoteImageCaptureV2?ImageFormat=jpg", m_ip.c_str(), (uint32_t)streamID);
|
||||
|
||||
int nRet = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, img, &m_lastErrorCode);
|
||||
if (0 == nRet)
|
||||
{
|
||||
bool qualityDowngraded = false;
|
||||
std::string originalConfig;
|
||||
if (img.size() < 1000)
|
||||
{
|
||||
qualityDowngraded = DowngradeQuality(originalConfig);
|
||||
XYLOG(XYLOG_SEVERITY_INFO,"Reduce Img Quality");
|
||||
}
|
||||
nRet = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, img, &m_lastErrorCode);
|
||||
if (!originalConfig.empty())
|
||||
{
|
||||
UpdateQuality(originalConfig);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> header = {0xFF, 0xD8, 0xFF, 0xE0}; // JPEG
|
||||
std::vector<uint8_t>::iterator it = std::search(img.begin(), img.end(), header.begin(), header.end());
|
||||
if (it != img.end() && it != img.begin())
|
||||
{
|
||||
img.erase(img.begin(), it);
|
||||
#ifndef NDEBUG
|
||||
int aa = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return nRet == 0;
|
||||
}
|
||||
|
||||
bool HangYuCtrl::DowngradeQuality(std::string& originalConfig)
|
||||
{
|
||||
bool res = false;
|
||||
char url[64] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Snapshot/Config", m_ip.c_str());
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
int nRet = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, data);
|
||||
if (0 == nRet)
|
||||
{
|
||||
std::string str = ByteArrayToString(&data[0], data.size());
|
||||
originalConfig = str;
|
||||
if (replaceAll(str, "<Quality>middle</Quality>", "<Quality>low</Quality>") == 0)
|
||||
{
|
||||
res = (replaceAll(str, "<Quality>high</Quality>", "<Quality>middle</Quality>") != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = true;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
data.clear();
|
||||
if (res)
|
||||
{
|
||||
nRet = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, str.c_str(), data);
|
||||
return 0 == nRet;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HangYuCtrl::UpdateQuality(const std::string& originalConfig)
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
char url[64] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Snapshot/Config", m_ip.c_str());
|
||||
int nRet = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, originalConfig.c_str(), data);
|
||||
return 0 == nRet;
|
||||
}
|
||||
|
||||
bool HangYuCtrl::UpgradeQuality()
|
||||
{
|
||||
bool res = false;
|
||||
char url[64] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Snapshot/Config", m_ip.c_str());
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
int nRet = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, data);
|
||||
if (0 == nRet)
|
||||
{
|
||||
std::string str = ByteArrayToString(&data[0], data.size());
|
||||
if (replaceAll(str, "<Quality>low</Quality>", "<Quality>middle</Quality>") == 0)
|
||||
{
|
||||
res = (replaceAll(str, "<Quality>middle</Quality>", "<Quality>high</Quality>") != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = true;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
data.clear();
|
||||
if (res)
|
||||
{
|
||||
nRet = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, str.c_str(), data);
|
||||
return 0 == nRet;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HangYuCtrl::QueryQuality(std::string& qualityContents)
|
||||
{
|
||||
char url[64] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Snapshot/Config", m_ip.c_str());
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
int nRet = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, data);
|
||||
if (0 == nRet && !data.empty())
|
||||
{
|
||||
qualityContents = ByteArrayToString(&data[0], data.size());
|
||||
}
|
||||
return (0 == nRet);
|
||||
}
|
||||
|
||||
bool HangYuCtrl::TakeVideo(uint8_t streamID, uint32_t duration, std::string path)
|
||||
{
|
||||
return false;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/4.
|
||||
//
|
||||
|
||||
#ifndef __MICROPHOTO_HANGYUCTRL_H__
|
||||
#define __MICROPHOTO_HANGYUCTRL_H__
|
||||
|
||||
#include "VendorCtrl.h"
|
||||
|
||||
class HangYuCtrl : public VendorCtrl
|
||||
{
|
||||
public:
|
||||
using VendorCtrl::VendorCtrl;
|
||||
virtual ~HangYuCtrl();
|
||||
|
||||
virtual bool SetOsd(uint8_t channel, std::string osd, uint8_t pos);
|
||||
virtual void EnableOsd(bool enable, uint8_t channel);
|
||||
virtual std::string GetStreamingUrl(uint8_t channel);
|
||||
virtual bool UpdateTime(time_t ts);
|
||||
virtual bool TakePhoto(uint8_t streamID, std::vector<uint8_t>& img);
|
||||
virtual bool TakeVideo(uint8_t streamID, uint32_t duration, std::string path);
|
||||
virtual bool HasAuthOnStreaming() const { return true; }
|
||||
virtual bool SetResolution(uint8_t channel, uint8_t streamID, uint32_t resX, uint32_t resY);
|
||||
|
||||
private:
|
||||
bool QueryQuality(std::string& qualityContents);
|
||||
bool DowngradeQuality(std::string& originalConfig);
|
||||
bool UpdateQuality(const std::string& originalConfig);
|
||||
bool UpgradeQuality();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //__MICROPHOTO_HANGYUCTRL_H__
|
@ -0,0 +1,204 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/4.
|
||||
//
|
||||
|
||||
#include "HikonCtrl.h"
|
||||
#include "netcamera.h"
|
||||
#include "httpclient.h"
|
||||
#include <LogThread.h>
|
||||
|
||||
#include <SpecData_JSON.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
HikonCtrl::~HikonCtrl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool HikonCtrl::SetResolution(uint8_t channel, uint8_t streamID, uint32_t resX, uint32_t resY)
|
||||
{
|
||||
//流类型范围1-4,1为主流
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Streams/%u/1", m_ip.c_str(), (uint32_t)channel);
|
||||
|
||||
std::vector<uint8_t> resData;
|
||||
|
||||
int res = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
|
||||
if (res != 0 || resData.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string xmlString(resData.begin(), resData.end());
|
||||
|
||||
size_t widthStart = xmlString.find("<ResolutionWidth>");
|
||||
size_t widthEnd = xmlString.find("</ResolutionWidth>");
|
||||
if (widthStart != std::string::npos && widthEnd != std::string::npos) {
|
||||
widthStart += std::string("<ResolutionWidth>").length();
|
||||
xmlString.replace(widthStart, widthEnd - widthStart, std::to_string(resX));
|
||||
}
|
||||
|
||||
size_t heightStart = xmlString.find("<ResolutionHeigth>");
|
||||
size_t heightEnd = xmlString.find("</ResolutionHeigth>");
|
||||
if (heightStart != std::string::npos && heightEnd != std::string::npos) {
|
||||
heightStart += std::string("<ResolutionHeigth>").length();
|
||||
xmlString.replace(heightStart, heightEnd - heightStart, std::to_string(resY));
|
||||
}
|
||||
|
||||
res = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, xmlString.c_str(), resData);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HikonCtrl::SetOsd(uint8_t channel, std::string osdstring, uint8_t pos)
|
||||
{
|
||||
// /LAPI/V1.0/Channels/<ID>/Media/OSDs/Contents
|
||||
//左上OSD
|
||||
|
||||
bool hasDateTime = (osdstring.find("$$DATETIME$$") != std::string::npos);
|
||||
size_t posi = osdstring.find("$$DATETIME$$");
|
||||
if (posi != std::string::npos) {
|
||||
size_t endPos = posi + 12;
|
||||
while (endPos < osdstring.size() && (osdstring[endPos] == ' ' || osdstring[endPos] == '\n')) {
|
||||
endPos++;
|
||||
}
|
||||
osdstring.erase(posi, endPos - posi);
|
||||
}
|
||||
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Pictures/%u/MultiOSDV2", m_ip.c_str(), (uint32_t)channel);
|
||||
std::vector<uint8_t> resData;
|
||||
std::replace(osdstring.begin(), osdstring.end(), '\n', '^');
|
||||
string xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><MultiLineOSD><DisplayTime><Enable>" + string(hasDateTime ? "true" : "false") + "</Enable><PosX>8</PosX><PosY>0</PosY></DisplayTime><OSD><ID>1</ID><Enable>false</Enable><Text>"+ osdstring+ "</Text><x>8</x><y>" + string(hasDateTime ? "24" : "0") + "</y></MultiLineOSD>";
|
||||
int res = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, xmlString.c_str(), resData);
|
||||
return res;
|
||||
}
|
||||
|
||||
void HikonCtrl::EnableOsd(bool enable, uint8_t channel)
|
||||
{
|
||||
//航煜 只能显示时间和一个OSD
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Pictures/%u/MultiOSDV2", m_ip.c_str(), (uint32_t)channel);
|
||||
|
||||
std::vector<uint8_t> resData;
|
||||
|
||||
int res = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
|
||||
if (res != 0 || resData.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string xmlString(resData.begin(), resData.end());
|
||||
|
||||
std::string enableStartTag = "<Enable>";
|
||||
std::string enableEndTag = "</Enable>";
|
||||
|
||||
size_t pos = 0;
|
||||
while ((pos = xmlString.find(enableStartTag, pos)) != std::string::npos) {
|
||||
size_t startPos = pos + enableStartTag.length();
|
||||
size_t endPos = xmlString.find(enableEndTag, startPos);
|
||||
if (endPos == std::string::npos) {
|
||||
break;
|
||||
}
|
||||
std::string newValue = enable ? "true" : "false";
|
||||
xmlString.replace(startPos, endPos - startPos, newValue);
|
||||
pos = endPos + enableEndTag.length();
|
||||
}
|
||||
|
||||
res = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, xmlString.c_str(), resData);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
// return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
std::string HikonCtrl::GetStreamingUrl(uint8_t channel)
|
||||
{
|
||||
// /LAPI/V1.0/Channels/<ID>/Media/Video/Streams/<ID>/LiveStreamURL?TransType=<Tran
|
||||
// sType>&TransProtocol=<TransProtocol>
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/Streams/%u/1/Transport", m_ip.c_str(), (uint32_t)channel);
|
||||
|
||||
std::vector<uint8_t> resData;
|
||||
|
||||
int res = 0;
|
||||
for (int idx = 0; idx < 10; idx++)
|
||||
{
|
||||
res = DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
|
||||
if (res == 0 && !resData.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res != 0 || resData.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
resData.push_back(0);
|
||||
const char* start = strstr((const char*)&resData[0], "<RTSPURI>");
|
||||
if (start == NULL)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
start += 9;
|
||||
const char* end = strstr(start, "</RTSPURI>");
|
||||
if (end == NULL)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return std::string(start, end);
|
||||
}
|
||||
|
||||
bool HikonCtrl::UpdateTime(time_t ts)
|
||||
{
|
||||
// /LAPI/V1.0/System/Time
|
||||
|
||||
// <?xml version="1.0" encoding="utf-8"?>
|
||||
//<Time>
|
||||
//<DateTimeFormat>
|
||||
//<!--req,string,YYYYMMDDWhhmmss,YYYYMMDDhhmmss,MMDDYYYYWhhmmss,MMD
|
||||
// DYYYYhhmmss,DDMMYYYYWhhmmss,DDMMYYYYhhmmss-->
|
||||
//</DateTimeFormat>
|
||||
//<TimeFormat><!--req,xs:string,12hour,24hour--></TimeFormat>
|
||||
//<SystemTime><!--req,xs:datetime,” 20040503T173008+08”--></SystemTime>
|
||||
//<SyncNTPFlag><!--req,xs:string,"Sync,NoSync"--></SyncNTPFlag>
|
||||
//</Time>
|
||||
|
||||
std::string reqData = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Time><SystemTime>"
|
||||
+ FormatLocalDateTime("%d%02d%02dT%02d%02d%02d") + "+08</SystemTime></Time>";
|
||||
|
||||
std::string url = "http://" + m_ip + "/System/Time";
|
||||
std::vector<uint8_t> resData;
|
||||
int res = DoPutRequest(url.c_str(), HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, reqData.c_str(), resData);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HikonCtrl::TakePhoto(uint8_t streamID, std::vector<uint8_t>& img)
|
||||
{
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/ISAPI/Streaming/channels/1/picture?", m_ip.c_str());
|
||||
int nRet = DoGetRequest(url, HTTP_AUTH_TYPE_DIGEST, m_userName.c_str(), m_password.c_str(), m_netHandle, img, &m_lastErrorCode);
|
||||
return nRet == 0;
|
||||
}
|
||||
|
||||
bool HikonCtrl::TakeVideo(uint8_t streamID, uint32_t duration, std::string path)
|
||||
{
|
||||
return false;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/4.
|
||||
//
|
||||
|
||||
#ifndef __MICROPHOTO_HIKONCTRL_H__
|
||||
#define __MICROPHOTO_HIKONCTRL_H__
|
||||
|
||||
#include "VendorCtrl.h"
|
||||
|
||||
class HikonCtrl : public VendorCtrl
|
||||
{
|
||||
public:
|
||||
using VendorCtrl::VendorCtrl;
|
||||
virtual ~HikonCtrl();
|
||||
|
||||
virtual bool SetOsd(uint8_t channel, std::string osd, uint8_t pos);
|
||||
virtual void EnableOsd(bool enable, uint8_t channel);
|
||||
virtual std::string GetStreamingUrl(uint8_t channel);
|
||||
virtual bool UpdateTime(time_t ts);
|
||||
virtual bool TakePhoto(uint8_t streamID, std::vector<uint8_t>& img);
|
||||
virtual bool TakeVideo(uint8_t streamID, uint32_t duration, std::string path);
|
||||
virtual bool HasAuthOnStreaming() const { return true; }
|
||||
virtual bool SetResolution(uint8_t channel, uint8_t streamID, uint32_t resX, uint32_t resY);
|
||||
|
||||
private:
|
||||
bool QueryQuality(std::string& qualityContents);
|
||||
bool DowngradeQuality(std::string& originalConfig);
|
||||
bool UpdateQuality(const std::string& originalConfig);
|
||||
bool UpgradeQuality();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //__MICROPHOTO_HIKONCTRL_H__
|
@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/4.
|
||||
//
|
||||
#include "VendorCtrl.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
VendorCtrl::VendorCtrl(const std::string& ip, const std::string& userName, const std::string& password, uint8_t channel, net_handle_t netHandle, bool syncTime/* = true*/) :
|
||||
m_ip(ip), m_userName(userName), m_password(password), m_channel(channel), m_netHandle(netHandle)
|
||||
{
|
||||
|
||||
}
|
||||
std::string VendorCtrl::CvtJSONToString(const Json::Value& data)
|
||||
{
|
||||
Json::StreamWriterBuilder builder;
|
||||
#ifndef NDEBUG
|
||||
builder["indentation"] = "\t"; // assume default for comments is None
|
||||
builder["emitUTF8"] = true;
|
||||
#else
|
||||
builder["indentation"] = "";
|
||||
#endif
|
||||
return Json::writeString(builder, data);
|
||||
}
|
||||
|
||||
bool VendorCtrl::IsTimeout() const
|
||||
{
|
||||
return m_lastErrorCode == CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/4.
|
||||
//
|
||||
|
||||
#ifndef MICROPHOTO_VENDORCTRL_H
|
||||
#define MICROPHOTO_VENDORCTRL_H
|
||||
|
||||
#include <string>
|
||||
#include <json/json.h>
|
||||
#include <android/multinetwork.h>
|
||||
|
||||
#define LEFT_TOP 0
|
||||
#define RIGHT_TOP 1
|
||||
#define LEFT_BOTTOM 2
|
||||
#define RIGHT_BOTTOM 3
|
||||
|
||||
class VendorCtrl {
|
||||
public:
|
||||
VendorCtrl(const std::string& ip, const std::string& userName, const std::string& password, uint8_t channel, net_handle_t netHandle, bool syncTime = true);
|
||||
virtual ~VendorCtrl() {}
|
||||
|
||||
virtual bool SetOsd(uint8_t channel, std::string osd, uint8_t pos) = 0;
|
||||
virtual void EnableOsd(bool enable, uint8_t channel) = 0;
|
||||
virtual std::string GetStreamingUrl(uint8_t channel) = 0;
|
||||
virtual bool UpdateTime(time_t ts) = 0;
|
||||
virtual bool TakePhoto(uint8_t streamID, std::vector<uint8_t>& img) = 0;
|
||||
virtual bool TakeVideo(uint8_t streamID, uint32_t duration, std::string path) = 0;
|
||||
virtual bool HasAuthOnStreaming() const { return false; }
|
||||
virtual bool SetResolution(uint8_t channel, uint8_t streamID, uint32_t resX, uint32_t resY) = 0;
|
||||
|
||||
|
||||
void UpdateNetHandle(net_handle_t netHandle) { m_netHandle = netHandle; }
|
||||
int GetLastError() const { return m_lastErrorCode; }
|
||||
bool IsTimeout() const;
|
||||
|
||||
protected:
|
||||
|
||||
std::string CvtJSONToString(const Json::Value& data);
|
||||
|
||||
protected:
|
||||
std::string m_ip;
|
||||
std::string m_userName;
|
||||
std::string m_password;
|
||||
uint8_t m_channel;
|
||||
net_handle_t m_netHandle;
|
||||
int m_lastErrorCode;
|
||||
};
|
||||
|
||||
|
||||
#endif //MICROPHOTO_VENDORCTRL_H
|
@ -0,0 +1,237 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/4.
|
||||
//
|
||||
|
||||
#include "YuShiCtrl.h"
|
||||
#include "httpclient.h"
|
||||
#include "netcamera.h"
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
YuShiCtrl::~YuShiCtrl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool YuShiCtrl::SetResolution(uint8_t channel, uint8_t streamID, uint32_t resX, uint32_t resY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YuShiCtrl::SetOsd(uint8_t channel, std::string osd, uint8_t pos)
|
||||
{
|
||||
// /LAPI/V1.0/Channels/<ID>/Media/OSDs/Contents
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/LAPI/V1.0/Channels/%u/Media/OSDs/Contents", m_ip.c_str(), (uint32_t)channel);
|
||||
std::vector<uint8_t> resData;
|
||||
|
||||
string jsonstring;
|
||||
switch (pos) {
|
||||
case LEFT_TOP:
|
||||
{
|
||||
OSDJson(0, 1, osd, 0, 0, true, jsonstring);
|
||||
break;
|
||||
}
|
||||
case RIGHT_TOP:
|
||||
{
|
||||
OSDJson(1, 1, osd, 9900, 0, false, jsonstring);
|
||||
break;
|
||||
}
|
||||
case LEFT_BOTTOM:
|
||||
{
|
||||
OSDJson(2, 1, osd, 0, 9900, false, jsonstring);
|
||||
break;
|
||||
}
|
||||
case RIGHT_BOTTOM:
|
||||
{
|
||||
OSDJson(3, 1, osd, 9900, 9900, false, jsonstring);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
int res = DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, jsonstring.c_str(), resData);
|
||||
return res;
|
||||
}
|
||||
|
||||
void YuShiCtrl::EnableOsd(bool enable, uint8_t channel)
|
||||
{
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/LAPI/V1.0/Channels/%u/Media/OSDs/Contents", m_ip.c_str(), (uint32_t)channel);
|
||||
std::vector<uint8_t> resData;
|
||||
int res =DoGetRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
|
||||
std::string jsonString(resData.begin(), resData.end());
|
||||
|
||||
Json::CharReaderBuilder reader;
|
||||
Json::Value root;
|
||||
std::string errors;
|
||||
std::istringstream s(jsonString);
|
||||
|
||||
if (!Json::parseFromStream(reader, s, &root, &errors)) {
|
||||
XYLOG(XYLOG_SEVERITY_ERROR, "Failed to parse JSON:%s", errors.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value& data = root["Response"]["Data"];
|
||||
if (data.isNull()) {
|
||||
XYLOG(XYLOG_SEVERITY_ERROR,"Data not found in JSON");
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value& contentList = data["ContentList"];
|
||||
for (auto& content : contentList) {
|
||||
content["Enabled"] = enable ? 1 : 0;
|
||||
}
|
||||
|
||||
Json::StreamWriterBuilder writer;
|
||||
std::string putJsonString = Json::writeString(writer, data);
|
||||
DoPutRequest(url, HTTP_AUTH_TYPE_BASIC, m_userName.c_str(), m_password.c_str(), m_netHandle, putJsonString.c_str(), resData);
|
||||
|
||||
|
||||
}
|
||||
|
||||
std::string YuShiCtrl::GetStreamingUrl(uint8_t channel)
|
||||
{
|
||||
// /LAPI/V1.0/Channels/<ID>/Media/Video/Streams/<ID>/LiveStreamURL?TransType=<Tran
|
||||
// sType>&TransProtocol=<TransProtocol>
|
||||
char url[128] = { 0 };
|
||||
snprintf(url, sizeof(url), "http://%s/LAPI/V1.0/Channels/%u/Media/Video/Streams/0/LiveStreamURL", m_ip.c_str(), (uint32_t)channel);
|
||||
|
||||
std::vector<uint8_t> resData;
|
||||
int res = DoGetRequest(url, HTTP_AUTH_TYPE_DIGEST, m_userName.c_str(), m_password.c_str(), m_netHandle, resData);
|
||||
if (res != 0 || resData.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
resData.push_back(0);
|
||||
Json::CharReaderBuilder builder;
|
||||
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
|
||||
|
||||
Json::Value json;
|
||||
const char* doc = (const char*)&(resData[0]);
|
||||
if (reader->parse(doc, doc + resData.size() - 1, &json, NULL))
|
||||
{
|
||||
if (json.isMember("Response"))
|
||||
{
|
||||
Json::Value& jsonRes = json["Response"];
|
||||
if (jsonRes.isMember("Data"))
|
||||
{
|
||||
Json::Value& jsonData = jsonRes["Data"];
|
||||
if (jsonData.isMember("URL"))
|
||||
{
|
||||
return std::string(jsonData["URL"].asCString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool YuShiCtrl::UpdateTime(time_t ts)
|
||||
{
|
||||
// /LAPI/V1.0/System/Time
|
||||
|
||||
#if 0
|
||||
Json::Value jsonData(Json::objectValue);
|
||||
|
||||
jsonData["TimeZone"] = "GMT+08:00";
|
||||
jsonData["DeviceTime"] = (int64_t)ts;
|
||||
jsonData["DateFormat"] = 0; // YYYY-MM-DD
|
||||
jsonData["HourFormat"] = 1; // 24H
|
||||
#endif
|
||||
|
||||
std::string contents = "{\"TimeZone\":\"GMT+08:00\",\"DateFormat\":0,\"HourFormat\":1,\"DeviceTime\":" + std::to_string(ts) + "}";
|
||||
|
||||
std::string url = "http://" + m_ip + "/LAPI/V1.0/System/Time";
|
||||
std::vector<uint8_t> resData;
|
||||
int res = DoPutRequest(url.c_str(), HTTP_AUTH_TYPE_DIGEST, m_userName.c_str(), m_password.c_str(), m_netHandle, contents.c_str(), resData);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YuShiCtrl::TakePhoto(uint8_t streamID, std::vector<uint8_t>& img)
|
||||
{
|
||||
// Yu Shi
|
||||
char url[128] = { 0 };
|
||||
int streamSid = 0; // should put into config
|
||||
snprintf(url, sizeof(url), "http://%s/LAPI/V1.0/Channels/%u/Media/Video/Streams/%d/Snapshot", m_ip.c_str(), (uint32_t)streamID, streamSid);
|
||||
|
||||
int nRet = DoGetRequest(url, HTTP_AUTH_TYPE_DIGEST, m_userName.c_str(), m_password.c_str(), m_netHandle, img, &m_lastErrorCode);
|
||||
return nRet == 0;
|
||||
}
|
||||
|
||||
bool YuShiCtrl::TakeVideo(uint8_t streamID, uint32_t duration, std::string path) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void YuShiCtrl::OSDJson(int id, bool enabled, std::string osdString, int x, int y, bool timeOn, std::string& jsonString)
|
||||
{
|
||||
Json::Value root;
|
||||
root["Num"] = 1;
|
||||
|
||||
Json::Value contentList(Json::arrayValue);
|
||||
|
||||
Json::Value content;
|
||||
content["ID"] = id;
|
||||
content["Enabled"] = enabled;
|
||||
|
||||
int row = 1;
|
||||
for (char ch : osdString) {
|
||||
if (ch == '\n') {
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
content["Num"] = row;
|
||||
Json::Value contentInfo(Json::arrayValue);
|
||||
size_t start = 0;
|
||||
size_t end = osdString.find('\n');
|
||||
|
||||
if(timeOn)
|
||||
{
|
||||
//如果在此位置显示时间
|
||||
Json::Value info;
|
||||
info["ContentType"] = 2;
|
||||
info["Value"] = "";
|
||||
contentInfo.append(info);
|
||||
}
|
||||
|
||||
for (int i = 0; i < row; i++)
|
||||
{
|
||||
std::string line;
|
||||
if (end == std::string::npos) {
|
||||
line = osdString.substr(start);
|
||||
} else {
|
||||
line = osdString.substr(start, end - start);
|
||||
start = end + 1;
|
||||
end = osdString.find('\n', start);
|
||||
}
|
||||
|
||||
Json::Value info;
|
||||
info["ContentType"] = 1;
|
||||
info["Value"] = line;
|
||||
contentInfo.append(info);
|
||||
}
|
||||
content["ContentInfo"] = contentInfo;
|
||||
|
||||
Json::Value area;
|
||||
Json::Value topLeft;
|
||||
topLeft["X"] = x; //9900
|
||||
topLeft["Y"] = y;
|
||||
area["TopLeft"] = topLeft;
|
||||
content["Area"] = area;
|
||||
|
||||
contentList.append(content);
|
||||
|
||||
root["ContentList"] = contentList;
|
||||
|
||||
Json::StreamWriterBuilder writer;
|
||||
jsonString = Json::writeString(writer, root);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
//
|
||||
// Created by Matthew on 2025/3/4.
|
||||
//
|
||||
|
||||
#ifndef MICROPHOTO_YUSHICTRL_H
|
||||
#define MICROPHOTO_YUSHICTRL_H
|
||||
|
||||
#include "VendorCtrl.h"
|
||||
|
||||
class YuShiCtrl : public VendorCtrl
|
||||
{
|
||||
public:
|
||||
using VendorCtrl::VendorCtrl;
|
||||
virtual ~YuShiCtrl();
|
||||
|
||||
virtual bool SetOsd(uint8_t channel, std::string osd, uint8_t pos);
|
||||
virtual void EnableOsd(bool enable, uint8_t channel);
|
||||
virtual std::string GetStreamingUrl(uint8_t streamID);
|
||||
virtual bool UpdateTime(time_t ts);
|
||||
virtual bool TakePhoto(uint8_t streamID, std::vector<uint8_t>& img);
|
||||
virtual bool TakeVideo(uint8_t streamID, uint32_t duration, std::string path);
|
||||
virtual bool SetResolution(uint8_t channel, uint8_t streamID, uint32_t resX, uint32_t resY);
|
||||
|
||||
private:
|
||||
void OSDJson(int id, bool enabled, std::string osdString, int x, int y, bool timeOn, std::string& jsonString);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //MICROPHOTO_YUSHICTRL_H
|
@ -0,0 +1,24 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <bits/ioctl.h>
|
||||
#include <json/json.h>
|
||||
|
||||
#include <android/multinetwork.h>
|
||||
#include "LogThread.h"
|
||||
|
||||
#ifndef __HTTP_CLIENT__
|
||||
#define __HTTP_CLIENT__
|
||||
|
||||
|
||||
bool setIPAddress(const char *if_name, const char *ip_addr, const char *net_mask, const char *gateway_addr);
|
||||
int DoGetRequest(const char* url, int authType, const char* userName, const char* password, net_handle_t netHandle, std::vector<uint8_t>& data, int* curlResVal = NULL);
|
||||
int DoPutRequest(const char* url, int authType, const char* userName, const char* password, net_handle_t netHandle, const char* contents, std::vector<uint8_t>& data, int* curlResVal = NULL);
|
||||
|
||||
#endif // __HTTP_CLIENT__
|
@ -0,0 +1,61 @@
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <android/multinetwork.h>
|
||||
|
||||
#ifndef __NET_CAMERA__
|
||||
#define __NET_CAMERA__
|
||||
|
||||
#define HTTP_AUTH_TYPE_NONE 0
|
||||
#define HTTP_AUTH_TYPE_BASIC 1
|
||||
#define HTTP_AUTH_TYPE_DIGEST 2
|
||||
|
||||
struct NET_PHOTO_INFO
|
||||
{
|
||||
net_handle_t netHandle;
|
||||
unsigned char authType; // 0, 1
|
||||
unsigned char reserved[7]; // for memory alignment
|
||||
char ip[24];
|
||||
char userName[8];
|
||||
char password[16];
|
||||
char url[128];
|
||||
char outputPath[128];
|
||||
};
|
||||
|
||||
/*
|
||||
struct NET_PHOTO_INFO
|
||||
{
|
||||
std::string ip;
|
||||
std::string userName;
|
||||
std::string password;
|
||||
std::string interface;
|
||||
std::string url;
|
||||
std::string outputPath;
|
||||
unsigned char authType; // 0, 1
|
||||
unsigned char reserved[7]; // for memory alignment
|
||||
};
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
}PIC_RESOLUTION;
|
||||
|
||||
|
||||
bool requestCapture(uint8_t channel, uint8_t preset, const NET_PHOTO_INFO& photoInfo);
|
||||
bool requestCapture(uint8_t channel, uint8_t preset, const NET_PHOTO_INFO& photoInfo, std::vector<uint8_t>& img);
|
||||
//bool setOSD(uint8_t channel, bool status, int type, uint32_t cameraId, const NET_PHOTO_INFO& photoInfo);
|
||||
int UniviewResolutionSet(const NET_PHOTO_INFO& photoInfo, int channel, unsigned int cmd);
|
||||
int uniview_resolution_jsoncpp_file_info(Json::Value &outdata, unsigned int cmd);
|
||||
|
||||
namespace nc_hk
|
||||
{
|
||||
bool requestCapture(uint8_t channel, uint8_t preset, const NET_PHOTO_INFO& photoInfo, std::vector<uint8_t>& img);
|
||||
}
|
||||
|
||||
|
||||
namespace nc_ys
|
||||
{
|
||||
bool requestCapture(uint8_t channel, uint8_t preset, const NET_PHOTO_INFO& photoInfo, std::vector<uint8_t>& img);
|
||||
}
|
||||
|
||||
#endif // __NET_CAMERA__
|
@ -1,222 +0,0 @@
|
||||
package com.xypower.mpapp;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.os.IBinder;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class FloatingWindow extends Service {
|
||||
|
||||
private Context mContext;
|
||||
private WindowManager mWindowManager;
|
||||
private View mView;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mContext = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
|
||||
|
||||
allAboutLayout(intent);
|
||||
moveView();
|
||||
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
|
||||
try {
|
||||
if (mView != null) {
|
||||
mWindowManager.removeView(mView);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ex.printStackTrace();
|
||||
Log.e("FW", "Exception " + ex.getMessage());
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
WindowManager.LayoutParams mWindowsParams;
|
||||
private void moveView() {
|
||||
/*
|
||||
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
|
||||
int width = (int) (metrics.widthPixels * 1f);
|
||||
int height = (int) (metrics.heightPixels * 1f);
|
||||
|
||||
mWindowsParams = new WindowManager.LayoutParams(
|
||||
width,//WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
height,//WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
//WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
|
||||
|
||||
(Build.VERSION.SDK_INT <= 25) ? WindowManager.LayoutParams.TYPE_PHONE : WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
|
||||
,
|
||||
|
||||
//WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
|
||||
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN // Not displaying keyboard on bg activity's EditText
|
||||
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
|
||||
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|
||||
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
|
||||
//WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, //Not work with EditText on keyboard
|
||||
PixelFormat.TRANSLUCENT);
|
||||
|
||||
|
||||
mWindowsParams.gravity = Gravity.TOP | Gravity.LEFT;
|
||||
//params.x = 0;
|
||||
mWindowsParams.y = 100;
|
||||
mWindowManager.addView(mView, mWindowsParams);
|
||||
|
||||
mView.setOnTouchListener(new View.OnTouchListener() {
|
||||
private int initialX;
|
||||
private int initialY;
|
||||
private float initialTouchX;
|
||||
private float initialTouchY;
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (System.currentTimeMillis() - startTime <= 300) {
|
||||
return false;
|
||||
}
|
||||
if (isViewInBounds(mView, (int) (event.getRawX()), (int) (event.getRawY()))) {
|
||||
editTextReceiveFocus();
|
||||
} else {
|
||||
editTextDontReceiveFocus();
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
initialX = mWindowsParams.x;
|
||||
initialY = mWindowsParams.y;
|
||||
initialTouchX = event.getRawX();
|
||||
initialTouchY = event.getRawY();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mWindowsParams.x = initialX + (int) (event.getRawX() - initialTouchX);
|
||||
mWindowsParams.y = initialY + (int) (event.getRawY() - initialTouchY);
|
||||
mWindowManager.updateViewLayout(mView, mWindowsParams);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
private boolean isViewInBounds(View view, int x, int y) {
|
||||
Rect outRect = new Rect();
|
||||
int[] location = new int[2];
|
||||
view.getDrawingRect(outRect);
|
||||
view.getLocationOnScreen(location);
|
||||
outRect.offset(location[0], location[1]);
|
||||
return outRect.contains(x, y);
|
||||
}
|
||||
|
||||
private void editTextReceiveFocus() {
|
||||
if (!wasInFocus) {
|
||||
mWindowsParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
mWindowManager.updateViewLayout(mView, mWindowsParams);
|
||||
wasInFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void editTextDontReceiveFocus() {
|
||||
if (wasInFocus) {
|
||||
mWindowsParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
mWindowManager.updateViewLayout(mView, mWindowsParams);
|
||||
wasInFocus = false;
|
||||
hideKeyboard(mContext, edt1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean wasInFocus = true;
|
||||
private EditText edt1;
|
||||
private void allAboutLayout(Intent intent) {
|
||||
|
||||
LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mView = layoutInflater.inflate(R.layout.ovelay_window, null);
|
||||
|
||||
edt1 = (EditText) mView.findViewById(R.id.edt1);
|
||||
final TextView tvValue = (TextView) mView.findViewById(R.id.tvValue);
|
||||
Button btnClose = (Button) mView.findViewById(R.id.btnClose);
|
||||
|
||||
edt1.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mWindowsParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
// mWindowsParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE;
|
||||
mWindowManager.updateViewLayout(mView, mWindowsParams);
|
||||
wasInFocus = true;
|
||||
showSoftKeyboard(v);
|
||||
}
|
||||
});
|
||||
|
||||
edt1.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||
tvValue.setText(edt1.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
btnClose.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
stopSelf();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void hideKeyboard(Context context, View view) {
|
||||
if (view != null) {
|
||||
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void showSoftKeyboard(View view) {
|
||||
if (view.requestFocus()) {
|
||||
InputMethodManager imm = (InputMethodManager)
|
||||
getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.xypower.mpapp;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
public class HeartBeatResponseReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if ("com.systemui.ACTION_HEARTBEAT_RESPONSE".equals(action)) {
|
||||
long timestamp = intent.getLongExtra("timestamp", 0);
|
||||
Log.d("MpApp","系统广播监听 timestamp:"+timestamp);
|
||||
MicroPhotoService.infoLog("收到heartbeat广播 timestamp:" + timestamp);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package com.xypower.mpapp;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.FileObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.xypower.common.MicroPhotoContext;
|
||||
import com.xypower.mpapp.databinding.ActivityLogBinding;
|
||||
import com.xypower.mpapp.utils.RandomReader;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class LogActivity extends AppCompatActivity {
|
||||
|
||||
public static final String TAG = "MPLOG";
|
||||
|
||||
public static final int MSG_WHAT_LOG_OBSERVER = MicroPhotoService.MSG_WHAT_MAX + 10;
|
||||
|
||||
public static final int MAX_LOG_LINES = 480;
|
||||
public static final int MIN_LOG_LINES = 120;
|
||||
|
||||
private ActivityLogBinding binding;
|
||||
|
||||
private Handler mHandler = null;
|
||||
|
||||
private LogFileObserver mLogFileObserver = null;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityLogBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
binding.logs.setText("");
|
||||
binding.logs.setMovementMethod(ScrollingMovementMethod.getInstance());
|
||||
binding.logs.setScrollbarFadingEnabled(false);
|
||||
|
||||
mHandler = new Handler(Looper.myLooper()) {
|
||||
@Override
|
||||
public void handleMessage(@NonNull Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_WHAT_LOG_OBSERVER:
|
||||
{
|
||||
byte[] bytes = (byte[])msg.obj;
|
||||
int bytesRead = msg.arg1;
|
||||
String log = null;
|
||||
try {
|
||||
log = new String(bytes, 0, bytesRead, "UTF-8");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (log != null) {
|
||||
binding.logs.append(log);
|
||||
int offset = binding.logs.getLineCount() * binding.logs.getLineHeight();
|
||||
if (offset > binding.logs.getHeight()) {
|
||||
binding.logs.scrollTo(0, offset - binding.logs.getHeight() + binding.logs.getLineHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
// call the superclass method first
|
||||
super.onResume();
|
||||
|
||||
try {
|
||||
String logFilePath = MicroPhotoContext.buildAppDir(this.getApplicationContext());
|
||||
logFilePath += "logs";
|
||||
File file = new File(logFilePath);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
logFilePath += "/log.txt";
|
||||
file = new File(logFilePath);
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
|
||||
mLogFileObserver = new LogFileObserver(logFilePath);
|
||||
mLogFileObserver.startWatching();
|
||||
Log.i(TAG, "Log Observer Started");
|
||||
|
||||
int lines = binding.logs.getLineCount();
|
||||
if (lines > MAX_LOG_LINES) {
|
||||
int excessLineNumber = lines - MIN_LOG_LINES;
|
||||
int eolIndex = -1;
|
||||
CharSequence charSequence = binding.logs.getText();
|
||||
for (int i = 0; i < excessLineNumber; i++) {
|
||||
do {
|
||||
eolIndex++;
|
||||
} while (eolIndex < charSequence.length() && charSequence.charAt(eolIndex) != '\n');
|
||||
}
|
||||
if (eolIndex < charSequence.length()) {
|
||||
binding.logs.getEditableText().delete(0, eolIndex + 1);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
// call the superclass method first
|
||||
super.onPause();
|
||||
|
||||
try {
|
||||
if (mLogFileObserver != null) {
|
||||
mLogFileObserver.stopWatching();
|
||||
mLogFileObserver = null;
|
||||
Log.i(TAG, "Log Observer Stopped");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// todo: goto back activity from here
|
||||
|
||||
finish();
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class LogFileObserver extends FileObserver {
|
||||
|
||||
private long mOffset = 0;
|
||||
private String mPath = null;
|
||||
public LogFileObserver(String path) {
|
||||
super(path, FileObserver.MODIFY | FileObserver.CREATE);
|
||||
|
||||
mPath = path;
|
||||
File file = new File(path);
|
||||
if (file.exists()) {
|
||||
mOffset = file.length();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onEvent(int event, String s) {
|
||||
int e = event & FileObserver.ALL_EVENTS;
|
||||
|
||||
if (e == FileObserver.MODIFY) {
|
||||
File file = new File(mPath);
|
||||
long newOffset = file.length();
|
||||
if (newOffset > mOffset) {
|
||||
RandomReader reader = new RandomReader(mPath, mOffset);
|
||||
|
||||
byte[] bytes = new byte[(int)(newOffset - mOffset)];
|
||||
int bytesRead = reader.read(bytes);
|
||||
mOffset += bytesRead;
|
||||
|
||||
Message msg = Message.obtain();
|
||||
msg.what = MSG_WHAT_LOG_OBSERVER;
|
||||
msg.obj = bytes;
|
||||
msg.arg1 = bytesRead;
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
} else if (e == FileObserver.CREATE) {
|
||||
mOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,76 +0,0 @@
|
||||
package com.xypower.mpapp;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class ScreenActionReceiver extends BroadcastReceiver {
|
||||
|
||||
private String TAG = "ScreenActionReceiver";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
//LOG
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Action: " + intent.getAction() + "\n");
|
||||
// sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
|
||||
String log = sb.toString();
|
||||
Log.d(TAG, log);
|
||||
Toast.makeText(context, log, Toast.LENGTH_SHORT).show();
|
||||
|
||||
String action = intent.getAction();
|
||||
try {
|
||||
|
||||
if (Intent.ACTION_SCREEN_ON.equals(action)) {
|
||||
Log.d(TAG, "screen is on...");
|
||||
Toast.makeText(context, "screen ON", Toast.LENGTH_SHORT);
|
||||
|
||||
//Run the locker
|
||||
|
||||
context.startService(new Intent(context, FloatingWindow.class));
|
||||
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
|
||||
Log.d(TAG, "screen is off...");
|
||||
Toast.makeText(context, "screen OFF", Toast.LENGTH_SHORT);
|
||||
|
||||
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
|
||||
Log.d(TAG, "screen is unlock...");
|
||||
Toast.makeText(context, "screen UNLOCK", Toast.LENGTH_SHORT);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(new Intent(context, FloatingWindow.class));
|
||||
} else {
|
||||
context.startService(new Intent(context, FloatingWindow.class));
|
||||
}
|
||||
|
||||
} else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
|
||||
Log.d(TAG, "boot completed...");
|
||||
Toast.makeText(context, "BOOTED..", Toast.LENGTH_SHORT);
|
||||
//Run the locker
|
||||
/* Intent i = new Intent(context, FloatingWindow.class);
|
||||
context.startService(i);
|
||||
|
||||
*/
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// context.startForegroundService(new Intent(context, FloatingWindow.class));
|
||||
} else {
|
||||
// context.startService(new Intent(context, FloatingWindow.class));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IntentFilter getFilter(){
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
filter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
return filter;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#00FF00"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M20,4h-3.17L15,2L9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,6h4.05l1.83,-2h4.24l1.83,2L20,6v12zM12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5 5,-2.24 5,-5 -2.24,-5 -5,-5zM12,15c-1.65,0 -3,-1.35 -3,-3s1.35,-3 3,-3 3,1.35 3,3 -1.35,3 -3,3z"/>
|
||||
</vector>
|
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
tools:context=".LogActivity">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/logs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="4dp"
|
||||
android:padding="4dp"
|
||||
android:background="@drawable/textview_border"
|
||||
android:orientation="horizontal"
|
||||
android:lineSpacingMultiplier="1.25"
|
||||
android:scrollbars="vertical"
|
||||
android:singleLine="false"
|
||||
android:text="Logs"
|
||||
android:textColor="@color/black"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="networkProtocols">
|
||||
<item>TCP</item>
|
||||
<item>UDP</item>
|
||||
<item>0-TCP</item>
|
||||
<item>1-UDP</item>
|
||||
<item>10-MQTT</item>
|
||||
</string-array>
|
||||
</resources>
|
@ -1,248 +0,0 @@
|
||||
package com.xypower.common;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.android.dx.stock.ProxyBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
public class HotspotManager {
|
||||
|
||||
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static class OreoWifiManager {
|
||||
private static final String TAG = OreoWifiManager.class.getSimpleName();
|
||||
|
||||
private Context mContext;
|
||||
private WifiManager mWifiManager;
|
||||
private ConnectivityManager mConnectivityManager;
|
||||
|
||||
public OreoWifiManager(Context c) {
|
||||
mContext = c;
|
||||
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
||||
mConnectivityManager = (ConnectivityManager) mContext.getSystemService(ConnectivityManager.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the Wifi SSID and password
|
||||
* Call this before {@code startTethering} if app is a system/privileged app
|
||||
* Requires: android.permission.TETHER_PRIVILEGED which is only granted to system apps
|
||||
*/
|
||||
public void configureHotspot(String name, String password) {
|
||||
WifiConfiguration apConfig = new WifiConfiguration();
|
||||
apConfig.SSID = name;
|
||||
apConfig.preSharedKey = password;
|
||||
apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
|
||||
try {
|
||||
Method setConfigMethod = mWifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
|
||||
boolean status = (boolean) setConfigMethod.invoke(mWifiManager, apConfig);
|
||||
Log.d(TAG, "setWifiApConfiguration - success? " + status);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error in configureHotspot");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks where tethering is on.
|
||||
* This is determined by the getTetheredIfaces() method,
|
||||
* that will return an empty array if not devices are tethered
|
||||
*
|
||||
* @return true if a tethered device is found, false if not found
|
||||
*/
|
||||
/*public boolean isTetherActive() {
|
||||
try {
|
||||
Method method = mConnectivityManager.getClass().getDeclaredMethod("getTetheredIfaces");
|
||||
if (method == null) {
|
||||
Log.e(TAG, "getTetheredIfaces is null");
|
||||
} else {
|
||||
String res[] = (String[]) method.invoke(mConnectivityManager, null);
|
||||
Log.d(TAG, "getTetheredIfaces invoked");
|
||||
Log.d(TAG, Arrays.toString(res));
|
||||
if (res.length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error in getTetheredIfaces");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* This enables tethering using the ssid/password defined in Settings App>Hotspot & tethering
|
||||
* Does not require app to have system/privileged access
|
||||
* Credit: Vishal Sharma - https://stackoverflow.com/a/52219887
|
||||
*/
|
||||
public boolean startTethering(final OnStartTetheringCallback callback) {
|
||||
|
||||
// On Pie if we try to start tethering while it is already on, it will
|
||||
// be disabled. This is needed when startTethering() is called programmatically.
|
||||
/*if (isTetherActive()) {
|
||||
Log.d(TAG, "Tether already active, returning");
|
||||
return false;
|
||||
}*/
|
||||
|
||||
File outputDir = mContext.getCodeCacheDir();
|
||||
Object proxy;
|
||||
try {
|
||||
proxy = ProxyBuilder.forClass(OnStartTetheringCallbackClass())
|
||||
.dexCache(outputDir).handler(new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
switch (method.getName()) {
|
||||
case "onTetheringStarted":
|
||||
callback.onTetheringStarted();
|
||||
break;
|
||||
case "onTetheringFailed":
|
||||
callback.onTetheringFailed();
|
||||
break;
|
||||
default:
|
||||
ProxyBuilder.callSuper(proxy, method, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}).build();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error in enableTethering ProxyBuilder");
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
Method method = null;
|
||||
try {
|
||||
method = mConnectivityManager.getClass().getDeclaredMethod("startTethering", int.class, boolean.class, OnStartTetheringCallbackClass(), Handler.class);
|
||||
if (method == null) {
|
||||
Log.e(TAG, "startTetheringMethod is null");
|
||||
} else {
|
||||
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE, false, proxy, null);
|
||||
Log.d(TAG, "startTethering invoked");
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error in enableTethering");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void stopTethering() {
|
||||
try {
|
||||
Method method = mConnectivityManager.getClass().getDeclaredMethod("stopTethering", int.class);
|
||||
if (method == null) {
|
||||
Log.e(TAG, "stopTetheringMethod is null");
|
||||
} else {
|
||||
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE);
|
||||
Log.d(TAG, "stopTethering invoked");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "stopTethering error: " + e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Class OnStartTetheringCallbackClass() {
|
||||
try {
|
||||
return Class.forName("android.net.ConnectivityManager$OnStartTetheringCallback");
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(TAG, "OnStartTetheringCallbackClass error: " + e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class OnStartTetheringCallback {
|
||||
/**
|
||||
* Called when tethering has been successfully started.
|
||||
*/
|
||||
public abstract void onTetheringStarted();
|
||||
|
||||
/**
|
||||
* Called when starting tethering failed.
|
||||
*/
|
||||
public abstract void onTetheringFailed();
|
||||
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private static void setHotspotOnPhone(Context mContext, boolean isEnable) {
|
||||
|
||||
OreoWifiManager mTestOreoWifiManager = null;
|
||||
|
||||
if (mTestOreoWifiManager ==null) {
|
||||
mTestOreoWifiManager = new OreoWifiManager(mContext);
|
||||
}
|
||||
|
||||
|
||||
if (isEnable){
|
||||
OnStartTetheringCallback callback = new OnStartTetheringCallback() {
|
||||
@Override
|
||||
public void onTetheringStarted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTetheringFailed() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
mTestOreoWifiManager.startTethering(callback);
|
||||
}else{
|
||||
mTestOreoWifiManager.stopTethering();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
public static void setWiFiApEnable(Context context, boolean isEnable) {
|
||||
ConnectivityManager mConnectivityManager= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (isEnable) {
|
||||
mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI, false, new ConnectivityManager.OnStartTetheringCallback() {
|
||||
@Override
|
||||
public void onTetheringStarted() {
|
||||
Log.d(TAG, "onTetheringStarted");
|
||||
// Don't fire a callback here, instead wait for the next update from wifi.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTetheringFailed() {
|
||||
Log.d(TAG, "onTetheringFailed");
|
||||
// TODO: Show error.
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
public static void enableHotspot(Context context, boolean isEnable) {
|
||||
// R: Adnroid 11
|
||||
// O: Android 8
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// Android 11
|
||||
setHotspotOnPhone(context, isEnable);
|
||||
}/* else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// Android 8
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"absHeartbeats":[33420,85808],"heartbeat":10,"mntnMode":0,"mpappMonitorTimeout":1800000,"port":40101,"quickHbMode":0,"quickHeartbeat":60,"separateNetwork":1,"server":"61.169.135.150","timeForKeepingLogs":15,"usingAbsHbTime":1}
|
@ -0,0 +1 @@
|
||||
{"autoExposure":1,"autoFocus":1,"awbMode":1,"cameraType":0,"compensation":0,"customHdr":0,"exposureTime":0,"hdrStep":0,"ldrEnabled":0,"orientation":0,"osd":{"leftTop":"%%DATETIME%% CH:%%CH%%\r\n\u4fe1\u53f7:%%SL%% %%BV%%V"},"quality":80,"recognization":0,"requestTemplate":2,"resolutionCX":5376,"resolutionCY":3024,"sceneMode":0,"sensitivity":0,"usbCamera":0,"usingRawFormat":0,"usingSysCamera":0,"vendor":0,"videoCX":1280,"videoCY":720,"videoDuration":5,"wait3ALocked":0,"zoom":0,"zoomRatio":1}
|
@ -0,0 +1 @@
|
||||
{"autoExposure":1,"autoFocus":1,"awbMode":1,"burstCaptures":4,"cameraType":0,"compensation":0,"customHdr":0,"exposureTime":0,"hdrStep":0,"ldrEnabled":0,"orientation":3,"osd":{"leftTop":"%%DATETIME%% CH:%%CH%%\r\n\u4fe1\u53f7:%%SL%% %%BV%%V"},"quality":80,"recognization":0,"requestTemplate":2,"resolutionCX":1920,"resolutionCY":1080,"sceneMode":0,"sensitivity":0,"usbCamera":0,"usingRawFormat":2,"usingSysCamera":0,"vendor":0,"videoCX":1280,"videoCY":720,"videoDuration":5,"wait3ALocked":0,"zoom":0,"zoomRatio":1}
|
@ -0,0 +1 @@
|
||||
{"autoExposure":1,"autoFocus":1,"awbMode":1,"cameraType":0,"compensation":0,"customHdr":0,"hdrStep":0,"ldrEnabled":0,"orientation":4,"osd":{"leftTop":"%%DATETIME%% CH:%%CH%%\r\n\u4fe1\u53f7:%%SL%% %%BV%%V"},"recognization":0,"requestTemplate":1,"resolutionCX":3264,"resolutionCY":2448,"sceneMode":0,"usbCamera":0,"usingRawFormat":0,"usingSysCamera":0,"vendor":0,"videoCX":1280,"videoCY":720,"videoDuration":5,"wait3ALocked":0}
|
@ -1 +1 @@
|
||||
{"blobName16":"354","blobName32":"366","blobName8":"output","borderColor":16776960,"enabled":1,"items":[{"enabled":1,"iid":0,"name":"\u6316\u6398\u673a","prob":0.5,"subType":5,"type":1},{"enabled":1,"iid":1,"name":"\u540a\u5854","prob":0.5,"subType":2,"type":1},{"enabled":1,"iid":2,"name":"\u540a\u8f66","prob":0.5,"subType":1,"type":1},{"enabled":1,"iid":3,"name":"\u6c34\u6ce5\u6cf5\u8f66","prob":0.5,"subType":4,"type":1},{"enabled":1,"iid":4,"name":"\u5c71\u706b","prob":0.5,"subType":40,"type":4},{"enabled":1,"iid":5,"name":"\u70df\u96fe","prob":0.5,"subType":41,"type":4},{"enabled":1,"iid":6,"name":"\u63a8\u571f\u673a","prob":0.5,"subType":3,"type":1},{"enabled":1,"iid":7,"name":"\u7ffb\u6597\u8f66","prob":0.5,"subType":10,"type":1},{"enabled":1,"iid":8,"name":"\u5bfc\u7ebf\u5f02\u7269","prob":0.5,"subType":1,"type":3},{"enabled":1,"iid":9,"name":"\u9632\u5c18\u7f51","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":10,"name":"\u538b\u8def\u673a","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":11,"name":"\u6405\u62cc\u8f66","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":12,"name":"\u6869\u673a","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":13,"name":"\u56f4\u6321","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":14,"name":"\u6c34\u9a6c","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":15,"name":"\u5b89\u5168\u5e3d","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":16,"name":"\u4e95\u76d6\u7f3a\u5931","prob":1.0099999904632568,"subType":2,"type":3}],"textColor":16776960,"thickness":4}
|
||||
{"blobName16":"354","blobName32":"366","blobName8":"output","borderColor":16776960,"enabled":0,"items":[{"enabled":1,"iid":0,"name":"\u6316\u6398\u673a","prob":0.5,"subType":5,"type":1},{"enabled":1,"iid":1,"name":"\u540a\u5854","prob":0.5,"subType":2,"type":1},{"enabled":1,"iid":2,"name":"\u540a\u8f66","prob":0.5,"subType":1,"type":1},{"enabled":1,"iid":3,"name":"\u6c34\u6ce5\u6cf5\u8f66","prob":0.5,"subType":4,"type":1},{"enabled":1,"iid":4,"name":"\u5c71\u706b","prob":0.5,"subType":40,"type":4},{"enabled":1,"iid":5,"name":"\u70df\u96fe","prob":0.5,"subType":41,"type":4},{"enabled":1,"iid":6,"name":"\u63a8\u571f\u673a","prob":0.5,"subType":3,"type":1},{"enabled":1,"iid":7,"name":"\u7ffb\u6597\u8f66","prob":0.5,"subType":10,"type":1},{"enabled":1,"iid":8,"name":"\u5bfc\u7ebf\u5f02\u7269","prob":0.5,"subType":1,"type":3},{"enabled":1,"iid":9,"name":"\u9632\u5c18\u7f51","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":10,"name":"\u538b\u8def\u673a","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":11,"name":"\u6405\u62cc\u8f66","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":12,"name":"\u6869\u673a","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":13,"name":"\u56f4\u6321","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":14,"name":"\u6c34\u9a6c","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":15,"name":"\u5b89\u5168\u5e3d","prob":1.0099999904632568,"subType":2,"type":3},{"enabled":1,"iid":16,"name":"\u4e95\u76d6\u7f3a\u5931","prob":1.0099999904632568,"subType":2,"type":3}],"textColor":16776960,"thickness":4,"version":"2024-12-30"}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue