1 // Copyright (c) 2018 Intel Corporation 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in all 11 // copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 // SOFTWARE. 20 21 #include "mfx_reflect.h" 22 23 #if defined(MFX_TRACE_ENABLE_REFLECT) 24 25 #include <iostream> 26 #include <iomanip> 27 #include <sstream> 28 #include <algorithm> 29 #include <cstddef> 30 31 #include "mfxstructures.h" 32 #include "mfxvp8.h" 33 #include "mfxvp9.h" 34 #include "mfxplugin.h" 35 #include "mfxmvc.h" 36 #include "mfxcamera.h" 37 #include "mfxfei.h" 38 #include "mfxla.h" 39 #include "mfxsc.h" 40 41 #if (MFX_VERSION >= 1027) 42 #include "mfxfeihevc.h" 43 #endif 44 45 #include "ts_typedef.h" 46 47 #include <memory> 48 49 namespace mfx_reflect 50 { 51 static AccessibleTypesCollection g_Reflection; 52 GetReflection()53 AccessibleTypesCollection GetReflection() 54 { 55 return g_Reflection; 56 } 57 Initialize()58 void AccessibleTypesCollection::Initialize() 59 { 60 if (!g_Reflection.m_bIsInitialized) 61 { 62 g_Reflection.DeclareMsdkStructs(); 63 g_Reflection.m_bIsInitialized = true; 64 } 65 } 66 67 template<class T> 68 struct mfx_ext_buffer_id { 69 enum { id = 0 }; 70 }; 71 72 #define EXTBUF(STRUCT, ID) \ 73 template<>struct mfx_ext_buffer_id<STRUCT> { \ 74 enum { id = ID }; }; 75 76 #include "ts_ext_buffers_decl.h" 77 SetFieldAddress()78 void AccessorField::SetFieldAddress() 79 { 80 m_P = (*m_Iterator)->GetAddress(m_BaseStruct.m_P); 81 char *result = (char*)m_P; 82 result += m_pReflection->FieldType->Size * m_IndexElement; 83 m_P = (void*)result; 84 } 85 operator ++()86 AccessorField& AccessorField::operator++() 87 { 88 m_IndexElement = 0; 89 m_Iterator++; 90 if (IsValid()) 91 { 92 SetIterator(m_Iterator); 93 } 94 return *this; 95 } 96 IsValid() const97 bool AccessorField::IsValid() const 98 { 99 return m_Iterator != m_BaseStruct.m_pReflection->m_Fields.end(); 100 } 101 AccessSubtype() const102 AccessorType AccessorField::AccessSubtype() const 103 { 104 return AccessorType(m_P, *(m_pReflection->FieldType)); 105 } 106 107 AccessField(ReflectedField::FieldsCollectionCI iter) const108 AccessorField AccessorType::AccessField(ReflectedField::FieldsCollectionCI iter) const 109 { 110 if (m_pReflection->m_Fields.end() != iter) 111 { 112 return AccessorField(*this, iter); // Address of base, not field. 113 } 114 else 115 { 116 throw std::invalid_argument(std::string("No such field")); 117 } 118 } 119 AccessField(const std::string & fieldName) const120 AccessorField AccessorType::AccessField(const std::string& fieldName) const 121 { 122 ReflectedField::FieldsCollectionCI iter = m_pReflection->FindField(fieldName); 123 return AccessField(iter); 124 } 125 AccessFirstField() const126 AccessorField AccessorType::AccessFirstField() const 127 { 128 return AccessField(m_pReflection->m_Fields.begin()); 129 } 130 AccessSubtype(const std::string & fieldName) const131 AccessorType AccessorType::AccessSubtype(const std::string& fieldName) const 132 { 133 return AccessField(fieldName).AccessSubtype(); 134 } 135 ReflectedType(ReflectedTypesCollection * pCollection,std::type_index typeIndex,const std::string & typeName,size_t size,bool isPointer,mfxU32 extBufferId)136 ReflectedType::ReflectedType(ReflectedTypesCollection *pCollection, std::type_index typeIndex, const std::string& typeName, size_t size, bool isPointer, mfxU32 extBufferId) 137 : m_TypeIndex(typeIndex) 138 , TypeNames(1, typeName) 139 , Size(size) 140 , m_pCollection(pCollection) 141 , m_bIsPointer(isPointer) 142 , ExtBufferId(extBufferId) 143 { 144 if (NULL == m_pCollection) 145 { 146 m_pCollection = NULL; 147 } 148 } 149 AddField(std::type_index typeIndex,const std::string & typeName,size_t typeSize,bool isPointer,size_t offset,const std::string & fieldName,size_t count,mfxU32 extBufferId)150 ReflectedField::SP ReflectedType::AddField(std::type_index typeIndex, const std::string &typeName, size_t typeSize, bool isPointer, size_t offset, const std::string &fieldName, size_t count, mfxU32 extBufferId) 151 { 152 ReflectedField::SP pField; 153 if (typeName.empty()) 154 { 155 throw std::invalid_argument(std::string("Unexpected behavior - typeName is empty")); 156 } 157 if (NULL == m_pCollection) 158 { 159 return pField; 160 } 161 else 162 { 163 ReflectedType* pType = m_pCollection->FindOrDeclareType(typeIndex, typeName, typeSize, isPointer, extBufferId).get(); 164 if (pType != NULL) 165 { 166 StringList::iterator findIterator = std::find(pType->TypeNames.begin(), pType->TypeNames.end(), typeName); 167 if (pType->TypeNames.end() == findIterator) 168 { 169 throw std::invalid_argument(std::string("Unexpected behavior - fieldTypeName is NULL")); 170 } 171 m_Fields.push_back(ReflectedField::SP(new ReflectedField(m_pCollection, this, pType, *findIterator, offset, fieldName, count))); //std::make_shared cannot access protected constructor 172 pField = m_Fields.back(); 173 } 174 return pField; 175 } 176 177 } 178 FindField(const std::string & fieldName) const179 ReflectedField::FieldsCollectionCI ReflectedType::FindField(const std::string& fieldName) const 180 { 181 ReflectedField::FieldsCollectionCI iter = m_Fields.begin(); 182 for (; iter != m_Fields.end(); ++iter) 183 { 184 if ((*iter)->FieldName == fieldName) 185 { 186 break; 187 } 188 } 189 return iter; 190 } 191 FindExistingByTypeInfoName(const char * name)192 ReflectedType::SP ReflectedTypesCollection::FindExistingByTypeInfoName(const char* name) //currenly we are not using this 193 { 194 for (Container::iterator iter = m_KnownTypes.begin(); iter != m_KnownTypes.end(); ++iter) 195 { 196 if (0 == strcmp(iter->first.name(), name)) 197 { 198 return iter->second; 199 } 200 } 201 ReflectedType::SP pEmptyType; 202 return pEmptyType; 203 } 204 FindExistingType(std::type_index typeIndex)205 ReflectedType::SP ReflectedTypesCollection::FindExistingType(std::type_index typeIndex) 206 { 207 Container::const_iterator it = m_KnownTypes.find(typeIndex); 208 if (m_KnownTypes.end() != it) 209 { 210 return it->second; 211 } 212 ReflectedType::SP pEmptyType; 213 return pEmptyType; 214 } 215 FindExtBufferTypeById(mfxU32 ExtBufferId)216 ReflectedType::SP ReflectedTypesCollection::FindExtBufferTypeById(mfxU32 ExtBufferId) //optimize with map (index -> type) 217 { 218 for (Container::iterator iter = m_KnownTypes.begin(); iter != m_KnownTypes.end(); ++iter) 219 { 220 if (ExtBufferId == iter->second->ExtBufferId) 221 { 222 return iter->second; 223 } 224 } 225 ReflectedType::SP pEmptyExtBufferType; 226 return pEmptyExtBufferType; 227 } 228 DeclareType(std::type_index typeIndex,const std::string & typeName,size_t typeSize,bool isPointer,mfxU32 extBufferId)229 ReflectedType::SP ReflectedTypesCollection::DeclareType(std::type_index typeIndex, const std::string& typeName, size_t typeSize, bool isPointer, mfxU32 extBufferId) 230 { 231 if (m_KnownTypes.end() == m_KnownTypes.find(typeIndex)) 232 { 233 ReflectedType::SP pType; 234 pType = std::make_shared<ReflectedType>(this, typeIndex, typeName, typeSize, isPointer, extBufferId); 235 m_KnownTypes.insert(std::make_pair(pType->m_TypeIndex, pType)); 236 return pType; 237 } 238 throw std::invalid_argument(std::string("Unexpected behavior - type is already declared")); 239 } 240 FindOrDeclareType(std::type_index typeIndex,const std::string & typeName,size_t typeSize,bool isPointer,mfxU32 extBufferId)241 ReflectedType::SP ReflectedTypesCollection::FindOrDeclareType(std::type_index typeIndex, const std::string& typeName, size_t typeSize, bool isPointer, mfxU32 extBufferId) 242 { 243 ReflectedType::SP pType = FindExistingType(typeIndex); 244 if (pType == NULL) 245 { 246 pType = DeclareType(typeIndex, typeName, typeSize, isPointer, extBufferId); 247 } 248 else 249 { 250 if (typeSize != pType->Size) 251 { 252 pType.reset(); 253 } 254 else if (!typeName.empty()) 255 { 256 ReflectedType::StringList::iterator findIterator = std::find(pType->TypeNames.begin(), pType->TypeNames.end(), typeName); 257 if (pType->TypeNames.end() == findIterator) 258 { 259 pType->TypeNames.push_back(typeName); 260 } 261 } 262 } 263 return pType; 264 } 265 PrintFieldIfTypeMatches(std::ostream & stream,AccessorField field)266 template <class T> bool PrintFieldIfTypeMatches(std::ostream& stream, AccessorField field) 267 { 268 bool bResult = false; 269 if (field.m_pReflection->FieldType->m_TypeIndex == field.m_pReflection->m_pCollection->FindExistingType<T>()->m_TypeIndex) 270 { 271 stream << field.Get<T>(); 272 bResult = true; 273 } 274 return bResult; 275 } 276 PrintFieldValue(std::ostream & stream,AccessorField field)277 void PrintFieldValue(std::ostream &stream, AccessorField field) 278 { 279 if (field.m_pReflection->FieldType->m_bIsPointer) 280 { 281 stream << "0x" << field.Get<void*>(); 282 } 283 else 284 { 285 bool bPrinted = false; 286 287 #define PRINT_IF_TYPE(T) if (!bPrinted) { bPrinted = PrintFieldIfTypeMatches<T>(stream, field); } 288 PRINT_IF_TYPE(mfxU16); 289 PRINT_IF_TYPE(mfxI16); 290 PRINT_IF_TYPE(mfxU32); 291 PRINT_IF_TYPE(mfxI32); 292 if (!bPrinted) 293 { 294 size_t fieldSize = field.m_pReflection->FieldType->Size; 295 { 296 stream << "<Unknown type \"" << field.m_pReflection->FieldType->m_TypeIndex.name() << "\" (size = " << fieldSize << ")>"; 297 } 298 } 299 } 300 } 301 PrintFieldName(std::ostream & stream,AccessorField field)302 void PrintFieldName(std::ostream &stream, AccessorField field) 303 { 304 stream << field.m_pReflection->FieldName; 305 if (field.m_pReflection->Count > 1) 306 { 307 stream << "[" << field.GetIndexElement() << "]"; 308 } 309 } 310 operator <<(std::ostream & stream,AccessorField field)311 std::ostream& operator<< (std::ostream& stream, AccessorField field) 312 { 313 PrintFieldName(stream, field); 314 stream << " = "; 315 PrintFieldValue(stream, field); 316 return stream; 317 } 318 operator <<(std::ostream & stream,AccessorType data)319 std::ostream& operator<< (std::ostream& stream, AccessorType data) 320 { 321 stream << data.m_pReflection->m_TypeIndex.name() << " = {"; 322 size_t nFields = data.m_pReflection->m_Fields.size(); 323 for (AccessorField field = data.AccessFirstField(); field.IsValid(); ++field) 324 { 325 if (nFields > 1) 326 { 327 stream << std::endl; 328 } 329 stream << "\t" << field; 330 } 331 stream << "}"; 332 return stream; 333 } 334 335 TypeComparisonResultP CompareExtBufferLists(mfxExtBuffer** pExtParam1, mfxU16 numExtParam1, mfxExtBuffer** pExtParam2, mfxU16 numExtParam2, ReflectedTypesCollection* collection); 336 AccessorTypeP GetAccessorOfExtBufferOriginalType(mfxExtBuffer& pExtInnerParam, ReflectedTypesCollection& collection); 337 CompareTwoStructs(AccessorType data1,AccessorType data2)338 TypeComparisonResultP CompareTwoStructs(AccessorType data1, AccessorType data2) // Always return not null result 339 { 340 TypeComparisonResultP result = std::make_shared<TypeComparisonResult>(); 341 if (data1.m_pReflection != data2.m_pReflection) 342 { 343 throw std::invalid_argument(std::string("Types mismatch")); 344 } 345 346 mfxExtBuffer** pExtParam1 = NULL; 347 mfxExtBuffer** pExtParam2 = NULL; 348 mfxU16 numExtParam = 0; 349 350 for (AccessorField field1 = data1.AccessFirstField(); field1.IsValid(); ++field1) 351 { 352 AccessorField field2 = data2.AccessField(field1.m_Iterator); 353 354 if (std::type_index(typeid(mfxExtBuffer**)) == field1.m_pReflection->FieldType->m_TypeIndex) 355 { 356 pExtParam1 = field1.Get<mfxExtBuffer**>(); 357 pExtParam2 = field2.Get<mfxExtBuffer**>(); 358 } 359 else if ((field1.m_pReflection->FieldName == "NumExtParam") && (field1.m_pReflection->FieldType->m_TypeIndex == std::type_index(typeid(mfxU16))) && (field2.m_pReflection->FieldType->m_TypeIndex == std::type_index(typeid(mfxU16)))) 360 { 361 if (field1.Get<mfxU16>() == field2.Get<mfxU16>()) 362 { 363 numExtParam = field1.Get<mfxU16>(); 364 } 365 else 366 { 367 throw std::invalid_argument(std::string("NumExtParam mismatch")); 368 } 369 } 370 else 371 { 372 for (size_t i = 0; i < field1.m_pReflection->Count; ++i) 373 { 374 field1.SetIndexElement(i); 375 field2.SetIndexElement(i); 376 377 AccessorType subtype1 = field1.AccessSubtype(); 378 TypeComparisonResultP subtypeResult = NULL; 379 380 if (subtype1.m_pReflection->m_Fields.size() > 0) 381 { 382 AccessorType subtype2 = field2.AccessSubtype(); 383 if (subtype1.m_pReflection != subtype2.m_pReflection) 384 { 385 throw std::invalid_argument(std::string("Subtypes mismatch - should never happen for same types")); 386 } 387 subtypeResult = CompareTwoStructs(subtype1, subtype2); 388 } 389 390 if (!field1.Equal(field2)) 391 { 392 FieldComparisonResult fields = { field1 , field2, subtypeResult }; 393 result->push_back(fields); 394 } 395 } 396 } 397 } 398 399 if ((pExtParam1 != NULL) && (pExtParam2 != NULL) && (numExtParam > 0)) 400 { 401 TypeComparisonResultP extBufferCompareResult = CompareExtBufferLists(pExtParam1, numExtParam, pExtParam2, numExtParam, data1.AccessFirstField().m_pReflection->m_pCollection); 402 if (extBufferCompareResult != NULL) 403 { 404 result->splice(result->end(), *extBufferCompareResult); //move elements of *extBufferCompareResult to the end of *result 405 if (!extBufferCompareResult->extBufferIdList.empty()) 406 { 407 result->extBufferIdList.splice(result->extBufferIdList.end(), extBufferCompareResult->extBufferIdList); 408 } 409 } 410 else 411 { 412 throw std::invalid_argument(std::string("Unexpected behavior - ExtBuffer comparison result is NULL")); 413 } 414 } 415 return result; 416 } 417 GetAccessorOfExtBufferOriginalType(mfxExtBuffer & pExtBufferParam,ReflectedTypesCollection & collection)418 AccessorTypeP GetAccessorOfExtBufferOriginalType(mfxExtBuffer& pExtBufferParam, ReflectedTypesCollection& collection) 419 { 420 AccessorTypeP pExtBuffer; 421 mfxU32 id = pExtBufferParam.BufferId; 422 if (0 != id) 423 { 424 ReflectedType::SP pTypeExtBuffer = collection.FindExtBufferTypeById(id); //find in KnownTypes this BufferId 425 if (pTypeExtBuffer != NULL) 426 { 427 pExtBuffer = std::make_shared<AccessorType>(&pExtBufferParam, *pTypeExtBuffer); 428 } 429 } 430 return pExtBuffer; 431 } 432 CompareExtBufferLists(mfxExtBuffer ** pExtParam1,mfxU16 numExtParam1,mfxExtBuffer ** pExtParam2,mfxU16 numExtParam2,ReflectedTypesCollection * collection)433 TypeComparisonResultP CompareExtBufferLists(mfxExtBuffer** pExtParam1, mfxU16 numExtParam1, mfxExtBuffer** pExtParam2, mfxU16 numExtParam2, ReflectedTypesCollection* collection) //always return not null result 434 { 435 TypeComparisonResultP result = std::make_shared<TypeComparisonResult>(); 436 if (NULL != pExtParam1 && NULL != pExtParam2 && NULL != collection) 437 { 438 for (int i = 0; i < numExtParam1 && i < numExtParam2; i++) 439 { 440 //supported only extBuffers with same Id order 441 if (NULL != pExtParam1[i] && NULL != pExtParam2[i]) 442 { 443 AccessorTypeP extBufferOriginTypeAccessor1 = GetAccessorOfExtBufferOriginalType(*pExtParam1[i], *collection); 444 AccessorTypeP extBufferOriginTypeAccessor2 = GetAccessorOfExtBufferOriginalType(*pExtParam2[i], *collection); 445 if (NULL != extBufferOriginTypeAccessor1 && NULL != extBufferOriginTypeAccessor2) 446 { 447 TypeComparisonResultP tempResult = CompareTwoStructs(*extBufferOriginTypeAccessor1, *extBufferOriginTypeAccessor2); 448 if (NULL != tempResult) 449 { 450 result->splice(result->end(), *tempResult); 451 } 452 else 453 { 454 throw std::invalid_argument(std::string("Unexpected behavior - comparison result is NULL")); 455 } 456 } 457 else 458 { 459 result->extBufferIdList.push_back(pExtParam1[i]->BufferId); 460 } 461 } 462 } 463 } 464 return result; 465 } 466 PrintStuctsComparisonResult(std::ostream & comparisonResult,const std::string & prefix,const TypeComparisonResultP & result)467 void PrintStuctsComparisonResult(std::ostream& comparisonResult, const std::string& prefix, const TypeComparisonResultP& result) 468 { 469 for (std::list<FieldComparisonResult>::iterator i = result->begin(); i != result->end(); ++i) 470 { 471 TypeComparisonResultP subtypeResult = i->subtypeComparisonResultP; 472 ReflectedType* aggregatingType = i->accessorField1.m_pReflection->AggregatingType; 473 std::list< std::string >::const_iterator it = aggregatingType->TypeNames.begin(); 474 std::string strTypeName = ((it != aggregatingType->TypeNames.end()) ? *(it) : "unknown_type"); 475 476 if (NULL != subtypeResult) 477 { 478 std::stringstream fieldName; 479 PrintFieldName(fieldName, i->accessorField1); 480 481 std::string strFieldName = fieldName.str(); 482 std::string newprefix; 483 484 newprefix = prefix.empty() ? (strTypeName + "." + strFieldName) : (prefix + "." + strFieldName); 485 PrintStuctsComparisonResult(comparisonResult, newprefix, subtypeResult); 486 } 487 else 488 { 489 if (!prefix.empty()) { comparisonResult << prefix << "."; } 490 else if (!strTypeName.empty()) { comparisonResult << strTypeName << "."; } 491 comparisonResult << i->accessorField1 << " -> "; 492 PrintFieldValue(comparisonResult, i->accessorField2); 493 comparisonResult << std::endl; 494 } 495 } 496 if (!result->extBufferIdList.empty()) 497 { 498 comparisonResult << "Id of unparsed ExtBuffer types: " << std::endl; 499 while (!result->extBufferIdList.empty()) 500 { 501 unsigned char* FourCC = reinterpret_cast<unsigned char*>(&result->extBufferIdList.front()); 502 comparisonResult << "0x" << std::hex << std::setfill('0') << result->extBufferIdList.front() << " \"" << FourCC[0] << FourCC[1] << FourCC[2] << FourCC[3] << "\""; 503 result->extBufferIdList.pop_front(); 504 if (!result->extBufferIdList.empty()) { comparisonResult << ", "; } 505 } 506 } 507 } 508 CompareStructsToString(AccessorType data1,AccessorType data2)509 std::string CompareStructsToString(AccessorType data1, AccessorType data2) 510 { 511 std::ostringstream comparisonResult; 512 if (data1.m_P == data2.m_P) 513 { 514 comparisonResult << "Comparing of VideoParams is unsupported: In and Out pointers are the same."; 515 } 516 else 517 { 518 comparisonResult << "Incompatible VideoParams were updated:" << std::endl; 519 TypeComparisonResultP result = CompareTwoStructs(data1, data2); 520 PrintStuctsComparisonResult(comparisonResult, "", result); 521 } 522 return comparisonResult.str(); 523 } 524 525 template <class T> AddFieldT(ReflectedType & type,const std::string typeName,size_t offset,const std::string fieldName,size_t count)526 ReflectedField::SP AddFieldT(ReflectedType &type, const std::string typeName, size_t offset, const std::string fieldName, size_t count) 527 { 528 unsigned int extBufId = 0; 529 extBufId = mfx_ext_buffer_id<T>::id; 530 bool isPointer = false; 531 isPointer = std::is_pointer<T>(); 532 return type.AddField(std::type_index(typeid(T)), typeName, sizeof(T), isPointer, offset, fieldName, count, extBufId); 533 } 534 535 template <class T> DeclareTypeT(ReflectedTypesCollection & collection,const std::string typeName)536 ReflectedType::SP DeclareTypeT(ReflectedTypesCollection& collection, const std::string typeName) 537 { 538 unsigned int extBufId = 0; 539 extBufId = mfx_ext_buffer_id<T>::id; 540 bool isPointer = false; 541 isPointer = std::is_pointer<T>(); 542 return collection.DeclareType(std::type_index(typeid(T)), typeName, sizeof(T), isPointer, extBufId); 543 } 544 DeclareMsdkStructs()545 void ReflectedTypesCollection::DeclareMsdkStructs() 546 { 547 #define STRUCT(TYPE, FIELDS) { \ 548 typedef TYPE BaseType; \ 549 ReflectedType::SP pType = DeclareTypeT<TYPE>(*this, #TYPE); \ 550 FIELDS \ 551 } 552 553 #define FIELD_T(FIELD_TYPE, FIELD_NAME) \ 554 (void)AddFieldT<FIELD_TYPE>( \ 555 *pType, \ 556 #FIELD_TYPE, \ 557 offsetof(BaseType, FIELD_NAME), \ 558 #FIELD_NAME, \ 559 (sizeof(((BaseType*)0)->FIELD_NAME)/sizeof(::FIELD_TYPE)) ); 560 561 #define FIELD_S(FIELD_TYPE, FIELD_NAME) FIELD_T(FIELD_TYPE, FIELD_NAME) 562 563 #include "ts_struct_decl.h" 564 } 565 } 566 567 #endif // #if defined(MFX_TRACE_ENABLE_REFLECT) 568