1 /* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 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 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18 #ifndef PVMF_MP4FFPARSER_OUTPORT_H_INCLUDED 19 #define PVMF_MP4FFPARSER_OUTPORT_H_INCLUDED 20 21 22 #ifndef OSCL_BASE_H_INCLUDED 23 #include "oscl_base.h" 24 #endif 25 26 #ifndef PVLOGGER_H_INCLUDED 27 #include "pvlogger.h" 28 #endif 29 30 #ifndef PVMF_PORT_BASE_IMPL_H_INCLUDED 31 #include "pvmf_port_base_impl.h" 32 #endif 33 34 #ifndef PVMI_CONFIG_AND_CAPABILITY_UTILS_H_INCLUDED 35 #include "pvmi_config_and_capability_utils.h" 36 #endif 37 38 #ifndef OSCL_MEM_MEMPOOL_H_INCLUDED 39 #include "oscl_mem_mempool.h" 40 #endif 41 42 #ifndef PVMF_SIMPLE_MEDIA_BUFFER_H_INCLUDED 43 #include "pvmf_simple_media_buffer.h" 44 #endif 45 46 #ifndef PVMF_TIMEDTEXT_H_INCLUDED 47 #include "pvmf_timedtext.h" 48 #endif 49 50 #ifndef PVMF_MEMPOOL_H_INCLUDED 51 #include "pvmf_mempool.h" 52 #endif 53 54 #ifndef PVMF_MEDIA_FRAG_GROUP_H_INCLUDED 55 #include "pvmf_media_frag_group.h" 56 #endif 57 58 #ifndef OSCL_TIMER_H_INCLUDED 59 #include "oscl_timer.h" 60 #endif 61 62 #ifndef PVMF_RESIZABLE_SIMPLE_MEDIAMSG_H_INCLUDED 63 #include "pvmf_resizable_simple_mediamsg.h" 64 #endif 65 66 #include "pvmf_mp4ffparser_node.h" 67 68 #define PVMF_MP4FFPARSERNODE_LOGERROR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m); 69 #define PVMF_MP4FFPARSERNODE_LOGWARNING(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_WARNING,m); 70 #define PVMF_MP4FFPARSERNODE_LOGINFOHI(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG,iLogger,PVLOGMSG_INFO,m); 71 #define PVMF_MP4FFPARSERNODE_LOGINFOMED(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG,iLogger,PVLOGMSG_INFO,m); 72 #define PVMF_MP4FFPARSERNODE_LOGINFOLOW(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iLogger,PVLOGMSG_INFO,m); 73 #define PVMF_MP4FFPARSERNODE_LOGINFO(m) PVMF_MP4FFPARSERNODE_LOGINFOMED(m) 74 #define PVMF_MP4FFPARSERNODE_LOGDATATRAFFIC(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iDataPathLogger,PVLOGMSG_INFO,m); 75 #define PVMF_MP4FFPARSERNODE_LOGDATATRAFFIC_AVC(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iAVCDataPathLogger,PVLOGMSG_INFO,m); 76 #define PVMF_MP4FFPARSERNODE_LOGCLOCK(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iClockLogger,PVLOGMSG_INFO,m); 77 #define PVMF_MP4FFPARSERNODE_LOGBIN(iPortLogger, m) PVLOGGER_LOGBIN(PVLOGMSG_INST_LLDBG, iPortLogger, PVLOGMSG_ERR, m); 78 #define PVMF_MP4FFPARSERNODE_LOGDIAGNOSTICS(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF,iDiagnosticsLogger,PVLOGMSG_INFO,m); 79 /** 80 * Port/Track information 81 */ 82 class MediaClockConverter; 83 84 class VideoTrackDimensionInfo 85 { 86 public: VideoTrackDimensionInfo()87 VideoTrackDimensionInfo() {}; ~VideoTrackDimensionInfo()88 virtual ~VideoTrackDimensionInfo() {}; VideoTrackDimensionInfo(const VideoTrackDimensionInfo & aSrc)89 VideoTrackDimensionInfo(const VideoTrackDimensionInfo& aSrc) 90 { 91 iTrackId = aSrc.iTrackId; 92 iWidth = aSrc.iWidth; 93 iHeight = aSrc.iHeight; 94 iDisplayWidth = aSrc.iDisplayWidth; 95 iDisplayHeight = aSrc.iDisplayHeight; 96 97 }; 98 99 uint32 iTrackId; 100 int32 iWidth; 101 int32 iHeight; 102 int32 iDisplayWidth; 103 int32 iDisplayHeight; 104 }; 105 106 class PVMP4FFNodeTrackPortInfo : public OsclMemPoolFixedChunkAllocatorObserver, 107 public OsclMemPoolResizableAllocatorObserver 108 { 109 public: 110 enum TrackState 111 { 112 TRACKSTATE_UNINITIALIZED, 113 TRACKSTATE_INITIALIZED, 114 TRACKSTATE_TRANSMITTING_GETDATA, 115 TRACKSTATE_TRANSMITTING_SENDDATA, 116 TRACKSTATE_TRACKDATAPOOLEMPTY, 117 TRACKSTATE_MEDIADATAPOOLEMPTY, 118 TRACKSTATE_MEDIADATAFRAGGROUPPOOLEMPTY, 119 TRACKSTATE_DESTFULL, 120 TRACKSTATE_INSUFFICIENTDATA, 121 TRACKSTATE_ENDOFTRACK, 122 TRACKSTATE_ERROR, 123 TRACKSTATE_DOWNLOAD_AUTOPAUSE, 124 TRACKSTATE_SEND_ENDOFTRACK, 125 TRACKSTATE_TRACKMAXDATASIZE_RESIZE, 126 TRACKSTATE_SKIP_CORRUPT_SAMPLE 127 }; 128 PVMP4FFNodeTrackPortInfo()129 PVMP4FFNodeTrackPortInfo() 130 { 131 iTrackId = -1; 132 iPortInterface = NULL; 133 iFormatType = PVMF_MIME_FORMAT_UNKNOWN; 134 iFormatTypeInteger = 0; 135 iClockConverter = NULL; 136 iState = TRACKSTATE_UNINITIALIZED; 137 iTrackMaxDataSize = 0; 138 iTrackMaxQueueDepth = 0; 139 iTrackDataMemoryPool = NULL; 140 iMediaDataImplAlloc = NULL; 141 iTextMediaDataImplAlloc = NULL; 142 iMediaDataMemPool = NULL; 143 iMediaDataGroupImplMemPool = NULL; 144 iMediaDataGroupAlloc = NULL; 145 iNode = NULL; 146 iTimestamp = 0; 147 iFirstFrameAfterRepositioning = false; 148 iSeqNum = 0; 149 iSendBOS = false; 150 151 iNumAMRSamplesToRetrieve = 0; 152 iCurrentTextSampleEntryIndex = 0; 153 154 /* bitstream logging */ 155 iPortLogger = NULL; 156 oFormatSpecificInfoLogged = false; 157 iMinTime = 0; 158 iMaxTime = 0; 159 iSumTime = 0; 160 iNumTimesMediaSampleRead = 0; 161 iNumSamples = 0; 162 163 //thumb nail mode 164 iThumbSampleDone = false; 165 166 iTargetNPTInMediaTimeScale = 0; 167 iLogger = PVLogger::GetLoggerObject("datapath.sourcenode.mp4parsernode"); 168 //PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"PVMP4FFNodeTrackPortInfo::PVMP4FFNodeTrackPortInfo")); 169 170 } 171 PVMP4FFNodeTrackPortInfo(const PVMP4FFNodeTrackPortInfo & aSrc)172 PVMP4FFNodeTrackPortInfo(const PVMP4FFNodeTrackPortInfo& aSrc) : 173 OsclMemPoolFixedChunkAllocatorObserver(aSrc), 174 OsclMemPoolResizableAllocatorObserver(aSrc) 175 { 176 iTrackId = aSrc.iTrackId; 177 iPortInterface = aSrc.iPortInterface; 178 iMimeType = aSrc.iMimeType; 179 iFormatType = aSrc.iFormatType; 180 iFormatTypeInteger = aSrc.iFormatTypeInteger; 181 iClockConverter = aSrc.iClockConverter; 182 iFormatSpecificConfig = aSrc.iFormatSpecificConfig; 183 iFormatSpecificConfigAndFirstSample = aSrc.iFormatSpecificConfigAndFirstSample; 184 iMediaData = aSrc.iMediaData; 185 iState = aSrc.iState; 186 iTrackMaxDataSize = aSrc.iTrackMaxDataSize; 187 iTrackMaxQueueDepth = aSrc.iTrackMaxQueueDepth; 188 iTrackDataMemoryPool = aSrc.iTrackDataMemoryPool; 189 iMediaDataImplAlloc = aSrc.iMediaDataImplAlloc; 190 iTextMediaDataImplAlloc = aSrc.iTextMediaDataImplAlloc; 191 iMediaDataMemPool = aSrc.iMediaDataMemPool; 192 iMediaDataGroupImplMemPool = aSrc.iMediaDataGroupImplMemPool; 193 iMediaDataGroupAlloc = aSrc.iMediaDataGroupAlloc; 194 iNode = aSrc.iNode; 195 iTimestamp = aSrc.iTimestamp; 196 iFirstFrameAfterRepositioning = aSrc.iFirstFrameAfterRepositioning; 197 iSeqNum = aSrc.iSeqNum; 198 iSendBOS = aSrc.iSendBOS; 199 200 iNumAMRSamplesToRetrieve = aSrc.iNumAMRSamplesToRetrieve; 201 iCurrentTextSampleEntryIndex = aSrc.iCurrentTextSampleEntryIndex; 202 iCurrentTextSampleEntry = aSrc.iCurrentTextSampleEntry; 203 204 /* bitstream logging */ 205 iPortLogger = aSrc.iPortLogger; 206 iLogFile = aSrc.iLogFile; 207 oFormatSpecificInfoLogged = aSrc.oFormatSpecificInfoLogged; 208 iBinAppenderPtr = aSrc.iBinAppenderPtr; 209 iNumSamples = aSrc.iNumSamples; 210 iMinTime = aSrc.iMinTime; 211 iMaxTime = aSrc.iMaxTime; 212 iSumTime = aSrc.iSumTime; 213 iNumTimesMediaSampleRead = aSrc.iNumTimesMediaSampleRead; 214 iThumbSampleDone = aSrc.iThumbSampleDone; 215 216 iTargetNPTInMediaTimeScale = aSrc.iTargetNPTInMediaTimeScale; 217 218 iLogger = aSrc.iLogger; 219 } 220 ~PVMP4FFNodeTrackPortInfo()221 virtual ~PVMP4FFNodeTrackPortInfo() 222 { 223 iCurrentTextSampleEntry.Unbind(); 224 } 225 226 // From OsclMemPoolFixedChunkAllocatorObserver freechunkavailable(OsclAny *)227 void freechunkavailable(OsclAny*) 228 { 229 230 if (iState == TRACKSTATE_MEDIADATAPOOLEMPTY || iState == TRACKSTATE_MEDIADATAFRAGGROUPPOOLEMPTY) 231 { 232 //PVLogger* iDataPathLogger = PVLogger::GetLoggerObject("datapath.sourcenode.mp4parsernode"); 233 //PVMF_MP4FFPARSERNODE_LOGDATATRAFFIC((0, "PVMP4PN - freechunkavailable - %s, TrackID=%d", this->iMimeType.get_cstr(), this->iTrackId)); 234 // Change state 235 iState = TRACKSTATE_TRANSMITTING_GETDATA; 236 if (iNode) 237 { 238 if (iNode->IsAdded()) 239 { 240 // Activate the parent node if necessary 241 iNode->RunIfNotReady(); 242 } 243 } 244 } 245 } 246 247 // From OsclMemPoolResizableAllocatorObserver 248 // Callback handler when mempool's deallocate() is called after 249 // calling notifyfreeblockavailable() on the mempool freeblockavailable(OsclAny *)250 void freeblockavailable(OsclAny*) 251 { 252 // Check if track is waiting for track data to be available 253 if (iState == TRACKSTATE_TRACKDATAPOOLEMPTY) 254 { 255 //PVLogger* iDataPathLogger = PVLogger::GetLoggerObject("datapath.sourcenode.mp4parsernode"); 256 //PVMF_MP4FFPARSERNODE_LOGDATATRAFFIC((0, "PVMP4PN - freechunkavailable - %s, TrackID=%d", this->iMimeType.get_cstr(), this->iTrackId)); 257 // Change state 258 iState = TRACKSTATE_TRANSMITTING_GETDATA; 259 if (iNode) 260 { 261 if (iNode->IsAdded()) 262 { 263 // Activate the parent node if necessary 264 iNode->RunIfNotReady(); 265 } 266 } 267 } 268 } 269 270 // Track ID number in MP4 FF 271 int32 iTrackId; 272 // Output port to send the data downstream 273 PVMFPortInterface* iPortInterface; 274 // Mime type for the port 275 OSCL_HeapString<OsclMemAllocator> iMimeType; 276 // Format type for the port 277 PVMFFormatType iFormatType; 278 // Integer Format type for the port 279 uint32 iFormatTypeInteger; 280 // Converter to convert from track timescale to milliseconds 281 MediaClockConverter* iClockConverter; 282 // Shared memory pointer holding the decoder specific config info for this track 283 OsclRefCounterMemFrag iFormatSpecificConfig; 284 // Shared memory pointer holding the decoder specific config info plus 285 // the first sample for this track 286 OsclRefCounterMemFrag iFormatSpecificConfigAndFirstSample; 287 // Shared memory pointer holding the currently retrieved track data 288 PVMFSharedMediaDataPtr iMediaData; 289 // Current state of this track 290 TrackState iState; 291 // The maximum expected track data size (depends on format) 292 uint32 iTrackMaxDataSize; 293 // The maximum queue depth for the track data (depend on format) 294 uint32 iTrackMaxQueueDepth; 295 // Output buffer memory pool 296 OsclMemPoolResizableAllocator *iTrackDataMemoryPool; 297 // Allocator for simple media data buffer impl 298 PVMFResizableSimpleMediaMsgAlloc *iMediaDataImplAlloc; 299 // Allocator for text track simple media data buffer impl 300 PVMFTimedTextMediaDataAlloc* iTextMediaDataImplAlloc; 301 // Memory pool for simple media data 302 PVMFMemPoolFixedChunkAllocator *iMediaDataMemPool; 303 // Memory pool for media data buffer impl that holds multiple media fragments 304 OsclMemPoolFixedChunkAllocator* iMediaDataGroupImplMemPool; 305 // Allocator for media frag group 306 PVMFMediaFragGroupCombinedAlloc<OsclMemAllocator>* iMediaDataGroupAlloc; 307 308 // MP4 FF parser node handle as AO class 309 OsclTimerObject* iNode; 310 // Timestamp 311 uint32 iTimestamp; 312 // Flag to indicate that next frame will be the first frame after repositioning 313 bool iFirstFrameAfterRepositioning; 314 // Sequence Number 315 uint32 iSeqNum; 316 // bos flag 317 bool iSendBOS; 318 319 // Format specific variables 320 // AMR track 321 uint32 iNumAMRSamplesToRetrieve; 322 // Timed text track 323 uint32 iCurrentTextSampleEntryIndex; 324 OsclSharedPtr<PVMFTimedTextSampleEntry> iCurrentTextSampleEntry; 325 326 /* bitstream logging */ 327 PVLogger* iPortLogger; 328 PVLogger *iLogger; 329 330 OSCL_HeapString<OsclMemAllocator> iLogFile; 331 bool oFormatSpecificInfoLogged; 332 OsclSharedPtr<PVLoggerAppender> iBinAppenderPtr; 333 uint32 iMinTime; 334 uint32 iMaxTime; 335 uint32 iSumTime; 336 uint32 iNumSamples; 337 uint32 iNumTimesMediaSampleRead; 338 339 //thumb nail mode 340 bool iThumbSampleDone; 341 342 // no-render related 343 uint32 iTargetNPTInMediaTimeScale; 344 }; 345 346 class PVMP4FFNodeTrackOMA2DRMInfo 347 { 348 public: PVMP4FFNodeTrackOMA2DRMInfo()349 PVMP4FFNodeTrackOMA2DRMInfo() 350 { 351 iTrackId = 0; 352 iDRMInfoSize = 0; 353 iDRMInfo = NULL; 354 iOMA2TrackAuthorizationInProgress = false; 355 iOMA2TrackAuthorizationComplete = false; 356 iOMA2TrackAuthorized = false; 357 }; 358 PVMP4FFNodeTrackOMA2DRMInfo(const PVMP4FFNodeTrackOMA2DRMInfo & aSrc)359 PVMP4FFNodeTrackOMA2DRMInfo(const PVMP4FFNodeTrackOMA2DRMInfo& aSrc) 360 { 361 Copy(aSrc); 362 }; 363 364 ~PVMP4FFNodeTrackOMA2DRMInfo()365 virtual ~PVMP4FFNodeTrackOMA2DRMInfo() 366 { 367 if (iDRMInfo != NULL) 368 { 369 OSCL_ARRAY_DELETE(iDRMInfo); 370 iDRMInfo = NULL; 371 } 372 }; 373 Copy(const PVMP4FFNodeTrackOMA2DRMInfo & aSrc)374 void Copy(const PVMP4FFNodeTrackOMA2DRMInfo& aSrc) 375 { 376 iTrackId = aSrc.iTrackId; 377 iDRMInfoSize = aSrc.iDRMInfoSize; 378 if (iDRMInfoSize > 0) 379 { 380 iDRMInfo = OSCL_ARRAY_NEW(uint8, iDRMInfoSize); 381 oscl_memcpy((OsclAny*)iDRMInfo, (OsclAny*)(aSrc.iDRMInfo), iDRMInfoSize); 382 } 383 iOMA2TrackAuthorizationInProgress = aSrc.iOMA2TrackAuthorizationInProgress; 384 iOMA2TrackAuthorizationComplete = aSrc.iOMA2TrackAuthorizationComplete; 385 iOMA2TrackAuthorized = aSrc.iOMA2TrackAuthorized; 386 }; 387 388 uint32 iTrackId; 389 uint32 iDRMInfoSize; 390 uint8* iDRMInfo; 391 bool iOMA2TrackAuthorizationInProgress; 392 bool iOMA2TrackAuthorizationComplete; 393 bool iOMA2TrackAuthorized; 394 }; 395 396 class PVMFMP4FFParserNode; 397 398 class PVMFMP4FFParserOutPort : public PvmfPortBaseImpl, 399 public PvmiCapabilityAndConfigPortFormatImpl 400 { 401 public: 402 PVMFMP4FFParserOutPort(int32 aTag, PVMFNodeInterface* aNode, const char*); 403 PVMFMP4FFParserOutPort(int32 aTag 404 , PVMFNodeInterface* aNode 405 , uint32 aInCapacity 406 , uint32 aInReserve 407 , uint32 aInThreshold 408 , uint32 aOutCapacity 409 , uint32 aOutReserve 410 , uint32 aOutThreshold 411 , const char*name); 412 ~PVMFMP4FFParserOutPort(); 413 414 // From PvmiCapabilityAndConfigPortFormatImpl interface 415 bool IsFormatSupported(PVMFFormatType); 416 void FormatUpdated(); 417 418 // To support config interface QueryInterface(const PVUuid & aUuid,OsclAny * & aPtr)419 void QueryInterface(const PVUuid &aUuid, OsclAny*&aPtr) 420 { 421 if (aUuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID) 422 { 423 aPtr = (PvmiCapabilityAndConfig*)this; 424 } 425 else 426 { 427 aPtr = NULL; 428 } 429 } 430 /* Over ride Connect() */ 431 PVMFStatus Connect(PVMFPortInterface* aPort); 432 433 /* Implement pure virtuals from PvmiCapabilityAndConfig interface */ 434 PVMFStatus getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, 435 PvmiKvp*& aParameters, int& num_parameter_elements, PvmiCapabilityContext aContext); 436 PVMFStatus releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements); 437 void setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, 438 int num_elements, PvmiKvp * & aRet_kvp); 439 PVMFStatus verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements); 440 441 /* Unsupported PvmiCapabilityAndConfig methods */ setObserver(PvmiConfigAndCapabilityCmdObserver * aObserver)442 void setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver) 443 { 444 OSCL_UNUSED_ARG(aObserver); 445 }; createContext(PvmiMIOSession aSession,PvmiCapabilityContext & aContext)446 void createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) 447 { 448 OSCL_UNUSED_ARG(aSession); 449 OSCL_UNUSED_ARG(aContext); 450 }; setContextParameters(PvmiMIOSession aSession,PvmiCapabilityContext & aContext,PvmiKvp * aParameters,int num_parameter_elements)451 void setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext, 452 PvmiKvp* aParameters, int num_parameter_elements) 453 { 454 OSCL_UNUSED_ARG(aSession); 455 OSCL_UNUSED_ARG(aContext); 456 OSCL_UNUSED_ARG(aParameters); 457 OSCL_UNUSED_ARG(num_parameter_elements); 458 }; DeleteContext(PvmiMIOSession aSession,PvmiCapabilityContext & aContext)459 void DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) 460 { 461 OSCL_UNUSED_ARG(aSession); 462 OSCL_UNUSED_ARG(aContext); 463 }; 464 PVMFCommandId setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, 465 int num_elements, PvmiKvp*& aRet_kvp, OsclAny* context = NULL) 466 { 467 OSCL_UNUSED_ARG(aRet_kvp); 468 OSCL_UNUSED_ARG(aSession); 469 OSCL_UNUSED_ARG(aParameters); 470 OSCL_UNUSED_ARG(num_elements); 471 OSCL_UNUSED_ARG(context); 472 return -1; 473 } getCapabilityMetric(PvmiMIOSession aSession)474 uint32 getCapabilityMetric(PvmiMIOSession aSession) 475 { 476 OSCL_UNUSED_ARG(aSession); 477 return 0; 478 } 479 480 481 private: 482 void Construct(); 483 bool pvmiSetPortFormatSpecificInfoSync(PvmiCapabilityAndConfig *aPort, 484 const char* aFormatValType); 485 486 bool pvmiGetPortFormatSpecificInfoSync(const char* aFormatValType, 487 PvmiKvp*& aKvp); 488 PVLogger *iLogger; 489 uint32 iNumFramesGenerated; //number of source frames generated. 490 uint32 iNumFramesConsumed; //number of frames consumed & discarded. 491 492 friend class PVMFMP4FFParserNode; 493 PVMFMP4FFParserNode* iMP4FFParserNode; 494 }; 495 496 #endif // PVMF_MP4FFPARSER_OUTPORT_H_INCLUDED 497