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