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
23const M4VIFI_UInt8   M4VIFI_ClipTable[1256]
24= {
250x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
280x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
420x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
450x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
480x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
500x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
530x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
550x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
710x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
720x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
730x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
740x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
800x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
830x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
840x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
850x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
860x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
870x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
880x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
890x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
900x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
910x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
920x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
930x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
940x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
950x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
960x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
970x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
980x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b,
990x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
1000x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
1010x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
1020x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b,
1030x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
1040x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b,
1050x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
1060x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
1070x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3,
1080xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
1090xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
1100xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb,
1110xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
1120xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
1130xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3,
1140xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
1150xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
1160xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
1170xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
1180xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
1190xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
1200xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1210xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1220xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1230xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1240xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1250xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1260xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1270xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1280xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1290xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1300xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1310xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1320xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1330xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1340xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1350xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1360xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1370xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1380xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1390xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1400xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1410xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1420xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1430xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1440xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1450xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1460xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1470xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1480xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1490xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1500xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1510xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1520xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1530xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1540xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1550xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1560xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1570xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1580xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1590xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1600xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1610xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1620xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1630xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1640xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1650xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1660xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1670xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1680xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1690xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1700xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1710xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1720xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1730xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1740xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1750xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1760xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1770xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1780xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1790xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1800xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1810xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
182};
183
184/* Division table for ( 65535/x ); x = 0 to 512 */
185const M4VIFI_UInt16  M4VIFI_DivTable[512]
186= {
1870, 65535, 32768, 21845, 16384, 13107, 10922, 9362,
1888192, 7281, 6553, 5957, 5461, 5041, 4681, 4369,
1894096, 3855, 3640, 3449, 3276, 3120, 2978, 2849,
1902730, 2621, 2520, 2427, 2340, 2259, 2184, 2114,
1912048, 1985, 1927, 1872, 1820, 1771, 1724, 1680,
1921638, 1598, 1560, 1524, 1489, 1456, 1424, 1394,
1931365, 1337, 1310, 1285, 1260, 1236, 1213, 1191,
1941170, 1149, 1129, 1110, 1092, 1074, 1057, 1040,
1951024, 1008, 992, 978, 963, 949, 936, 923,
196910, 897, 885, 873, 862, 851, 840, 829,
197819, 809, 799, 789, 780, 771, 762, 753,
198744, 736, 728, 720, 712, 704, 697, 689,
199682, 675, 668, 661, 655, 648, 642, 636,
200630, 624, 618, 612, 606, 601, 595, 590,
201585, 579, 574, 569, 564, 560, 555, 550,
202546, 541, 537, 532, 528, 524, 520, 516,
203512, 508, 504, 500, 496, 492, 489, 485,
204481, 478, 474, 471, 468, 464, 461, 458,
205455, 451, 448, 445, 442, 439, 436, 434,
206431, 428, 425, 422, 420, 417, 414, 412,
207409, 407, 404, 402, 399, 397, 394, 392,
208390, 387, 385, 383, 381, 378, 376, 374,
209372, 370, 368, 366, 364, 362, 360, 358,
210356, 354, 352, 350, 348, 346, 344, 343,
211341, 339, 337, 336, 334, 332, 330, 329,
212327, 326, 324, 322, 321, 319, 318, 316,
213315, 313, 312, 310, 309, 307, 306, 304,
214303, 302, 300, 299, 297, 296, 295, 293,
215292, 291, 289, 288, 287, 286, 284, 283,
216282, 281, 280, 278, 277, 276, 275, 274,
217273, 271, 270, 269, 268, 267, 266, 265,
218264, 263, 262, 261, 260, 259, 258, 257,
219256, 255, 254, 253, 252, 251, 250, 249,
220248, 247, 246, 245, 244, 243, 242, 241,
221240, 240, 239, 238, 237, 236, 235, 234,
222234, 233, 232, 231, 230, 229, 229, 228,
223227, 226, 225, 225, 224, 223, 222, 222,
224221, 220, 219, 219, 218, 217, 217, 216,
225215, 214, 214, 213, 212, 212, 211, 210,
226210, 209, 208, 208, 207, 206, 206, 205,
227204, 204, 203, 202, 202, 201, 201, 200,
228199, 199, 198, 197, 197, 196, 196, 195,
229195, 194, 193, 193, 192, 192, 191, 191,
230190, 189, 189, 188, 188, 187, 187, 186,
231186, 185, 185, 184, 184, 183, 183, 182,
232182, 181, 181, 180, 180, 179, 179, 178,
233178, 177, 177, 176, 176, 175, 175, 174,
234174, 173, 173, 172, 172, 172, 171, 171,
235170, 170, 169, 169, 168, 168, 168, 167,
236167, 166, 166, 165, 165, 165, 164, 164,
237163, 163, 163, 162, 162, 161, 161, 161,
238160, 160, 159, 159, 159, 158, 158, 157,
239157, 157, 156, 156, 156, 155, 155, 154,
240154, 154, 153, 153, 153, 152, 152, 152,
241151, 151, 151, 150, 150, 149, 149, 149,
242148, 148, 148, 147, 147, 147, 146, 146,
243146, 145, 145, 145, 144, 144, 144, 144,
244143, 143, 143, 142, 142, 142, 141, 141,
245141, 140, 140, 140, 140, 139, 139, 139,
246138, 138, 138, 137, 137, 137, 137, 136,
247136, 136, 135, 135, 135, 135, 134, 134,
248134, 134, 133, 133, 133, 132, 132, 132,
249132, 131, 131, 131, 131, 130, 130, 130,
250130, 129, 129, 129, 129, 128, 128, 128
251};
252
253const M4VIFI_Int32  const_storage1[8]
254= {
2550x00002568, 0x00003343,0x00000649,0x00000d0f, 0x0000D86C, 0x0000D83B, 0x00010000, 0x00010000
256};
257
258const M4VIFI_Int32  const_storage[8]
259= {
2600x00002568, 0x00003343, 0x1BF800, 0x00000649, 0x00000d0f, 0x110180, 0x40cf, 0x22BE00
261};
262
263
264const M4VIFI_UInt16  *M4VIFI_DivTable_zero
265 = &M4VIFI_DivTable[0];
266
267const M4VIFI_UInt8   *M4VIFI_ClipTable_zero
268 = &M4VIFI_ClipTable[500];
269
270M4VIFI_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
300M4VIFI_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*/
351M4OSA_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*/
512M4OSA_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*/
737M4OSA_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
833unsigned 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*/
942M4OSA_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*/
1007M4OSA_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*/
1082M4VIFI_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/***************************************************************************
1248Proto:
1249M4VIFI_UInt8    M4VIFI_RGB888toYUV420(void *pUserData, M4VIFI_ImagePlane *PlaneIn, M4VIFI_ImagePlane PlaneOut[3]);
1250Author:     Patrice Martinez / Philips Digital Networks - MP4Net
1251Purpose:    filling of the YUV420 plane from a BGR24 plane
1252Abstract:   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
1258In:         RGB24 plane
1259InOut:      none
1260Out:        array of 3 M4VIFI_ImagePlane structures
1261Modified:   ML: RGB function modified to BGR.
1262***************************************************************************/
1263M4VIFI_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
1394M4VIFI_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*/
1441M4VIFI_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
1666M4OSA_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*/
1960typedef 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*/
1973typedef 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*/
2009M4OSA_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
2048M4AIR_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*/
2073M4OSA_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*/
2110M4OSA_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*/
2316M4OSA_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*/
2855M4OSA_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}
2962M4OSA_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
2988M4OSA_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
3020M4OSA_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
3068M4OSA_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
3090M4OSA_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
3104M4OSA_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
3206M4OSA_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
3241M4OSA_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
3272M4OSA_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
3579android::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
3676M4VIFI_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
3713M4VIFI_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
3750M4VIFI_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
3831M4OSA_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