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