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