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