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 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 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 ***************************************************************************/ 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 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 } 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 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 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 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 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 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 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 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 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 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 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 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 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 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