1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "VideoEditorTools.h"
18 #include "PreviewRenderer.h"
19 /*+ Handle the image files here */
20 #include <utils/Log.h>
21 /*- Handle the image files here */
22
23 const M4VIFI_UInt8 M4VIFI_ClipTable[1256]
24 = {
25 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
88 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
89 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
90 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
91 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
92 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
93 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
94 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
95 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
96 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
97 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
98 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b,
99 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
100 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
101 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
102 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b,
103 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
104 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b,
105 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
106 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
107 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3,
108 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
109 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
110 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb,
111 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
112 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
113 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3,
114 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
115 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
116 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
117 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
118 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
119 0xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
121 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
122 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
123 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
124 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
126 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
128 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
131 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
136 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
137 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
138 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
139 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
140 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
142 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
144 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
145 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
147 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
148 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
149 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
152 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
153 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
155 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
157 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
158 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
159 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
160 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
161 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
162 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
163 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
164 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
165 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
166 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
167 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
168 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
169 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
170 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
171 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
172 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
173 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
174 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
175 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
176 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
177 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
178 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
179 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
180 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
181 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
182 };
183
184 /* Division table for ( 65535/x ); x = 0 to 512 */
185 const M4VIFI_UInt16 M4VIFI_DivTable[512]
186 = {
187 0, 65535, 32768, 21845, 16384, 13107, 10922, 9362,
188 8192, 7281, 6553, 5957, 5461, 5041, 4681, 4369,
189 4096, 3855, 3640, 3449, 3276, 3120, 2978, 2849,
190 2730, 2621, 2520, 2427, 2340, 2259, 2184, 2114,
191 2048, 1985, 1927, 1872, 1820, 1771, 1724, 1680,
192 1638, 1598, 1560, 1524, 1489, 1456, 1424, 1394,
193 1365, 1337, 1310, 1285, 1260, 1236, 1213, 1191,
194 1170, 1149, 1129, 1110, 1092, 1074, 1057, 1040,
195 1024, 1008, 992, 978, 963, 949, 936, 923,
196 910, 897, 885, 873, 862, 851, 840, 829,
197 819, 809, 799, 789, 780, 771, 762, 753,
198 744, 736, 728, 720, 712, 704, 697, 689,
199 682, 675, 668, 661, 655, 648, 642, 636,
200 630, 624, 618, 612, 606, 601, 595, 590,
201 585, 579, 574, 569, 564, 560, 555, 550,
202 546, 541, 537, 532, 528, 524, 520, 516,
203 512, 508, 504, 500, 496, 492, 489, 485,
204 481, 478, 474, 471, 468, 464, 461, 458,
205 455, 451, 448, 445, 442, 439, 436, 434,
206 431, 428, 425, 422, 420, 417, 414, 412,
207 409, 407, 404, 402, 399, 397, 394, 392,
208 390, 387, 385, 383, 381, 378, 376, 374,
209 372, 370, 368, 366, 364, 362, 360, 358,
210 356, 354, 352, 350, 348, 346, 344, 343,
211 341, 339, 337, 336, 334, 332, 330, 329,
212 327, 326, 324, 322, 321, 319, 318, 316,
213 315, 313, 312, 310, 309, 307, 306, 304,
214 303, 302, 300, 299, 297, 296, 295, 293,
215 292, 291, 289, 288, 287, 286, 284, 283,
216 282, 281, 280, 278, 277, 276, 275, 274,
217 273, 271, 270, 269, 268, 267, 266, 265,
218 264, 263, 262, 261, 260, 259, 258, 257,
219 256, 255, 254, 253, 252, 251, 250, 249,
220 248, 247, 246, 245, 244, 243, 242, 241,
221 240, 240, 239, 238, 237, 236, 235, 234,
222 234, 233, 232, 231, 230, 229, 229, 228,
223 227, 226, 225, 225, 224, 223, 222, 222,
224 221, 220, 219, 219, 218, 217, 217, 216,
225 215, 214, 214, 213, 212, 212, 211, 210,
226 210, 209, 208, 208, 207, 206, 206, 205,
227 204, 204, 203, 202, 202, 201, 201, 200,
228 199, 199, 198, 197, 197, 196, 196, 195,
229 195, 194, 193, 193, 192, 192, 191, 191,
230 190, 189, 189, 188, 188, 187, 187, 186,
231 186, 185, 185, 184, 184, 183, 183, 182,
232 182, 181, 181, 180, 180, 179, 179, 178,
233 178, 177, 177, 176, 176, 175, 175, 174,
234 174, 173, 173, 172, 172, 172, 171, 171,
235 170, 170, 169, 169, 168, 168, 168, 167,
236 167, 166, 166, 165, 165, 165, 164, 164,
237 163, 163, 163, 162, 162, 161, 161, 161,
238 160, 160, 159, 159, 159, 158, 158, 157,
239 157, 157, 156, 156, 156, 155, 155, 154,
240 154, 154, 153, 153, 153, 152, 152, 152,
241 151, 151, 151, 150, 150, 149, 149, 149,
242 148, 148, 148, 147, 147, 147, 146, 146,
243 146, 145, 145, 145, 144, 144, 144, 144,
244 143, 143, 143, 142, 142, 142, 141, 141,
245 141, 140, 140, 140, 140, 139, 139, 139,
246 138, 138, 138, 137, 137, 137, 137, 136,
247 136, 136, 135, 135, 135, 135, 134, 134,
248 134, 134, 133, 133, 133, 132, 132, 132,
249 132, 131, 131, 131, 131, 130, 130, 130,
250 130, 129, 129, 129, 129, 128, 128, 128
251 };
252
253 const M4VIFI_Int32 const_storage1[8]
254 = {
255 0x00002568, 0x00003343,0x00000649,0x00000d0f, 0x0000D86C, 0x0000D83B, 0x00010000, 0x00010000
256 };
257
258 const M4VIFI_Int32 const_storage[8]
259 = {
260 0x00002568, 0x00003343, 0x1BF800, 0x00000649, 0x00000d0f, 0x110180, 0x40cf, 0x22BE00
261 };
262
263
264 const M4VIFI_UInt16 *M4VIFI_DivTable_zero
265 = &M4VIFI_DivTable[0];
266
267 const M4VIFI_UInt8 *M4VIFI_ClipTable_zero
268 = &M4VIFI_ClipTable[500];
269
M4VIFI_YUV420PlanarToYUV420Semiplanar(void * user_data,M4VIFI_ImagePlane * PlaneIn,M4VIFI_ImagePlane * PlaneOut)270 M4VIFI_UInt8 M4VIFI_YUV420PlanarToYUV420Semiplanar(void *user_data,
271 M4VIFI_ImagePlane *PlaneIn, M4VIFI_ImagePlane *PlaneOut ) {
272
273 M4VIFI_UInt32 i;
274 M4VIFI_UInt8 *p_buf_src, *p_buf_dest, *p_buf_src_u, *p_buf_src_v;
275 M4VIFI_UInt8 return_code = M4VIFI_OK;
276
277 /* the filter is implemented with the assumption that the width is equal to stride */
278 if(PlaneIn[0].u_width != PlaneIn[0].u_stride)
279 return M4VIFI_INVALID_PARAM;
280
281 /* The input Y Plane is the same as the output Y Plane */
282 p_buf_src = &(PlaneIn[0].pac_data[PlaneIn[0].u_topleft]);
283 p_buf_dest = &(PlaneOut[0].pac_data[PlaneOut[0].u_topleft]);
284 memcpy((void *)p_buf_dest,(void *)p_buf_src ,
285 PlaneOut[0].u_width * PlaneOut[0].u_height);
286
287 /* The U and V components are planar. The need to be made interleaved */
288 p_buf_src_u = &(PlaneIn[1].pac_data[PlaneIn[1].u_topleft]);
289 p_buf_src_v = &(PlaneIn[2].pac_data[PlaneIn[2].u_topleft]);
290 p_buf_dest = &(PlaneOut[1].pac_data[PlaneOut[1].u_topleft]);
291
292 for(i = 0; i < PlaneOut[1].u_width*PlaneOut[1].u_height; i++)
293 {
294 *p_buf_dest++ = *p_buf_src_u++;
295 *p_buf_dest++ = *p_buf_src_v++;
296 }
297 return return_code;
298 }
299
M4VIFI_SemiplanarYUV420toYUV420(void * user_data,M4VIFI_ImagePlane * PlaneIn,M4VIFI_ImagePlane * PlaneOut)300 M4VIFI_UInt8 M4VIFI_SemiplanarYUV420toYUV420(void *user_data,
301 M4VIFI_ImagePlane *PlaneIn, M4VIFI_ImagePlane *PlaneOut ) {
302
303 M4VIFI_UInt32 i;
304 M4VIFI_UInt8 *p_buf_src, *p_buf_dest, *p_buf_src_u, *p_buf_src_v;
305 M4VIFI_UInt8 *p_buf_dest_u,*p_buf_dest_v,*p_buf_src_uv;
306 M4VIFI_UInt8 return_code = M4VIFI_OK;
307
308 /* the filter is implemented with the assumption that the width is equal to stride */
309 if(PlaneIn[0].u_width != PlaneIn[0].u_stride)
310 return M4VIFI_INVALID_PARAM;
311
312 /* The input Y Plane is the same as the output Y Plane */
313 p_buf_src = &(PlaneIn[0].pac_data[PlaneIn[0].u_topleft]);
314 p_buf_dest = &(PlaneOut[0].pac_data[PlaneOut[0].u_topleft]);
315 memcpy((void *)p_buf_dest,(void *)p_buf_src ,
316 PlaneOut[0].u_width * PlaneOut[0].u_height);
317
318 /* The U and V components are planar. The need to be made interleaved */
319 p_buf_src_uv = &(PlaneIn[1].pac_data[PlaneIn[1].u_topleft]);
320 p_buf_dest_u = &(PlaneOut[1].pac_data[PlaneOut[1].u_topleft]);
321 p_buf_dest_v = &(PlaneOut[2].pac_data[PlaneOut[2].u_topleft]);
322
323 for(i = 0; i < PlaneOut[1].u_width*PlaneOut[1].u_height; i++)
324 {
325 *p_buf_dest_u++ = *p_buf_src_uv++;
326 *p_buf_dest_v++ = *p_buf_src_uv++;
327 }
328 return return_code;
329 }
330
331
332 /**
333 ******************************************************************************
334 * prototype M4VSS3GPP_externalVideoEffectColor(M4OSA_Void *pFunctionContext,
335 * M4VIFI_ImagePlane *PlaneIn,
336 * M4VIFI_ImagePlane *PlaneOut,
337 * M4VSS3GPP_ExternalProgress *pProgress,
338 * M4OSA_UInt32 uiEffectKind)
339 *
340 * @brief This function apply a color effect on an input YUV420 planar frame
341 * @note
342 * @param pFunctionContext(IN) Contains which color to apply (not very clean ...)
343 * @param PlaneIn (IN) Input YUV420 planar
344 * @param PlaneOut (IN/OUT) Output YUV420 planar
345 * @param pProgress (IN/OUT) Progress indication (0-100)
346 * @param uiEffectKind (IN) Unused
347 *
348 * @return M4VIFI_OK: No error
349 ******************************************************************************
350 */
M4VSS3GPP_externalVideoEffectColor(M4OSA_Void * pFunctionContext,M4VIFI_ImagePlane * PlaneIn,M4VIFI_ImagePlane * PlaneOut,M4VSS3GPP_ExternalProgress * pProgress,M4OSA_UInt32 uiEffectKind)351 M4OSA_ERR M4VSS3GPP_externalVideoEffectColor(M4OSA_Void *pFunctionContext,
352 M4VIFI_ImagePlane *PlaneIn, M4VIFI_ImagePlane *PlaneOut,
353 M4VSS3GPP_ExternalProgress *pProgress, M4OSA_UInt32 uiEffectKind) {
354
355 M4VIFI_Int32 plane_number;
356 M4VIFI_UInt32 i,j;
357 M4VIFI_UInt8 *p_buf_src, *p_buf_dest;
358 M4xVSS_ColorStruct* ColorContext = (M4xVSS_ColorStruct*)pFunctionContext;
359
360 for (plane_number = 0; plane_number < 3; plane_number++)
361 {
362 p_buf_src =
363 &(PlaneIn[plane_number].pac_data[PlaneIn[plane_number].u_topleft]);
364
365 p_buf_dest =
366 &(PlaneOut[plane_number].pac_data[PlaneOut[plane_number].u_topleft]);
367 for (i = 0; i < PlaneOut[plane_number].u_height; i++)
368 {
369 /**
370 * Chrominance */
371 if(plane_number==1 || plane_number==2)
372 {
373 //switch ((M4OSA_UInt32)pFunctionContext) // commented because a structure for the effects context exist
374 switch (ColorContext->colorEffectType)
375 {
376 case M4xVSS_kVideoEffectType_BlackAndWhite:
377 memset((void *)p_buf_dest,128,
378 PlaneIn[plane_number].u_width);
379 break;
380 case M4xVSS_kVideoEffectType_Pink:
381 memset((void *)p_buf_dest,255,
382 PlaneIn[plane_number].u_width);
383 break;
384 case M4xVSS_kVideoEffectType_Green:
385 memset((void *)p_buf_dest,0,
386 PlaneIn[plane_number].u_width);
387 break;
388 case M4xVSS_kVideoEffectType_Sepia:
389 if(plane_number==1)
390 {
391 memset((void *)p_buf_dest,117,
392 PlaneIn[plane_number].u_width);
393 }
394 else
395 {
396 memset((void *)p_buf_dest,139,
397 PlaneIn[plane_number].u_width);
398 }
399 break;
400 case M4xVSS_kVideoEffectType_Negative:
401 memcpy((void *)p_buf_dest,
402 (void *)p_buf_src ,PlaneOut[plane_number].u_width);
403 break;
404
405 case M4xVSS_kVideoEffectType_ColorRGB16:
406 {
407 M4OSA_UInt16 r = 0,g = 0,b = 0,y = 0,u = 0,v = 0;
408
409 /*first get the r, g, b*/
410 b = (ColorContext->rgb16ColorData & 0x001f);
411 g = (ColorContext->rgb16ColorData & 0x07e0)>>5;
412 r = (ColorContext->rgb16ColorData & 0xf800)>>11;
413
414 /*keep y, but replace u and v*/
415 if(plane_number==1)
416 {
417 /*then convert to u*/
418 u = U16(r, g, b);
419 memset((void *)p_buf_dest,(M4OSA_UInt8)u,
420 PlaneIn[plane_number].u_width);
421 }
422 if(plane_number==2)
423 {
424 /*then convert to v*/
425 v = V16(r, g, b);
426 memset((void *)p_buf_dest,(M4OSA_UInt8)v,
427 PlaneIn[plane_number].u_width);
428 }
429 }
430 break;
431 case M4xVSS_kVideoEffectType_Gradient:
432 {
433 M4OSA_UInt16 r = 0,g = 0,b = 0,y = 0,u = 0,v = 0;
434
435 /*first get the r, g, b*/
436 b = (ColorContext->rgb16ColorData & 0x001f);
437 g = (ColorContext->rgb16ColorData & 0x07e0)>>5;
438 r = (ColorContext->rgb16ColorData & 0xf800)>>11;
439
440 /*for color gradation*/
441 b = (M4OSA_UInt16)( b - ((b*i)/PlaneIn[plane_number].u_height));
442 g = (M4OSA_UInt16)(g - ((g*i)/PlaneIn[plane_number].u_height));
443 r = (M4OSA_UInt16)(r - ((r*i)/PlaneIn[plane_number].u_height));
444
445 /*keep y, but replace u and v*/
446 if(plane_number==1)
447 {
448 /*then convert to u*/
449 u = U16(r, g, b);
450 memset((void *)p_buf_dest,(M4OSA_UInt8)u,
451 PlaneIn[plane_number].u_width);
452 }
453 if(plane_number==2)
454 {
455 /*then convert to v*/
456 v = V16(r, g, b);
457 memset((void *)p_buf_dest,(M4OSA_UInt8)v,
458 PlaneIn[plane_number].u_width);
459 }
460 }
461 break;
462 default:
463 return M4VIFI_INVALID_PARAM;
464 }
465 }
466 /**
467 * Luminance */
468 else
469 {
470 //switch ((M4OSA_UInt32)pFunctionContext)// commented because a structure for the effects context exist
471 switch (ColorContext->colorEffectType)
472 {
473 case M4xVSS_kVideoEffectType_Negative:
474 for(j=0;j<PlaneOut[plane_number].u_width;j++)
475 {
476 p_buf_dest[j] = 255 - p_buf_src[j];
477 }
478 break;
479 default:
480 memcpy((void *)p_buf_dest,
481 (void *)p_buf_src ,PlaneOut[plane_number].u_width);
482 break;
483 }
484 }
485 p_buf_src += PlaneIn[plane_number].u_stride;
486 p_buf_dest += PlaneOut[plane_number].u_stride;
487 }
488 }
489
490 return M4VIFI_OK;
491 }
492
493 /**
494 ******************************************************************************
495 * prototype M4VSS3GPP_externalVideoEffectFraming(M4OSA_Void *pFunctionContext,
496 * M4VIFI_ImagePlane *PlaneIn,
497 * M4VIFI_ImagePlane *PlaneOut,
498 * M4VSS3GPP_ExternalProgress *pProgress,
499 * M4OSA_UInt32 uiEffectKind)
500 *
501 * @brief This function add a fixed or animated image on an input YUV420 planar frame
502 * @note
503 * @param pFunctionContext(IN) Contains which color to apply (not very clean ...)
504 * @param PlaneIn (IN) Input YUV420 planar
505 * @param PlaneOut (IN/OUT) Output YUV420 planar
506 * @param pProgress (IN/OUT) Progress indication (0-100)
507 * @param uiEffectKind (IN) Unused
508 *
509 * @return M4VIFI_OK: No error
510 ******************************************************************************
511 */
M4VSS3GPP_externalVideoEffectFraming(M4OSA_Void * userData,M4VIFI_ImagePlane PlaneIn[3],M4VIFI_ImagePlane * PlaneOut,M4VSS3GPP_ExternalProgress * pProgress,M4OSA_UInt32 uiEffectKind)512 M4OSA_ERR M4VSS3GPP_externalVideoEffectFraming(
513 M4OSA_Void *userData, M4VIFI_ImagePlane PlaneIn[3],
514 M4VIFI_ImagePlane *PlaneOut, M4VSS3GPP_ExternalProgress *pProgress,
515 M4OSA_UInt32 uiEffectKind ) {
516
517 M4VIFI_UInt32 x,y;
518
519 M4VIFI_UInt8 *p_in_Y = PlaneIn[0].pac_data;
520 M4VIFI_UInt8 *p_in_U = PlaneIn[1].pac_data;
521 M4VIFI_UInt8 *p_in_V = PlaneIn[2].pac_data;
522
523 M4xVSS_FramingStruct* Framing = M4OSA_NULL;
524 M4xVSS_FramingStruct* currentFraming = M4OSA_NULL;
525 M4VIFI_UInt8 *FramingRGB = M4OSA_NULL;
526
527 M4VIFI_UInt8 *p_out0;
528 M4VIFI_UInt8 *p_out1;
529 M4VIFI_UInt8 *p_out2;
530
531 M4VIFI_UInt32 topleft[2];
532
533 M4OSA_UInt8 transparent1 =
534 (M4OSA_UInt8)((TRANSPARENT_COLOR & 0xFF00)>>8);
535 M4OSA_UInt8 transparent2 = (M4OSA_UInt8)TRANSPARENT_COLOR;
536
537 #ifndef DECODE_GIF_ON_SAVING
538 Framing = (M4xVSS_FramingStruct *)userData;
539 currentFraming = (M4xVSS_FramingStruct *)Framing->pCurrent;
540 FramingRGB = Framing->FramingRgb->pac_data;
541 #endif /*DECODE_GIF_ON_SAVING*/
542
543 #ifdef DECODE_GIF_ON_SAVING
544 M4OSA_ERR err;
545 Framing =
546 (M4xVSS_FramingStruct *)((M4xVSS_FramingContext*)userData)->aFramingCtx;
547 if(Framing == M4OSA_NULL)
548 {
549 ((M4xVSS_FramingContext*)userData)->clipTime = pProgress->uiOutputTime;
550 err = M4xVSS_internalDecodeGIF(userData);
551 if(M4NO_ERROR != err)
552 {
553 M4OSA_TRACE1_1("M4VSS3GPP_externalVideoEffectFraming: \
554 Error in M4xVSS_internalDecodeGIF: 0x%x", err);
555 return err;
556 }
557 Framing =
558 (M4xVSS_FramingStruct *)((M4xVSS_FramingContext*)userData)->aFramingCtx;
559 /* Initializes first GIF time */
560 ((M4xVSS_FramingContext*)userData)->current_gif_time =
561 pProgress->uiOutputTime;
562 }
563 currentFraming = (M4xVSS_FramingStruct *)Framing;
564 FramingRGB = Framing->FramingRgb->pac_data;
565 #endif /*DECODE_GIF_ON_SAVING*/
566
567 /**
568 * Initialize input / output plane pointers */
569 p_in_Y += PlaneIn[0].u_topleft;
570 p_in_U += PlaneIn[1].u_topleft;
571 p_in_V += PlaneIn[2].u_topleft;
572
573 p_out0 = PlaneOut[0].pac_data;
574 p_out1 = PlaneOut[1].pac_data;
575 p_out2 = PlaneOut[2].pac_data;
576
577 /**
578 * Depending on time, initialize Framing frame to use */
579 if(Framing->previousClipTime == -1)
580 {
581 Framing->previousClipTime = pProgress->uiOutputTime;
582 }
583
584 /**
585 * If the current clip time has reach the duration of one frame of the framing picture
586 * we need to step to next framing picture */
587 #ifdef DECODE_GIF_ON_SAVING
588 if(((M4xVSS_FramingContext*)userData)->b_animated == M4OSA_TRUE)
589 {
590 while((((M4xVSS_FramingContext*)userData)->current_gif_time + currentFraming->duration) < pProgress->uiOutputTime)
591 {
592 ((M4xVSS_FramingContext*)userData)->clipTime =
593 pProgress->uiOutputTime;
594
595 err = M4xVSS_internalDecodeGIF(userData);
596 if(M4NO_ERROR != err)
597 {
598 M4OSA_TRACE1_1("M4VSS3GPP_externalVideoEffectFraming: Error in M4xVSS_internalDecodeGIF: 0x%x", err);
599 return err;
600 }
601 if(currentFraming->duration != 0)
602 {
603 ((M4xVSS_FramingContext*)userData)->current_gif_time += currentFraming->duration;
604 }
605 else
606 {
607 ((M4xVSS_FramingContext*)userData)->current_gif_time +=
608 pProgress->uiOutputTime - Framing->previousClipTime;
609 }
610 Framing = (M4xVSS_FramingStruct *)((M4xVSS_FramingContext*)userData)->aFramingCtx;
611 currentFraming = (M4xVSS_FramingStruct *)Framing;
612 FramingRGB = Framing->FramingRgb->pac_data;
613 }
614 }
615 #else
616 Framing->pCurrent = currentFraming->pNext;
617 currentFraming = (M4xVSS_FramingStruct*)Framing->pCurrent;
618 #endif /*DECODE_GIF_ON_SAVING*/
619
620 Framing->previousClipTime = pProgress->uiOutputTime;
621 FramingRGB = currentFraming->FramingRgb->pac_data;
622 topleft[0] = currentFraming->topleft_x;
623 topleft[1] = currentFraming->topleft_y;
624
625 for( x=0 ;x < PlaneIn[0].u_height ; x++)
626 {
627 for( y=0 ;y < PlaneIn[0].u_width ; y++)
628 {
629 /**
630 * To handle framing with input size != output size
631 * Framing is applyed if coordinates matches between framing/topleft and input plane */
632 if( y < (topleft[0] + currentFraming->FramingYuv[0].u_width) &&
633 y >= topleft[0] &&
634 x < (topleft[1] + currentFraming->FramingYuv[0].u_height) &&
635 x >= topleft[1])
636 {
637
638 /*Alpha blending support*/
639 M4OSA_Float alphaBlending = 1;
640 #ifdef DECODE_GIF_ON_SAVING
641 M4xVSS_internalEffectsAlphaBlending* alphaBlendingStruct =
642 (M4xVSS_internalEffectsAlphaBlending*)((M4xVSS_FramingContext*)userData)->alphaBlendingStruct;
643 #else
644 M4xVSS_internalEffectsAlphaBlending* alphaBlendingStruct =
645 (M4xVSS_internalEffectsAlphaBlending*)((M4xVSS_FramingStruct*)userData)->alphaBlendingStruct;
646 #endif //#ifdef DECODE_GIF_ON_SAVING
647
648 if(alphaBlendingStruct != M4OSA_NULL)
649 {
650 if(pProgress->uiProgress < (M4OSA_UInt32)(alphaBlendingStruct->m_fadeInTime*10))
651 {
652 alphaBlending = ((M4OSA_Float)(alphaBlendingStruct->m_middle - alphaBlendingStruct->m_start)*pProgress->uiProgress/(alphaBlendingStruct->m_fadeInTime*10));
653 alphaBlending += alphaBlendingStruct->m_start;
654 alphaBlending /= 100;
655 }
656 else if(pProgress->uiProgress >= (M4OSA_UInt32)(alphaBlendingStruct->m_fadeInTime*10) && pProgress->uiProgress < 1000 - (M4OSA_UInt32)(alphaBlendingStruct->m_fadeOutTime*10))
657 {
658 alphaBlending = (M4OSA_Float)((M4OSA_Float)alphaBlendingStruct->m_middle/100);
659 }
660 else if(pProgress->uiProgress >= 1000 - (M4OSA_UInt32)(alphaBlendingStruct->m_fadeOutTime*10))
661 {
662 alphaBlending = ((M4OSA_Float)(alphaBlendingStruct->m_middle - alphaBlendingStruct->m_end))*(1000 - pProgress->uiProgress)/(alphaBlendingStruct->m_fadeOutTime*10);
663 alphaBlending += alphaBlendingStruct->m_end;
664 alphaBlending /= 100;
665 }
666 }
667
668 /**/
669
670 if((*(FramingRGB)==transparent1) && (*(FramingRGB+1)==transparent2))
671 {
672 *( p_out0+y+x*PlaneOut[0].u_stride)=(*(p_in_Y+y+x*PlaneIn[0].u_stride));
673 *( p_out1+(y>>1)+(x>>1)*PlaneOut[1].u_stride)=(*(p_in_U+(y>>1)+(x>>1)*PlaneIn[1].u_stride));
674 *( p_out2+(y>>1)+(x>>1)*PlaneOut[2].u_stride)=(*(p_in_V+(y>>1)+(x>>1)*PlaneIn[2].u_stride));
675 }
676 else
677 {
678 *( p_out0+y+x*PlaneOut[0].u_stride)=(*(currentFraming->FramingYuv[0].pac_data+(y-topleft[0])+(x-topleft[1])*currentFraming->FramingYuv[0].u_stride))*alphaBlending;
679 *( p_out0+y+x*PlaneOut[0].u_stride)+=(*(p_in_Y+y+x*PlaneIn[0].u_stride))*(1-alphaBlending);
680 *( p_out1+(y>>1)+(x>>1)*PlaneOut[1].u_stride)=(*(currentFraming->FramingYuv[1].pac_data+((y-topleft[0])>>1)+((x-topleft[1])>>1)*currentFraming->FramingYuv[1].u_stride))*alphaBlending;
681 *( p_out1+(y>>1)+(x>>1)*PlaneOut[1].u_stride)+=(*(p_in_U+(y>>1)+(x>>1)*PlaneIn[1].u_stride))*(1-alphaBlending);
682 *( p_out2+(y>>1)+(x>>1)*PlaneOut[2].u_stride)=(*(currentFraming->FramingYuv[2].pac_data+((y-topleft[0])>>1)+((x-topleft[1])>>1)*currentFraming->FramingYuv[2].u_stride))*alphaBlending;
683 *( p_out2+(y>>1)+(x>>1)*PlaneOut[2].u_stride)+=(*(p_in_V+(y>>1)+(x>>1)*PlaneIn[2].u_stride))*(1-alphaBlending);
684 }
685 if( PlaneIn[0].u_width < (topleft[0] + currentFraming->FramingYuv[0].u_width) &&
686 y == PlaneIn[0].u_width-1)
687 {
688 FramingRGB = FramingRGB + 2 * (topleft[0] + currentFraming->FramingYuv[0].u_width - PlaneIn[0].u_width + 1);
689 }
690 else
691 {
692 FramingRGB = FramingRGB + 2;
693 }
694 }
695 /**
696 * Just copy input plane to output plane */
697 else
698 {
699 *( p_out0+y+x*PlaneOut[0].u_stride)=*(p_in_Y+y+x*PlaneIn[0].u_stride);
700 *( p_out1+(y>>1)+(x>>1)*PlaneOut[1].u_stride)=*(p_in_U+(y>>1)+(x>>1)*PlaneIn[1].u_stride);
701 *( p_out2+(y>>1)+(x>>1)*PlaneOut[2].u_stride)=*(p_in_V+(y>>1)+(x>>1)*PlaneIn[2].u_stride);
702 }
703 }
704 }
705
706 #ifdef DECODE_GIF_ON_SAVING
707 if(pProgress->bIsLast == M4OSA_TRUE
708 && (M4OSA_Bool)((M4xVSS_FramingContext*)userData)->b_IsFileGif == M4OSA_TRUE)
709 {
710 M4xVSS_internalDecodeGIF_Cleaning((M4xVSS_FramingContext*)userData);
711 }
712 #endif /*DECODE_GIF_ON_SAVING*/
713 return M4VIFI_OK;
714 }
715
716
717 /**
718 ******************************************************************************
719 * prototype M4VSS3GPP_externalVideoEffectFifties(M4OSA_Void *pFunctionContext,
720 * M4VIFI_ImagePlane *PlaneIn,
721 * M4VIFI_ImagePlane *PlaneOut,
722 * M4VSS3GPP_ExternalProgress *pProgress,
723 * M4OSA_UInt32 uiEffectKind)
724 *
725 * @brief This function make a video look as if it was taken in the fifties
726 * @note
727 * @param pUserData (IN) Context
728 * @param pPlaneIn (IN) Input YUV420 planar
729 * @param pPlaneOut (IN/OUT) Output YUV420 planar
730 * @param pProgress (IN/OUT) Progress indication (0-100)
731 * @param uiEffectKind (IN) Unused
732 *
733 * @return M4VIFI_OK: No error
734 * @return M4ERR_PARAMETER: pFiftiesData, pPlaneOut or pProgress are NULL (DEBUG only)
735 ******************************************************************************
736 */
M4VSS3GPP_externalVideoEffectFifties(M4OSA_Void * pUserData,M4VIFI_ImagePlane * pPlaneIn,M4VIFI_ImagePlane * pPlaneOut,M4VSS3GPP_ExternalProgress * pProgress,M4OSA_UInt32 uiEffectKind)737 M4OSA_ERR M4VSS3GPP_externalVideoEffectFifties(
738 M4OSA_Void *pUserData, M4VIFI_ImagePlane *pPlaneIn,
739 M4VIFI_ImagePlane *pPlaneOut, M4VSS3GPP_ExternalProgress *pProgress,
740 M4OSA_UInt32 uiEffectKind )
741 {
742 M4VIFI_UInt32 x, y, xShift;
743 M4VIFI_UInt8 *pInY = pPlaneIn[0].pac_data;
744 M4VIFI_UInt8 *pOutY, *pInYbegin;
745 M4VIFI_UInt8 *pInCr,* pOutCr;
746 M4VIFI_Int32 plane_number;
747
748 /* Internal context*/
749 M4xVSS_FiftiesStruct* p_FiftiesData = (M4xVSS_FiftiesStruct *)pUserData;
750
751 /* Initialize input / output plane pointers */
752 pInY += pPlaneIn[0].u_topleft;
753 pOutY = pPlaneOut[0].pac_data;
754 pInYbegin = pInY;
755
756 /* Initialize the random */
757 if(p_FiftiesData->previousClipTime < 0)
758 {
759 M4OSA_randInit();
760 M4OSA_rand((M4OSA_Int32*)&(p_FiftiesData->shiftRandomValue), (pPlaneIn[0].u_height) >> 4);
761 M4OSA_rand((M4OSA_Int32*)&(p_FiftiesData->stripeRandomValue), (pPlaneIn[0].u_width)<< 2);
762 p_FiftiesData->previousClipTime = pProgress->uiOutputTime;
763 }
764
765 /* Choose random values if we have reached the duration of a partial effect */
766 else if( (pProgress->uiOutputTime - p_FiftiesData->previousClipTime) > p_FiftiesData->fiftiesEffectDuration)
767 {
768 M4OSA_rand((M4OSA_Int32*)&(p_FiftiesData->shiftRandomValue), (pPlaneIn[0].u_height) >> 4);
769 M4OSA_rand((M4OSA_Int32*)&(p_FiftiesData->stripeRandomValue), (pPlaneIn[0].u_width)<< 2);
770 p_FiftiesData->previousClipTime = pProgress->uiOutputTime;
771 }
772
773 /* Put in Sepia the chrominance */
774 for (plane_number = 1; plane_number < 3; plane_number++)
775 {
776 pInCr = pPlaneIn[plane_number].pac_data + pPlaneIn[plane_number].u_topleft;
777 pOutCr = pPlaneOut[plane_number].pac_data + pPlaneOut[plane_number].u_topleft;
778
779 for (x = 0; x < pPlaneOut[plane_number].u_height; x++)
780 {
781 if (1 == plane_number)
782 memset((void *)pOutCr, 117,pPlaneIn[plane_number].u_width); /* U value */
783 else
784 memset((void *)pOutCr, 139,pPlaneIn[plane_number].u_width); /* V value */
785
786 pInCr += pPlaneIn[plane_number].u_stride;
787 pOutCr += pPlaneOut[plane_number].u_stride;
788 }
789 }
790
791 /* Compute the new pixels values */
792 for( x = 0 ; x < pPlaneIn[0].u_height ; x++)
793 {
794 M4VIFI_UInt8 *p_outYtmp, *p_inYtmp;
795
796 /* Compute the xShift (random value) */
797 if (0 == (p_FiftiesData->shiftRandomValue % 5 ))
798 xShift = (x + p_FiftiesData->shiftRandomValue ) % (pPlaneIn[0].u_height - 1);
799 else
800 xShift = (x + (pPlaneIn[0].u_height - p_FiftiesData->shiftRandomValue) ) % (pPlaneIn[0].u_height - 1);
801
802 /* Initialize the pointers */
803 p_outYtmp = pOutY + 1; /* yShift of 1 pixel */
804 p_inYtmp = pInYbegin + (xShift * pPlaneIn[0].u_stride); /* Apply the xShift */
805
806 for( y = 0 ; y < pPlaneIn[0].u_width ; y++)
807 {
808 /* Set Y value */
809 if (xShift > (pPlaneIn[0].u_height - 4))
810 *p_outYtmp = 40; /* Add some horizontal black lines between the two parts of the image */
811 else if ( y == p_FiftiesData->stripeRandomValue)
812 *p_outYtmp = 90; /* Add a random vertical line for the bulk */
813 else
814 *p_outYtmp = *p_inYtmp;
815
816
817 /* Go to the next pixel */
818 p_outYtmp++;
819 p_inYtmp++;
820
821 /* Restart at the beginning of the line for the last pixel*/
822 if (y == (pPlaneIn[0].u_width - 2))
823 p_outYtmp = pOutY;
824 }
825
826 /* Go to the next line */
827 pOutY += pPlaneOut[0].u_stride;
828 }
829
830 return M4VIFI_OK;
831 }
832
M4VFL_modifyLumaWithScale(M4ViComImagePlane * plane_in,M4ViComImagePlane * plane_out,unsigned long lum_factor,void * user_data)833 unsigned char M4VFL_modifyLumaWithScale(M4ViComImagePlane *plane_in,
834 M4ViComImagePlane *plane_out,
835 unsigned long lum_factor,
836 void *user_data)
837 {
838 unsigned short *p_src, *p_dest, *p_src_line, *p_dest_line;
839 unsigned char *p_csrc, *p_cdest, *p_csrc_line, *p_cdest_line;
840 unsigned long pix_src;
841 unsigned long u_outpx, u_outpx2;
842 unsigned long u_width, u_stride, u_stride_out,u_height, pix;
843 long i, j;
844
845 /* copy or filter chroma */
846 u_width = plane_in[1].u_width;
847 u_height = plane_in[1].u_height;
848 u_stride = plane_in[1].u_stride;
849 u_stride_out = plane_out[1].u_stride;
850 p_cdest_line = (unsigned char *) &plane_out[1].pac_data[plane_out[1].u_topleft];
851 p_csrc_line = (unsigned char *) &plane_in[1].pac_data[plane_in[1].u_topleft];
852
853 if (lum_factor > 256)
854 {
855 p_cdest = (unsigned char *) &plane_out[2].pac_data[plane_out[2].u_topleft];
856 p_csrc = (unsigned char *) &plane_in[2].pac_data[plane_in[2].u_topleft];
857 /* copy chroma */
858 for (j = u_height; j != 0; j--)
859 {
860 for (i = u_width; i != 0; i--)
861 {
862 memcpy((void *)p_cdest_line, (void *)p_csrc_line, u_width);
863 memcpy((void *)p_cdest, (void *)p_csrc, u_width);
864 }
865 p_cdest_line += u_stride_out;
866 p_cdest += u_stride_out;
867 p_csrc_line += u_stride;
868 p_csrc += u_stride;
869 }
870 }
871 else
872 {
873 /* filter chroma */
874 pix = (1024 - lum_factor) << 7;
875 for (j = u_height; j != 0; j--)
876 {
877 p_cdest = p_cdest_line;
878 p_csrc = p_csrc_line;
879 for (i = u_width; i != 0; i--)
880 {
881 *p_cdest++ = ((pix + (*p_csrc++ & 0xFF) * lum_factor) >> LUM_FACTOR_MAX);
882 }
883 p_cdest_line += u_stride_out;
884 p_csrc_line += u_stride;
885 }
886 p_cdest_line = (unsigned char *) &plane_out[2].pac_data[plane_out[2].u_topleft];
887 p_csrc_line = (unsigned char *) &plane_in[2].pac_data[plane_in[2].u_topleft];
888 for (j = u_height; j != 0; j--)
889 {
890 p_cdest = p_cdest_line;
891 p_csrc = p_csrc_line;
892 for (i = u_width; i != 0; i--)
893 {
894 *p_cdest++ = ((pix + (*p_csrc & 0xFF) * lum_factor) >> LUM_FACTOR_MAX);
895 }
896 p_cdest_line += u_stride_out;
897 p_csrc_line += u_stride;
898 }
899 }
900 /* apply luma factor */
901 u_width = plane_in[0].u_width;
902 u_height = plane_in[0].u_height;
903 u_stride = (plane_in[0].u_stride >> 1);
904 u_stride_out = (plane_out[0].u_stride >> 1);
905 p_dest = (unsigned short *) &plane_out[0].pac_data[plane_out[0].u_topleft];
906 p_src = (unsigned short *) &plane_in[0].pac_data[plane_in[0].u_topleft];
907 p_dest_line = p_dest;
908 p_src_line = p_src;
909
910 for (j = u_height; j != 0; j--)
911 {
912 p_dest = p_dest_line;
913 p_src = p_src_line;
914 for (i = (u_width >> 1); i != 0; i--)
915 {
916 pix_src = (unsigned long) *p_src++;
917 pix = pix_src & 0xFF;
918 u_outpx = ((pix * lum_factor) >> LUM_FACTOR_MAX);
919 pix = ((pix_src & 0xFF00) >> 8);
920 u_outpx2 = (((pix * lum_factor) >> LUM_FACTOR_MAX)<< 8) ;
921 *p_dest++ = (unsigned short) (u_outpx2 | u_outpx);
922 }
923 p_dest_line += u_stride_out;
924 p_src_line += u_stride;
925 }
926
927 return 0;
928 }
929
930 /******************************************************************************
931 * prototype M4OSA_ERR M4xVSS_internalConvertRGBtoYUV(M4xVSS_FramingStruct* framingCtx)
932 * @brief This function converts an RGB565 plane to YUV420 planar
933 * @note It is used only for framing effect
934 * It allocates output YUV planes
935 * @param framingCtx (IN) The framing struct containing input RGB565 plane
936 *
937 * @return M4NO_ERROR: No error
938 * @return M4ERR_PARAMETER: At least one of the function parameters is null
939 * @return M4ERR_ALLOC: Allocation error (no more memory)
940 ******************************************************************************
941 */
M4xVSS_internalConvertRGBtoYUV(M4xVSS_FramingStruct * framingCtx)942 M4OSA_ERR M4xVSS_internalConvertRGBtoYUV(M4xVSS_FramingStruct* framingCtx)
943 {
944 M4OSA_ERR err;
945
946 /**
947 * Allocate output YUV planes */
948 framingCtx->FramingYuv = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"M4xVSS_internalConvertRGBtoYUV: Output plane YUV");
949 if(framingCtx->FramingYuv == M4OSA_NULL)
950 {
951 M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertRGBtoYUV");
952 return M4ERR_ALLOC;
953 }
954 framingCtx->FramingYuv[0].u_width = framingCtx->FramingRgb->u_width;
955 framingCtx->FramingYuv[0].u_height = framingCtx->FramingRgb->u_height;
956 framingCtx->FramingYuv[0].u_topleft = 0;
957 framingCtx->FramingYuv[0].u_stride = framingCtx->FramingRgb->u_width;
958 framingCtx->FramingYuv[0].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc((framingCtx->FramingYuv[0].u_width*framingCtx->FramingYuv[0].u_height*3)>>1, M4VS, (M4OSA_Char*)"Alloc for the Convertion output YUV");;
959 if(framingCtx->FramingYuv[0].pac_data == M4OSA_NULL)
960 {
961 M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertRGBtoYUV");
962 return M4ERR_ALLOC;
963 }
964 framingCtx->FramingYuv[1].u_width = (framingCtx->FramingRgb->u_width)>>1;
965 framingCtx->FramingYuv[1].u_height = (framingCtx->FramingRgb->u_height)>>1;
966 framingCtx->FramingYuv[1].u_topleft = 0;
967 framingCtx->FramingYuv[1].u_stride = (framingCtx->FramingRgb->u_width)>>1;
968 framingCtx->FramingYuv[1].pac_data = framingCtx->FramingYuv[0].pac_data + framingCtx->FramingYuv[0].u_width * framingCtx->FramingYuv[0].u_height;
969 framingCtx->FramingYuv[2].u_width = (framingCtx->FramingRgb->u_width)>>1;
970 framingCtx->FramingYuv[2].u_height = (framingCtx->FramingRgb->u_height)>>1;
971 framingCtx->FramingYuv[2].u_topleft = 0;
972 framingCtx->FramingYuv[2].u_stride = (framingCtx->FramingRgb->u_width)>>1;
973 framingCtx->FramingYuv[2].pac_data = framingCtx->FramingYuv[1].pac_data + framingCtx->FramingYuv[1].u_width * framingCtx->FramingYuv[1].u_height;
974
975 /**
976 * Convert input RGB 565 to YUV 420 to be able to merge it with output video in framing effect */
977 err = M4VIFI_xVSS_RGB565toYUV420(M4OSA_NULL, framingCtx->FramingRgb, framingCtx->FramingYuv);
978 if(err != M4NO_ERROR)
979 {
980 M4OSA_TRACE1_1("M4xVSS_internalConvertRGBtoYUV: error when converting from RGB to YUV: 0x%x\n", err);
981 }
982
983 framingCtx->duration = 0;
984 framingCtx->previousClipTime = -1;
985 framingCtx->previewOffsetClipTime = -1;
986
987 /**
988 * Only one element in the chained list (no animated image with RGB buffer...) */
989 framingCtx->pCurrent = framingCtx;
990 framingCtx->pNext = framingCtx;
991
992 return M4NO_ERROR;
993 }
994
995 /******************************************************************************
996 * prototype M4OSA_ERR M4xVSS_internalConvertRGB888toYUV(M4xVSS_FramingStruct* framingCtx)
997 * @brief This function converts an RGB888 plane to YUV420 planar
998 * @note It is used only for framing effect
999 * It allocates output YUV planes
1000 * @param framingCtx (IN) The framing struct containing input RGB888 plane
1001 *
1002 * @return M4NO_ERROR: No error
1003 * @return M4ERR_PARAMETER: At least one of the function parameters is null
1004 * @return M4ERR_ALLOC: Allocation error (no more memory)
1005 ******************************************************************************
1006 */
M4xVSS_internalConvertRGB888toYUV(M4xVSS_FramingStruct * framingCtx)1007 M4OSA_ERR M4xVSS_internalConvertRGB888toYUV(M4xVSS_FramingStruct* framingCtx)
1008 {
1009 M4OSA_ERR err;
1010
1011 /**
1012 * Allocate output YUV planes */
1013 framingCtx->FramingYuv = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"M4xVSS_internalConvertRGBtoYUV: Output plane YUV");
1014 if(framingCtx->FramingYuv == M4OSA_NULL)
1015 {
1016 M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertRGBtoYUV");
1017 return M4ERR_ALLOC;
1018 }
1019 framingCtx->FramingYuv[0].u_width = framingCtx->FramingRgb->u_width;
1020 framingCtx->FramingYuv[0].u_height = framingCtx->FramingRgb->u_height;
1021 framingCtx->FramingYuv[0].u_topleft = 0;
1022 framingCtx->FramingYuv[0].u_stride = framingCtx->FramingRgb->u_width;
1023 framingCtx->FramingYuv[0].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc((framingCtx->FramingYuv[0].u_width*framingCtx->FramingYuv[0].u_height*3)>>1, M4VS, (M4OSA_Char*)"Alloc for the Convertion output YUV");;
1024 if(framingCtx->FramingYuv[0].pac_data == M4OSA_NULL)
1025 {
1026 M4OSA_TRACE1_0("Allocation error in M4xVSS_internalConvertRGBtoYUV");
1027 return M4ERR_ALLOC;
1028 }
1029 framingCtx->FramingYuv[1].u_width = (framingCtx->FramingRgb->u_width)>>1;
1030 framingCtx->FramingYuv[1].u_height = (framingCtx->FramingRgb->u_height)>>1;
1031 framingCtx->FramingYuv[1].u_topleft = 0;
1032 framingCtx->FramingYuv[1].u_stride = (framingCtx->FramingRgb->u_width)>>1;
1033 framingCtx->FramingYuv[1].pac_data = framingCtx->FramingYuv[0].pac_data + framingCtx->FramingYuv[0].u_width * framingCtx->FramingYuv[0].u_height;
1034 framingCtx->FramingYuv[2].u_width = (framingCtx->FramingRgb->u_width)>>1;
1035 framingCtx->FramingYuv[2].u_height = (framingCtx->FramingRgb->u_height)>>1;
1036 framingCtx->FramingYuv[2].u_topleft = 0;
1037 framingCtx->FramingYuv[2].u_stride = (framingCtx->FramingRgb->u_width)>>1;
1038 framingCtx->FramingYuv[2].pac_data = framingCtx->FramingYuv[1].pac_data + framingCtx->FramingYuv[1].u_width * framingCtx->FramingYuv[1].u_height;
1039
1040 /**
1041 * Convert input RGB888 to YUV 420 to be able to merge it with output video in framing effect */
1042 err = M4VIFI_RGB888toYUV420(M4OSA_NULL, framingCtx->FramingRgb, framingCtx->FramingYuv);
1043 if(err != M4NO_ERROR)
1044 {
1045 M4OSA_TRACE1_1("M4xVSS_internalConvertRGBtoYUV: error when converting from RGB to YUV: 0x%x\n", err);
1046 }
1047
1048 framingCtx->duration = 0;
1049 framingCtx->previousClipTime = -1;
1050 framingCtx->previewOffsetClipTime = -1;
1051
1052 /**
1053 * Only one element in the chained list (no animated image with RGB buffer...) */
1054 framingCtx->pCurrent = framingCtx;
1055 framingCtx->pNext = framingCtx;
1056
1057 return M4NO_ERROR;
1058 }
1059
1060 /**
1061 ******************************************************************************
1062 * M4VIFI_UInt8 M4VIFI_RGB565toYUV420 (void *pUserData,
1063 * M4VIFI_ImagePlane *pPlaneIn,
1064 * M4VIFI_ImagePlane *pPlaneOut)
1065 * @author Patrice Martinez / Philips Digital Networks - MP4Net
1066 * @brief transform RGB565 image to a YUV420 image.
1067 * @note Convert RGB565 to YUV420,
1068 * Loop on each row ( 2 rows by 2 rows )
1069 * Loop on each column ( 2 col by 2 col )
1070 * Get 4 RGB samples from input data and build 4 output Y samples
1071 * and each single U & V data
1072 * end loop on col
1073 * end loop on row
1074 * @param pUserData: (IN) User Specific Data
1075 * @param pPlaneIn: (IN) Pointer to RGB565 Plane
1076 * @param pPlaneOut: (OUT) Pointer to YUV420 buffer Plane
1077 * @return M4VIFI_OK: there is no error
1078 * @return M4VIFI_ILLEGAL_FRAME_HEIGHT: YUV Plane height is ODD
1079 * @return M4VIFI_ILLEGAL_FRAME_WIDTH: YUV Plane width is ODD
1080 ******************************************************************************
1081 */
M4VIFI_xVSS_RGB565toYUV420(void * pUserData,M4VIFI_ImagePlane * pPlaneIn,M4VIFI_ImagePlane * pPlaneOut)1082 M4VIFI_UInt8 M4VIFI_xVSS_RGB565toYUV420(void *pUserData, M4VIFI_ImagePlane *pPlaneIn,
1083 M4VIFI_ImagePlane *pPlaneOut)
1084 {
1085 M4VIFI_UInt32 u32_width, u32_height;
1086 M4VIFI_UInt32 u32_stride_Y, u32_stride2_Y, u32_stride_U, u32_stride_V;
1087 M4VIFI_UInt32 u32_stride_rgb, u32_stride_2rgb;
1088 M4VIFI_UInt32 u32_col, u32_row;
1089
1090 M4VIFI_Int32 i32_r00, i32_r01, i32_r10, i32_r11;
1091 M4VIFI_Int32 i32_g00, i32_g01, i32_g10, i32_g11;
1092 M4VIFI_Int32 i32_b00, i32_b01, i32_b10, i32_b11;
1093 M4VIFI_Int32 i32_y00, i32_y01, i32_y10, i32_y11;
1094 M4VIFI_Int32 i32_u00, i32_u01, i32_u10, i32_u11;
1095 M4VIFI_Int32 i32_v00, i32_v01, i32_v10, i32_v11;
1096 M4VIFI_UInt8 *pu8_yn, *pu8_ys, *pu8_u, *pu8_v;
1097 M4VIFI_UInt8 *pu8_y_data, *pu8_u_data, *pu8_v_data;
1098 M4VIFI_UInt8 *pu8_rgbn_data, *pu8_rgbn;
1099 M4VIFI_UInt16 u16_pix1, u16_pix2, u16_pix3, u16_pix4;
1100 M4VIFI_UInt8 count_null=0;
1101
1102 /* Check planes height are appropriate */
1103 if( (pPlaneIn->u_height != pPlaneOut[0].u_height) ||
1104 (pPlaneOut[0].u_height != (pPlaneOut[1].u_height<<1)) ||
1105 (pPlaneOut[0].u_height != (pPlaneOut[2].u_height<<1)))
1106 {
1107 return M4VIFI_ILLEGAL_FRAME_HEIGHT;
1108 }
1109
1110 /* Check planes width are appropriate */
1111 if( (pPlaneIn->u_width != pPlaneOut[0].u_width) ||
1112 (pPlaneOut[0].u_width != (pPlaneOut[1].u_width<<1)) ||
1113 (pPlaneOut[0].u_width != (pPlaneOut[2].u_width<<1)))
1114 {
1115 return M4VIFI_ILLEGAL_FRAME_WIDTH;
1116 }
1117
1118 /* Set the pointer to the beginning of the output data buffers */
1119 pu8_y_data = pPlaneOut[0].pac_data + pPlaneOut[0].u_topleft;
1120 pu8_u_data = pPlaneOut[1].pac_data + pPlaneOut[1].u_topleft;
1121 pu8_v_data = pPlaneOut[2].pac_data + pPlaneOut[2].u_topleft;
1122
1123 /* Set the pointer to the beginning of the input data buffers */
1124 pu8_rgbn_data = pPlaneIn->pac_data + pPlaneIn->u_topleft;
1125
1126 /* Get the size of the output image */
1127 u32_width = pPlaneOut[0].u_width;
1128 u32_height = pPlaneOut[0].u_height;
1129
1130 /* Set the size of the memory jumps corresponding to row jump in each output plane */
1131 u32_stride_Y = pPlaneOut[0].u_stride;
1132 u32_stride2_Y = u32_stride_Y << 1;
1133 u32_stride_U = pPlaneOut[1].u_stride;
1134 u32_stride_V = pPlaneOut[2].u_stride;
1135
1136 /* Set the size of the memory jumps corresponding to row jump in input plane */
1137 u32_stride_rgb = pPlaneIn->u_stride;
1138 u32_stride_2rgb = u32_stride_rgb << 1;
1139
1140
1141 /* Loop on each row of the output image, input coordinates are estimated from output ones */
1142 /* Two YUV rows are computed at each pass */
1143 for (u32_row = u32_height ;u32_row != 0; u32_row -=2)
1144 {
1145 /* Current Y plane row pointers */
1146 pu8_yn = pu8_y_data;
1147 /* Next Y plane row pointers */
1148 pu8_ys = pu8_yn + u32_stride_Y;
1149 /* Current U plane row pointer */
1150 pu8_u = pu8_u_data;
1151 /* Current V plane row pointer */
1152 pu8_v = pu8_v_data;
1153
1154 pu8_rgbn = pu8_rgbn_data;
1155
1156 /* Loop on each column of the output image */
1157 for (u32_col = u32_width; u32_col != 0 ; u32_col -=2)
1158 {
1159 /* Get four RGB 565 samples from input data */
1160 u16_pix1 = *( (M4VIFI_UInt16 *) pu8_rgbn);
1161 u16_pix2 = *( (M4VIFI_UInt16 *) (pu8_rgbn + CST_RGB_16_SIZE));
1162 u16_pix3 = *( (M4VIFI_UInt16 *) (pu8_rgbn + u32_stride_rgb));
1163 u16_pix4 = *( (M4VIFI_UInt16 *) (pu8_rgbn + u32_stride_rgb + CST_RGB_16_SIZE));
1164
1165 /* Unpack RGB565 to 8bit R, G, B */
1166 /* (x,y) */
1167 GET_RGB565(i32_b00,i32_g00,i32_r00,u16_pix1);
1168 /* (x+1,y) */
1169 GET_RGB565(i32_b10,i32_g10,i32_r10,u16_pix2);
1170 /* (x,y+1) */
1171 GET_RGB565(i32_b01,i32_g01,i32_r01,u16_pix3);
1172 /* (x+1,y+1) */
1173 GET_RGB565(i32_b11,i32_g11,i32_r11,u16_pix4);
1174 /* If RGB is transparent color (0, 63, 0), we transform it to white (31,63,31) */
1175 if(i32_b00 == 0 && i32_g00 == 63 && i32_r00 == 0)
1176 {
1177 i32_b00 = 31;
1178 i32_r00 = 31;
1179 }
1180 if(i32_b10 == 0 && i32_g10 == 63 && i32_r10 == 0)
1181 {
1182 i32_b10 = 31;
1183 i32_r10 = 31;
1184 }
1185 if(i32_b01 == 0 && i32_g01 == 63 && i32_r01 == 0)
1186 {
1187 i32_b01 = 31;
1188 i32_r01 = 31;
1189 }
1190 if(i32_b11 == 0 && i32_g11 == 63 && i32_r11 == 0)
1191 {
1192 i32_b11 = 31;
1193 i32_r11 = 31;
1194 }
1195 /* Convert RGB value to YUV */
1196 i32_u00 = U16(i32_r00, i32_g00, i32_b00);
1197 i32_v00 = V16(i32_r00, i32_g00, i32_b00);
1198 /* luminance value */
1199 i32_y00 = Y16(i32_r00, i32_g00, i32_b00);
1200
1201 i32_u10 = U16(i32_r10, i32_g10, i32_b10);
1202 i32_v10 = V16(i32_r10, i32_g10, i32_b10);
1203 /* luminance value */
1204 i32_y10 = Y16(i32_r10, i32_g10, i32_b10);
1205
1206 i32_u01 = U16(i32_r01, i32_g01, i32_b01);
1207 i32_v01 = V16(i32_r01, i32_g01, i32_b01);
1208 /* luminance value */
1209 i32_y01 = Y16(i32_r01, i32_g01, i32_b01);
1210
1211 i32_u11 = U16(i32_r11, i32_g11, i32_b11);
1212 i32_v11 = V16(i32_r11, i32_g11, i32_b11);
1213 /* luminance value */
1214 i32_y11 = Y16(i32_r11, i32_g11, i32_b11);
1215
1216 /* Store luminance data */
1217 pu8_yn[0] = (M4VIFI_UInt8)i32_y00;
1218 pu8_yn[1] = (M4VIFI_UInt8)i32_y10;
1219 pu8_ys[0] = (M4VIFI_UInt8)i32_y01;
1220 pu8_ys[1] = (M4VIFI_UInt8)i32_y11;
1221 *pu8_u = (M4VIFI_UInt8)((i32_u00 + i32_u01 + i32_u10 + i32_u11 + 2) >> 2);
1222 *pu8_v = (M4VIFI_UInt8)((i32_v00 + i32_v01 + i32_v10 + i32_v11 + 2) >> 2);
1223 /* Prepare for next column */
1224 pu8_rgbn += (CST_RGB_16_SIZE<<1);
1225 /* Update current Y plane line pointer*/
1226 pu8_yn += 2;
1227 /* Update next Y plane line pointer*/
1228 pu8_ys += 2;
1229 /* Update U plane line pointer*/
1230 pu8_u ++;
1231 /* Update V plane line pointer*/
1232 pu8_v ++;
1233 } /* End of horizontal scanning */
1234
1235 /* Prepare pointers for the next row */
1236 pu8_y_data += u32_stride2_Y;
1237 pu8_u_data += u32_stride_U;
1238 pu8_v_data += u32_stride_V;
1239 pu8_rgbn_data += u32_stride_2rgb;
1240
1241
1242 } /* End of vertical scanning */
1243
1244 return M4VIFI_OK;
1245 }
1246
1247 /***************************************************************************
1248 Proto:
1249 M4VIFI_UInt8 M4VIFI_RGB888toYUV420(void *pUserData, M4VIFI_ImagePlane *PlaneIn, M4VIFI_ImagePlane PlaneOut[3]);
1250 Author: Patrice Martinez / Philips Digital Networks - MP4Net
1251 Purpose: filling of the YUV420 plane from a BGR24 plane
1252 Abstract: Loop on each row ( 2 rows by 2 rows )
1253 Loop on each column ( 2 col by 2 col )
1254 Get 4 BGR samples from input data and build 4 output Y samples and each single U & V data
1255 end loop on col
1256 end loop on row
1257
1258 In: RGB24 plane
1259 InOut: none
1260 Out: array of 3 M4VIFI_ImagePlane structures
1261 Modified: ML: RGB function modified to BGR.
1262 ***************************************************************************/
M4VIFI_RGB888toYUV420(void * pUserData,M4VIFI_ImagePlane * PlaneIn,M4VIFI_ImagePlane PlaneOut[3])1263 M4VIFI_UInt8 M4VIFI_RGB888toYUV420(void *pUserData, M4VIFI_ImagePlane *PlaneIn, M4VIFI_ImagePlane PlaneOut[3])
1264 {
1265
1266 M4VIFI_UInt32 u32_width, u32_height;
1267 M4VIFI_UInt32 u32_stride_Y, u32_stride2_Y, u32_stride_U, u32_stride_V, u32_stride_rgb, u32_stride_2rgb;
1268 M4VIFI_UInt32 u32_col, u32_row;
1269
1270 M4VIFI_Int32 i32_r00, i32_r01, i32_r10, i32_r11;
1271 M4VIFI_Int32 i32_g00, i32_g01, i32_g10, i32_g11;
1272 M4VIFI_Int32 i32_b00, i32_b01, i32_b10, i32_b11;
1273 M4VIFI_Int32 i32_y00, i32_y01, i32_y10, i32_y11;
1274 M4VIFI_Int32 i32_u00, i32_u01, i32_u10, i32_u11;
1275 M4VIFI_Int32 i32_v00, i32_v01, i32_v10, i32_v11;
1276 M4VIFI_UInt8 *pu8_yn, *pu8_ys, *pu8_u, *pu8_v;
1277 M4VIFI_UInt8 *pu8_y_data, *pu8_u_data, *pu8_v_data;
1278 M4VIFI_UInt8 *pu8_rgbn_data, *pu8_rgbn;
1279
1280 /* check sizes */
1281 if( (PlaneIn->u_height != PlaneOut[0].u_height) ||
1282 (PlaneOut[0].u_height != (PlaneOut[1].u_height<<1)) ||
1283 (PlaneOut[0].u_height != (PlaneOut[2].u_height<<1)))
1284 return M4VIFI_ILLEGAL_FRAME_HEIGHT;
1285
1286 if( (PlaneIn->u_width != PlaneOut[0].u_width) ||
1287 (PlaneOut[0].u_width != (PlaneOut[1].u_width<<1)) ||
1288 (PlaneOut[0].u_width != (PlaneOut[2].u_width<<1)))
1289 return M4VIFI_ILLEGAL_FRAME_WIDTH;
1290
1291
1292 /* set the pointer to the beginning of the output data buffers */
1293 pu8_y_data = PlaneOut[0].pac_data + PlaneOut[0].u_topleft;
1294 pu8_u_data = PlaneOut[1].pac_data + PlaneOut[1].u_topleft;
1295 pu8_v_data = PlaneOut[2].pac_data + PlaneOut[2].u_topleft;
1296
1297 /* idem for input buffer */
1298 pu8_rgbn_data = PlaneIn->pac_data + PlaneIn->u_topleft;
1299
1300 /* get the size of the output image */
1301 u32_width = PlaneOut[0].u_width;
1302 u32_height = PlaneOut[0].u_height;
1303
1304 /* set the size of the memory jumps corresponding to row jump in each output plane */
1305 u32_stride_Y = PlaneOut[0].u_stride;
1306 u32_stride2_Y= u32_stride_Y << 1;
1307 u32_stride_U = PlaneOut[1].u_stride;
1308 u32_stride_V = PlaneOut[2].u_stride;
1309
1310 /* idem for input plane */
1311 u32_stride_rgb = PlaneIn->u_stride;
1312 u32_stride_2rgb = u32_stride_rgb << 1;
1313
1314 /* loop on each row of the output image, input coordinates are estimated from output ones */
1315 /* two YUV rows are computed at each pass */
1316 for (u32_row = u32_height ;u32_row != 0; u32_row -=2)
1317 {
1318 /* update working pointers */
1319 pu8_yn = pu8_y_data;
1320 pu8_ys = pu8_yn + u32_stride_Y;
1321
1322 pu8_u = pu8_u_data;
1323 pu8_v = pu8_v_data;
1324
1325 pu8_rgbn= pu8_rgbn_data;
1326
1327 /* loop on each column of the output image*/
1328 for (u32_col = u32_width; u32_col != 0 ; u32_col -=2)
1329 {
1330 /* get RGB samples of 4 pixels */
1331 GET_RGB24(i32_r00, i32_g00, i32_b00, pu8_rgbn, 0);
1332 GET_RGB24(i32_r10, i32_g10, i32_b10, pu8_rgbn, CST_RGB_24_SIZE);
1333 GET_RGB24(i32_r01, i32_g01, i32_b01, pu8_rgbn, u32_stride_rgb);
1334 GET_RGB24(i32_r11, i32_g11, i32_b11, pu8_rgbn, u32_stride_rgb + CST_RGB_24_SIZE);
1335
1336 i32_u00 = U24(i32_r00, i32_g00, i32_b00);
1337 i32_v00 = V24(i32_r00, i32_g00, i32_b00);
1338 i32_y00 = Y24(i32_r00, i32_g00, i32_b00); /* matrix luminance */
1339 pu8_yn[0]= (M4VIFI_UInt8)i32_y00;
1340
1341 i32_u10 = U24(i32_r10, i32_g10, i32_b10);
1342 i32_v10 = V24(i32_r10, i32_g10, i32_b10);
1343 i32_y10 = Y24(i32_r10, i32_g10, i32_b10);
1344 pu8_yn[1]= (M4VIFI_UInt8)i32_y10;
1345
1346 i32_u01 = U24(i32_r01, i32_g01, i32_b01);
1347 i32_v01 = V24(i32_r01, i32_g01, i32_b01);
1348 i32_y01 = Y24(i32_r01, i32_g01, i32_b01);
1349 pu8_ys[0]= (M4VIFI_UInt8)i32_y01;
1350
1351 i32_u11 = U24(i32_r11, i32_g11, i32_b11);
1352 i32_v11 = V24(i32_r11, i32_g11, i32_b11);
1353 i32_y11 = Y24(i32_r11, i32_g11, i32_b11);
1354 pu8_ys[1] = (M4VIFI_UInt8)i32_y11;
1355
1356 *pu8_u = (M4VIFI_UInt8)((i32_u00 + i32_u01 + i32_u10 + i32_u11 + 2) >> 2);
1357 *pu8_v = (M4VIFI_UInt8)((i32_v00 + i32_v01 + i32_v10 + i32_v11 + 2) >> 2);
1358
1359 pu8_rgbn += (CST_RGB_24_SIZE<<1);
1360 pu8_yn += 2;
1361 pu8_ys += 2;
1362
1363 pu8_u ++;
1364 pu8_v ++;
1365 } /* end of horizontal scanning */
1366
1367 pu8_y_data += u32_stride2_Y;
1368 pu8_u_data += u32_stride_U;
1369 pu8_v_data += u32_stride_V;
1370 pu8_rgbn_data += u32_stride_2rgb;
1371
1372
1373 } /* End of vertical scanning */
1374
1375 return M4VIFI_OK;
1376 }
1377
1378 /** YUV420 to YUV420 */
1379 /**
1380 *******************************************************************************************
1381 * M4VIFI_UInt8 M4VIFI_YUV420toYUV420 (void *pUserData,
1382 * M4VIFI_ImagePlane *pPlaneIn,
1383 * M4VIFI_ImagePlane *pPlaneOut)
1384 * @brief Transform YUV420 image to a YUV420 image.
1385 * @param pUserData: (IN) User Specific Data (Unused - could be NULL)
1386 * @param pPlaneIn: (IN) Pointer to YUV plane buffer
1387 * @param pPlaneOut: (OUT) Pointer to YUV Plane
1388 * @return M4VIFI_OK: there is no error
1389 * @return M4VIFI_ILLEGAL_FRAME_HEIGHT: Error in plane height
1390 * @return M4VIFI_ILLEGAL_FRAME_WIDTH: Error in plane width
1391 *******************************************************************************************
1392 */
1393
M4VIFI_YUV420toYUV420(void * user_data,M4VIFI_ImagePlane PlaneIn[3],M4VIFI_ImagePlane * PlaneOut)1394 M4VIFI_UInt8 M4VIFI_YUV420toYUV420(void *user_data, M4VIFI_ImagePlane PlaneIn[3], M4VIFI_ImagePlane *PlaneOut )
1395 {
1396 M4VIFI_Int32 plane_number;
1397 M4VIFI_UInt32 i;
1398 M4VIFI_UInt8 *p_buf_src, *p_buf_dest;
1399
1400 for (plane_number = 0; plane_number < 3; plane_number++)
1401 {
1402 p_buf_src = &(PlaneIn[plane_number].pac_data[PlaneIn[plane_number].u_topleft]);
1403 p_buf_dest = &(PlaneOut[plane_number].pac_data[PlaneOut[plane_number].u_topleft]);
1404 for (i = 0; i < PlaneOut[plane_number].u_height; i++)
1405 {
1406 memcpy((void *)p_buf_dest, (void *)p_buf_src ,PlaneOut[plane_number].u_width);
1407 p_buf_src += PlaneIn[plane_number].u_stride;
1408 p_buf_dest += PlaneOut[plane_number].u_stride;
1409 }
1410 }
1411 return M4VIFI_OK;
1412 }
1413
1414 /**
1415 ***********************************************************************************************
1416 * M4VIFI_UInt8 M4VIFI_ResizeBilinearYUV420toYUV420(void *pUserData, M4VIFI_ImagePlane *pPlaneIn,
1417 * M4VIFI_ImagePlane *pPlaneOut)
1418 * @author David Dana (PHILIPS Software)
1419 * @brief Resizes YUV420 Planar plane.
1420 * @note Basic structure of the function
1421 * Loop on each row (step 2)
1422 * Loop on each column (step 2)
1423 * Get four Y samples and 1 U & V sample
1424 * Resize the Y with corresponing U and V samples
1425 * Place the YUV in the ouput plane
1426 * end loop column
1427 * end loop row
1428 * For resizing bilinear interpolation linearly interpolates along
1429 * each row, and then uses that result in a linear interpolation down each column.
1430 * Each estimated pixel in the output image is a weighted
1431 * combination of its four neighbours. The ratio of compression
1432 * or dilatation is estimated using input and output sizes.
1433 * @param pUserData: (IN) User Data
1434 * @param pPlaneIn: (IN) Pointer to YUV420 (Planar) plane buffer
1435 * @param pPlaneOut: (OUT) Pointer to YUV420 (Planar) plane
1436 * @return M4VIFI_OK: there is no error
1437 * @return M4VIFI_ILLEGAL_FRAME_HEIGHT: Error in height
1438 * @return M4VIFI_ILLEGAL_FRAME_WIDTH: Error in width
1439 ***********************************************************************************************
1440 */
M4VIFI_ResizeBilinearYUV420toYUV420(void * pUserData,M4VIFI_ImagePlane * pPlaneIn,M4VIFI_ImagePlane * pPlaneOut)1441 M4VIFI_UInt8 M4VIFI_ResizeBilinearYUV420toYUV420(void *pUserData,
1442 M4VIFI_ImagePlane *pPlaneIn,
1443 M4VIFI_ImagePlane *pPlaneOut)
1444 {
1445 M4VIFI_UInt8 *pu8_data_in, *pu8_data_out, *pu8dum;
1446 M4VIFI_UInt32 u32_plane;
1447 M4VIFI_UInt32 u32_width_in, u32_width_out, u32_height_in, u32_height_out;
1448 M4VIFI_UInt32 u32_stride_in, u32_stride_out;
1449 M4VIFI_UInt32 u32_x_inc, u32_y_inc;
1450 M4VIFI_UInt32 u32_x_accum, u32_y_accum, u32_x_accum_start;
1451 M4VIFI_UInt32 u32_width, u32_height;
1452 M4VIFI_UInt32 u32_y_frac;
1453 M4VIFI_UInt32 u32_x_frac;
1454 M4VIFI_UInt32 u32_temp_value;
1455 M4VIFI_UInt8 *pu8_src_top;
1456 M4VIFI_UInt8 *pu8_src_bottom;
1457
1458 M4VIFI_UInt8 u8Wflag = 0;
1459 M4VIFI_UInt8 u8Hflag = 0;
1460 M4VIFI_UInt32 loop = 0;
1461
1462
1463 /*
1464 If input width is equal to output width and input height equal to
1465 output height then M4VIFI_YUV420toYUV420 is called.
1466 */
1467 if ((pPlaneIn[0].u_height == pPlaneOut[0].u_height) &&
1468 (pPlaneIn[0].u_width == pPlaneOut[0].u_width))
1469 {
1470 return M4VIFI_YUV420toYUV420(pUserData, pPlaneIn, pPlaneOut);
1471 }
1472
1473 /* Check for the YUV width and height are even */
1474 if ((IS_EVEN(pPlaneIn[0].u_height) == FALSE) ||
1475 (IS_EVEN(pPlaneOut[0].u_height) == FALSE))
1476 {
1477 return M4VIFI_ILLEGAL_FRAME_HEIGHT;
1478 }
1479
1480 if ((IS_EVEN(pPlaneIn[0].u_width) == FALSE) ||
1481 (IS_EVEN(pPlaneOut[0].u_width) == FALSE))
1482 {
1483 return M4VIFI_ILLEGAL_FRAME_WIDTH;
1484 }
1485
1486 /* Loop on planes */
1487 for(u32_plane = 0;u32_plane < PLANES;u32_plane++)
1488 {
1489 /* Set the working pointers at the beginning of the input/output data field */
1490 pu8_data_in = pPlaneIn[u32_plane].pac_data + pPlaneIn[u32_plane].u_topleft;
1491 pu8_data_out = pPlaneOut[u32_plane].pac_data + pPlaneOut[u32_plane].u_topleft;
1492
1493 /* Get the memory jump corresponding to a row jump */
1494 u32_stride_in = pPlaneIn[u32_plane].u_stride;
1495 u32_stride_out = pPlaneOut[u32_plane].u_stride;
1496
1497 /* Set the bounds of the active image */
1498 u32_width_in = pPlaneIn[u32_plane].u_width;
1499 u32_height_in = pPlaneIn[u32_plane].u_height;
1500
1501 u32_width_out = pPlaneOut[u32_plane].u_width;
1502 u32_height_out = pPlaneOut[u32_plane].u_height;
1503
1504 /*
1505 For the case , width_out = width_in , set the flag to avoid
1506 accessing one column beyond the input width.In this case the last
1507 column is replicated for processing
1508 */
1509 if (u32_width_out == u32_width_in) {
1510 u32_width_out = u32_width_out-1;
1511 u8Wflag = 1;
1512 }
1513
1514 /* Compute horizontal ratio between src and destination width.*/
1515 if (u32_width_out >= u32_width_in)
1516 {
1517 u32_x_inc = ((u32_width_in-1) * MAX_SHORT) / (u32_width_out-1);
1518 }
1519 else
1520 {
1521 u32_x_inc = (u32_width_in * MAX_SHORT) / (u32_width_out);
1522 }
1523
1524 /*
1525 For the case , height_out = height_in , set the flag to avoid
1526 accessing one row beyond the input height.In this case the last
1527 row is replicated for processing
1528 */
1529 if (u32_height_out == u32_height_in) {
1530 u32_height_out = u32_height_out-1;
1531 u8Hflag = 1;
1532 }
1533
1534 /* Compute vertical ratio between src and destination height.*/
1535 if (u32_height_out >= u32_height_in)
1536 {
1537 u32_y_inc = ((u32_height_in - 1) * MAX_SHORT) / (u32_height_out-1);
1538 }
1539 else
1540 {
1541 u32_y_inc = (u32_height_in * MAX_SHORT) / (u32_height_out);
1542 }
1543
1544 /*
1545 Calculate initial accumulator value : u32_y_accum_start.
1546 u32_y_accum_start is coded on 15 bits, and represents a value
1547 between 0 and 0.5
1548 */
1549 if (u32_y_inc >= MAX_SHORT)
1550 {
1551 /*
1552 Keep the fractionnal part, assimung that integer part is coded
1553 on the 16 high bits and the fractional on the 15 low bits
1554 */
1555 u32_y_accum = u32_y_inc & 0xffff;
1556
1557 if (!u32_y_accum)
1558 {
1559 u32_y_accum = MAX_SHORT;
1560 }
1561
1562 u32_y_accum >>= 1;
1563 }
1564 else
1565 {
1566 u32_y_accum = 0;
1567 }
1568
1569
1570 /*
1571 Calculate initial accumulator value : u32_x_accum_start.
1572 u32_x_accum_start is coded on 15 bits, and represents a value
1573 between 0 and 0.5
1574 */
1575 if (u32_x_inc >= MAX_SHORT)
1576 {
1577 u32_x_accum_start = u32_x_inc & 0xffff;
1578
1579 if (!u32_x_accum_start)
1580 {
1581 u32_x_accum_start = MAX_SHORT;
1582 }
1583
1584 u32_x_accum_start >>= 1;
1585 }
1586 else
1587 {
1588 u32_x_accum_start = 0;
1589 }
1590
1591 u32_height = u32_height_out;
1592
1593 /*
1594 Bilinear interpolation linearly interpolates along each row, and
1595 then uses that result in a linear interpolation donw each column.
1596 Each estimated pixel in the output image is a weighted combination
1597 of its four neighbours according to the formula:
1598 F(p',q')=f(p,q)R(-a)R(b)+f(p,q-1)R(-a)R(b-1)+f(p+1,q)R(1-a)R(b)+
1599 f(p+&,q+1)R(1-a)R(b-1) with R(x) = / x+1 -1 =< x =< 0 \ 1-x
1600 0 =< x =< 1 and a (resp. b)weighting coefficient is the distance
1601 from the nearest neighbor in the p (resp. q) direction
1602 */
1603
1604 do { /* Scan all the row */
1605
1606 /* Vertical weight factor */
1607 u32_y_frac = (u32_y_accum>>12)&15;
1608
1609 /* Reinit accumulator */
1610 u32_x_accum = u32_x_accum_start;
1611
1612 u32_width = u32_width_out;
1613
1614 do { /* Scan along each row */
1615 pu8_src_top = pu8_data_in + (u32_x_accum >> 16);
1616 pu8_src_bottom = pu8_src_top + u32_stride_in;
1617 u32_x_frac = (u32_x_accum >> 12)&15; /* Horizontal weight factor */
1618
1619 /* Weighted combination */
1620 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) +
1621 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) +
1622 (pu8_src_bottom[0]*(16-u32_x_frac) +
1623 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8);
1624
1625 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
1626
1627 /* Update horizontal accumulator */
1628 u32_x_accum += u32_x_inc;
1629 } while(--u32_width);
1630
1631 /*
1632 This u8Wflag flag gets in to effect if input and output
1633 width is same, and height may be different. So previous
1634 pixel is replicated here
1635 */
1636 if (u8Wflag) {
1637 *pu8_data_out = (M4VIFI_UInt8)u32_temp_value;
1638 }
1639
1640 pu8dum = (pu8_data_out-u32_width_out);
1641 pu8_data_out = pu8_data_out + u32_stride_out - u32_width_out;
1642
1643 /* Update vertical accumulator */
1644 u32_y_accum += u32_y_inc;
1645 if (u32_y_accum>>16) {
1646 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * u32_stride_in;
1647 u32_y_accum &= 0xffff;
1648 }
1649 } while(--u32_height);
1650
1651 /*
1652 This u8Hflag flag gets in to effect if input and output height
1653 is same, and width may be different. So previous pixel row is
1654 replicated here
1655 */
1656 if (u8Hflag) {
1657 for(loop =0; loop < (u32_width_out+u8Wflag); loop++) {
1658 *pu8_data_out++ = (M4VIFI_UInt8)*pu8dum++;
1659 }
1660 }
1661 }
1662
1663 return M4VIFI_OK;
1664 }
1665
applyRenderingMode(M4VIFI_ImagePlane * pPlaneIn,M4VIFI_ImagePlane * pPlaneOut,M4xVSS_MediaRendering mediaRendering)1666 M4OSA_ERR applyRenderingMode(M4VIFI_ImagePlane* pPlaneIn, M4VIFI_ImagePlane* pPlaneOut, M4xVSS_MediaRendering mediaRendering)
1667 {
1668 M4OSA_ERR err = M4NO_ERROR;
1669
1670 if(mediaRendering == M4xVSS_kResizing)
1671 {
1672 /**
1673 * Call the resize filter. From the intermediate frame to the encoder image plane */
1674 err = M4VIFI_ResizeBilinearYUV420toYUV420(M4OSA_NULL, pPlaneIn, pPlaneOut);
1675 if (M4NO_ERROR != err)
1676 {
1677 M4OSA_TRACE1_1("applyRenderingMode: M4ViFilResizeBilinearYUV420toYUV420 returns 0x%x!", err);
1678 return err;
1679 }
1680 }
1681 else
1682 {
1683 M4AIR_Params Params;
1684 M4OSA_Context m_air_context;
1685 M4VIFI_ImagePlane pImagePlanesTemp[3];
1686 M4VIFI_ImagePlane* pPlaneTemp;
1687 M4OSA_UInt8* pOutPlaneY = pPlaneOut[0].pac_data + pPlaneOut[0].u_topleft;
1688 M4OSA_UInt8* pOutPlaneU = pPlaneOut[1].pac_data + pPlaneOut[1].u_topleft;
1689 M4OSA_UInt8* pOutPlaneV = pPlaneOut[2].pac_data + pPlaneOut[2].u_topleft;
1690 M4OSA_UInt8* pInPlaneY = NULL;
1691 M4OSA_UInt8* pInPlaneU = NULL;
1692 M4OSA_UInt8* pInPlaneV = NULL;
1693 M4OSA_UInt32 i;
1694
1695 /*to keep media aspect ratio*/
1696 /*Initialize AIR Params*/
1697 Params.m_inputCoord.m_x = 0;
1698 Params.m_inputCoord.m_y = 0;
1699 Params.m_inputSize.m_height = pPlaneIn->u_height;
1700 Params.m_inputSize.m_width = pPlaneIn->u_width;
1701 Params.m_outputSize.m_width = pPlaneOut->u_width;
1702 Params.m_outputSize.m_height = pPlaneOut->u_height;
1703 Params.m_bOutputStripe = M4OSA_FALSE;
1704 Params.m_outputOrientation = M4COMMON_kOrientationTopLeft;
1705
1706 /**
1707 Media rendering: Black borders*/
1708 if(mediaRendering == M4xVSS_kBlackBorders)
1709 {
1710 memset((void *)pPlaneOut[0].pac_data,Y_PLANE_BORDER_VALUE,(pPlaneOut[0].u_height*pPlaneOut[0].u_stride));
1711 memset((void *)pPlaneOut[1].pac_data,U_PLANE_BORDER_VALUE,(pPlaneOut[1].u_height*pPlaneOut[1].u_stride));
1712 memset((void *)pPlaneOut[2].pac_data,V_PLANE_BORDER_VALUE,(pPlaneOut[2].u_height*pPlaneOut[2].u_stride));
1713
1714 pImagePlanesTemp[0].u_width = pPlaneOut[0].u_width;
1715 pImagePlanesTemp[0].u_height = pPlaneOut[0].u_height;
1716 pImagePlanesTemp[0].u_stride = pPlaneOut[0].u_width;
1717 pImagePlanesTemp[0].u_topleft = 0;
1718 pImagePlanesTemp[0].pac_data = M4OSA_NULL;
1719
1720 pImagePlanesTemp[1].u_width = pPlaneOut[1].u_width;
1721 pImagePlanesTemp[1].u_height = pPlaneOut[1].u_height;
1722 pImagePlanesTemp[1].u_stride = pPlaneOut[1].u_width;
1723 pImagePlanesTemp[1].u_topleft = 0;
1724 pImagePlanesTemp[1].pac_data = M4OSA_NULL;
1725
1726 pImagePlanesTemp[2].u_width = pPlaneOut[2].u_width;
1727 pImagePlanesTemp[2].u_height = pPlaneOut[2].u_height;
1728 pImagePlanesTemp[2].u_stride = pPlaneOut[2].u_width;
1729 pImagePlanesTemp[2].u_topleft = 0;
1730 pImagePlanesTemp[2].pac_data = M4OSA_NULL;
1731
1732 /* Allocates plan in local image plane structure */
1733 pImagePlanesTemp[0].pac_data = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(pImagePlanesTemp[0].u_width * pImagePlanesTemp[0].u_height, M4VS, (M4OSA_Char*)"applyRenderingMode: temporary plane bufferY") ;
1734 if(pImagePlanesTemp[0].pac_data == M4OSA_NULL)
1735 {
1736 M4OSA_TRACE1_0("Error alloc in applyRenderingMode");
1737 return M4ERR_ALLOC;
1738 }
1739 pImagePlanesTemp[1].pac_data = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(pImagePlanesTemp[1].u_width * pImagePlanesTemp[1].u_height, M4VS, (M4OSA_Char*)"applyRenderingMode: temporary plane bufferU") ;
1740 if(pImagePlanesTemp[1].pac_data == M4OSA_NULL)
1741 {
1742
1743 M4OSA_TRACE1_0("Error alloc in applyRenderingMode");
1744 return M4ERR_ALLOC;
1745 }
1746 pImagePlanesTemp[2].pac_data = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(pImagePlanesTemp[2].u_width * pImagePlanesTemp[2].u_height, M4VS, (M4OSA_Char*)"applyRenderingMode: temporary plane bufferV") ;
1747 if(pImagePlanesTemp[2].pac_data == M4OSA_NULL)
1748 {
1749
1750 M4OSA_TRACE1_0("Error alloc in applyRenderingMode");
1751 return M4ERR_ALLOC;
1752 }
1753
1754 pInPlaneY = pImagePlanesTemp[0].pac_data ;
1755 pInPlaneU = pImagePlanesTemp[1].pac_data ;
1756 pInPlaneV = pImagePlanesTemp[2].pac_data ;
1757
1758 memset((void *)pImagePlanesTemp[0].pac_data,Y_PLANE_BORDER_VALUE,(pImagePlanesTemp[0].u_height*pImagePlanesTemp[0].u_stride));
1759 memset((void *)pImagePlanesTemp[1].pac_data,U_PLANE_BORDER_VALUE,(pImagePlanesTemp[1].u_height*pImagePlanesTemp[1].u_stride));
1760 memset((void *)pImagePlanesTemp[2].pac_data,V_PLANE_BORDER_VALUE,(pImagePlanesTemp[2].u_height*pImagePlanesTemp[2].u_stride));
1761
1762 if((M4OSA_UInt32)((pPlaneIn->u_height * pPlaneOut->u_width) /pPlaneIn->u_width) <= pPlaneOut->u_height)//Params.m_inputSize.m_height < Params.m_inputSize.m_width)
1763 {
1764 /*it is height so black borders will be on the top and on the bottom side*/
1765 Params.m_outputSize.m_width = pPlaneOut->u_width;
1766 Params.m_outputSize.m_height = (M4OSA_UInt32)((pPlaneIn->u_height * pPlaneOut->u_width) /pPlaneIn->u_width);
1767 /*number of lines at the top*/
1768 pImagePlanesTemp[0].u_topleft = (M4xVSS_ABS((M4OSA_Int32)(pImagePlanesTemp[0].u_height-Params.m_outputSize.m_height)>>1))*pImagePlanesTemp[0].u_stride;
1769 pImagePlanesTemp[0].u_height = Params.m_outputSize.m_height;
1770 pImagePlanesTemp[1].u_topleft = (M4xVSS_ABS((M4OSA_Int32)(pImagePlanesTemp[1].u_height-(Params.m_outputSize.m_height>>1)))>>1)*pImagePlanesTemp[1].u_stride;
1771 pImagePlanesTemp[1].u_height = Params.m_outputSize.m_height>>1;
1772 pImagePlanesTemp[2].u_topleft = (M4xVSS_ABS((M4OSA_Int32)(pImagePlanesTemp[2].u_height-(Params.m_outputSize.m_height>>1)))>>1)*pImagePlanesTemp[2].u_stride;
1773 pImagePlanesTemp[2].u_height = Params.m_outputSize.m_height>>1;
1774 }
1775 else
1776 {
1777 /*it is width so black borders will be on the left and right side*/
1778 Params.m_outputSize.m_height = pPlaneOut->u_height;
1779 Params.m_outputSize.m_width = (M4OSA_UInt32)((pPlaneIn->u_width * pPlaneOut->u_height) /pPlaneIn->u_height);
1780
1781 pImagePlanesTemp[0].u_topleft = (M4xVSS_ABS((M4OSA_Int32)(pImagePlanesTemp[0].u_width-Params.m_outputSize.m_width)>>1));
1782 pImagePlanesTemp[0].u_width = Params.m_outputSize.m_width;
1783 pImagePlanesTemp[1].u_topleft = (M4xVSS_ABS((M4OSA_Int32)(pImagePlanesTemp[1].u_width-(Params.m_outputSize.m_width>>1)))>>1);
1784 pImagePlanesTemp[1].u_width = Params.m_outputSize.m_width>>1;
1785 pImagePlanesTemp[2].u_topleft = (M4xVSS_ABS((M4OSA_Int32)(pImagePlanesTemp[2].u_width-(Params.m_outputSize.m_width>>1)))>>1);
1786 pImagePlanesTemp[2].u_width = Params.m_outputSize.m_width>>1;
1787 }
1788
1789 /*Width and height have to be even*/
1790 Params.m_outputSize.m_width = (Params.m_outputSize.m_width>>1)<<1;
1791 Params.m_outputSize.m_height = (Params.m_outputSize.m_height>>1)<<1;
1792 Params.m_inputSize.m_width = (Params.m_inputSize.m_width>>1)<<1;
1793 Params.m_inputSize.m_height = (Params.m_inputSize.m_height>>1)<<1;
1794 pImagePlanesTemp[0].u_width = (pImagePlanesTemp[0].u_width>>1)<<1;
1795 pImagePlanesTemp[1].u_width = (pImagePlanesTemp[1].u_width>>1)<<1;
1796 pImagePlanesTemp[2].u_width = (pImagePlanesTemp[2].u_width>>1)<<1;
1797 pImagePlanesTemp[0].u_height = (pImagePlanesTemp[0].u_height>>1)<<1;
1798 pImagePlanesTemp[1].u_height = (pImagePlanesTemp[1].u_height>>1)<<1;
1799 pImagePlanesTemp[2].u_height = (pImagePlanesTemp[2].u_height>>1)<<1;
1800
1801 /*Check that values are coherent*/
1802 if(Params.m_inputSize.m_height == Params.m_outputSize.m_height)
1803 {
1804 Params.m_inputSize.m_width = Params.m_outputSize.m_width;
1805 }
1806 else if(Params.m_inputSize.m_width == Params.m_outputSize.m_width)
1807 {
1808 Params.m_inputSize.m_height = Params.m_outputSize.m_height;
1809 }
1810 pPlaneTemp = pImagePlanesTemp;
1811
1812
1813 }
1814
1815 /**
1816 Media rendering: Cropping*/
1817 if(mediaRendering == M4xVSS_kCropping)
1818 {
1819 Params.m_outputSize.m_height = pPlaneOut->u_height;
1820 Params.m_outputSize.m_width = pPlaneOut->u_width;
1821 if((Params.m_outputSize.m_height * Params.m_inputSize.m_width) /Params.m_outputSize.m_width<Params.m_inputSize.m_height)
1822 {
1823 /*height will be cropped*/
1824 Params.m_inputSize.m_height = (M4OSA_UInt32)((Params.m_outputSize.m_height * Params.m_inputSize.m_width) /Params.m_outputSize.m_width);
1825 Params.m_inputSize.m_height = (Params.m_inputSize.m_height>>1)<<1;
1826 Params.m_inputCoord.m_y = (M4OSA_Int32)((M4OSA_Int32)((pPlaneIn->u_height - Params.m_inputSize.m_height))>>1);
1827 }
1828 else
1829 {
1830 /*width will be cropped*/
1831 Params.m_inputSize.m_width = (M4OSA_UInt32)((Params.m_outputSize.m_width * Params.m_inputSize.m_height) /Params.m_outputSize.m_height);
1832 Params.m_inputSize.m_width = (Params.m_inputSize.m_width>>1)<<1;
1833 Params.m_inputCoord.m_x = (M4OSA_Int32)((M4OSA_Int32)((pPlaneIn->u_width - Params.m_inputSize.m_width))>>1);
1834 }
1835 pPlaneTemp = pPlaneOut;
1836 }
1837
1838 /**
1839 * Call AIR functions */
1840 err = M4AIR_create(&m_air_context, M4AIR_kYUV420P);
1841 if(err != M4NO_ERROR)
1842 {
1843
1844 M4OSA_TRACE1_1("applyRenderingMode: Error when initializing AIR: 0x%x", err);
1845 for(i=0; i<3; i++)
1846 {
1847 if(pImagePlanesTemp[i].pac_data != M4OSA_NULL)
1848 {
1849 free(pImagePlanesTemp[i].pac_data);
1850 pImagePlanesTemp[i].pac_data = M4OSA_NULL;
1851 }
1852 }
1853 return err;
1854 }
1855
1856
1857 err = M4AIR_configure(m_air_context, &Params);
1858 if(err != M4NO_ERROR)
1859 {
1860
1861 M4OSA_TRACE1_1("applyRenderingMode: Error when configuring AIR: 0x%x", err);
1862 M4AIR_cleanUp(m_air_context);
1863 for(i=0; i<3; i++)
1864 {
1865 if(pImagePlanesTemp[i].pac_data != M4OSA_NULL)
1866 {
1867 free(pImagePlanesTemp[i].pac_data);
1868 pImagePlanesTemp[i].pac_data = M4OSA_NULL;
1869 }
1870 }
1871 return err;
1872 }
1873
1874 err = M4AIR_get(m_air_context, pPlaneIn, pPlaneTemp);
1875 if(err != M4NO_ERROR)
1876 {
1877 M4OSA_TRACE1_1("applyRenderingMode: Error when getting AIR plane: 0x%x", err);
1878 M4AIR_cleanUp(m_air_context);
1879 for(i=0; i<3; i++)
1880 {
1881 if(pImagePlanesTemp[i].pac_data != M4OSA_NULL)
1882 {
1883 free(pImagePlanesTemp[i].pac_data);
1884 pImagePlanesTemp[i].pac_data = M4OSA_NULL;
1885 }
1886 }
1887 return err;
1888 }
1889
1890 if(mediaRendering == M4xVSS_kBlackBorders)
1891 {
1892 for(i=0; i<pPlaneOut[0].u_height; i++)
1893 {
1894 memcpy((void *)pOutPlaneY, (void *)pInPlaneY, pPlaneOut[0].u_width);
1895 pInPlaneY += pPlaneOut[0].u_width;
1896 pOutPlaneY += pPlaneOut[0].u_stride;
1897 }
1898 for(i=0; i<pPlaneOut[1].u_height; i++)
1899 {
1900 memcpy((void *)pOutPlaneU, (void *)pInPlaneU, pPlaneOut[1].u_width);
1901 pInPlaneU += pPlaneOut[1].u_width;
1902 pOutPlaneU += pPlaneOut[1].u_stride;
1903 }
1904 for(i=0; i<pPlaneOut[2].u_height; i++)
1905 {
1906 memcpy((void *)pOutPlaneV, (void *)pInPlaneV, pPlaneOut[2].u_width);
1907 pInPlaneV += pPlaneOut[2].u_width;
1908 pOutPlaneV += pPlaneOut[2].u_stride;
1909 }
1910
1911 for(i=0; i<3; i++)
1912 {
1913 if(pImagePlanesTemp[i].pac_data != M4OSA_NULL)
1914 {
1915 free(pImagePlanesTemp[i].pac_data);
1916 pImagePlanesTemp[i].pac_data = M4OSA_NULL;
1917 }
1918 }
1919 }
1920
1921 if (m_air_context != M4OSA_NULL) {
1922 M4AIR_cleanUp(m_air_context);
1923 m_air_context = M4OSA_NULL;
1924 }
1925 }
1926
1927 return err;
1928 }
1929
1930 //TODO: remove this code after link with videoartist lib
1931 /* M4AIR code*/
1932 #define M4AIR_YUV420_FORMAT_SUPPORTED
1933 #define M4AIR_YUV420A_FORMAT_SUPPORTED
1934
1935 /************************* COMPILATION CHECKS ***************************/
1936 #ifndef M4AIR_YUV420_FORMAT_SUPPORTED
1937 #ifndef M4AIR_BGR565_FORMAT_SUPPORTED
1938 #ifndef M4AIR_RGB565_FORMAT_SUPPORTED
1939 #ifndef M4AIR_BGR888_FORMAT_SUPPORTED
1940 #ifndef M4AIR_RGB888_FORMAT_SUPPORTED
1941 #ifndef M4AIR_JPG_FORMAT_SUPPORTED
1942
1943 #error "Please define at least one input format for the AIR component"
1944
1945 #endif
1946 #endif
1947 #endif
1948 #endif
1949 #endif
1950 #endif
1951
1952 /************************ M4AIR INTERNAL TYPES DEFINITIONS ***********************/
1953
1954 /**
1955 ******************************************************************************
1956 * enum M4AIR_States
1957 * @brief The following enumeration defines the internal states of the AIR.
1958 ******************************************************************************
1959 */
1960 typedef enum
1961 {
1962 M4AIR_kCreated, /**< State after M4AIR_create has been called */
1963 M4AIR_kConfigured /**< State after M4AIR_configure has been called */
1964 }M4AIR_States;
1965
1966
1967 /**
1968 ******************************************************************************
1969 * struct M4AIR_InternalContext
1970 * @brief The following structure is the internal context of the AIR.
1971 ******************************************************************************
1972 */
1973 typedef struct
1974 {
1975 M4AIR_States m_state; /**< Internal state */
1976 M4AIR_InputFormatType m_inputFormat; /**< Input format like YUV420Planar, RGB565, JPG, etc ... */
1977 M4AIR_Params m_params; /**< Current input Parameter of the processing */
1978 M4OSA_UInt32 u32_x_inc[4]; /**< ratio between input and ouput width for YUV */
1979 M4OSA_UInt32 u32_y_inc[4]; /**< ratio between input and ouput height for YUV */
1980 M4OSA_UInt32 u32_x_accum_start[4]; /**< horizontal initial accumulator value */
1981 M4OSA_UInt32 u32_y_accum_start[4]; /**< Vertical initial accumulator value */
1982 M4OSA_UInt32 u32_x_accum[4]; /**< save of horizontal accumulator value */
1983 M4OSA_UInt32 u32_y_accum[4]; /**< save of vertical accumulator value */
1984 M4OSA_UInt8* pu8_data_in[4]; /**< Save of input plane pointers in case of stripe mode */
1985 M4OSA_UInt32 m_procRows; /**< Number of processed rows, used in stripe mode only */
1986 M4OSA_Bool m_bOnlyCopy; /**< Flag to know if we just perform a copy or a bilinear interpolation */
1987 M4OSA_Bool m_bFlipX; /**< Depend on output orientation, used during processing to revert processing order in X coordinates */
1988 M4OSA_Bool m_bFlipY; /**< Depend on output orientation, used during processing to revert processing order in Y coordinates */
1989 M4OSA_Bool m_bRevertXY; /**< Depend on output orientation, used during processing to revert X and Y processing order (+-90° rotation) */
1990 }M4AIR_InternalContext;
1991
1992 /********************************* MACROS *******************************/
1993 #define M4ERR_CHECK_NULL_RETURN_VALUE(retval, pointer) if ((pointer) == M4OSA_NULL) return ((M4OSA_ERR)(retval));
1994
1995
1996 /********************** M4AIR PUBLIC API IMPLEMENTATION ********************/
1997 /**
1998 ******************************************************************************
1999 * M4OSA_ERR M4AIR_create(M4OSA_Context* pContext,M4AIR_InputFormatType inputFormat)
2000 * @author Arnaud Collard
2001 * @brief This function initialize an instance of the AIR.
2002 * @param pContext: (IN/OUT) Address of the context to create
2003 * @param inputFormat: (IN) input format type.
2004 * @return M4NO_ERROR: there is no error
2005 * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only). Invalid formatType
2006 * @return M4ERR_ALLOC: No more memory is available
2007 ******************************************************************************
2008 */
M4AIR_create(M4OSA_Context * pContext,M4AIR_InputFormatType inputFormat)2009 M4OSA_ERR M4AIR_create(M4OSA_Context* pContext,M4AIR_InputFormatType inputFormat)
2010 {
2011 M4OSA_ERR err = M4NO_ERROR ;
2012 M4AIR_InternalContext* pC = M4OSA_NULL ;
2013 /* Check that the address on the context is not NULL */
2014 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_PARAMETER, pContext) ;
2015
2016 *pContext = M4OSA_NULL ;
2017
2018 /* Internal Context creation */
2019 pC = (M4AIR_InternalContext*)M4OSA_32bitAlignedMalloc(sizeof(M4AIR_InternalContext), M4AIR, (M4OSA_Char*)"AIR internal context") ;
2020 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_ALLOC, pC) ;
2021
2022
2023 /* Check if the input format is supported */
2024 switch(inputFormat)
2025 {
2026 #ifdef M4AIR_YUV420_FORMAT_SUPPORTED
2027 case M4AIR_kYUV420P:
2028 break ;
2029 #endif
2030 #ifdef M4AIR_YUV420A_FORMAT_SUPPORTED
2031 case M4AIR_kYUV420AP:
2032 break ;
2033 #endif
2034 default:
2035 err = M4ERR_AIR_FORMAT_NOT_SUPPORTED;
2036 goto M4AIR_create_cleanup ;
2037 }
2038
2039 /**< Save input format and update state */
2040 pC->m_inputFormat = inputFormat;
2041 pC->m_state = M4AIR_kCreated;
2042
2043 /* Return the context to the caller */
2044 *pContext = pC ;
2045
2046 return M4NO_ERROR ;
2047
2048 M4AIR_create_cleanup:
2049 /* Error management : we destroy the context if needed */
2050 if(M4OSA_NULL != pC)
2051 {
2052 free(pC) ;
2053 }
2054
2055 *pContext = M4OSA_NULL ;
2056
2057 return err ;
2058 }
2059
2060
2061
2062 /**
2063 ******************************************************************************
2064 * M4OSA_ERR M4AIR_cleanUp(M4OSA_Context pContext)
2065 * @author Arnaud Collard
2066 * @brief This function destroys an instance of the AIR component
2067 * @param pContext: (IN) Context identifying the instance to destroy
2068 * @return M4NO_ERROR: there is no error
2069 * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only).
2070 * @return M4ERR_STATE: Internal state is incompatible with this function call.
2071 ******************************************************************************
2072 */
M4AIR_cleanUp(M4OSA_Context pContext)2073 M4OSA_ERR M4AIR_cleanUp(M4OSA_Context pContext)
2074 {
2075 M4AIR_InternalContext* pC = (M4AIR_InternalContext*)pContext ;
2076
2077 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_PARAMETER, pContext) ;
2078
2079 /**< Check state */
2080 if((M4AIR_kCreated != pC->m_state)&&(M4AIR_kConfigured != pC->m_state))
2081 {
2082 return M4ERR_STATE;
2083 }
2084 free(pC) ;
2085
2086 return M4NO_ERROR ;
2087
2088 }
2089
2090
2091 /**
2092 ******************************************************************************
2093 * M4OSA_ERR M4AIR_configure(M4OSA_Context pContext, M4AIR_Params* pParams)
2094 * @brief This function will configure the AIR.
2095 * @note It will set the input and output coordinates and sizes,
2096 * and indicates if we will proceed in stripe or not.
2097 * In case a M4AIR_get in stripe mode was on going, it will cancel this previous processing
2098 * and reset the get process.
2099 * @param pContext: (IN) Context identifying the instance
2100 * @param pParams->m_bOutputStripe:(IN) Stripe mode.
2101 * @param pParams->m_inputCoord: (IN) X,Y coordinates of the first valid pixel in input.
2102 * @param pParams->m_inputSize: (IN) input ROI size.
2103 * @param pParams->m_outputSize: (IN) output size.
2104 * @return M4NO_ERROR: there is no error
2105 * @return M4ERR_ALLOC: No more memory space to add a new effect.
2106 * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only).
2107 * @return M4ERR_AIR_FORMAT_NOT_SUPPORTED: the requested input format is not supported.
2108 ******************************************************************************
2109 */
M4AIR_configure(M4OSA_Context pContext,M4AIR_Params * pParams)2110 M4OSA_ERR M4AIR_configure(M4OSA_Context pContext, M4AIR_Params* pParams)
2111 {
2112 M4AIR_InternalContext* pC = (M4AIR_InternalContext*)pContext ;
2113 M4OSA_UInt32 i,u32_width_in, u32_width_out, u32_height_in, u32_height_out;
2114 M4OSA_UInt32 nb_planes;
2115
2116 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_PARAMETER, pContext) ;
2117
2118 if(M4AIR_kYUV420AP == pC->m_inputFormat)
2119 {
2120 nb_planes = 4;
2121 }
2122 else
2123 {
2124 nb_planes = 3;
2125 }
2126
2127 /**< Check state */
2128 if((M4AIR_kCreated != pC->m_state)&&(M4AIR_kConfigured != pC->m_state))
2129 {
2130 return M4ERR_STATE;
2131 }
2132
2133 /** Save parameters */
2134 pC->m_params = *pParams;
2135
2136 /* Check for the input&output width and height are even */
2137 if( ((pC->m_params.m_inputSize.m_height)&0x1) ||
2138 ((pC->m_params.m_inputSize.m_height)&0x1))
2139 {
2140 return M4ERR_AIR_ILLEGAL_FRAME_SIZE;
2141 }
2142
2143 if( ((pC->m_params.m_inputSize.m_width)&0x1) ||
2144 ((pC->m_params.m_inputSize.m_width)&0x1))
2145 {
2146 return M4ERR_AIR_ILLEGAL_FRAME_SIZE;
2147 }
2148 if(((pC->m_params.m_inputSize.m_width) == (pC->m_params.m_outputSize.m_width))
2149 &&((pC->m_params.m_inputSize.m_height) == (pC->m_params.m_outputSize.m_height)))
2150 {
2151 /**< No resize in this case, we will just copy input in output */
2152 pC->m_bOnlyCopy = M4OSA_TRUE;
2153 }
2154 else
2155 {
2156 pC->m_bOnlyCopy = M4OSA_FALSE;
2157
2158 /**< Initialize internal variables used for resize filter */
2159 for(i=0;i<nb_planes;i++)
2160 {
2161
2162 u32_width_in = ((i==0)||(i==3))?pC->m_params.m_inputSize.m_width:(pC->m_params.m_inputSize.m_width+1)>>1;
2163 u32_height_in = ((i==0)||(i==3))?pC->m_params.m_inputSize.m_height:(pC->m_params.m_inputSize.m_height+1)>>1;
2164 u32_width_out = ((i==0)||(i==3))?pC->m_params.m_outputSize.m_width:(pC->m_params.m_outputSize.m_width+1)>>1;
2165 u32_height_out = ((i==0)||(i==3))?pC->m_params.m_outputSize.m_height:(pC->m_params.m_outputSize.m_height+1)>>1;
2166
2167 /* Compute horizontal ratio between src and destination width.*/
2168 if (u32_width_out >= u32_width_in)
2169 {
2170 pC->u32_x_inc[i] = ((u32_width_in-1) * 0x10000) / (u32_width_out-1);
2171 }
2172 else
2173 {
2174 pC->u32_x_inc[i] = (u32_width_in * 0x10000) / (u32_width_out);
2175 }
2176
2177 /* Compute vertical ratio between src and destination height.*/
2178 if (u32_height_out >= u32_height_in)
2179 {
2180 pC->u32_y_inc[i] = ((u32_height_in - 1) * 0x10000) / (u32_height_out-1);
2181 }
2182 else
2183 {
2184 pC->u32_y_inc[i] = (u32_height_in * 0x10000) / (u32_height_out);
2185 }
2186
2187 /*
2188 Calculate initial accumulator value : u32_y_accum_start.
2189 u32_y_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
2190 */
2191 if (pC->u32_y_inc[i] >= 0x10000)
2192 {
2193 /*
2194 Keep the fractionnal part, assimung that integer part is coded
2195 on the 16 high bits and the fractionnal on the 15 low bits
2196 */
2197 pC->u32_y_accum_start[i] = pC->u32_y_inc[i] & 0xffff;
2198
2199 if (!pC->u32_y_accum_start[i])
2200 {
2201 pC->u32_y_accum_start[i] = 0x10000;
2202 }
2203
2204 pC->u32_y_accum_start[i] >>= 1;
2205 }
2206 else
2207 {
2208 pC->u32_y_accum_start[i] = 0;
2209 }
2210 /**< Take into account that Y coordinate can be odd
2211 in this case we have to put a 0.5 offset
2212 for U and V plane as there a 2 times sub-sampled vs Y*/
2213 if((pC->m_params.m_inputCoord.m_y&0x1)&&((i==1)||(i==2)))
2214 {
2215 pC->u32_y_accum_start[i] += 0x8000;
2216 }
2217
2218 /*
2219 Calculate initial accumulator value : u32_x_accum_start.
2220 u32_x_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
2221 */
2222
2223 if (pC->u32_x_inc[i] >= 0x10000)
2224 {
2225 pC->u32_x_accum_start[i] = pC->u32_x_inc[i] & 0xffff;
2226
2227 if (!pC->u32_x_accum_start[i])
2228 {
2229 pC->u32_x_accum_start[i] = 0x10000;
2230 }
2231
2232 pC->u32_x_accum_start[i] >>= 1;
2233 }
2234 else
2235 {
2236 pC->u32_x_accum_start[i] = 0;
2237 }
2238 /**< Take into account that X coordinate can be odd
2239 in this case we have to put a 0.5 offset
2240 for U and V plane as there a 2 times sub-sampled vs Y*/
2241 if((pC->m_params.m_inputCoord.m_x&0x1)&&((i==1)||(i==2)))
2242 {
2243 pC->u32_x_accum_start[i] += 0x8000;
2244 }
2245 }
2246 }
2247
2248 /**< Reset variable used for stripe mode */
2249 pC->m_procRows = 0;
2250
2251 /**< Initialize var for X/Y processing order according to orientation */
2252 pC->m_bFlipX = M4OSA_FALSE;
2253 pC->m_bFlipY = M4OSA_FALSE;
2254 pC->m_bRevertXY = M4OSA_FALSE;
2255 switch(pParams->m_outputOrientation)
2256 {
2257 case M4COMMON_kOrientationTopLeft:
2258 break;
2259 case M4COMMON_kOrientationTopRight:
2260 pC->m_bFlipX = M4OSA_TRUE;
2261 break;
2262 case M4COMMON_kOrientationBottomRight:
2263 pC->m_bFlipX = M4OSA_TRUE;
2264 pC->m_bFlipY = M4OSA_TRUE;
2265 break;
2266 case M4COMMON_kOrientationBottomLeft:
2267 pC->m_bFlipY = M4OSA_TRUE;
2268 break;
2269 case M4COMMON_kOrientationLeftTop:
2270 pC->m_bRevertXY = M4OSA_TRUE;
2271 break;
2272 case M4COMMON_kOrientationRightTop:
2273 pC->m_bRevertXY = M4OSA_TRUE;
2274 pC->m_bFlipY = M4OSA_TRUE;
2275 break;
2276 case M4COMMON_kOrientationRightBottom:
2277 pC->m_bRevertXY = M4OSA_TRUE;
2278 pC->m_bFlipX = M4OSA_TRUE;
2279 pC->m_bFlipY = M4OSA_TRUE;
2280 break;
2281 case M4COMMON_kOrientationLeftBottom:
2282 pC->m_bRevertXY = M4OSA_TRUE;
2283 pC->m_bFlipX = M4OSA_TRUE;
2284 break;
2285 default:
2286 return M4ERR_PARAMETER;
2287 }
2288 /**< Update state */
2289 pC->m_state = M4AIR_kConfigured;
2290
2291 return M4NO_ERROR ;
2292 }
2293
2294
2295 /**
2296 ******************************************************************************
2297 * M4OSA_ERR M4AIR_get(M4OSA_Context pContext, M4VIFI_ImagePlane* pIn, M4VIFI_ImagePlane* pOut)
2298 * @brief This function will provide the requested resized area of interest according to settings
2299 * provided in M4AIR_configure.
2300 * @note In case the input format type is JPEG, input plane(s)
2301 * in pIn is not used. In normal mode, dimension specified in output plane(s) structure must be the
2302 * same than the one specified in M4AIR_configure. In stripe mode, only the width will be the same,
2303 * height will be taken as the stripe height (typically 16).
2304 * In normal mode, this function is call once to get the full output picture. In stripe mode, it is called
2305 * for each stripe till the whole picture has been retrieved,and the position of the output stripe in the output picture
2306 * is internally incremented at each step.
2307 * Any call to M4AIR_configure during stripe process will reset this one to the beginning of the output picture.
2308 * @param pContext: (IN) Context identifying the instance
2309 * @param pIn: (IN) Plane structure containing input Plane(s).
2310 * @param pOut: (IN/OUT) Plane structure containing output Plane(s).
2311 * @return M4NO_ERROR: there is no error
2312 * @return M4ERR_ALLOC: No more memory space to add a new effect.
2313 * @return M4ERR_PARAMETER: pContext is M4OSA_NULL (debug only).
2314 ******************************************************************************
2315 */
M4AIR_get(M4OSA_Context pContext,M4VIFI_ImagePlane * pIn,M4VIFI_ImagePlane * pOut)2316 M4OSA_ERR M4AIR_get(M4OSA_Context pContext, M4VIFI_ImagePlane* pIn, M4VIFI_ImagePlane* pOut)
2317 {
2318 M4AIR_InternalContext* pC = (M4AIR_InternalContext*)pContext ;
2319 M4OSA_UInt32 i,j,k,u32_x_frac,u32_y_frac,u32_x_accum,u32_y_accum,u32_shift;
2320 M4OSA_UInt8 *pu8_data_in, *pu8_data_in_org, *pu8_data_in_tmp, *pu8_data_out;
2321 M4OSA_UInt8 *pu8_src_top;
2322 M4OSA_UInt8 *pu8_src_bottom;
2323 M4OSA_UInt32 u32_temp_value;
2324 M4OSA_Int32 i32_tmp_offset;
2325 M4OSA_UInt32 nb_planes;
2326
2327
2328
2329 M4ERR_CHECK_NULL_RETURN_VALUE(M4ERR_PARAMETER, pContext) ;
2330
2331 /**< Check state */
2332 if(M4AIR_kConfigured != pC->m_state)
2333 {
2334 return M4ERR_STATE;
2335 }
2336
2337 if(M4AIR_kYUV420AP == pC->m_inputFormat)
2338 {
2339 nb_planes = 4;
2340 }
2341 else
2342 {
2343 nb_planes = 3;
2344 }
2345
2346 /**< Loop on each Plane */
2347 for(i=0;i<nb_planes;i++)
2348 {
2349
2350 /* Set the working pointers at the beginning of the input/output data field */
2351
2352 u32_shift = ((i==0)||(i==3))?0:1; /**< Depend on Luma or Chroma */
2353
2354 if((M4OSA_FALSE == pC->m_params.m_bOutputStripe)||((M4OSA_TRUE == pC->m_params.m_bOutputStripe)&&(0 == pC->m_procRows)))
2355 {
2356 /**< For input, take care about ROI */
2357 pu8_data_in = pIn[i].pac_data + pIn[i].u_topleft + (pC->m_params.m_inputCoord.m_x>>u32_shift)
2358 + (pC->m_params.m_inputCoord.m_y >> u32_shift) * pIn[i].u_stride;
2359
2360 /** Go at end of line/column in case X/Y scanning is flipped */
2361 if(M4OSA_TRUE == pC->m_bFlipX)
2362 {
2363 pu8_data_in += ((pC->m_params.m_inputSize.m_width)>>u32_shift) -1 ;
2364 }
2365 if(M4OSA_TRUE == pC->m_bFlipY)
2366 {
2367 pu8_data_in += ((pC->m_params.m_inputSize.m_height>>u32_shift) -1) * pIn[i].u_stride;
2368 }
2369
2370 /**< Initialize accumulators in case we are using it (bilinear interpolation) */
2371 if( M4OSA_FALSE == pC->m_bOnlyCopy)
2372 {
2373 pC->u32_x_accum[i] = pC->u32_x_accum_start[i];
2374 pC->u32_y_accum[i] = pC->u32_y_accum_start[i];
2375 }
2376
2377 }
2378 else
2379 {
2380 /**< In case of stripe mode for other than first stripe, we need to recover input pointer from internal context */
2381 pu8_data_in = pC->pu8_data_in[i];
2382 }
2383
2384 /**< In every mode, output data are at the beginning of the output plane */
2385 pu8_data_out = pOut[i].pac_data + pOut[i].u_topleft;
2386
2387 /**< Initialize input offset applied after each pixel */
2388 if(M4OSA_FALSE == pC->m_bFlipY)
2389 {
2390 i32_tmp_offset = pIn[i].u_stride;
2391 }
2392 else
2393 {
2394 i32_tmp_offset = -pIn[i].u_stride;
2395 }
2396
2397 /**< In this case, no bilinear interpolation is needed as input and output dimensions are the same */
2398 if( M4OSA_TRUE == pC->m_bOnlyCopy)
2399 {
2400 /**< No +-90° rotation */
2401 if(M4OSA_FALSE == pC->m_bRevertXY)
2402 {
2403 /**< No flip on X abscissa */
2404 if(M4OSA_FALSE == pC->m_bFlipX)
2405 {
2406 M4OSA_UInt32 loc_height = pOut[i].u_height;
2407 M4OSA_UInt32 loc_width = pOut[i].u_width;
2408 M4OSA_UInt32 loc_stride = pIn[i].u_stride;
2409 /**< Loop on each row */
2410 for (j=0; j<loc_height; j++)
2411 {
2412 /**< Copy one whole line */
2413 memcpy((void *)pu8_data_out, (void *)pu8_data_in, loc_width);
2414
2415 /**< Update pointers */
2416 pu8_data_out += pOut[i].u_stride;
2417 if(M4OSA_FALSE == pC->m_bFlipY)
2418 {
2419 pu8_data_in += loc_stride;
2420 }
2421 else
2422 {
2423 pu8_data_in -= loc_stride;
2424 }
2425 }
2426 }
2427 else
2428 {
2429 /**< Loop on each row */
2430 for(j=0;j<pOut[i].u_height;j++)
2431 {
2432 /**< Loop on each pixel of 1 row */
2433 for(k=0;k<pOut[i].u_width;k++)
2434 {
2435 *pu8_data_out++ = *pu8_data_in--;
2436 }
2437
2438 /**< Update pointers */
2439 pu8_data_out += (pOut[i].u_stride - pOut[i].u_width);
2440
2441 pu8_data_in += pOut[i].u_width + i32_tmp_offset;
2442
2443 }
2444 }
2445 }
2446 /**< Here we have a +-90° rotation */
2447 else
2448 {
2449
2450 /**< Loop on each row */
2451 for(j=0;j<pOut[i].u_height;j++)
2452 {
2453 pu8_data_in_tmp = pu8_data_in;
2454
2455 /**< Loop on each pixel of 1 row */
2456 for(k=0;k<pOut[i].u_width;k++)
2457 {
2458 *pu8_data_out++ = *pu8_data_in_tmp;
2459
2460 /**< Update input pointer in order to go to next/past line */
2461 pu8_data_in_tmp += i32_tmp_offset;
2462 }
2463
2464 /**< Update pointers */
2465 pu8_data_out += (pOut[i].u_stride - pOut[i].u_width);
2466 if(M4OSA_FALSE == pC->m_bFlipX)
2467 {
2468 pu8_data_in ++;
2469 }
2470 else
2471 {
2472 pu8_data_in --;
2473 }
2474 }
2475 }
2476 }
2477 /**< Bilinear interpolation */
2478 else
2479 {
2480
2481 if(3 != i) /**< other than alpha plane */
2482 {
2483 /**No +-90° rotation */
2484 if(M4OSA_FALSE == pC->m_bRevertXY)
2485 {
2486
2487 /**< Loop on each row */
2488 for(j=0;j<pOut[i].u_height;j++)
2489 {
2490 /* Vertical weight factor */
2491 u32_y_frac = (pC->u32_y_accum[i]>>12)&15;
2492
2493 /* Reinit horizontal weight factor */
2494 u32_x_accum = pC->u32_x_accum_start[i];
2495
2496
2497
2498 if(M4OSA_TRUE == pC->m_bFlipX)
2499 {
2500
2501 /**< Loop on each output pixel in a row */
2502 for(k=0;k<pOut[i].u_width;k++)
2503 {
2504
2505 u32_x_frac = (u32_x_accum >> 12)&15; /* Fraction of Horizontal weight factor */
2506
2507 pu8_src_top = (pu8_data_in - (u32_x_accum >> 16)) -1 ;
2508
2509 pu8_src_bottom = pu8_src_top + i32_tmp_offset;
2510
2511 /* Weighted combination */
2512 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[1]*(16-u32_x_frac) +
2513 pu8_src_top[0]*u32_x_frac)*(16-u32_y_frac) +
2514 (pu8_src_bottom[1]*(16-u32_x_frac) +
2515 pu8_src_bottom[0]*u32_x_frac)*u32_y_frac )>>8);
2516
2517 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
2518
2519 /* Update horizontal accumulator */
2520 u32_x_accum += pC->u32_x_inc[i];
2521 }
2522 }
2523
2524 else
2525 {
2526 /**< Loop on each output pixel in a row */
2527 for(k=0;k<pOut[i].u_width;k++)
2528 {
2529 u32_x_frac = (u32_x_accum >> 12)&15; /* Fraction of Horizontal weight factor */
2530
2531 pu8_src_top = pu8_data_in + (u32_x_accum >> 16);
2532
2533 pu8_src_bottom = pu8_src_top + i32_tmp_offset;
2534
2535 /* Weighted combination */
2536 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) +
2537 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) +
2538 (pu8_src_bottom[0]*(16-u32_x_frac) +
2539 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8);
2540
2541 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
2542
2543 /* Update horizontal accumulator */
2544 u32_x_accum += pC->u32_x_inc[i];
2545 }
2546
2547 }
2548
2549 pu8_data_out += pOut[i].u_stride - pOut[i].u_width;
2550
2551 /* Update vertical accumulator */
2552 pC->u32_y_accum[i] += pC->u32_y_inc[i];
2553 if (pC->u32_y_accum[i]>>16)
2554 {
2555 pu8_data_in = pu8_data_in + (pC->u32_y_accum[i] >> 16) * i32_tmp_offset;
2556 pC->u32_y_accum[i] &= 0xffff;
2557 }
2558 }
2559 }
2560 /** +-90° rotation */
2561 else
2562 {
2563 pu8_data_in_org = pu8_data_in;
2564
2565 /**< Loop on each output row */
2566 for(j=0;j<pOut[i].u_height;j++)
2567 {
2568 /* horizontal weight factor */
2569 u32_x_frac = (pC->u32_x_accum[i]>>12)&15;
2570
2571 /* Reinit accumulator */
2572 u32_y_accum = pC->u32_y_accum_start[i];
2573
2574 if(M4OSA_TRUE == pC->m_bFlipX)
2575 {
2576
2577 /**< Loop on each output pixel in a row */
2578 for(k=0;k<pOut[i].u_width;k++)
2579 {
2580
2581 u32_y_frac = (u32_y_accum >> 12)&15; /* Vertical weight factor */
2582
2583
2584 pu8_src_top = (pu8_data_in - (pC->u32_x_accum[i] >> 16)) - 1;
2585
2586 pu8_src_bottom = pu8_src_top + i32_tmp_offset;
2587
2588 /* Weighted combination */
2589 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[1]*(16-u32_x_frac) +
2590 pu8_src_top[0]*u32_x_frac)*(16-u32_y_frac) +
2591 (pu8_src_bottom[1]*(16-u32_x_frac) +
2592 pu8_src_bottom[0]*u32_x_frac)*u32_y_frac )>>8);
2593
2594 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
2595
2596 /* Update vertical accumulator */
2597 u32_y_accum += pC->u32_y_inc[i];
2598 if (u32_y_accum>>16)
2599 {
2600 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * i32_tmp_offset;
2601 u32_y_accum &= 0xffff;
2602 }
2603
2604 }
2605 }
2606 else
2607 {
2608 /**< Loop on each output pixel in a row */
2609 for(k=0;k<pOut[i].u_width;k++)
2610 {
2611
2612 u32_y_frac = (u32_y_accum >> 12)&15; /* Vertical weight factor */
2613
2614 pu8_src_top = pu8_data_in + (pC->u32_x_accum[i] >> 16);
2615
2616 pu8_src_bottom = pu8_src_top + i32_tmp_offset;
2617
2618 /* Weighted combination */
2619 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) +
2620 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) +
2621 (pu8_src_bottom[0]*(16-u32_x_frac) +
2622 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8);
2623
2624 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
2625
2626 /* Update vertical accumulator */
2627 u32_y_accum += pC->u32_y_inc[i];
2628 if (u32_y_accum>>16)
2629 {
2630 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * i32_tmp_offset;
2631 u32_y_accum &= 0xffff;
2632 }
2633 }
2634 }
2635 pu8_data_out += pOut[i].u_stride - pOut[i].u_width;
2636
2637 /* Update horizontal accumulator */
2638 pC->u32_x_accum[i] += pC->u32_x_inc[i];
2639
2640 pu8_data_in = pu8_data_in_org;
2641 }
2642
2643 }
2644 }/** 3 != i */
2645 else
2646 {
2647 /**No +-90° rotation */
2648 if(M4OSA_FALSE == pC->m_bRevertXY)
2649 {
2650
2651 /**< Loop on each row */
2652 for(j=0;j<pOut[i].u_height;j++)
2653 {
2654 /* Vertical weight factor */
2655 u32_y_frac = (pC->u32_y_accum[i]>>12)&15;
2656
2657 /* Reinit horizontal weight factor */
2658 u32_x_accum = pC->u32_x_accum_start[i];
2659
2660
2661
2662 if(M4OSA_TRUE == pC->m_bFlipX)
2663 {
2664
2665 /**< Loop on each output pixel in a row */
2666 for(k=0;k<pOut[i].u_width;k++)
2667 {
2668
2669 u32_x_frac = (u32_x_accum >> 12)&15; /* Fraction of Horizontal weight factor */
2670
2671 pu8_src_top = (pu8_data_in - (u32_x_accum >> 16)) -1 ;
2672
2673 pu8_src_bottom = pu8_src_top + i32_tmp_offset;
2674
2675 /* Weighted combination */
2676 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[1]*(16-u32_x_frac) +
2677 pu8_src_top[0]*u32_x_frac)*(16-u32_y_frac) +
2678 (pu8_src_bottom[1]*(16-u32_x_frac) +
2679 pu8_src_bottom[0]*u32_x_frac)*u32_y_frac )>>8);
2680
2681 u32_temp_value= (u32_temp_value >> 7)*0xff;
2682
2683 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
2684
2685 /* Update horizontal accumulator */
2686 u32_x_accum += pC->u32_x_inc[i];
2687 }
2688 }
2689
2690 else
2691 {
2692 /**< Loop on each output pixel in a row */
2693 for(k=0;k<pOut[i].u_width;k++)
2694 {
2695 u32_x_frac = (u32_x_accum >> 12)&15; /* Fraction of Horizontal weight factor */
2696
2697 pu8_src_top = pu8_data_in + (u32_x_accum >> 16);
2698
2699 pu8_src_bottom = pu8_src_top + i32_tmp_offset;
2700
2701 /* Weighted combination */
2702 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) +
2703 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) +
2704 (pu8_src_bottom[0]*(16-u32_x_frac) +
2705 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8);
2706
2707 u32_temp_value= (u32_temp_value >> 7)*0xff;
2708
2709 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
2710
2711 /* Update horizontal accumulator */
2712 u32_x_accum += pC->u32_x_inc[i];
2713 }
2714
2715 }
2716
2717 pu8_data_out += pOut[i].u_stride - pOut[i].u_width;
2718
2719 /* Update vertical accumulator */
2720 pC->u32_y_accum[i] += pC->u32_y_inc[i];
2721 if (pC->u32_y_accum[i]>>16)
2722 {
2723 pu8_data_in = pu8_data_in + (pC->u32_y_accum[i] >> 16) * i32_tmp_offset;
2724 pC->u32_y_accum[i] &= 0xffff;
2725 }
2726 }
2727
2728 } /**< M4OSA_FALSE == pC->m_bRevertXY */
2729 /** +-90° rotation */
2730 else
2731 {
2732 pu8_data_in_org = pu8_data_in;
2733
2734 /**< Loop on each output row */
2735 for(j=0;j<pOut[i].u_height;j++)
2736 {
2737 /* horizontal weight factor */
2738 u32_x_frac = (pC->u32_x_accum[i]>>12)&15;
2739
2740 /* Reinit accumulator */
2741 u32_y_accum = pC->u32_y_accum_start[i];
2742
2743 if(M4OSA_TRUE == pC->m_bFlipX)
2744 {
2745
2746 /**< Loop on each output pixel in a row */
2747 for(k=0;k<pOut[i].u_width;k++)
2748 {
2749
2750 u32_y_frac = (u32_y_accum >> 12)&15; /* Vertical weight factor */
2751
2752
2753 pu8_src_top = (pu8_data_in - (pC->u32_x_accum[i] >> 16)) - 1;
2754
2755 pu8_src_bottom = pu8_src_top + i32_tmp_offset;
2756
2757 /* Weighted combination */
2758 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[1]*(16-u32_x_frac) +
2759 pu8_src_top[0]*u32_x_frac)*(16-u32_y_frac) +
2760 (pu8_src_bottom[1]*(16-u32_x_frac) +
2761 pu8_src_bottom[0]*u32_x_frac)*u32_y_frac )>>8);
2762
2763 u32_temp_value= (u32_temp_value >> 7)*0xff;
2764
2765 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
2766
2767 /* Update vertical accumulator */
2768 u32_y_accum += pC->u32_y_inc[i];
2769 if (u32_y_accum>>16)
2770 {
2771 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * i32_tmp_offset;
2772 u32_y_accum &= 0xffff;
2773 }
2774
2775 }
2776 }
2777 else
2778 {
2779 /**< Loop on each output pixel in a row */
2780 for(k=0;k<pOut[i].u_width;k++)
2781 {
2782
2783 u32_y_frac = (u32_y_accum >> 12)&15; /* Vertical weight factor */
2784
2785 pu8_src_top = pu8_data_in + (pC->u32_x_accum[i] >> 16);
2786
2787 pu8_src_bottom = pu8_src_top + i32_tmp_offset;
2788
2789 /* Weighted combination */
2790 u32_temp_value = (M4VIFI_UInt8)(((pu8_src_top[0]*(16-u32_x_frac) +
2791 pu8_src_top[1]*u32_x_frac)*(16-u32_y_frac) +
2792 (pu8_src_bottom[0]*(16-u32_x_frac) +
2793 pu8_src_bottom[1]*u32_x_frac)*u32_y_frac )>>8);
2794
2795 u32_temp_value= (u32_temp_value >> 7)*0xff;
2796
2797 *pu8_data_out++ = (M4VIFI_UInt8)u32_temp_value;
2798
2799 /* Update vertical accumulator */
2800 u32_y_accum += pC->u32_y_inc[i];
2801 if (u32_y_accum>>16)
2802 {
2803 pu8_data_in = pu8_data_in + (u32_y_accum >> 16) * i32_tmp_offset;
2804 u32_y_accum &= 0xffff;
2805 }
2806 }
2807 }
2808 pu8_data_out += pOut[i].u_stride - pOut[i].u_width;
2809
2810 /* Update horizontal accumulator */
2811 pC->u32_x_accum[i] += pC->u32_x_inc[i];
2812
2813 pu8_data_in = pu8_data_in_org;
2814
2815 }
2816 } /**< M4OSA_TRUE == pC->m_bRevertXY */
2817 }/** 3 == i */
2818 }
2819 /**< In case of stripe mode, save current input pointer */
2820 if(M4OSA_TRUE == pC->m_params.m_bOutputStripe)
2821 {
2822 pC->pu8_data_in[i] = pu8_data_in;
2823 }
2824 }
2825
2826 /**< Update number of processed rows, reset it if we have finished with the whole processing */
2827 pC->m_procRows += pOut[0].u_height;
2828 if(M4OSA_FALSE == pC->m_bRevertXY)
2829 {
2830 if(pC->m_params.m_outputSize.m_height <= pC->m_procRows) pC->m_procRows = 0;
2831 }
2832 else
2833 {
2834 if(pC->m_params.m_outputSize.m_width <= pC->m_procRows) pC->m_procRows = 0;
2835 }
2836
2837 return M4NO_ERROR ;
2838
2839 }
2840 /*+ Handle the image files here */
2841
2842 /**
2843 ******************************************************************************
2844 * M4OSA_ERR LvGetImageThumbNail(M4OSA_UChar *fileName, M4OSA_Void **pBuffer)
2845 * @brief This function gives YUV420 buffer of a given image file (in argb888 format)
2846 * @Note: The caller of the function is responsible to free the yuv buffer allocated
2847 * @param fileName: (IN) Path to the filename of the image argb data
2848 * @param height: (IN) Height of the image
2849 * @param width: (OUT) pBuffer pointer to the address where the yuv data address needs to be returned.
2850 * @return M4NO_ERROR: there is no error
2851 * @return M4ERR_ALLOC: No more memory space to add a new effect.
2852 * @return M4ERR_FILE_NOT_FOUND: if the file passed does not exists.
2853 ******************************************************************************
2854 */
LvGetImageThumbNail(const char * fileName,M4OSA_UInt32 height,M4OSA_UInt32 width,M4OSA_Void ** pBuffer)2855 M4OSA_ERR LvGetImageThumbNail(const char *fileName, M4OSA_UInt32 height, M4OSA_UInt32 width, M4OSA_Void **pBuffer) {
2856
2857 M4VIFI_ImagePlane rgbPlane, *yuvPlane;
2858 M4OSA_UInt32 frameSize_argb = (width * height * 4); // argb data
2859 M4OSA_Context lImageFileFp = M4OSA_NULL;
2860 M4OSA_ERR err = M4NO_ERROR;
2861
2862 M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_32bitAlignedMalloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data");
2863 if(pTmpData == M4OSA_NULL) {
2864 ALOGE("Failed to allocate memory for Image clip");
2865 return M4ERR_ALLOC;
2866 }
2867
2868 /** Read the argb data from the passed file. */
2869 M4OSA_ERR lerr = M4OSA_fileReadOpen(&lImageFileFp, (M4OSA_Void *) fileName, M4OSA_kFileRead);
2870
2871 if((lerr != M4NO_ERROR) || (lImageFileFp == M4OSA_NULL))
2872 {
2873 ALOGE("LVPreviewController: Can not open the file ");
2874 free(pTmpData);
2875 return M4ERR_FILE_NOT_FOUND;
2876 }
2877 lerr = M4OSA_fileReadData(lImageFileFp, (M4OSA_MemAddr8)pTmpData, &frameSize_argb);
2878 if(lerr != M4NO_ERROR)
2879 {
2880 ALOGE("LVPreviewController: can not read the data ");
2881 M4OSA_fileReadClose(lImageFileFp);
2882 free(pTmpData);
2883 return lerr;
2884 }
2885 M4OSA_fileReadClose(lImageFileFp);
2886
2887 M4OSA_UInt32 frameSize = (width * height * 3); //Size of YUV420 data.
2888 rgbPlane.pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(frameSize, M4VS, (M4OSA_Char*)"Image clip RGB888 data");
2889 if(rgbPlane.pac_data == M4OSA_NULL)
2890 {
2891 ALOGE("Failed to allocate memory for Image clip");
2892 free(pTmpData);
2893 return M4ERR_ALLOC;
2894 }
2895
2896 /** Remove the alpha channel */
2897 for (M4OSA_UInt32 i=0, j = 0; i < frameSize_argb; i++) {
2898 if ((i % 4) == 0) continue;
2899 rgbPlane.pac_data[j] = pTmpData[i];
2900 j++;
2901 }
2902 free(pTmpData);
2903
2904 #ifdef FILE_DUMP
2905 FILE *fp = fopen("/sdcard/Input/test_rgb.raw", "wb");
2906 if(fp == NULL)
2907 ALOGE("Errors file can not be created");
2908 else {
2909 fwrite(rgbPlane.pac_data, frameSize, 1, fp);
2910 fclose(fp);
2911 }
2912 #endif
2913 rgbPlane.u_height = height;
2914 rgbPlane.u_width = width;
2915 rgbPlane.u_stride = width*3;
2916 rgbPlane.u_topleft = 0;
2917
2918 yuvPlane = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane),
2919 M4VS, (M4OSA_Char*)"M4xVSS_internalConvertRGBtoYUV: Output plane YUV");
2920 yuvPlane[0].u_height = height;
2921 yuvPlane[0].u_width = width;
2922 yuvPlane[0].u_stride = width;
2923 yuvPlane[0].u_topleft = 0;
2924 yuvPlane[0].pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(yuvPlane[0].u_height * yuvPlane[0].u_width * 1.5, M4VS, (M4OSA_Char*)"imageClip YUV data");
2925
2926 yuvPlane[1].u_height = yuvPlane[0].u_height >>1;
2927 yuvPlane[1].u_width = yuvPlane[0].u_width >> 1;
2928 yuvPlane[1].u_stride = yuvPlane[1].u_width;
2929 yuvPlane[1].u_topleft = 0;
2930 yuvPlane[1].pac_data = (M4VIFI_UInt8*)(yuvPlane[0].pac_data + yuvPlane[0].u_height * yuvPlane[0].u_width);
2931
2932 yuvPlane[2].u_height = yuvPlane[0].u_height >>1;
2933 yuvPlane[2].u_width = yuvPlane[0].u_width >> 1;
2934 yuvPlane[2].u_stride = yuvPlane[2].u_width;
2935 yuvPlane[2].u_topleft = 0;
2936 yuvPlane[2].pac_data = (M4VIFI_UInt8*)(yuvPlane[1].pac_data + yuvPlane[1].u_height * yuvPlane[1].u_width);
2937
2938
2939 err = M4VIFI_RGB888toYUV420(M4OSA_NULL, &rgbPlane, yuvPlane);
2940 //err = M4VIFI_BGR888toYUV420(M4OSA_NULL, &rgbPlane, yuvPlane);
2941 if(err != M4NO_ERROR)
2942 {
2943 ALOGE("error when converting from RGB to YUV: 0x%x\n", (unsigned int)err);
2944 }
2945 free(rgbPlane.pac_data);
2946
2947 //ALOGE("RGB to YUV done");
2948 #ifdef FILE_DUMP
2949 FILE *fp1 = fopen("/sdcard/Input/test_yuv.raw", "wb");
2950 if(fp1 == NULL)
2951 ALOGE("Errors file can not be created");
2952 else {
2953 fwrite(yuvPlane[0].pac_data, yuvPlane[0].u_height * yuvPlane[0].u_width * 1.5, 1, fp1);
2954 fclose(fp1);
2955 }
2956 #endif
2957 *pBuffer = yuvPlane[0].pac_data;
2958 free(yuvPlane);
2959 return M4NO_ERROR;
2960
2961 }
prepareYUV420ImagePlane(M4VIFI_ImagePlane * plane,M4OSA_UInt32 width,M4OSA_UInt32 height,M4VIFI_UInt8 * buffer,M4OSA_UInt32 reportedWidth,M4OSA_UInt32 reportedHeight)2962 M4OSA_Void prepareYUV420ImagePlane(M4VIFI_ImagePlane *plane,
2963 M4OSA_UInt32 width, M4OSA_UInt32 height, M4VIFI_UInt8 *buffer,
2964 M4OSA_UInt32 reportedWidth, M4OSA_UInt32 reportedHeight) {
2965
2966 //Y plane
2967 plane[0].u_width = width;
2968 plane[0].u_height = height;
2969 plane[0].u_stride = reportedWidth;
2970 plane[0].u_topleft = 0;
2971 plane[0].pac_data = buffer;
2972
2973 // U plane
2974 plane[1].u_width = width/2;
2975 plane[1].u_height = height/2;
2976 plane[1].u_stride = reportedWidth >> 1;
2977 plane[1].u_topleft = 0;
2978 plane[1].pac_data = buffer+(reportedWidth*reportedHeight);
2979
2980 // V Plane
2981 plane[2].u_width = width/2;
2982 plane[2].u_height = height/2;
2983 plane[2].u_stride = reportedWidth >> 1;
2984 plane[2].u_topleft = 0;
2985 plane[2].pac_data = plane[1].pac_data + ((reportedWidth/2)*(reportedHeight/2));
2986 }
2987
prepareYV12ImagePlane(M4VIFI_ImagePlane * plane,M4OSA_UInt32 width,M4OSA_UInt32 height,M4OSA_UInt32 stride,M4VIFI_UInt8 * buffer)2988 M4OSA_Void prepareYV12ImagePlane(M4VIFI_ImagePlane *plane,
2989 M4OSA_UInt32 width, M4OSA_UInt32 height, M4OSA_UInt32 stride,
2990 M4VIFI_UInt8 *buffer) {
2991
2992 //Y plane
2993 plane[0].u_width = width;
2994 plane[0].u_height = height;
2995 plane[0].u_stride = stride;
2996 plane[0].u_topleft = 0;
2997 plane[0].pac_data = buffer;
2998
2999 // U plane
3000 plane[1].u_width = width/2;
3001 plane[1].u_height = height/2;
3002 plane[1].u_stride = android::PreviewRenderer::ALIGN(plane[0].u_stride/2, 16);
3003 plane[1].u_topleft = 0;
3004 plane[1].pac_data = (buffer
3005 + plane[0].u_height * plane[0].u_stride
3006 + (plane[0].u_height/2) * android::PreviewRenderer::ALIGN((
3007 plane[0].u_stride / 2), 16));
3008
3009 // V Plane
3010 plane[2].u_width = width/2;
3011 plane[2].u_height = height/2;
3012 plane[2].u_stride = android::PreviewRenderer::ALIGN(plane[0].u_stride/2, 16);
3013 plane[2].u_topleft = 0;
3014 plane[2].pac_data = (buffer +
3015 plane[0].u_height * android::PreviewRenderer::ALIGN(plane[0].u_stride, 16));
3016
3017
3018 }
3019
swapImagePlanes(M4VIFI_ImagePlane * planeIn,M4VIFI_ImagePlane * planeOut,M4VIFI_UInt8 * buffer1,M4VIFI_UInt8 * buffer2)3020 M4OSA_Void swapImagePlanes(
3021 M4VIFI_ImagePlane *planeIn, M4VIFI_ImagePlane *planeOut,
3022 M4VIFI_UInt8 *buffer1, M4VIFI_UInt8 *buffer2) {
3023
3024 planeIn[0].u_height = planeOut[0].u_height;
3025 planeIn[0].u_width = planeOut[0].u_width;
3026 planeIn[0].u_stride = planeOut[0].u_stride;
3027 planeIn[0].u_topleft = planeOut[0].u_topleft;
3028 planeIn[0].pac_data = planeOut[0].pac_data;
3029
3030 /**
3031 * U plane */
3032 planeIn[1].u_width = planeOut[1].u_width;
3033 planeIn[1].u_height = planeOut[1].u_height;
3034 planeIn[1].u_stride = planeOut[1].u_stride;
3035 planeIn[1].u_topleft = planeOut[1].u_topleft;
3036 planeIn[1].pac_data = planeOut[1].pac_data;
3037 /**
3038 * V Plane */
3039 planeIn[2].u_width = planeOut[2].u_width;
3040 planeIn[2].u_height = planeOut[2].u_height;
3041 planeIn[2].u_stride = planeOut[2].u_stride;
3042 planeIn[2].u_topleft = planeOut[2].u_topleft;
3043 planeIn[2].pac_data = planeOut[2].pac_data;
3044
3045 if(planeOut[0].pac_data == (M4VIFI_UInt8*)buffer1)
3046 {
3047 planeOut[0].pac_data = (M4VIFI_UInt8*)buffer2;
3048 planeOut[1].pac_data = (M4VIFI_UInt8*)(buffer2 +
3049 planeOut[0].u_width*planeOut[0].u_height);
3050
3051 planeOut[2].pac_data = (M4VIFI_UInt8*)(buffer2 +
3052 planeOut[0].u_width*planeOut[0].u_height +
3053 planeOut[1].u_width*planeOut[1].u_height);
3054 }
3055 else
3056 {
3057 planeOut[0].pac_data = (M4VIFI_UInt8*)buffer1;
3058 planeOut[1].pac_data = (M4VIFI_UInt8*)(buffer1 +
3059 planeOut[0].u_width*planeOut[0].u_height);
3060
3061 planeOut[2].pac_data = (M4VIFI_UInt8*)(buffer1 +
3062 planeOut[0].u_width*planeOut[0].u_height +
3063 planeOut[1].u_width*planeOut[1].u_height);
3064 }
3065
3066 }
3067
computePercentageDone(M4OSA_UInt32 ctsMs,M4OSA_UInt32 effectStartTimeMs,M4OSA_UInt32 effectDuration,M4OSA_Double * percentageDone)3068 M4OSA_Void computePercentageDone(
3069 M4OSA_UInt32 ctsMs, M4OSA_UInt32 effectStartTimeMs,
3070 M4OSA_UInt32 effectDuration, M4OSA_Double *percentageDone) {
3071
3072 M4OSA_Double videoEffectTime =0;
3073
3074 // Compute how far from the beginning of the effect we are, in clip-base time.
3075 videoEffectTime =
3076 (M4OSA_Int32)(ctsMs+ 0.5) - effectStartTimeMs;
3077
3078 // To calculate %, substract timeIncrement
3079 // because effect should finish on the last frame
3080 // which is from CTS = (eof-timeIncrement) till CTS = eof
3081 *percentageDone =
3082 videoEffectTime / ((M4OSA_Float)effectDuration);
3083
3084 if(*percentageDone < 0.0) *percentageDone = 0.0;
3085 if(*percentageDone > 1.0) *percentageDone = 1.0;
3086
3087 }
3088
3089
computeProgressForVideoEffect(M4OSA_UInt32 ctsMs,M4OSA_UInt32 effectStartTimeMs,M4OSA_UInt32 effectDuration,M4VSS3GPP_ExternalProgress * extProgress)3090 M4OSA_Void computeProgressForVideoEffect(
3091 M4OSA_UInt32 ctsMs, M4OSA_UInt32 effectStartTimeMs,
3092 M4OSA_UInt32 effectDuration, M4VSS3GPP_ExternalProgress* extProgress) {
3093
3094 M4OSA_Double percentageDone =0;
3095
3096 computePercentageDone(ctsMs, effectStartTimeMs, effectDuration, &percentageDone);
3097
3098 extProgress->uiProgress = (M4OSA_UInt32)( percentageDone * 1000 );
3099 extProgress->uiOutputTime = (M4OSA_UInt32)(ctsMs + 0.5);
3100 extProgress->uiClipTime = extProgress->uiOutputTime;
3101 extProgress->bIsLast = M4OSA_FALSE;
3102 }
3103
prepareFramingStructure(M4xVSS_FramingStruct * framingCtx,M4VSS3GPP_EffectSettings * effectsSettings,M4OSA_UInt32 index,M4VIFI_UInt8 * overlayRGB,M4VIFI_UInt8 * overlayYUV)3104 M4OSA_ERR prepareFramingStructure(
3105 M4xVSS_FramingStruct* framingCtx,
3106 M4VSS3GPP_EffectSettings* effectsSettings, M4OSA_UInt32 index,
3107 M4VIFI_UInt8* overlayRGB, M4VIFI_UInt8* overlayYUV) {
3108
3109 M4OSA_ERR err = M4NO_ERROR;
3110
3111 // Force input RGB buffer to even size to avoid errors in YUV conversion
3112 framingCtx->FramingRgb = effectsSettings[index].xVSS.pFramingBuffer;
3113 framingCtx->FramingRgb->u_width = framingCtx->FramingRgb->u_width & ~1;
3114 framingCtx->FramingRgb->u_height = framingCtx->FramingRgb->u_height & ~1;
3115 framingCtx->FramingYuv = NULL;
3116
3117 framingCtx->duration = effectsSettings[index].uiDuration;
3118 framingCtx->topleft_x = effectsSettings[index].xVSS.topleft_x;
3119 framingCtx->topleft_y = effectsSettings[index].xVSS.topleft_y;
3120 framingCtx->pCurrent = framingCtx;
3121 framingCtx->pNext = framingCtx;
3122 framingCtx->previousClipTime = -1;
3123
3124 framingCtx->alphaBlendingStruct =
3125 (M4xVSS_internalEffectsAlphaBlending*)M4OSA_32bitAlignedMalloc(
3126 sizeof(M4xVSS_internalEffectsAlphaBlending), M4VS,
3127 (M4OSA_Char*)"alpha blending struct");
3128
3129 framingCtx->alphaBlendingStruct->m_fadeInTime =
3130 effectsSettings[index].xVSS.uialphaBlendingFadeInTime;
3131
3132 framingCtx->alphaBlendingStruct->m_fadeOutTime =
3133 effectsSettings[index].xVSS.uialphaBlendingFadeOutTime;
3134
3135 framingCtx->alphaBlendingStruct->m_end =
3136 effectsSettings[index].xVSS.uialphaBlendingEnd;
3137
3138 framingCtx->alphaBlendingStruct->m_middle =
3139 effectsSettings[index].xVSS.uialphaBlendingMiddle;
3140
3141 framingCtx->alphaBlendingStruct->m_start =
3142 effectsSettings[index].xVSS.uialphaBlendingStart;
3143
3144 // If new Overlay buffer, convert from RGB to YUV
3145 if((overlayRGB != framingCtx->FramingRgb->pac_data) || (overlayYUV == NULL) ) {
3146
3147 // If YUV buffer exists, delete it
3148 if(overlayYUV != NULL) {
3149 free(overlayYUV);
3150 overlayYUV = NULL;
3151 }
3152 if(effectsSettings[index].xVSS.rgbType == M4VSS3GPP_kRGB565) {
3153 // Input RGB565 plane is provided,
3154 // let's convert it to YUV420, and update framing structure
3155 err = M4xVSS_internalConvertRGBtoYUV(framingCtx);
3156 }
3157 else if(effectsSettings[index].xVSS.rgbType == M4VSS3GPP_kRGB888) {
3158 // Input RGB888 plane is provided,
3159 // let's convert it to YUV420, and update framing structure
3160 err = M4xVSS_internalConvertRGB888toYUV(framingCtx);
3161 }
3162 else {
3163 err = M4ERR_PARAMETER;
3164 }
3165 overlayYUV = framingCtx->FramingYuv[0].pac_data;
3166 overlayRGB = framingCtx->FramingRgb->pac_data;
3167
3168 }
3169 else {
3170 ALOGV(" YUV buffer reuse");
3171 framingCtx->FramingYuv = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(
3172 3*sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"YUV");
3173
3174 if(framingCtx->FramingYuv == M4OSA_NULL) {
3175 return M4ERR_ALLOC;
3176 }
3177
3178 framingCtx->FramingYuv[0].u_width = framingCtx->FramingRgb->u_width;
3179 framingCtx->FramingYuv[0].u_height = framingCtx->FramingRgb->u_height;
3180 framingCtx->FramingYuv[0].u_topleft = 0;
3181 framingCtx->FramingYuv[0].u_stride = framingCtx->FramingRgb->u_width;
3182 framingCtx->FramingYuv[0].pac_data = (M4VIFI_UInt8*)overlayYUV;
3183
3184 framingCtx->FramingYuv[1].u_width = (framingCtx->FramingRgb->u_width)>>1;
3185 framingCtx->FramingYuv[1].u_height = (framingCtx->FramingRgb->u_height)>>1;
3186 framingCtx->FramingYuv[1].u_topleft = 0;
3187 framingCtx->FramingYuv[1].u_stride = (framingCtx->FramingRgb->u_width)>>1;
3188 framingCtx->FramingYuv[1].pac_data = framingCtx->FramingYuv[0].pac_data +
3189 framingCtx->FramingYuv[0].u_width * framingCtx->FramingYuv[0].u_height;
3190
3191 framingCtx->FramingYuv[2].u_width = (framingCtx->FramingRgb->u_width)>>1;
3192 framingCtx->FramingYuv[2].u_height = (framingCtx->FramingRgb->u_height)>>1;
3193 framingCtx->FramingYuv[2].u_topleft = 0;
3194 framingCtx->FramingYuv[2].u_stride = (framingCtx->FramingRgb->u_width)>>1;
3195 framingCtx->FramingYuv[2].pac_data = framingCtx->FramingYuv[1].pac_data +
3196 framingCtx->FramingYuv[1].u_width * framingCtx->FramingYuv[1].u_height;
3197
3198 framingCtx->duration = 0;
3199 framingCtx->previousClipTime = -1;
3200 framingCtx->previewOffsetClipTime = -1;
3201
3202 }
3203 return err;
3204 }
3205
applyColorEffect(M4xVSS_VideoEffectType colorEffect,M4VIFI_ImagePlane * planeIn,M4VIFI_ImagePlane * planeOut,M4VIFI_UInt8 * buffer1,M4VIFI_UInt8 * buffer2,M4OSA_UInt16 rgbColorData)3206 M4OSA_ERR applyColorEffect(M4xVSS_VideoEffectType colorEffect,
3207 M4VIFI_ImagePlane *planeIn, M4VIFI_ImagePlane *planeOut,
3208 M4VIFI_UInt8 *buffer1, M4VIFI_UInt8 *buffer2, M4OSA_UInt16 rgbColorData) {
3209
3210 M4xVSS_ColorStruct colorContext;
3211 M4OSA_ERR err = M4NO_ERROR;
3212
3213 colorContext.colorEffectType = colorEffect;
3214 colorContext.rgb16ColorData = rgbColorData;
3215
3216 err = M4VSS3GPP_externalVideoEffectColor(
3217 (M4OSA_Void *)&colorContext, planeIn, planeOut, NULL,
3218 colorEffect);
3219
3220 if(err != M4NO_ERROR) {
3221 ALOGV("M4VSS3GPP_externalVideoEffectColor(%d) error %d",
3222 colorEffect, err);
3223
3224 if(NULL != buffer1) {
3225 free(buffer1);
3226 buffer1 = NULL;
3227 }
3228 if(NULL != buffer2) {
3229 free(buffer2);
3230 buffer2 = NULL;
3231 }
3232 return err;
3233 }
3234
3235 // The out plane now becomes the in plane for adding other effects
3236 swapImagePlanes(planeIn, planeOut, buffer1, buffer2);
3237
3238 return err;
3239 }
3240
applyLumaEffect(M4VSS3GPP_VideoEffectType videoEffect,M4VIFI_ImagePlane * planeIn,M4VIFI_ImagePlane * planeOut,M4VIFI_UInt8 * buffer1,M4VIFI_UInt8 * buffer2,M4OSA_Int32 lum_factor)3241 M4OSA_ERR applyLumaEffect(M4VSS3GPP_VideoEffectType videoEffect,
3242 M4VIFI_ImagePlane *planeIn, M4VIFI_ImagePlane *planeOut,
3243 M4VIFI_UInt8 *buffer1, M4VIFI_UInt8 *buffer2, M4OSA_Int32 lum_factor) {
3244
3245 M4OSA_ERR err = M4NO_ERROR;
3246
3247 err = M4VFL_modifyLumaWithScale(
3248 (M4ViComImagePlane*)planeIn,(M4ViComImagePlane*)planeOut,
3249 lum_factor, NULL);
3250
3251 if(err != M4NO_ERROR) {
3252 ALOGE("M4VFL_modifyLumaWithScale(%d) error %d", videoEffect, (int)err);
3253
3254 if(NULL != buffer1) {
3255 free(buffer1);
3256 buffer1= NULL;
3257 }
3258 if(NULL != buffer2) {
3259 free(buffer2);
3260 buffer2= NULL;
3261 }
3262 return err;
3263 }
3264
3265 // The out plane now becomes the in plane for adding other effects
3266 swapImagePlanes(planeIn, planeOut,(M4VIFI_UInt8 *)buffer1,
3267 (M4VIFI_UInt8 *)buffer2);
3268
3269 return err;
3270 }
3271
applyEffectsAndRenderingMode(vePostProcessParams * params,M4OSA_UInt32 reportedWidth,M4OSA_UInt32 reportedHeight)3272 M4OSA_ERR applyEffectsAndRenderingMode(vePostProcessParams *params,
3273 M4OSA_UInt32 reportedWidth, M4OSA_UInt32 reportedHeight) {
3274
3275 M4OSA_ERR err = M4NO_ERROR;
3276 M4VIFI_ImagePlane planeIn[3], planeOut[3];
3277 M4VIFI_UInt8 *finalOutputBuffer = NULL, *tempOutputBuffer= NULL;
3278 M4OSA_Double percentageDone =0;
3279 M4OSA_Int32 lum_factor;
3280 M4VSS3GPP_ExternalProgress extProgress;
3281 M4xVSS_FiftiesStruct fiftiesCtx;
3282 M4OSA_UInt32 frameSize = 0, i=0;
3283
3284 frameSize = (params->videoWidth*params->videoHeight*3) >> 1;
3285
3286 finalOutputBuffer = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(frameSize, M4VS,
3287 (M4OSA_Char*)("lvpp finalOutputBuffer"));
3288
3289 if(finalOutputBuffer == NULL) {
3290 ALOGE("applyEffectsAndRenderingMode: malloc error");
3291 return M4ERR_ALLOC;
3292 }
3293
3294 // allocate the tempOutputBuffer
3295 tempOutputBuffer = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(
3296 ((params->videoHeight*params->videoWidth*3)>>1), M4VS, (M4OSA_Char*)("lvpp colorBuffer"));
3297
3298 if(tempOutputBuffer == NULL) {
3299 ALOGE("applyEffectsAndRenderingMode: malloc error tempOutputBuffer");
3300 if(NULL != finalOutputBuffer) {
3301 free(finalOutputBuffer);
3302 finalOutputBuffer = NULL;
3303 }
3304 return M4ERR_ALLOC;
3305 }
3306
3307 // Initialize the In plane
3308 prepareYUV420ImagePlane(planeIn, params->videoWidth, params->videoHeight,
3309 params->vidBuffer, reportedWidth, reportedHeight);
3310
3311 // Initialize the Out plane
3312 prepareYUV420ImagePlane(planeOut, params->videoWidth, params->videoHeight,
3313 (M4VIFI_UInt8 *)tempOutputBuffer, params->videoWidth, params->videoHeight);
3314
3315 // The planeIn contains the YUV420 input data to postprocessing node
3316 // and planeOut will contain the YUV420 data with effect
3317 // In each successive if condition, apply filter to successive
3318 // output YUV frame so that concurrent effects are both applied
3319
3320 if(params->currentVideoEffect & VIDEO_EFFECT_BLACKANDWHITE) {
3321 err = applyColorEffect(M4xVSS_kVideoEffectType_BlackAndWhite,
3322 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3323 (M4VIFI_UInt8 *)tempOutputBuffer, 0);
3324 if(err != M4NO_ERROR) {
3325 return err;
3326 }
3327 }
3328
3329 if(params->currentVideoEffect & VIDEO_EFFECT_PINK) {
3330 err = applyColorEffect(M4xVSS_kVideoEffectType_Pink,
3331 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3332 (M4VIFI_UInt8 *)tempOutputBuffer, 0);
3333 if(err != M4NO_ERROR) {
3334 return err;
3335 }
3336 }
3337
3338 if(params->currentVideoEffect & VIDEO_EFFECT_GREEN) {
3339 err = applyColorEffect(M4xVSS_kVideoEffectType_Green,
3340 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3341 (M4VIFI_UInt8 *)tempOutputBuffer, 0);
3342 if(err != M4NO_ERROR) {
3343 return err;
3344 }
3345 }
3346
3347 if(params->currentVideoEffect & VIDEO_EFFECT_SEPIA) {
3348 err = applyColorEffect(M4xVSS_kVideoEffectType_Sepia,
3349 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3350 (M4VIFI_UInt8 *)tempOutputBuffer, 0);
3351 if(err != M4NO_ERROR) {
3352 return err;
3353 }
3354 }
3355
3356 if(params->currentVideoEffect & VIDEO_EFFECT_NEGATIVE) {
3357 err = applyColorEffect(M4xVSS_kVideoEffectType_Negative,
3358 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3359 (M4VIFI_UInt8 *)tempOutputBuffer, 0);
3360 if(err != M4NO_ERROR) {
3361 return err;
3362 }
3363 }
3364
3365 if(params->currentVideoEffect & VIDEO_EFFECT_GRADIENT) {
3366 // find the effect in effectSettings array
3367 for(i=0;i<params->numberEffects;i++) {
3368 if(params->effectsSettings[i].VideoEffectType ==
3369 (M4VSS3GPP_VideoEffectType)M4xVSS_kVideoEffectType_Gradient)
3370 break;
3371 }
3372 err = applyColorEffect(M4xVSS_kVideoEffectType_Gradient,
3373 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3374 (M4VIFI_UInt8 *)tempOutputBuffer,
3375 params->effectsSettings[i].xVSS.uiRgb16InputColor);
3376 if(err != M4NO_ERROR) {
3377 return err;
3378 }
3379 }
3380
3381 if(params->currentVideoEffect & VIDEO_EFFECT_COLOR_RGB16) {
3382 // Find the effect in effectSettings array
3383 for(i=0;i<params->numberEffects;i++) {
3384 if(params->effectsSettings[i].VideoEffectType ==
3385 (M4VSS3GPP_VideoEffectType)M4xVSS_kVideoEffectType_ColorRGB16)
3386 break;
3387 }
3388 err = applyColorEffect(M4xVSS_kVideoEffectType_ColorRGB16,
3389 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3390 (M4VIFI_UInt8 *)tempOutputBuffer,
3391 params->effectsSettings[i].xVSS.uiRgb16InputColor);
3392 if(err != M4NO_ERROR) {
3393 return err;
3394 }
3395 }
3396
3397 if(params->currentVideoEffect & VIDEO_EFFECT_FIFTIES) {
3398 // Find the effect in effectSettings array
3399 for(i=0;i<params->numberEffects;i++) {
3400 if(params->effectsSettings[i].VideoEffectType ==
3401 (M4VSS3GPP_VideoEffectType)M4xVSS_kVideoEffectType_Fifties)
3402 break;
3403 }
3404 if(i < params->numberEffects) {
3405 computeProgressForVideoEffect(params->timeMs,
3406 params->effectsSettings[i].uiStartTime,
3407 params->effectsSettings[i].uiDuration, &extProgress);
3408
3409 if(params->isFiftiesEffectStarted) {
3410 fiftiesCtx.previousClipTime = -1;
3411 }
3412 fiftiesCtx.fiftiesEffectDuration =
3413 1000/params->effectsSettings[i].xVSS.uiFiftiesOutFrameRate;
3414
3415 fiftiesCtx.shiftRandomValue = 0;
3416 fiftiesCtx.stripeRandomValue = 0;
3417
3418 err = M4VSS3GPP_externalVideoEffectFifties(
3419 (M4OSA_Void *)&fiftiesCtx, planeIn, planeOut, &extProgress,
3420 M4xVSS_kVideoEffectType_Fifties);
3421
3422 if(err != M4NO_ERROR) {
3423 ALOGE("M4VSS3GPP_externalVideoEffectFifties error 0x%x", (unsigned int)err);
3424
3425 if(NULL != finalOutputBuffer) {
3426 free(finalOutputBuffer);
3427 finalOutputBuffer = NULL;
3428 }
3429 if(NULL != tempOutputBuffer) {
3430 free(tempOutputBuffer);
3431 tempOutputBuffer = NULL;
3432 }
3433 return err;
3434 }
3435
3436 // The out plane now becomes the in plane for adding other effects
3437 swapImagePlanes(planeIn, planeOut,(M4VIFI_UInt8 *)finalOutputBuffer,
3438 (M4VIFI_UInt8 *)tempOutputBuffer);
3439 }
3440 }
3441
3442 if(params->currentVideoEffect & VIDEO_EFFECT_FRAMING) {
3443
3444 M4xVSS_FramingStruct framingCtx;
3445 // Find the effect in effectSettings array
3446 for(i=0;i<params->numberEffects;i++) {
3447 if(params->effectsSettings[i].VideoEffectType ==
3448 (M4VSS3GPP_VideoEffectType)M4xVSS_kVideoEffectType_Framing) {
3449 if((params->effectsSettings[i].uiStartTime <= params->timeMs + params->timeOffset) &&
3450 ((params->effectsSettings[i].uiStartTime+
3451 params->effectsSettings[i].uiDuration) >= params->timeMs + params->timeOffset))
3452 {
3453 break;
3454 }
3455 }
3456 }
3457 if(i < params->numberEffects) {
3458 computeProgressForVideoEffect(params->timeMs,
3459 params->effectsSettings[i].uiStartTime,
3460 params->effectsSettings[i].uiDuration, &extProgress);
3461
3462 err = prepareFramingStructure(&framingCtx,
3463 params->effectsSettings, i, params->overlayFrameRGBBuffer,
3464 params->overlayFrameYUVBuffer);
3465
3466 if(err == M4NO_ERROR) {
3467 err = M4VSS3GPP_externalVideoEffectFraming(
3468 (M4OSA_Void *)&framingCtx, planeIn, planeOut, &extProgress,
3469 M4xVSS_kVideoEffectType_Framing);
3470 }
3471
3472 free(framingCtx.alphaBlendingStruct);
3473
3474 if(framingCtx.FramingYuv != NULL) {
3475 free(framingCtx.FramingYuv);
3476 framingCtx.FramingYuv = NULL;
3477 }
3478 //If prepareFramingStructure / M4VSS3GPP_externalVideoEffectFraming
3479 // returned error, then return from function
3480 if(err != M4NO_ERROR) {
3481
3482 if(NULL != finalOutputBuffer) {
3483 free(finalOutputBuffer);
3484 finalOutputBuffer = NULL;
3485 }
3486 if(NULL != tempOutputBuffer) {
3487 free(tempOutputBuffer);
3488 tempOutputBuffer = NULL;
3489 }
3490 return err;
3491 }
3492
3493 // The out plane now becomes the in plane for adding other effects
3494 swapImagePlanes(planeIn, planeOut,(M4VIFI_UInt8 *)finalOutputBuffer,
3495 (M4VIFI_UInt8 *)tempOutputBuffer);
3496 }
3497 }
3498
3499 if(params->currentVideoEffect & VIDEO_EFFECT_FADEFROMBLACK) {
3500 /* find the effect in effectSettings array*/
3501 for(i=0;i<params->numberEffects;i++) {
3502 if(params->effectsSettings[i].VideoEffectType ==
3503 M4VSS3GPP_kVideoEffectType_FadeFromBlack)
3504 break;
3505 }
3506
3507 if(i < params->numberEffects) {
3508 computePercentageDone(params->timeMs,
3509 params->effectsSettings[i].uiStartTime,
3510 params->effectsSettings[i].uiDuration, &percentageDone);
3511
3512 // Compute where we are in the effect (scale is 0->1024)
3513 lum_factor = (M4OSA_Int32)( percentageDone * 1024 );
3514 // Apply the darkening effect
3515 err = applyLumaEffect(M4VSS3GPP_kVideoEffectType_FadeFromBlack,
3516 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3517 (M4VIFI_UInt8 *)tempOutputBuffer, lum_factor);
3518 if(err != M4NO_ERROR) {
3519 return err;
3520 }
3521 }
3522 }
3523
3524 if(params->currentVideoEffect & VIDEO_EFFECT_FADETOBLACK) {
3525 // Find the effect in effectSettings array
3526 for(i=0;i<params->numberEffects;i++) {
3527 if(params->effectsSettings[i].VideoEffectType ==
3528 M4VSS3GPP_kVideoEffectType_FadeToBlack)
3529 break;
3530 }
3531 if(i < params->numberEffects) {
3532 computePercentageDone(params->timeMs,
3533 params->effectsSettings[i].uiStartTime,
3534 params->effectsSettings[i].uiDuration, &percentageDone);
3535
3536 // Compute where we are in the effect (scale is 0->1024)
3537 lum_factor = (M4OSA_Int32)( (1.0-percentageDone) * 1024 );
3538 // Apply the darkening effect
3539 err = applyLumaEffect(M4VSS3GPP_kVideoEffectType_FadeToBlack,
3540 planeIn, planeOut, (M4VIFI_UInt8 *)finalOutputBuffer,
3541 (M4VIFI_UInt8 *)tempOutputBuffer, lum_factor);
3542 if(err != M4NO_ERROR) {
3543 return err;
3544 }
3545 }
3546 }
3547
3548 ALOGV("doMediaRendering CALL getBuffer()");
3549 // Set the output YUV420 plane to be compatible with YV12 format
3550 // W & H even
3551 // YVU instead of YUV
3552 // align buffers on 32 bits
3553
3554 // Y plane
3555 //in YV12 format, sizes must be even
3556 M4OSA_UInt32 yv12PlaneWidth = ((params->outVideoWidth +1)>>1)<<1;
3557 M4OSA_UInt32 yv12PlaneHeight = ((params->outVideoHeight+1)>>1)<<1;
3558
3559 prepareYV12ImagePlane(planeOut, yv12PlaneWidth, yv12PlaneHeight,
3560 (M4OSA_UInt32)params->outBufferStride, (M4VIFI_UInt8 *)params->pOutBuffer);
3561
3562 err = applyRenderingMode(planeIn, planeOut, params->renderingMode);
3563
3564 if(M4OSA_NULL != finalOutputBuffer) {
3565 free(finalOutputBuffer);
3566 finalOutputBuffer= M4OSA_NULL;
3567 }
3568 if(M4OSA_NULL != tempOutputBuffer) {
3569 free(tempOutputBuffer);
3570 tempOutputBuffer = M4OSA_NULL;
3571 }
3572 if(err != M4NO_ERROR) {
3573 ALOGV("doVideoPostProcessing: applyRenderingMode returned err=%d",err);
3574 return err;
3575 }
3576 return M4NO_ERROR;
3577 }
3578
getVideoSizeByResolution(M4VIDEOEDITING_VideoFrameSize resolution,uint32_t * pWidth,uint32_t * pHeight)3579 android::status_t getVideoSizeByResolution(
3580 M4VIDEOEDITING_VideoFrameSize resolution,
3581 uint32_t *pWidth, uint32_t *pHeight) {
3582
3583 uint32_t frameWidth, frameHeight;
3584
3585 if (pWidth == NULL) {
3586 ALOGE("getVideoFrameSizeByResolution invalid pointer for pWidth");
3587 return android::BAD_VALUE;
3588 }
3589 if (pHeight == NULL) {
3590 ALOGE("getVideoFrameSizeByResolution invalid pointer for pHeight");
3591 return android::BAD_VALUE;
3592 }
3593
3594 switch (resolution) {
3595 case M4VIDEOEDITING_kSQCIF:
3596 frameWidth = 128;
3597 frameHeight = 96;
3598 break;
3599
3600 case M4VIDEOEDITING_kQQVGA:
3601 frameWidth = 160;
3602 frameHeight = 120;
3603 break;
3604
3605 case M4VIDEOEDITING_kQCIF:
3606 frameWidth = 176;
3607 frameHeight = 144;
3608 break;
3609
3610 case M4VIDEOEDITING_kQVGA:
3611 frameWidth = 320;
3612 frameHeight = 240;
3613 break;
3614
3615 case M4VIDEOEDITING_kCIF:
3616 frameWidth = 352;
3617 frameHeight = 288;
3618 break;
3619
3620 case M4VIDEOEDITING_kVGA:
3621 frameWidth = 640;
3622 frameHeight = 480;
3623 break;
3624
3625 case M4VIDEOEDITING_kWVGA:
3626 frameWidth = 800;
3627 frameHeight = 480;
3628 break;
3629
3630 case M4VIDEOEDITING_kNTSC:
3631 frameWidth = 720;
3632 frameHeight = 480;
3633 break;
3634
3635 case M4VIDEOEDITING_k640_360:
3636 frameWidth = 640;
3637 frameHeight = 360;
3638 break;
3639
3640 case M4VIDEOEDITING_k854_480:
3641 frameWidth = 854;
3642 frameHeight = 480;
3643 break;
3644
3645 case M4VIDEOEDITING_k1280_720:
3646 frameWidth = 1280;
3647 frameHeight = 720;
3648 break;
3649
3650 case M4VIDEOEDITING_k1080_720:
3651 frameWidth = 1080;
3652 frameHeight = 720;
3653 break;
3654
3655 case M4VIDEOEDITING_k960_720:
3656 frameWidth = 960;
3657 frameHeight = 720;
3658 break;
3659
3660 case M4VIDEOEDITING_k1920_1080:
3661 frameWidth = 1920;
3662 frameHeight = 1080;
3663 break;
3664
3665 default:
3666 ALOGE("Unsupported video resolution %d.", resolution);
3667 return android::BAD_VALUE;
3668 }
3669
3670 *pWidth = frameWidth;
3671 *pHeight = frameHeight;
3672
3673 return android::OK;
3674 }
3675
M4VIFI_Rotate90LeftYUV420toYUV420(void * pUserData,M4VIFI_ImagePlane * pPlaneIn,M4VIFI_ImagePlane * pPlaneOut)3676 M4VIFI_UInt8 M4VIFI_Rotate90LeftYUV420toYUV420(void* pUserData,
3677 M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut) {
3678
3679 M4VIFI_Int32 plane_number;
3680 M4VIFI_UInt32 i,j, u_stride;
3681 M4VIFI_UInt8 *p_buf_src, *p_buf_dest;
3682
3683 /**< Loop on Y,U and V planes */
3684 for (plane_number = 0; plane_number < 3; plane_number++) {
3685 /**< Get adresses of first valid pixel in input and output buffer */
3686 /**< As we have a -90° rotation, first needed pixel is the upper-right one */
3687 p_buf_src =
3688 &(pPlaneIn[plane_number].pac_data[pPlaneIn[plane_number].u_topleft]) +
3689 pPlaneOut[plane_number].u_height - 1 ;
3690 p_buf_dest =
3691 &(pPlaneOut[plane_number].pac_data[pPlaneOut[plane_number].u_topleft]);
3692 u_stride = pPlaneIn[plane_number].u_stride;
3693 /**< Loop on output rows */
3694 for (i = 0; i < pPlaneOut[plane_number].u_height; i++) {
3695 /**< Loop on all output pixels in a row */
3696 for (j = 0; j < pPlaneOut[plane_number].u_width; j++) {
3697 *p_buf_dest++= *p_buf_src;
3698 p_buf_src += u_stride; /**< Go to the next row */
3699 }
3700
3701 /**< Go on next row of the output frame */
3702 p_buf_dest +=
3703 pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width;
3704 /**< Go to next pixel in the last row of the input frame*/
3705 p_buf_src -=
3706 pPlaneIn[plane_number].u_stride * pPlaneOut[plane_number].u_width + 1 ;
3707 }
3708 }
3709
3710 return M4VIFI_OK;
3711 }
3712
M4VIFI_Rotate90RightYUV420toYUV420(void * pUserData,M4VIFI_ImagePlane * pPlaneIn,M4VIFI_ImagePlane * pPlaneOut)3713 M4VIFI_UInt8 M4VIFI_Rotate90RightYUV420toYUV420(void* pUserData,
3714 M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut) {
3715
3716 M4VIFI_Int32 plane_number;
3717 M4VIFI_UInt32 i,j, u_stride;
3718 M4VIFI_UInt8 *p_buf_src, *p_buf_dest;
3719
3720 /**< Loop on Y,U and V planes */
3721 for (plane_number = 0; plane_number < 3; plane_number++) {
3722 /**< Get adresses of first valid pixel in input and output buffer */
3723 /**< As we have a +90° rotation, first needed pixel is the left-down one */
3724 p_buf_src =
3725 &(pPlaneIn[plane_number].pac_data[pPlaneIn[plane_number].u_topleft]) +
3726 (pPlaneIn[plane_number].u_stride * (pPlaneOut[plane_number].u_width - 1));
3727 p_buf_dest =
3728 &(pPlaneOut[plane_number].pac_data[pPlaneOut[plane_number].u_topleft]);
3729 u_stride = pPlaneIn[plane_number].u_stride;
3730 /**< Loop on output rows */
3731 for (i = 0; i < pPlaneOut[plane_number].u_height; i++) {
3732 /**< Loop on all output pixels in a row */
3733 for (j = 0; j < pPlaneOut[plane_number].u_width; j++) {
3734 *p_buf_dest++= *p_buf_src;
3735 p_buf_src -= u_stride; /**< Go to the previous row */
3736 }
3737
3738 /**< Go on next row of the output frame */
3739 p_buf_dest +=
3740 pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width;
3741 /**< Go to next pixel in the last row of the input frame*/
3742 p_buf_src +=
3743 pPlaneIn[plane_number].u_stride * pPlaneOut[plane_number].u_width +1 ;
3744 }
3745 }
3746
3747 return M4VIFI_OK;
3748 }
3749
M4VIFI_Rotate180YUV420toYUV420(void * pUserData,M4VIFI_ImagePlane * pPlaneIn,M4VIFI_ImagePlane * pPlaneOut)3750 M4VIFI_UInt8 M4VIFI_Rotate180YUV420toYUV420(void* pUserData,
3751 M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut) {
3752 M4VIFI_Int32 plane_number;
3753 M4VIFI_UInt32 i,j;
3754 M4VIFI_UInt8 *p_buf_src, *p_buf_dest, temp_pix1;
3755
3756 /**< Loop on Y,U and V planes */
3757 for (plane_number = 0; plane_number < 3; plane_number++) {
3758 /**< Get adresses of first valid pixel in input and output buffer */
3759 p_buf_src =
3760 &(pPlaneIn[plane_number].pac_data[pPlaneIn[plane_number].u_topleft]);
3761 p_buf_dest =
3762 &(pPlaneOut[plane_number].pac_data[pPlaneOut[plane_number].u_topleft]);
3763
3764 /**< If pPlaneIn = pPlaneOut, the algorithm will be different */
3765 if (p_buf_src == p_buf_dest) {
3766 /**< Get Address of last pixel in the last row of the frame */
3767 p_buf_dest +=
3768 pPlaneOut[plane_number].u_stride*(pPlaneOut[plane_number].u_height-1) +
3769 pPlaneOut[plane_number].u_width - 1;
3770
3771 /**< We loop (height/2) times on the rows.
3772 * In case u_height is odd, the row at the middle of the frame
3773 * has to be processed as must be mirrored */
3774 for (i = 0; i < ((pPlaneOut[plane_number].u_height)>>1); i++) {
3775 for (j = 0; j < pPlaneOut[plane_number].u_width; j++) {
3776 temp_pix1= *p_buf_dest;
3777 *p_buf_dest--= *p_buf_src;
3778 *p_buf_src++ = temp_pix1;
3779 }
3780 /**< Go on next row in top of frame */
3781 p_buf_src +=
3782 pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width;
3783 /**< Go to the last pixel in previous row in bottom of frame*/
3784 p_buf_dest -=
3785 pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width;
3786 }
3787
3788 /**< Mirror middle row in case height is odd */
3789 if ((pPlaneOut[plane_number].u_height%2)!= 0) {
3790 p_buf_src =
3791 &(pPlaneOut[plane_number].pac_data[pPlaneIn[plane_number].u_topleft]);
3792 p_buf_src +=
3793 pPlaneOut[plane_number].u_stride*(pPlaneOut[plane_number].u_height>>1);
3794 p_buf_dest =
3795 p_buf_src + pPlaneOut[plane_number].u_width;
3796
3797 /**< We loop u_width/2 times on this row.
3798 * In case u_width is odd, the pixel at the middle of this row
3799 * remains unchanged */
3800 for (j = 0; j < (pPlaneOut[plane_number].u_width>>1); j++) {
3801 temp_pix1= *p_buf_dest;
3802 *p_buf_dest--= *p_buf_src;
3803 *p_buf_src++ = temp_pix1;
3804 }
3805 }
3806 } else {
3807 /**< Get Address of last pixel in the last row of the output frame */
3808 p_buf_dest +=
3809 pPlaneOut[plane_number].u_stride*(pPlaneOut[plane_number].u_height-1) +
3810 pPlaneIn[plane_number].u_width - 1;
3811
3812 /**< Loop on rows */
3813 for (i = 0; i < pPlaneOut[plane_number].u_height; i++) {
3814 for (j = 0; j < pPlaneOut[plane_number].u_width; j++) {
3815 *p_buf_dest--= *p_buf_src++;
3816 }
3817
3818 /**< Go on next row in top of input frame */
3819 p_buf_src +=
3820 pPlaneIn[plane_number].u_stride - pPlaneOut[plane_number].u_width;
3821 /**< Go to last pixel of previous row in bottom of input frame*/
3822 p_buf_dest -=
3823 pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width;
3824 }
3825 }
3826 }
3827
3828 return M4VIFI_OK;
3829 }
3830
applyVideoRotation(M4OSA_Void * pBuffer,M4OSA_UInt32 width,M4OSA_UInt32 height,M4OSA_UInt32 rotation)3831 M4OSA_ERR applyVideoRotation(M4OSA_Void* pBuffer, M4OSA_UInt32 width,
3832 M4OSA_UInt32 height, M4OSA_UInt32 rotation) {
3833
3834 M4OSA_ERR err = M4NO_ERROR;
3835 M4VIFI_ImagePlane planeIn[3], planeOut[3];
3836
3837 if (pBuffer == M4OSA_NULL) {
3838 ALOGE("applyVideoRotation: NULL input frame");
3839 return M4ERR_PARAMETER;
3840 }
3841 M4OSA_UInt8* outPtr = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc(
3842 (width*height*1.5), M4VS, (M4OSA_Char*)("rotation out ptr"));
3843 if (outPtr == M4OSA_NULL) {
3844 return M4ERR_ALLOC;
3845 }
3846
3847 // In plane
3848 prepareYUV420ImagePlane(planeIn, width,
3849 height, (M4VIFI_UInt8 *)pBuffer, width, height);
3850
3851 // Out plane
3852 if (rotation != 180) {
3853 prepareYUV420ImagePlane(planeOut, height,
3854 width, outPtr, height, width);
3855 }
3856
3857 switch(rotation) {
3858 case 90:
3859 M4VIFI_Rotate90RightYUV420toYUV420(M4OSA_NULL, planeIn, planeOut);
3860 memcpy(pBuffer, (void *)outPtr, (width*height*1.5));
3861 break;
3862
3863 case 180:
3864 // In plane rotation, so planeOut = planeIn
3865 M4VIFI_Rotate180YUV420toYUV420(M4OSA_NULL, planeIn, planeIn);
3866 break;
3867
3868 case 270:
3869 M4VIFI_Rotate90LeftYUV420toYUV420(M4OSA_NULL, planeIn, planeOut);
3870 memcpy(pBuffer, (void *)outPtr, (width*height*1.5));
3871 break;
3872
3873 default:
3874 ALOGE("invalid rotation param %d", (int)rotation);
3875 err = M4ERR_PARAMETER;
3876 break;
3877 }
3878
3879 free((void *)outPtr);
3880 return err;
3881
3882 }
3883
3884