locked
Could not extract timecode from DV AVI file RRS feed

  • Question

  • Hi, I've read through the following reference links:


     and created a test for reading DV AVI file, print out the timecode while previewing the video.

    The program runs and the video is displayed. But the extracted timecode is wrong (always returns some constants). Could you please take a a look and point out what is wrong with my code? I'm quite new to DirectShow, so I chose the way of constructing my graph manually:
    File Reader --> AVI Splitter --> Sample Grabber -->   .... (rendered)

    Note: I've exclude all the HRESULT checking for simplification. 
    Note: I've tested my video using 3-rd party program and I could see the timecode displayed correctly. If you need the test video then please tell me.
    #include <tchar.h>
    #include <conio.h>
    #include <dshow.h>
    
    #pragma include_alias( "dxtrans.h", "qedit.h" )
    #define __IDxtCompositor_INTERFACE_DEFINED__
    #define __IDxtAlphaSetter_INTERFACE_DEFINED__
    #define __IDxtJpeg_INTERFACE_DEFINED__
    #define __IDxtKey_INTERFACE_DEFINED__
    #include <qedit.h>	// for using Sample Grabber
    
    
    typedef struct { 
    	BYTE  bytes[80]; 
    } DV_DIFBlock; 
    
    typedef struct { 
    	DV_DIFBlock header[1]; 
    } DV_Header; 
    
    typedef struct { 
    	DV_DIFBlock subcode[2]; 
    } DV_Subcode; 
    
    typedef struct { 
    	DV_DIFBlock skip[2]; 
    	BYTE  skip48[48]; 
    	BYTE  magic_60; 
    	BYTE  magic_FF_1; 
    	BYTE  magic_FF_2; 
    	BYTE  PAL20; 
    	BYTE  magic_FF_3; 
    	BYTE  magic_61; 
    	BYTE  magic_33; 
    	BYTE  aspect_16x9_CF; 
    	BYTE  magic_FD; 
    	BYTE  magic_FF_4; 
    	BYTE  magic_62; 
    	BYTE  magic_FF_5; 
    	BYTE  day:5;   //max = 0x31 
    	BYTE  msb_day:3; 
    	BYTE  month:5;  //max = 0x12 
    	BYTE  msb_month:3; 
    	BYTE  year;   //max = 0x99 
    	BYTE  magic_63; 
    	BYTE  magic_FF_6; 
    	BYTE  second:6;  //max = 0x59 
    	BYTE  msb_second:2; 
    	BYTE  minute:6;  //max = 0x59 
    	BYTE  msb_minute:2; 
    	BYTE  hour:6;   //max = 0x23 
    	BYTE  msb_hour:2; 
    	BYTE  skip12[12]; 
    } DV_Vaux; 
    
    typedef struct { 
    	DV_DIFBlock bytes[144]; 
    } DV_AVData; 
    
    typedef struct { 
    	DV_Header header; 
    	DV_Subcode subcodes; 
    	DV_Vaux  vaux; 
    	DV_AVData avdata; 
    } DV_DIFSequence; 
    
    typedef DV_DIFSequence DV_Frame_NTSC[10]; 
    typedef DV_DIFSequence DV_Frame_PAL[12]; 
    
    #define BCD(x) (((x & 0xf0) >> 4) * 10 + (x & 0x0f)) 
    
    class ScanSample : public ISampleGrabberCB
    {
    	// trying to quickly create this ISampleGrabberCB, I hope these dummy methods are OK
    	HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject) { return S_OK; }
    	ULONG STDMETHODCALLTYPE AddRef(void) { return 0; }
    	ULONG STDMETHODCALLTYPE Release(void) { return 0; }
    	HRESULT STDMETHODCALLTYPE BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen) { return S_OK; }
    
    	HRESULT STDMETHODCALLTYPE SampleCB(double SampleTime, IMediaSample *pSample)
    	{
    		BYTE *pbData;
    		HRESULT hr = pSample->GetPointer(&pbData);
    		DV_Frame_PAL *frame = (DV_Frame_PAL *) pbData;
    		DV_DIFSequence *s0 = frame[0];
    
    		int year =  2000 + BCD(s0->vaux.year);
    		int month = BCD(s0->vaux.month);
    		int day = BCD(s0->vaux.day);
    		int hour = BCD(s0->vaux.hour);
    		int minute = BCD(s0->vaux.minute);
    		int second = BCD(s0->vaux.second);
    
    		printf("\n%d %d %d %d %d %", 
    			year,
    			month,
    			day,
    			hour,
    			minute,
    			second); // <---- always print out "2165 25 25 45 45
    		return S_OK;
    	}
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	HRESULT hr = CoInitialize(NULL);
    
    	// Builds a basic graph.
    	IGraphBuilder *pGraph;
    	ICaptureGraphBuilder2 *pBuilder;
    	IMediaControl *pControl;
    	IMediaEventEx *pEvent;
    	hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph);
    	hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuilder);
    	hr = pBuilder->SetFiltergraph(pGraph);
    	hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
    	hr = pGraph->QueryInterface(IID_IMediaEventEx, (void**)&pEvent);
    
    	// Adds file source filter.
    	IBaseFilter *pSource;
    	IFileSourceFilter *pFileSource;
    	hr = CoCreateInstance(CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pSource);
    	hr = pSource->QueryInterface(IID_IFileSourceFilter, (void**)&pFileSource);
    	hr = pFileSource->Load(_T("D:\\testCamera_0.avi"), NULL);
    	hr = pGraph->AddFilter(pSource, _T("File Source"));
    
    	// Adds avi splitter
    	IBaseFilter *pSplitter = NULL;
    	hr = CoCreateInstance(CLSID_AviSplitter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pSplitter);
    	hr = pGraph->AddFilter(pSplitter, _T("Avi Splitter"));
    
    	// Adds sample grabber
    	IBaseFilter *pGrabberFilter = NULL;
    	ISampleGrabber *pGrabber = NULL;
    	hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pGrabberFilter);
    	hr = pGraph->AddFilter(pGrabberFilter, _T("Sample Grabber"));
    	hr = pGrabberFilter->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);
    	ISampleGrabberCB *pCallback = new ScanSample();
    	hr = pGrabber->SetCallback(pCallback, 0);
    
    	IEnumPins* pEnumPins;
    	IPin* pSampleGrabberInput =NULL, *pSampleGrabberOutput = NULL, *pPin = NULL;
    	ULONG fetched; 
    	PIN_INFO pinInfo;
    	hr = pGrabberFilter->EnumPins(&pEnumPins);
    	while(pEnumPins->Next(1, &pPin, &fetched) == S_OK)
    	{
    		hr = pPin->QueryPinInfo(&pinInfo);
    		if(pinInfo.dir == PINDIR_OUTPUT)
    			pSampleGrabberOutput = pPin;
    		else pSampleGrabberInput = pPin;
    	}
    	pEnumPins->Release();
    
    	// Renders the stream.	
    	IPin *pOutPin=NULL, *pInPin=NULL;
    	hr = pSource->FindPin(_T("Output"), &pOutPin);
    	hr = pSplitter->FindPin(_T("input pin"), &pInPin);
    	hr = pGraph->Connect(pOutPin, pInPin);
    
    	hr = pSplitter->FindPin(_T("Stream 00"), &pOutPin);
    	hr = pGraph->Connect(pOutPin, pSampleGrabberInput);
    
    	pGraph->Render(pSampleGrabberOutput);
    
    	// Starts
    	if(SUCCEEDED(hr)) 
    	{
    		pControl->Run();
    		long evCode = 0;
    		pEvent->WaitForCompletion(INFINITE, &evCode);
    	}
    
    	pGrabber->Release();
    	pGrabberFilter->Release();
    
    	pFileSource->Release();
    	pSource->Release();
    	pEvent->Release();
    	pControl->Release();
    	pBuilder->Release();
    	pGraph->Release();
    
    	CoUninitialize();
    	printf("\n\nDone.");
    	getch();
    	return 0;
    }
    


    Ben
    Thursday, March 11, 2010 8:24 AM

Answers

  • Ok, I've managed to find the DV frame format here, and solve my problem. The SMPTE (LTC) timecode is actually embedded inside Subcode blocks. Here's the code, in case somebody else may need:

     

    typedef struct { 
    	BYTE  bytes[80]; 
    } DV_DIFBlock; 
    
    typedef struct { 
    	DV_DIFBlock header[1]; 
    } DV_Header; 
    
    typedef struct {	// 5 bytes
    // b0:
    	BYTE packType;	// 0x13
    // b1:
    	BYTE frame:6;	// BCD
    	BYTE dropFrameFlag:1;
    	BYTE colourFrameSync:1;
    // b2:
    	BYTE second:7;	// BCD
    	BYTE unknown:1;
    // b3:
    	BYTE minute:7;	// BCD
    	BYTE binaryGroupFlag0:1;
    // b4:
    	BYTE hour:6;	// BCD
    	BYTE binaryGroupFlag12:2;
    } TC_TIMECODE;
    
    typedef struct {	// 8 bytes
    // b0:
    	BYTE arbitrary:4;
    	BYTE apt:3;
    	BYTE whichHalfOfChannel:1;
    // b1:
    	BYTE syncBlockNo:4;
    	BYTE arbitrary1:4;
    // b2:
    	BYTE reserved;
    // b3-7:
    	TC_TIMECODE timecode;
    } DV_Subcode_Structure;
    
    typedef struct {		
    	BYTE header[3];
    	DV_Subcode_Structure subcode[6];
    	BYTE reserved[29];
    } DV_Subcode_Block;
    
    typedef struct {			// 2 blocks = 160 bytes
    	DV_Subcode_Block blocks[2];
    } DV_Subcode; 
    
    typedef struct { 
    	DV_DIFBlock skip[2]; 
    	BYTE  skip48[48]; 
    	BYTE  magic_60; 
    	BYTE  magic_FF_1; 
    	BYTE  magic_FF_2; 
    	BYTE  PAL20; 
    	BYTE  magic_FF_3; 
    	BYTE  magic_61; 
    	BYTE  magic_33; 
    	BYTE  aspect_16x9_CF; 
    	BYTE  magic_FD; 
    	BYTE  magic_FF_4; 
    	BYTE  magic_62; 
    	BYTE  magic_FF_5; 
    	BYTE  day:5;   //max = 0x31 
    	BYTE  msb_day:3; 
    	BYTE  month:5;  //max = 0x12 
    	BYTE  msb_month:3; 
    	BYTE  year;   //max = 0x99 
    	BYTE  magic_63; 
    	BYTE  magic_FF_6; 
    	BYTE  second:6;  //max = 0x59 
    	BYTE  msb_second:2; 
    	BYTE  minute:6;  //max = 0x59 
    	BYTE  msb_minute:2; 
    	BYTE  hour:6;   //max = 0x23 
    	BYTE  msb_hour:2; 
    	BYTE  skip12[12]; 
    } DV_Vaux; 
    
    typedef struct { 
    	DV_DIFBlock bytes[144]; 
    } DV_AVData; 
    
    typedef struct { 
    	DV_Header header; 
    	DV_Subcode subcodes; 
    	DV_Vaux  vaux; 
    	DV_AVData avdata; 
    } DV_DIFSequence; 
    
    typedef DV_DIFSequence DV_Frame_NTSC[10]; 
    typedef DV_DIFSequence DV_Frame_PAL[12]; 
    
    
    #define BCD(x) (((x & 0xf0) >> 4) * 10 + (x & 0x0f)) 
    

     

    Extracting timecode from my callback:

     

    DV_DIFSequence* seq = (DV_DIFSequence*)pbData;
    TC_TIMECODE timecode = seq[0].subcodes.blocks[0].subcode[0].timecode;
    int hour = BCD(timecode.hour);
    int minute = BCD(timecode.minute);
    int second = BCD(timecode.second);
    int frame = BCD(timecode.frame);
    printf("\n%d:%d:%d.%d", 
    		hour, minute, second, frame);

     

     

    Thanks a lot for all the help throughout the way!

     


    Ben
    • Marked as answer by pckben Saturday, March 20, 2010 10:22 AM
    Saturday, March 20, 2010 10:21 AM

All replies

  • Just a thought, have you tried testing against both type 1 and type 2 DV files? The format of the data coming out of the AVI splitter will be different.

    TTFN,
       Jon

    Thursday, March 11, 2010 8:50 AM
  • Although you are building your graph manually, it is not correct in terms of forcing the sample grabber to grab uncompressed frames :
    - you are not forcing the medatype,
    - you are connecting the Slitter and Grabber pins using Connect(), which is intelligent connect, and may therefore introduce a decompressor without telling you anything,
    - you are not checking your graph by registering it in the ROT.

    So there is a possibility that the graph you build is not the correct one.

    This being said, I am not sure this is the reason why you are not getting the timecode.

    Try :
    DV_DIFSequence *s0 = (DV_DIFSequence *) pbData;
    Michel Roujansky, http://www.roujansky.com
    Thursday, March 11, 2010 8:59 AM
  • Hi, glad to see your quick answers!

    Ok, I added the following lines
    // Sets media type for sample grabber.
    	AM_MEDIA_TYPE mediaType;
    	ZeroMemory(&mediaType, sizeof(AM_MEDIA_TYPE));
    	mediaType.majortype = MEDIATYPE_Video;
    	mediaType.subtype = MEDIASUBTYPE_RGB24;
    	hr = pGrabber->SetMediaType(&mediaType);
    
    this should make the AVI formatting of my recording and playback programs identical. The result has changed, but still not correct (the year changes, but the rest are zero constants). I also tried changing intelligent Connect() to ConnectDirect(pPinOut, pPinIn, NULL). As a result, my Sample Grabber could not connect to the splitter's output pin. This shows that Michel was correct, a decompressor might have been added before the grabber. 

    I'm not sure what you're saying in "checking your graph by registering it in the ROT". Could you tell me more about it?

    @Jon: I understand that there are AVI type-1 and type-2 files. How do I check this? Anyway, I use similar code for recording and save to file, so I expect they should be compatible?

    Regards,

    Ben
    Thursday, March 11, 2010 9:55 AM
  • No, you want MEDIASUBTYPE_DVSD

    You can get the timecode from compressed dv video only.

    Michel Roujansky, http://www.roujansky.com
    Thursday, March 11, 2010 12:50 PM
  • Actually I was wrong in the previous post: if i do ConnectDirect without adding the set media type code segment, the connection are all ok (returns S_OK). After adding the set media type, either using RGB24 (same as my capturing code), or DVSD as suggested, ConnectDirect between the avi splitter and frame grabber fails. Any suggestion?

    Thanks,

    Ben
    Thursday, March 11, 2010 1:53 PM
  • If someone could run a test on my code and tell me what's wrong, it would be really appreciated. I've been stuck on this problem for several days.

    Best,

    Ben
    Wednesday, March 17, 2010 10:59 AM
  • You should work with some method here.
    1) Check that you are building the right graph. Register it in the ROT, connect remotely and verify it.
    2) Make sure the sample grabber is connected after the avi splitter (does not matter how you do the connection. If ConnectDirect() without any mediatype works, that's fine)
    3) verify that you are getting raw compressed DV frames; the size should be exactly 144000 bytes.
    4) dump one of these frames. Check that your algorithm works on your captured frame and gives a reasonable value.

    Michel Roujansky, http://www.roujansky.com
    Wednesday, March 17, 2010 8:46 PM
  • Hi Michel,
    Thanks for replying. Here's an update:

    1. I've registered the graph in the ROT using the following method:
    HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)    
    {   
    	IMoniker*              pMoniker;   
    	IRunningObjectTable*   pROT;   
    	WCHAR wsz[128];   
    	HRESULT hr;   
    
    	if (FAILED(GetRunningObjectTable(0, &pROT)))   
    		return E_FAIL;   
    
    	wsprintfW(wsz, L"FilterGraph %08x pid %08x\0", (DWORD_PTR) pUnkGraph,    
    		GetCurrentProcessId());   
    
    	hr = CreateItemMoniker(L"!", wsz, &pMoniker);   
    	if (SUCCEEDED(hr))    
    		hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph,    
    		pMoniker, pdwRegister);   
    
    	return hr;   
    }   
    All the lines are passed without any FAILED(hr). However, when I open GraphEdt, it doesn't displayed in the list of remote graph. Does this mean that my graph failed to register?

    2. In my SampleGrabberCB, i checked the sample size and it is 144000 bytes. I checked through the vaux structure, and saw that all the magic fields have the value as expected. I.e. magic_60 = 0x60, magic_FF_? = 0xFF, etc.  Does this mean my media sample is the correct DV frame? (if it's not, probably those magic fields should be wrong, too, right?) But the date/time related fields are some wrong constants. I've checked with SceneEditor with the same dv avi file and it can display the timecode, so the timecode should be there in the test file.

    3. I've modified the code to force it to work with DV AVI type-1 file (Mediatype between AviSplitter and SampleGrabber is: MEDIATYPE_Interleaved + MEDIASUBTYPE_dvsd). My test file is confirmed to be type-1 using other software, too. Does this look OK?

    Do you have any suggestion next?

    Thank you,
    Thursday, March 18, 2010 6:23 AM
  • Update: I just learnt that I need to register proppage.dll to use remote spy feature (I'm using Windows 7, btw). So I use GraphEdt and load my graph remotely. My SampleGrabber is right after AviSplitter, its Input and Output properties are the same: 

    - Major Type: Interleaved

    - Sub Type: dvsd

    - Format: DV Stream

    - Audio Format: 12 bits

     PAL Aspect Ratios: 4:3 full format

    I have no idea why my time code are not extracted. Is there any possibility that the time code is located somewhere else in the DV frame? (ie. The above vaux structure is wrong?)

    Friday, March 19, 2010 4:00 AM
  • What values are you getting?

    The values are BCD encoded (covered in the SDK docs under "Getting Timecode from the Device").  It looks like you are decoding them.

    Also note that the date information is stored in each  DV_DIFSequence so you can check other ones (there are 12 for PAL).

    Another idea is to try a miniDV camcorder and compare the results with your Canopus.


    Please use Vote As Helpful (green up arrow at top-left of posts) and Mark As Answer where appropriate.
    My dshow site is http://tmhare.mvps.org.
    Friday, March 19, 2010 6:15 AM
  • The raw value extracted are (constants):

    • year = 0xFF, (decoded = 165)
    • month = day = 0x1F, (decoded = 25)
    • hour = minute = second = 0x3F, (decoded = 45)

    all other 'magic' fields are as expected:

    • magic_60 = 0x60, 
    • magic_FF_1 = 0xFF, etc.
    • except for magic_33 = 0x3F
    I check through 12 sequences and the results are:
    • On odd sequences, the extracted values are as above
    • On even sequences, date/time fields are the same, but 'magic' fields are all 0xFF

    Just a quick thought: will it be easier to do all these using the newest framework, ie. Windows Media Foundation? Otherwise, I think I'm just gonna save my recorded timecode to a meta-data file, and then map it with the relative AVI time information for retrieving my desire frames for post-processing later on...


    Ben
    Friday, March 19, 2010 8:09 AM
  • Media Foundation only supports capture in Windows 7.  Also, I don't think it supports capture from DV devices over FireWire.

    I recommend you try a miniDV camcorder to verify that your VAUX data is coming in correctly.  The Canopus device may need some configuration to get the timestamps injected.


    Please use Vote As Helpful (green up arrow at top-left of posts) and Mark As Answer where appropriate.
    My dshow site is http://tmhare.mvps.org.
    Friday, March 19, 2010 1:33 PM
  • I'm sure the timecode is there in the recorded AVI files. I used third party software and saw the SMPTE timecode extracted.

    The weird thing I've also tried is: when I use the same VAUX structure and apply to the MediaSample grabbed from the online stream from the device, I got the same result, despite using IAMTimecodeReader::GetTimecode give me the correct timecode.This means that the given VAUX is wrong in my application. Do you know where I can find the format of a DV Frame? I tried Google it but all refers to some "Blue Book" which I could not find.


    Ben
    Saturday, March 20, 2010 2:20 AM
  • Ok, I've managed to find the DV frame format here, and solve my problem. The SMPTE (LTC) timecode is actually embedded inside Subcode blocks. Here's the code, in case somebody else may need:

     

    typedef struct { 
    	BYTE  bytes[80]; 
    } DV_DIFBlock; 
    
    typedef struct { 
    	DV_DIFBlock header[1]; 
    } DV_Header; 
    
    typedef struct {	// 5 bytes
    // b0:
    	BYTE packType;	// 0x13
    // b1:
    	BYTE frame:6;	// BCD
    	BYTE dropFrameFlag:1;
    	BYTE colourFrameSync:1;
    // b2:
    	BYTE second:7;	// BCD
    	BYTE unknown:1;
    // b3:
    	BYTE minute:7;	// BCD
    	BYTE binaryGroupFlag0:1;
    // b4:
    	BYTE hour:6;	// BCD
    	BYTE binaryGroupFlag12:2;
    } TC_TIMECODE;
    
    typedef struct {	// 8 bytes
    // b0:
    	BYTE arbitrary:4;
    	BYTE apt:3;
    	BYTE whichHalfOfChannel:1;
    // b1:
    	BYTE syncBlockNo:4;
    	BYTE arbitrary1:4;
    // b2:
    	BYTE reserved;
    // b3-7:
    	TC_TIMECODE timecode;
    } DV_Subcode_Structure;
    
    typedef struct {		
    	BYTE header[3];
    	DV_Subcode_Structure subcode[6];
    	BYTE reserved[29];
    } DV_Subcode_Block;
    
    typedef struct {			// 2 blocks = 160 bytes
    	DV_Subcode_Block blocks[2];
    } DV_Subcode; 
    
    typedef struct { 
    	DV_DIFBlock skip[2]; 
    	BYTE  skip48[48]; 
    	BYTE  magic_60; 
    	BYTE  magic_FF_1; 
    	BYTE  magic_FF_2; 
    	BYTE  PAL20; 
    	BYTE  magic_FF_3; 
    	BYTE  magic_61; 
    	BYTE  magic_33; 
    	BYTE  aspect_16x9_CF; 
    	BYTE  magic_FD; 
    	BYTE  magic_FF_4; 
    	BYTE  magic_62; 
    	BYTE  magic_FF_5; 
    	BYTE  day:5;   //max = 0x31 
    	BYTE  msb_day:3; 
    	BYTE  month:5;  //max = 0x12 
    	BYTE  msb_month:3; 
    	BYTE  year;   //max = 0x99 
    	BYTE  magic_63; 
    	BYTE  magic_FF_6; 
    	BYTE  second:6;  //max = 0x59 
    	BYTE  msb_second:2; 
    	BYTE  minute:6;  //max = 0x59 
    	BYTE  msb_minute:2; 
    	BYTE  hour:6;   //max = 0x23 
    	BYTE  msb_hour:2; 
    	BYTE  skip12[12]; 
    } DV_Vaux; 
    
    typedef struct { 
    	DV_DIFBlock bytes[144]; 
    } DV_AVData; 
    
    typedef struct { 
    	DV_Header header; 
    	DV_Subcode subcodes; 
    	DV_Vaux  vaux; 
    	DV_AVData avdata; 
    } DV_DIFSequence; 
    
    typedef DV_DIFSequence DV_Frame_NTSC[10]; 
    typedef DV_DIFSequence DV_Frame_PAL[12]; 
    
    
    #define BCD(x) (((x & 0xf0) >> 4) * 10 + (x & 0x0f)) 
    

     

    Extracting timecode from my callback:

     

    DV_DIFSequence* seq = (DV_DIFSequence*)pbData;
    TC_TIMECODE timecode = seq[0].subcodes.blocks[0].subcode[0].timecode;
    int hour = BCD(timecode.hour);
    int minute = BCD(timecode.minute);
    int second = BCD(timecode.second);
    int frame = BCD(timecode.frame);
    printf("\n%d:%d:%d.%d", 
    		hour, minute, second, frame);

     

     

    Thanks a lot for all the help throughout the way!

     


    Ben
    • Marked as answer by pckben Saturday, March 20, 2010 10:22 AM
    Saturday, March 20, 2010 10:21 AM
  • Thank you for contributing your discovery.  I didn't know about this separate part of the VAUX structure for SMTPE timecode.  I'm sure this will be useful for someone else in the future.
    Please use Vote As Helpful (green up arrow at top-left of posts) and Mark As Answer where appropriate.
    My dshow site is http://tmhare.mvps.org.
    Monday, March 22, 2010 1:08 PM
  • Awesome, this is something I was looking for for some time!

    Would you mind reposting the entire final code, there had been a lot of churn on the initial listing?

    Thanks!

    Thursday, May 20, 2010 12:02 AM