Help - Search - Members - Calendar
Full Version: BDA Channel Scanning
DVB Owners Discussion Forum - dvbowners.com > Technical & Development Forums > BDA Driver Development
Spectrum
Let me just start by saying I haven't actually tried this in code. I've done a lot of reading and I want to assist others to understand the process (in theory).

What we are trying to do here is get the TIF filter to tell us when it has new information regarding the TS that we are locked on to. Then we try tuning to EVERY possible channel and capture the information the TIF filter collects.

We do this in two parts. We firstly "connect" the TIF filter to ourselves so it will notify us when changes to the TS occur, then we kick off a channel scan.

To connect the TIF filter to ourselves:

First implement the IGuideDataEvent interface on your class.
http://msdn.microsoft.com/library/en-us/di...ntinterface.asp
After we have connected to the TIF filter, it will call us on this interface to notify us of changes to program and service information. The TIF filter will want to run QueryInterface on us to see that we support the IGuideDataEvent interface so don't forget to implement the IUnknown interface as well.

Then find the TIF filter in your graph. The way you do this depends on how you've built the graph in the first place. If you have manually built the graph then you'll already have a reference to it.

Once you have the TIF filter, get a reference to its IConnectionPointContainer interface.
http://msdn.microsoft.com/library/en-us/co.../cmi_c_2ar8.asp

CODE
private:

   DWORD m_dwAdviseCookie; //The cookie given to us by Advise

   IConnectionPoint *m_pConnection; //The interface where we called Advise/Unadvise.



...



Then after the TIF has been created.



...



HRESULT hr = E_UNEXPECTED;

IConnectionPointContainer *pContaner = NULL;

IConnectionPoint          *pConnection = NULL;



// First we need to get the IConnectionPointContainer

// interface from the TIF

hr = pTIF->QueryInterface(__uuidof(IConnectionPointContainer),(void **)&pContainer);

if (SUCCEEDED(hr)) {

   // Now, see if the event source will fire off events of the IGuideDataEvent kind.

   hr = pContainer->FindConnectionPoint(__uuidof(IGuideDataEvent), &m_pConnection);

   if (SUCCEEDED(hr)) {

       IUnknown *me = 0;

       // We know this will work...

       this->QueryInterface(__uuidof(IUnknown),(void **)&me);

       // Now that we know that the source fires our kind of events, we can attach to it.

       hr = m_pConnection->Advise(me, &m_dwAdviseCookie);

   }

   // We are done with this interface now so we free it up.

   pContainer->Release();

}



...



// In our cleanup code when the application is destroying filters,

// before destroying the TIF filter disconnect the connection point.

m_pConnection->Unadvise(m_dwAdviseCookie);

// And release the connection

m_pConnection->Release();


That's enough to register with the TIF filter to send us events.

Now when tuning we expect our IGuideDataEvent::ServiceChanged() method to be called when the TIF gets new channel information.

The documentation specifies that we MUST NOT block in any method in the IGuideDataEvent interface. What this means is that we must somehow inform our application that there are changes waiting to be read and return immediately.

As to how this is accomplished depends on the application you are writing. If you are writing this for a GUI then you could use GUI events. If for a command line app, use threads and blocking.

For example, you could have an application thread block on an event and then have ServiceChanged() set some internal variables and then call SetEvent() to get the thread running again.
CODE
private:

   HANDLE m_hGuideDataChangedEvent;



HRESULT CMyClass::ServiceChanged(VARIANT varServiceDescriptionID) {



   HRESULT Result = S_OK;



   m_bServiceChanged = TRUE;



   SetEvent(m_hGuideDataChangedEvent);



   return Result;



}





CMyClass::GuideCheckingThread(...) {



   m_hGuideDataChangedEvent = CreateEvent(

       NULL,

       TRUE,

       FALSE,

       "GuideDataChangedEvent"

       );



   if (m_hGuideDataChangedEvent != NULL) {



       while (1) {

           ResetEvent(m_hGuideDataChangedEvent);



           WaitForSingleObject(m_hGuideDataChangedEvent, INFINITE);



           if (m_bServiceChanged == TRUE) {

               // Get updated service parameters



               ...



               // Reset m_bServiceChanged

               m_bServiceChanged = FALSE;

           }



           if (m_bProgramChanged == TRUE) {

               ...

           }



           if ...

       }

   }

}





In the following block use the TIF filter's IGuideData interface to get services.

if (m_bServiceChanged == TRUE) {

   // Get updated service parameters

   HRESULT hr = E_UNEXPECTED;

   IGuideData *pGuideData = NULL;

   IEnumTuneRequests *pEnumTuneRequests = NULL;



   // First we need to get the IGuideData

   // interface from the TIF

   hr = pTIF->QueryInterface(__uuidof(IGuideData),(void **)&pGuideData);

   if (SUCCEEDED(hr)) {

       pGuideData->GetServices(&pEnumTuneRequests);

And so on to get TuneRequests:
http://msdn.microsoft.com/library/en-us/di...getservices.asp

This SHOULD get you all the information you need to tune programs.

Incidently getting the TIF to call our IGuideData interface is how we get Now/Next information and probably other good stuff.
Spectrum
The next step is to scan all frequencies in order to get a TS to the TIF. Obviously if you know the frequencies of the broadcaster in your area you may just want to tune each one in turn and capture the data from the TIF. To be flexible however we need the option of tuning in to all possible frequencies for discovery purposes or for those who are unsure which frequencies are in use.


You may be wondering how it knows which channels to tune into - you tell it of course!

For this we use the DVB-t Network Provider filter's IFrequencyMap interface.
http://msdn.microsoft.com/library/en-us/di...apinterface.asp

Use the put_CountryCode() method to tell it to use Australian frequencies. We're country 61 and I think this has a definition of F_OZ__BROAD somewhere. If there is no frequency mapping defined for the country passed to put_CountryCode() (and there probably won't be for Australia) it will return an error. However, it stores the new country/region code, and the application can create a new frequency table by calling the put_FrequencyMapping() method.

To save you the hassle, I've supplied the array of frequencies for Australia. So just call
put_FrequencyMapping(150, ulFrequencyList);

The DVB-t Network Provider filter makes scanning all channels relatively easy using the IScanningTuner interface; in particular the AutoProgram() method. When you want to run a full scan, you call AutoProgram() which runs in the background and will tune in to each channel once. One thing I'm not sure about is how to know when scanning is complete - the documentation does not mention this??
http://msdn.microsoft.com/library/en-us/di...erinterface.asp

CODE
/*
 * Australian Digital Television Broadcast Frequency List
 *
 * Most broadcasts will use the channel centre frequency, but it
 * is perfectly legal to use a +/- 125kHz offset, so the complete
 * set is provided here.
 *
 * In all there are 150 valid frequencies.
 *
 * These values are in kilohertz, multiply by 1000 to get Hertz.
 */

static const ULONG ulFrequencyList[150] = {

    // Band III VHF
    177375, 177500, 177625,  // 6
    184375, 184500, 184625,  // 7
    191375, 191500, 191625,  // 8
    198375, 198500, 198625,  // 9
    205375, 205500, 205625,  // 9A
    212375, 212500, 212625,  // 10
    219375, 219500, 219625,  // 11
    226375, 226500, 226625,  // 12

    // Band IV UHF
    529375, 529500, 529625,  // 28
    536375, 536500, 536625,  // 29
    543375, 543500, 543625,  // 30
    550375, 550500, 550625,  // 31
    557375, 557500, 557625,  // 32
    564375, 564500, 564625,  // 33
    571375, 571500, 571625,  // 34
    578375, 578500, 578625,  // 35

    // Band V UHF
    585375, 585500, 585625,  // 36
    592375, 592500, 592625,  // 37
    599375, 599500, 599625,  // 38
    606375, 606500, 606625,  // 39
    613375, 613500, 613625,  // 40
    620375, 620500, 620625,  // 41
    627375, 627500, 627625,  // 42
    634375, 634500, 634625,  // 43
    641375, 641500, 641625,  // 44
    648375, 648500, 648625,  // 45
    655375, 655500, 655625,  // 46
    662375, 662500, 662625,  // 47
    669375, 669500, 669625,  // 48
    676375, 676500, 676625,  // 49
    683375, 683500, 683625,  // 50
    690375, 690500, 690625,  // 51
    697375, 697500, 697625,  // 52
    704375, 704500, 704625,  // 53
    711375, 711500, 711625,  // 54
    718375, 718500, 718625,  // 55
    725375, 725500, 725625,  // 56
    732375, 732500, 732625,  // 57
    739375, 739500, 739625,  // 58
    746375, 746500, 746625,  // 59
    753375, 753500, 753625,  // 60
    760375, 760500, 760625,  // 61
    767375, 767500, 767625,  // 62
    774375, 774500, 774625,  // 63
    781375, 781500, 781625,  // 64
    788375, 788500, 788625,  // 65
    795375, 795500, 795625,  // 66
    802375, 802500, 802625,  // 67
    809375, 809500, 809625,  // 68
    816375, 816500, 816625   // 69

};


Hopefully someone will give all this a go.

Spectrum
JoeyBloggs
Yep, When I have things a bit more stable, I will definitely give it a go biggrin.gif
Spectrum
If you notice my absence in this forum it's because I'll be on holiday for a week in Melbourne. I'll leave you guys to have all the fun. Catch you later.

Spectrum.
null_pointer
Welcome to sunny Melbourne Spectrum :-)
null_pointer
The main problem is what do you do with the raw SECTION data once you get it, you need to know the data structure to extract the info you want. I have had a bit of a play with this and found that is is much easier to use the PSI filter to extract the program and elemental streams etc.

The PSI filter is an example filter that comes with the DirectX 9 SDK, it parses the PSI data from a TS and gives you program info.

From a WS point of view all I need is the program ID and elemental stream id's for each program, following is some sample code that uses the PSI filter to extract his info.

CODE
// removes each filter from the graph

HRESULT

CBDAFilterGraph::GetProgramInfo()

{

    HRESULT hr = S_OK;



    IMpeg2PsiParser *pMpeg2PSI;



    CLSID psiCID;

    CComBSTR bstrTemp ("{AE1A2884-540E-4077-B1AB-67A34A72298C}");



    hr = CLSIDFromString(bstrTemp, &psiCID);



    hr = m_pPSI->QueryInterface(psiCID, (void **)&pMpeg2PSI);



   if (FAILED (hr))

   {

       printf("win32-DLL-BDA : Cannot QI for IMpeg2PsiParser on the PSI filter
");

       return hr;

   }



    int progCount = 0;



    pMpeg2PSI->GetCountOfPrograms(&progCount);



    printf("PROGRAM INFO : Number of programs = %d

", progCount);



    for(int x = 0; x < progCount; x++)

    {



 WORD progID = 0;

 pMpeg2PSI->GetRecordProgramNumber(x, &progID);

 printf("PROGRAM INFO : Number %d ID = %d ", x, progID);



 WORD transNum = 0;

 pMpeg2PSI->GetCountOfElementaryStreams(progID, &transNum);



 for(WORD y = 0; y < transNum; y++)

 {

     BYTE elType = 0;

     pMpeg2PSI->GetRecordStreamType(progID, y, &elType);



     WORD elPID = 0;

     pMpeg2PSI->GetRecordElementaryPid(progID, y, &elPID);



     if(elType == 2)

     {

   printf(" VPID=%d ", elPID);

     }

     else if(elType == 4)

     {

   printf(" APID=%d ", elPID);

     }



 }

 printf("
");

    }



    pMpeg2PSI->Release();



    return hr;

}


Here is some sample output.

QUOTE
PROGRAM INFO : Number of programs = 4

PROGRAM INFO : Number 0 ID = 0
PROGRAM INFO : Number 1 ID = 1072  VPID=519  APID=720
PROGRAM INFO : Number 2 ID = 1073  VPID=512
PROGRAM INFO : Number 3 ID = 1074  VPID=517  APID=700


As you can see the AC3 stream do not get identified as audio, I will look at fixing the PSI filter to properly identify AC3.

This is just an example but will give you the program info etc from a TS stream, it is all I need so this is probably what I will be using for WS.
nate
QUOTE
As you can see the AC3 stream do not get identified as audio, I will look at fixing the PSI filter to properly identify AC3.

Months ago I started looking into making the psi parser determine ac3 streams also, but i got distracted and never got back to it.
I don't think there's a way to differentiate between ac3 private streams and other private streams such as teletext from the psi data. I think you need to look at the actual packets in the private stream to get this information. It should just be a matter of mapping the private stream pid to the pin going to the psi parser and then figuring out which bits of the private stream determine it's type.
null_pointer
Yes, after looking at the PSI filter code it looks like the stream type is coming directly from the table data in the TS.

This is probably why the TwinHan SDK has problems determining AC3 as well.
JoeyBloggs
Nate, what are your feelings on incorporating ATL in DigiWatch. So we can all use smart com pointers and text conversion stuff T2OLE etc ? With stuff we are developing for the BDASample. I think its likely that DigiWatch will become the sample once things are rolled into it.
nate
QUOTE
Nate, what are your feelings on incorporating ATL in DigiWatch. So we can all use smart com pointers and text conversion stuff T2OLE etc ? With stuff we are developing for the BDASample. I think its likely that DigiWatch will become the sample once things are rolled into it.

Maybe. I don't want the exe to get bloated though. I havn't used ATL before so i don't know how much bigger it'll make the exe.
What are smart com pointers and how will they help?
In terms of text conversion, the mbstowcs function converts ASCI to UNICODE fine.

I'm not saying no, i just need a little convincing.
bionicdonkey
QUOTE
QUOTE
Nate, what are your feelings on incorporating ATL in DigiWatch. So we can all use smart com pointers and text conversion stuff T2OLE etc ? With stuff we are developing for the BDASample. I think its likely that DigiWatch will become the sample once things are rolled into it.

Maybe. I don't want the exe to get bloated though. I havn't used ATL before so i don't know how much bigger it'll make the exe.
What are smart com pointers and how will they help?
In terms of text conversion, the mbstowcs function converts ASCI to UNICODE fine.

I'm not saying no, i just need a little convincing.


Is it possible to do the BDA stuff without ATL?
null_pointer
Yes absolutly, "Active Template Library" or ALT is just a Template system that helps when programming with "Component Object Model" or COM, see the following url's for more info.

http://msdn.microsoft.com/library/default....le_Overview.asp

http://msdn.microsoft.com/library/default....tlreference.asp
JoeyBloggs
Not sure how much bigger including the ATL lib will make DigiWatch. It's certainly possible to do it without it.

Using ATL smart pointers can help for example if you allocate them on the stack and throw an exception. As the stack unwinds the smart pointer destructors ensure that their native com pointers are Released().

mbstowcs assumes that you are only compiling either ascii or unicode. Using the T macros ensure that you can compile for both transparently.

It's no biggy I will continue to use both MFC and ATL internally but converting code fragments back and forth is not a major issue. It's just that the current BDASample code does use CComPtr and CComQIPtr's at the moment. I'm happy to go either way with it. I currently have a mish mash of both styles anyway :wink:
bionicdonkey
I started to make a BDA DVBInput for DigitalWatch but was using ATL, i'll try to change the code to work without it. I learning all this stuff as i'm going so i don't know if i'll get it to work, but i'm still going to have a go.

Regards,
Josh
null_pointer
If you have started with ALT then keep going, ALT does not add that
much overhead, to put it in perspective a real world example is good,
the BDA Sample is only 56K when build for Release, that incudes icons
dialogues and all.

ALT is a very good tool for COM based programming, it helps out with
recourse management, i.e. stuff gets released when things goes bad :-)

The only ALT you really need is the Auto Pointers, and from memory
that is the only thing used in the sample anyway.
bionicdonkey
Ok, I try to get it going with ATL then if i get it working, i'll have a go doing it without it for the experience.
JoeyBloggs
Well I have implemented a inner listener class for the IGuideData ConnectionPoint from the TransportInformationFilter

CODE
class CGuideDataEventListener : public IGuideDataEvent

{

public:

HRESULT STDMETHODCALLTYPE QueryInterface(REFIID rstUUID, void** ppInterface)



ULONG STDMETHODCALLTYPE AddRef()              

ULONG STDMETHODCALLTYPE Release()              



HRESULT STDMETHODCALLTYPE GuideDataAcquired()              

HRESULT STDMETHODCALLTYPE ProgramChanged(VARIANT stVariant)

HRESULT STDMETHODCALLTYPE ServiceChanged(VARIANT stVariant)

HRESULT STDMETHODCALLTYPE ScheduleEntryChanged(VARIANT stVariant)

HRESULT STDMETHODCALLTYPE ProgramDeleted(VARIANT stVariant)

HRESULT STDMETHODCALLTYPE ServiceDeleted(VARIANT stVariant)

HRESULT STDMETHODCALLTYPE ScheduleDeleted(VARIANT stVariant)



DWORD& GetAdviseCookieReference() //The cookie given to us by Advise    

IConnectionPoint*& GetConnectionPointReference() //The interface where we called Advise/Unadvise.



private:



ULONG                    m_ulRefCount;

DWORD                    m_dwAdviseCookie; //The cookie given to us by Advise    

IConnectionPoint*        m_piConnection;   //The interface where we called Advise/Unadvise.



};


I couldn't find any way to manually load the TIF so I just looked for the IID_IGuideData interface afterwards :roll:

CODE
if (SUCCEEDED(hr)) { hr = RenderFilterPin(m_pNetworkProvider, "Antenna Out"); }



/////////////////////////



if (true)

{

    FindInterfaceInGraph(m_piGraphBuilder, IID_IGuideData, &m_piTransportInformationFilter, reinterpret_cast<void**>(&m_piGuideData) );



    IConnectionPointContainer* piContainer  = NULL;

    

    hr = m_piTransportInformationFilter->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void**>(&piContainer) );



    if (SUCCEEDED(hr))

    {    

 m_poGuideDataEventListener = new CGuideDataEventListener();



 hr = piContainer->FindConnectionPoint(IID_IGuideDataEvent, &m_poGuideDataEventListener->GetConnectionPointReference() );    

 

 if (SUCCEEDED(hr))

 {

     hr = m_poGuideDataEventListener->GetConnectionPointReference()->Advise(m_poGuideDataEventListener, &m_poGuideDataEventListener->GetAdviseCookieReference() );

     

     piContainer->Release();

 }

    }

}



/////////////////////////



m_fGraphBuilt   = true;

m_fGraphFailure = false;


and whilst I get the notifications after tuning in a channel

CGuideDataEventListener::ProgramChanged(VARIANT stVariant)
CGuideDataEventListener::ScheduleEntryChanged(VARIANT stVariant)
CGuideDataEventListener::ServiceChanged(VARIANT stVariant)


the variant parameter is always VT_EMPTY :roll:

If I then attempt to enumerate any information from the TIF I just get empty enumerator's with no information provided at all :cry:
null_pointer
Joey,

Could you post your code you use to iterate through the IEnumVARIANT that gets filled in by the GetGuideProgramIDs call to the IGuideData Interface.

Whenever I call next on the IEnumVARIANT I get a 80004003 (E_NULLPOINTER) HRESULT.
JoeyBloggs
CODE
///////////////////////////////////////////////////////////////////////////////

void GetTransportInformationFilterData()

{

    HRESULT hr = S_OK;



    /////////////////////////



   if (true)

    {

 IBaseFilter* piBaseFilter = NULL;

 ITuner*      piTuner      = NULL;



 FindInterfaceInGraph(m_piGraphBuilder, IID_ITuner, &piBaseFilter, reinterpret_cast<void**>(&piTuner) );



 if (piTuner != NULL)

 {

     long lSignalStrength = 0;



     hr = piTuner->get_SignalStrength(&lSignalStrength);



     MYTRACE("Signal Strength = %ldn", lSignalStrength);



     piTuner->Release();

 }

 else

 {

     MYTRACE("FindInterfaceInGraph(m_piGraphBuilder, IID_ITuner - FAILED !!!n");

 }

    }



    /////////////////////////



   if (true)

    {

 IBaseFilter*           piBaseFilter       = NULL;

 IBDA_SignalStatistics* piSignalStatistics = NULL;



 FindInterfaceInGraph(m_piGraphBuilder, IID_IBDA_SignalStatistics, &piBaseFilter, reinterpret_cast<void**>(&piSignalStatistics) );



 if (piSignalStatistics != NULL)

 {

     long lSignalStrength = 0;

     long lSignalQuality  = 0;



     hr = piSignalStatistics->get_SignalStrength(&lSignalStrength);

     hr = piSignalStatistics->get_SignalQuality (&lSignalQuality );



     MYTRACE("Signal Strength = %ldn", lSignalStrength);

     MYTRACE("Signal Quality  = %ldn", lSignalQuality );



     piSignalStatistics->Release();

 }

 else

 {

     MYTRACE("FindInterfaceInGraph(m_piGraphBuilder, IID_IBDA_SignalStatistics - FAILED !!!n");

 }

    }



    /////////////////////////

    

    if (m_piGuideData != NULL)

    {

 IEnumVARIANT*  piEnumProgramEntries = NULL;



 hr = m_piGuideData->GetGuideProgramIDs(&piEnumProgramEntries);



 if (SUCCEEDED(hr))

 {

     CComVariant                varProgramEntryId;

     IEnumGuideDataProperties*  piEnumProperties = NULL;

     

     MYTRACE("while (piEnumProgramEntries->Next(1, &varProgramEntryId, 0) == S_OK)n");



     hr = piEnumProgramEntries->Reset();



     while (piEnumProgramEntries->Next(1, &varProgramEntryId, 0) == S_OK)

     {

   hr = m_piGuideData->GetProgramProperties(varProgramEntryId, &piEnumProperties);



   if (SUCCEEDED(hr))

   {

       MYTRACE("m_piGuideData->GetProgramProperties()n");



       piEnumProperties->Release();

   }

   else

   {

       MYTRACE("m_piGuideData->GetProgramProperties() - FAILED !!!n");

   }

     }



     piEnumProgramEntries->Release();

 }



 /////////////

 

 IEnumTuneRequests*  piEnumTuneRequests = NULL;



 hr = m_piGuideData->GetServices(&piEnumTuneRequests);



 if (SUCCEEDED(hr))

 {

     ITuneRequest*  piTuneRequest = NULL;

     IComponents*   piComponents  = NULL;



     MYTRACE("while (piEnumTuneRequests->Next(1, &piTuneRequest, 0) == S_OK)n");



     //hr = piEnumTuneRequests->Reset();



     while (piEnumTuneRequests->Next(1, &piTuneRequest, 0) == S_OK)

     {

   hr = piTuneRequest->get_Components(&piComponents);



   if (SUCCEEDED(hr))

   {

       MYTRACE("piTuneRequest->get_Components(&piComponents)n");



       long lComponents = 0;



       hr = piComponents->get_Count(&lComponents);





       MYTRACE("FOUND COMPONENTS %ldn", lComponents);





       IEnumComponents* piEnumComponents = NULL;

       IComponent*      piComponent      = NULL;



       hr = piComponents->EnumComponents(&piEnumComponents);



       if (SUCCEEDED(hr))

       {

     while (piEnumComponents->Next(1, &piComponent, 0) == S_OK)

     {

         MYTRACE("FOUND A COMPONENT - piComponentn");

     

         piComponent->Release();

     }



     piEnumComponents->Release();

       }



       piComponents->Release();

   }

   else

   {

       MYTRACE("piTuneRequest->get_Components(&piComponents) - FAILED !!!n");

   }



   piTuneRequest->Release();

     }



     piEnumTuneRequests->Release();

 }



 /////////////



 IEnumVARIANT*  piEnumScheduleEntries = NULL;



 hr = m_piGuideData->GetScheduleEntryIDs(&piEnumScheduleEntries);



 if (SUCCEEDED(hr))

 {

     CComVariant                varScheduleEntryId;

     IEnumGuideDataProperties*  piEnumProperties = NULL;

     

     MYTRACE("while (piEnumScheduleEntries->Next(1, &varScheduleEntryId, 0) == S_OK)n");



     hr = piEnumScheduleEntries->Reset();



     while (piEnumScheduleEntries->Next(1, &varScheduleEntryId, 0) == S_OK)

     {

   hr = m_piGuideData->GetScheduleEntryProperties(varScheduleEntryId, &piEnumProperties);



   if (SUCCEEDED(hr))

   {

       MYTRACE("m_piGuideData->GetScheduleEntryProperties()n");



       piEnumProperties->Release();

   }

   else

   {

       MYTRACE("m_piGuideData->GetScheduleEntryProperties() - FAILED !!!n");

   }

     }



     piEnumScheduleEntries->Release();

 }

 else

 {

     MYTRACE("m_piGuideData->GetScheduleEntryIDs(&piEnumScheduleEntries) - FAILED !!!n");

 }

    }

    else

    {

 MYTRACE("m_piGuideData == NULL - FAILED !!!n");

    }

}
null_pointer
Joey,

Can you get anything at all out of the TIF filter? Does you above code work?
JoeyBloggs
Well I don't get failures as such. The Enumerators just skip straight thru with any elements found.

this didn't help either //hr = piEnumTuneRequests->Reset();
null_pointer
Empty Element Enumerator, perhaps that is what I am seeing, when I call ->Next on the enumerator I get an HRESULT of 80004003 which according to the DXErr.exe util is as follows:

HRESULT: 0x80004003 (2147500035)
Name: E_POINTER
Description: Invalid pointer
Severity code: Failed
Facility Code: FACILITY_NULL (0)
Error Code: 0x4003 (16387)

From my understanding the ->Next call should always return OK unless something bad happened, the num items returned would be zero when there was no more elements etc.
JoeyBloggs
Nope

If you change the enumeration loops like this then yes you get hr = 0x80004003 as they fail ->Next() So I guess that's normal :? :?:

CODE
while ( (hr = piEnumTuneRequests->Next(1, &piTuneRequest, 0)) == S_OK)
JoeyBloggs
Tried cloning the enumerators before using them which failed miserably. Pointing to them NOT being valid ~

CODE
hr = piEnumTuneRequests->Clone(piEnumTuneRequests2);



while ( (hr = piEnumTuneRequests2->Next(1, &piTuneRequest, 0)) == S_OK)



<etc>
null_pointer
Try the following, it looks like you have to pass in the ret value or else it does not work.

CODE
unsigned long ret = 1;

CComVariant varProgramEntryId;

IEnumVARIANT *piEnumProgramEntries;

hr = pGuideData->GetGuideProgramIDs(&piEnumProgramEntries);



piEnumProgramEntries->Reset();



while(SUCCEEDED(piEnumProgramEntries->Next(1, &varProgramEntryId, &ret)) && ret > 0)

{

  IEnumGuideDataProperties *ppEnumProperties;

  hr = pGuideData->GetProgramProperties(varProgramEntryId, &ppEnumProperties);





  IGuideDataProperty *ppProp;

  unsigned long pcelt = 1;



  while(SUCCEEDED(ppEnumProperties->Next(1, &ppProp, &pcelt)) && pcelt > 0)

  {



     CComBSTR name;

     ppProp->get_Name(&name);



     CComVariant value;

     ppProp->get_Value(&value);



     // Do stuff here



  }



}
JoeyBloggs
Yup, good one. That's fixed some of it smile.gif Confirming that you can now get N&N data (via the TIF) from the TS stream.

this isn't working for me yet sad.gif

CODE
IEnumComponents* piEnumComponents = NULL;

IComponent*      piComponent      = NULL;

IMPEG2Component* piMPEG2Component = NULL;



long             lProgramNumber   = 0;

long             lPID             = 0;



hr = piComponents->EnumComponents(&piEnumComponents);



if (SUCCEEDED(hr))

{

    while (piEnumComponents->Next(1, &piComponent, &ulRetrieved) == S_OK)

    {

 hr = piComponent->QueryInterface(IID_IMPEG2Component, reinterpret_cast<void**>(&piMPEG2Component) );



 if (SUCCEEDED(hr))

 {

     piMPEG2Component->get_ProgramNumber(&lProgramNumber);

     piMPEG2Component->get_PID          (&lPID          );



     MYTRACE("FOUND an IMPEG2Component ProgramNumer = %ld PID = %ldn", lProgramNumber, lPID);



     piMPEG2Component->Release();

 }

 else

 {

     MYTRACE("FOUND an IComponentn");

 }



 piComponent->Release();

    }



    piEnumComponents->Release();

}
bionicdonkey
Has anyone made a standalone BDA channel scanning app yet?
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2008 Invision Power Services, Inc.