Welcome Guest! To enable all features, please Login or Register.

Notification

Icon
Error

Options
View
Last Go to last post Unread Go to first unread post
#1 Posted : Thursday, April 20, 2017 12:20:27 PM(UTC)

Walter  
Walter

Groups: Tech Support, Administrators
Posts: 320

Was thanked: 3 time(s) in 3 post(s)

The LEAD MPEG-2 Transport Demultiplexer supports parsing KLV as defined by SMPTE 336M-2001. Through the ILMMpgDmxCallback callback provided by the MPEG-2 TS demux, LEADTOOLS will provide any Universal, Local, or Minimum metadata found. It is up to the calling application to then look at the key and the the associated value.

In the LEADTOOLS SDK, the MPEG-2 Transport (player) demo illustrates how this is done. This demo specifically handles known KLV from Predator UAVs. Other KLV is ignored by the demo.

With the MPEG-2 Transport demo, the C++ code adding the callback looks like this:
Code:

ILMMpgDmx *CMainFrame::GetMPEG2DemuxInterface()
{
   IUnknown *pSplitter;
   HRESULT hr = m_player->GetSubObject(ltmmPlay_Object_Splitter, &pSplitter);
   if(SUCCEEDED(hr))
   {
      ILMMpgDmx *pMpgDmx;
      hr = pSplitter->QueryInterface(IID_ILMMpgDmx, (void **)&pMpgDmx);
      if(SUCCEEDED(hr))
      {
         pSplitter->Release();
         return pMpgDmx;
      }
      pSplitter->Release();
   }
   return NULL;
}

void CMainFrame::EnableMPEG2DemuxCallback()
{
   HRESULT hr;
   ILMMpgDmx *pMpgDmx = GetMPEG2DemuxInterface();
   if(pMpgDmx)
   {
      // make sure the demux is not using the callback I am about to destroy
      pMpgDmx->put_CallbackObj(NULL);

      DeleteCallbackClass();

      m_pCallback = new CMPEG2DemuxCallback(pMpgDmx);

      // Force the callback to be called in the main thread. C++ applications in general can handle data in another thread, but our app is using MFC
      // Our callback will display data in a window and MFC doesn't work well when you use windows from threads other than the main thread
      // So, for simplicity, we will ask the demux to send the data to the main thread
      hr = pMpgDmx->put_CallInSameThread(VARIANT_TRUE);
      hr = pMpgDmx->put_CallbackObj(m_pCallback);

      pMpgDmx->Release();
   }
}


And the DataAvailable() function being called looks like this:
Code:

HRESULT STDMETHODCALLTYPE CMPEG2DemuxCallback::DataAvailable
( 
   /* [in] */ VARIANT *pData,
   /* [in] */ long lDataSize,
   /* [in] */ FileTypeConstants fileType,
   /* [in] */ long streamPID,
   /* [in] */ long streamType,
   /* [in] */ PTSTypeConstants PTSType,
   /* [in] */ double PTS,
   /* [in] */ long flags
)
{
   // skip small (most likely invalid) data chunks
   if(lDataSize <= 1)
      return S_OK;

   //refresh control
   { 
      static const DWORD MIN_REFRESH_TIME = 1000 ;//1 second
      static DWORD dwLastTime = 0 ;//allow first data to be displayed

      DWORD dwCurTime = GetTickCount ( ) ;

      if ( dwCurTime - dwLastTime < MIN_REFRESH_TIME )
      {         
         return S_OK ;
      }
      else
      {
         dwLastTime = dwCurTime ;
      }
   }
   
   CPrivateDataView* pDataView = CPrivateDataViewManager::GetPrivateDataListView ( ) ;

   if(!pDataView)
      return S_OK;//skip

   pDataView->SetRedraw ( FALSE ) ;
   pDataView->GetListCtrl ( ).DeleteAllItems ( ) ;

   {
      HRESULT hr;
      
      if(flags & DataFlag_IsKLV)
      {
         ILMKlvParser* pParser;

         hr = m_pMpgDmx->GetKlvParser(streamPID, &pParser);
         if(FAILED(hr)) return hr;

         hr = EnumKlvKeys(pParser, pDataView, NULL, pData, lDataSize, flags);
         if(FAILED(hr)) 
         { 
            pParser->Release() ;

            return hr;
         }

         pParser->Release();
      }
      else if(flags & DataFlag_IsAscii)
      {
         CString str;

         hr = DumpVariantAsAscii(str, pData, lDataSize);
         if(FAILED(hr))
            return hr;

         pDataView->AddValue (str) ;
      }
      else if(flags & DataFlag_IsBinary)
      {
         CString str;

         hr = DumpVariantAsBinary(str, pData, lDataSize);
         if(FAILED(hr))
            return hr;

         pDataView->AddValue (str) ;
      }
      else
      {
         ASSERT ( FALSE ) ;      
         return E_UNEXPECTED;
      }
   }

   pDataView->SetRedraw ( TRUE ) ;
   pDataView->RedrawWindow ( ) ;

   return S_OK ;
}


The code recursively calls the EnumKlvKeys() method to handle decoding parent and child keys and uses the ILMKlvParser::GetKey() to get the data from they key.
Walter Bates
Senior Support Engineer
LEAD Technologies, Inc.
LEAD Logo
 

Try the latest version of LEADTOOLS for free for 60 days by downloading the evaluation: https://www.leadtools.com/downloads

Wanna join the discussion? Login to your LEADTOOLS Support accountor Register a new forum account.

You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Powered by YAF.NET | YAF.NET © 2003-2017, Yet Another Forum.NET
This page was generated in 0.123 seconds.