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