|
|
|
date: Mon, 14 Jul 2008 16:46:01 -0700,
group: microsoft.public.win32.programmer.directx.video
back
WMV 9 DMO Encoder/Decoder usage with live stream
I am using VS2005 Pro, Directx9, WMV 9 Encoder/Decoder and DirectShow. I am
using two platforms; WindowsMobile (on a PocketPC) and XP(PC). I am sending a
live video stream from the mobile to the PC which renders it using VMR9.
The live video stream works perfectly without using an encoder/decoder. But
when using the WMV 9 Encoder/Decoder there are issues. At first nothing was
rendering on the PC. After setting the synchpoint to always be TRUE on the
IMediaSample, the video was rending, but very slow, about 1 frame per second.
I was told on a newsgroup posting to set to the DMO encoder's
IPropertyBag::Write(L"_COMPLEXITYEX"), with a value of 1. With this I am
getting about 1 frame per 100ms which is much better but I am getting
decoding problems, the image is being corrupted on and off. Is there maybe
some compatibility issues between using the encoder from mobile and decoder
on pc? Other settings that must be done? Details below on the code.
I am also getting an EC_BUFFER_FULL event from the BufferFilter after maybe
20sec on the encoder side. So I probably have some frames which are maybe
discarded. It could maybe causing the decoding problem.
On WindowsMobile I am using the WMV9 Encoder with fourcc WMV3 (which is the
only one available). The filter graph I have used is the following
CameraFilter + BufferFilter + DMOEncoderFilter + StackFilter
The reason why I used the BufferFilter was because the DMO Encoder IN pin
was only accepting a majortype of VideoBuffered.
m_pCaptureGraphBuilder.CoCreateInstance( CLSID_CaptureGraphBuilder );
pFilterGraph.CoCreateInstance( CLSID_FilterGraph );
m_pCaptureGraphBuilder->SetFiltergraph( pFilterGraph );
m_pVideoCaptureFilter.CoCreateInstance( CLSID_VideoCapture );
pBuffer.CoCreateInstance( CLSID_BufferingFilter );
hr= pVideoEncoder.CoCreateInstance( CLSID_DMOWrapperFilter );
hr= pVideoEncoder.QueryInterface( &pWrapperFilter );
pWrapperFilter->Init( CLSID_CWMV9EncMediaObject, DMOCATEGORY_VIDEO_ENCODER );
CComPtr<IPropertyBag> pPropertyBag2;
CComVariant var;
var.vt = VT_I4;
var.lVal = 1;
hr= pVideoEncoder.QueryInterface( &pPropertyBag2 );
hr = pPropertyBag2->Write(L"_COMPLEXITYEX", &var);
I have connected my pins with the following;
hr = pFilterGraph->ConnectDirect(m_pCamOutPin , m_pBufferInPin, 0);
hr = pFilterGraph->ConnectDirect(m_pBufferOutPin , m_pEncoderInPin, 0);
hr = pFilterGraph->ConnectDirect(m_pEncoderOutPin , stackPin, 0);
The Camera AM_MEDIA_TYPE is the following
+ majortype {...} _GUID
Data1 0x73646976 unsigned long int
Data2 0x0000 unsigned short
Data3 0x0010 unsigned short
+ Data4 0x005ff268 "â¬" unsigned char[8]
- subtype {...} _GUID
Data1 0x32315659 unsigned long int
Data2 0x0000 unsigned short
Data3 0x0010 unsigned short
+ Data4 0x005ff278 "â¬" unsigned char[8]
bFixedSizeSamples 0x00000001 int
bTemporalCompression 0x00000000 int
lSampleSize 0x0001c200 unsigned long int
+ formattype {...} _GUID
+ pUnk 0x00000000 {IUnknown*} IUnknown*
cbFormat 0x00000468 unsigned long int
+ pbFormat 0x005ff770 "" unsigned char*
- vih 0x00001000 {rcSource={...} rcTarget={...} dwBitRate=0x00000000
...} tagVIDEOINFOHEADER*
+ rcSource {top=0x00000000 bottom=0x00000000 left=0x00000000
right=0x00000000} tagRECT
+ rcTarget {top=0x00000000 bottom=0x00000000 left=0x00000000
right=0x00000000} tagRECT
dwBitRate 0x00000000 unsigned long int
dwBitErrorRate 0x00000000 unsigned long int
AvgTimePerFrame 0x0000000000000000 __int64
- bmiHeader {biSize=0x00000000 biWidth=0x00000000 biHeight=0x00000000
...} tagBITMAPINFOHEADER
biSize 0x00000000 unsigned long int
biWidth 0x00000000 long int
biHeight 0x00000000 long int
biPlanes 0x0000 unsigned short
biBitCount 0x0000 unsigned short
biCompression 0x00000000 unsigned long int
biSizeImage 0x00000000 unsigned long int
biXPelsPerMeter 0x00000000 long int
biYPelsPerMeter 0x00000000 long int
biClrUsed 0x00000000 unsigned long int
biClrImportant 0x00000000 unsigned long int
The EncoderOutput pin media type
- majortype {...} _GUID
Data1 686006909 unsigned long int
Data2 24392 unsigned short
Data3 18176 unsigned short
+ Data4 0x1225f9cc "â;Iâ `ÅÅ â¹WMV3" unsigned char[8]
- subtype {...} _GUID
Data1 861293911 unsigned long int
Data2 0 unsigned short
Data3 16 unsigned short
+ Data4 0x1225f9dc "â¬" unsigned char[8]
bFixedSizeSamples 0 int
bTemporalCompression 1 int
lSampleSize 0 unsigned long int
+ formattype {...} _GUID
+ pUnk 0x00000000 {IUnknown*} IUnknown*
cbFormat 93 unsigned long int
+ pbFormat 0x00548b20 "" unsigned char*
- vih 0x005ff860 {rcSource={...} rcTarget={...} dwBitRate=0
...} tagVIDEOINFOHEADER*
+ rcSource {top=0 bottom=0 left=0 right=0} tagRECT
+ rcTarget {top=0 bottom=0 left=0 right=0} tagRECT
dwBitRate 0 unsigned long int
dwBitErrorRate 0 unsigned long int
AvgTimePerFrame 666666 __int64
- bmiHeader {biSize=40 biWidth=240 biHeight=320 ...} tagBITMAPINFOHEADER
biSize 40 unsigned long int
biWidth 240 long int
biHeight 320 long int
biPlanes 1 unsigned short
biBitCount 12 unsigned short
biCompression 842094169 unsigned long int
biSizeImage 115200 unsigned long int
biXPelsPerMeter 0 long int
biYPelsPerMeter 0 long int
biClrUsed 0 unsigned long int
biClrImportant 0 unsigned long int
I have added the 5 byte WMV3 private data collected during encoder into the
decoder on the receiver side. I also am saving the synchpoint value on the
encoding side and setting it on the receiver side.
The receiver side I am setting my source filter with the following
HRESULT RtpOutputPin::GetMediaType( CMediaType *mediaType )
{
mediaType->SetType( &MEDIATYPE_Video );
mediaType->SetTemporalCompression(TRUE);
mediaType->SetSampleSize( 0 );
mediaType->SetFormatType( &FORMAT_VideoInfo );
GUID guid;
guid.Data1 = this->fourcc;
guid.Data2 = MEDIATYPE_Video.Data2;
guid.Data3 = MEDIATYPE_Video.Data3;
for( int i = 0; i < 8; i++ )
{
guid.Data4[i] = MEDIATYPE_Video.Data4[i];
}
mediaType->SetSubtype( &guid );
unsigned short sizeBuf = sizeof( VIDEOINFOHEADER);
BYTE *mediaBuffer = mediaType->AllocFormatBuffer(sizeBuf + 5);
VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *) mediaBuffer;
vih->AvgTimePerFrame = 666666;
vih->dwBitErrorRate = 0;
vih->dwBitRate = 0x0; .
RECT rect;
rect.bottom = 0;
rect.left = 0;
rect.right = 0;
rect.top = 0;
vih->rcSource = rect;
vih->rcTarget = rect;
vih->bmiHeader.biSize = sizeof( BITMAPINFOHEADER)+ 5; // should be 0x28
vih->bmiHeader.biWidth = this->frameWidth;
vih->bmiHeader.biHeight = this->frameHeight;
vih->bmiHeader.biPlanes = 0x01;
vih->bmiHeader.biBitCount = 24;
vih->bmiHeader.biCompression = fourcc;
vih->bmiHeader.biSizeImage = 115200;
vih->bmiHeader.biXPelsPerMeter = 0;
vih->bmiHeader.biYPelsPerMeter = 0;
vih->bmiHeader.biClrImportant = 0;
vih->bmiHeader.biClrUsed = 0;
BYTE newData[5];
newData[0] = 0x07;
newData[1] = 0xf1;
newData[2] = 0x8a;
newData[3] = 0x01;
newData[4] = 0x00;
memcpy( (void *)(mediaBuffer + sizeBuf), (void *)newData, 5);
return S_OK;
}
My FilterGraph on the receiver side (PC) looks like this;
StackFilter + DMO Encoder + VMR 9
CoCreateInstance( CLSID_VideoMixingRenderer9, 0,
CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void **) filter );
pVideoDecoder.CoCreateInstance( CLSID_DMOWrapperFilter );
pVideoDecoder.QueryInterface( &pWrapperFilter );
pWrapperFilter->Init( CLSID_CWMVDecMediaObject, DMOCATEGORY_VIDEO_DECODER
);
hr = receiveGraph->AddFilter( pVideoDecoder, L"WMV DMO Decoder" );
hr = receiveGraph->ConnectDirect( rtpStackOutputPin(), m_pDecoderInPin, 0);
hr = receiveGraph->ConnectDirect( m_pDecoderOutPin, rendererInputPin(), 0);
date: Mon, 14 Jul 2008 16:46:01 -0700
author: Kris
Re: WMV 9 DMO Encoder/Decoder usage with live stream
Well I am not certain what could be wrong then. The only thing I am not
setting is the timestamp. I did not think I needed it because when I do not
set the complexity I do not have the decoding errors in the image.
Maybe it's do to with my custom stack filter then? There is a ::FillBuffer()
method which gets called for each packets recceived ... maybe something in
there is missing or wrong?
::FillBuffer( IMediaSample *sample )
{
// Receive a new buffer on the stack.
BYTE *buffer;
long length;
long bufferlen;
HRESULT hr = sample->GetPointer( &buffer );
if( hr != S_OK )
{
return hr;
}
HRESULT synchpoint;
HRESULT preroll;
HRESULT discontinuity;
unsigned int payloadType2;
payloadType2 = stack->payloadType;
length = sample->GetSize();
bufferlen = stack->receiveMedia( (char *) buffer, length );
hr = sample->SetActualDataLength( bufferlen );
if( hr != S_OK )
{
return hr;
}
if (bufferlen != 0)
{
fprintf(fp, "%s",
"++New Sample Receive \n" );
synchpoint = sample->IsSyncPoint();
fprintf(fp, "%s%ld%s",
" current synchpoint: ", synchpoint, "\n");
//pay load type is carrying the synchpoint for now
if (payloadType2 == S_OK)
{
hr = sample->SetSyncPoint(TRUE);
}
else
{
hr = sample->SetSyncPoint(FALSE);
}
synchpoint = sample->IsSyncPoint();
preroll = sample->IsPreroll();
discontinuity = sample->IsDiscontinuity();
fprintf(fp, "%s%ld%s%ld%s%ld%s",
" synchpoint: ", synchpoint,
" preroll: " , preroll,
" discontinuity: ", discontinuity, "\n" );
}
return S_OK;
}
There is also a DecideBufferSize( IMemAllocator *alloc, ALLOCATOR_PROPERTIES
*allocProps ) but that gets called only once.
::DecideBufferSize( IMemAllocator *alloc,
ALLOCATOR_PROPERTIES *allocProps )
{
// function accesses CBaseFilter.m_mt, provide mutual
// exclusion
CAutoLock autoLock( m_pFilter->pStateLock() );
VIDEOINFO *videoInfo = (VIDEOINFO *) m_mt.Format();
// Make sure there are some buffers. (This seems odd, wouldn't the
allocator
// always need some buffers?)
if( 0 == allocProps->cBuffers )
{
allocProps->cBuffers = 1;
}
// Make sure the buffer size is big enough to hold the media sample
if( (long) videoInfo->bmiHeader.biSizeImage > allocProps->cbBuffer )
{
allocProps->cbBuffer = videoInfo->bmiHeader.biSizeImage;
}
// Set the modified properties
ALLOCATOR_PROPERTIES actualProps;
HRESULT hr = alloc->SetProperties( allocProps, &actualProps );
if( FAILED( hr ) )
{
return hr;
}
// Check that we have usable properties...
if( ( actualProps.cBuffers == 0 ) ||
( actualProps.cbBuffer < allocProps->cbBuffer ) )
{
return E_FAIL;
}
return S_OK;
}
"Alessandro Angeli" wrote:
> From: "Kris"
>
> > I am doing that ... I am sending the synchpoint from the
> > sending to the receiver. When the complexity is set to 1
> > ... it will not play right away. I read somewhere that it
> > would only start decoding if it got the first frame to be
> > a keyframe... see this post. I am seeing this behavior.
>
> The WMV decoder, like any decoder that supports
> delta-frames, starts decoding at a keyframe, aka at a sync
> point. On the other hand, the first frame the WMV encoder
> outputs is a keyframe so, unless you are dropping frame in
> your newtwork protocol implementation, the first frame the
> decoder receives is a keyframe and it can start decoding
> right away.
>
> > This is something wrong with what is currently there?
> > this has work with fourcc of WMV3/DIVX and NTVC
>
> You can do it your way if you want to: it is just more
> complicated and slightly slower (not that it matters).
>
> > We done with with a codec of DIVX and everything worked
> > fine. I am just having a lot of issues with WMV3. I could
>
> I have implemented your same framework twice so far and I
> have had no problems with the WMV encoder.
>
> > set up some debug to see if the AM_MEDIA_TYPE is
> > changing. So you are saying that the DMO encoder can
> > change this at any point during live encoding?
>
> Not during encoding, but at each connection of the pins,
> which happens at least once per execution of your
> application on the mobile side.
>
>
> --
> // Alessandro Angeli
> // MVP :: DirectShow / MediaFoundation
> // mvpnews at riseoftheants dot com
> // http://www.riseoftheants.com/mmx/faq.htm
>
>
>
date: Tue, 15 Jul 2008 06:47:07 -0700
author: Kris
Re: WMV 9 DMO Encoder/Decoder usage with live stream
From: "Kris"
>> - Who calls your FillBuffer()?
>
> I am not certain I though the FilterGraph did ... I am
> reusing code that was not written by me.
[...]
>> - What base classses are you using?
>
> CSourceStream
CSourceStream spawns a worker thread that calls FillBuffer()
as fast as possible, depending on the time it takes
FillBuffer() itself to execute and a sample to be processed
and rendered downstream.
>> - How do you receive data from the network?
>
> RTP packets... socket
>
>> - What network protocol?
>
> RTP
RTP is based on UDP which implies 2 important factors: the
packet order is not guaranteed and the packets may be
dropped without you knowing about it for any number of
reasons (network errors, transmission errors, you are not
fast ebough in reading them and the recvq fills up...).
>> - Are you sure you are not dropping frames?
>
> I could be ... I will double check on that ... but it did
> not seem to be when I was sending RAW data or the WMV3
> with complexity not set
The timing is different now: you send more than 10 times
faster than before.
>> - Why don't you also transfer the other sample flags and
>> the timestamps?
>
> I will change the code to send the timestamps. I not
> exactly certain how to do that. Can I simply get the time
> from the GetTime on the sender side and then use SetTime
> on the receiver side? I know you mentioned something
> about Timestamps needing to match but I did not quiet
> understood that.
Let's call firstStartTime the start time of the first sample
you send. Instead of sending (startTime,stopTime), you send
(startTime-firstStartTime,stopTime-firstStartTime).
Let's call firstClockTime the clock time when you receive
the first sample (CSourceStream::m_pFilter->StreamTime()).
You call
IMediaSample::SetTime(startTime+firstClockTime,stopTime+firstClockTime).
CSource+CSourceStream works well for file sources and other
sequential synchronous pull-mode (that is, on-demand)
sources, but they are a *very* bad choice for an
asynchronous push-mode (that is, "live") source. Even more
so if the source is not sequential, like UDP is. That means
that you should write a live capture push source filter
(well, a subset of one):
http://msdn.microsoft.com/en-us/library/ms787518(VS.85).aspx
You need to recvFrom() as soon as there is data pending,
regardless of whether you can deliver it downstream (while
CSourceStream blocks). If you can not deliver, you must
queue the data without blocking (which implies 2 threads:
one that receives and one that delivers, with a queue in
between).
You must use the RTP sequence number to re-order the samples
you receive in the queue. If a sample is missing, you must
wait for it before delivering the following samples but only
wait at most until it is almost time to render the next
available sample. If you deliver after a gap, set the
discontinuity flag on the first sample that follows. If you
receive a sample too late, discard it.
Put the start time in the RTP packet's timestamp (scaled
down to millisecs). You do not need to set the stop time. If
you want yo set the stop time, wait until you receive the
next sample, than use its start time as stop time for the
previous one (of course, if you are missing the next sample,
just do not set the stop time).
You can use RTP's marker bit to mark sync points.
If you have samples that do not fit in a single RTP payload,
you need to fragment and reasseble them.
And so on... Unless you have a very good reason to use a
UDP-based transport, you should use a TCP-based one and all
of this would go away.
--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Tue, 15 Jul 2008 18:12:21 -0400
author: Alessandro Angeli
Re: WMV 9 DMO Encoder/Decoder usage with live stream
From: "Kris"
> The packets are reassembled ... and given to the decoder
> as one frame. When I was sending RAW data .. there is was
> 80 packets per frame being disassembled and reassembled
> The RTP filter being the problem is very low.
>
> This is what I have now with your requested time changes.
> Same results as before. Below are logs.
[...]
I am out of ideas. I suggest you do the following:
- prefix each sample you transmit with the following header
(or equivalent, since you are already doing most of this):
#pragma pack(4)
struct {
LONGLONG start;
LONGLONG stop;
LONGLONG index;
DWORD size;
DWORD flags;
#define FLAG_SYNC 1
#define FLAG_PREROLL 2
#define FLAG_DISC 4
DWORD checksum;
};
#pragma pack()
start and stop are normalized to zero by subtracting the
start time of the first sample. index is the zero-based
frame index. checksum is any checksum you like, for example
the 16-bit Internet checksum is easy to compute, but a
stronger checksum (e.g. CRC-16 or CRC-32 ot Adler-32) would
be better:
/// THIS IS NOT REALLY THE INTERNET CHECKSUM
DWORD checksum(DWORD size, LPBYTE data)
{
DWORD s = 0;
WORD* p = (WORD*)data;
WORD* q = p + (size >> 1);
while(p < q) s += *p++;
return s;
}
On both sides, for each sample print out the header and the
first and last 8 BYTEs of the data (or more, even all of
them). If the send and receive sequences are not identical,
something is wrong. If they are, I am at a loss.
I suggest you print the info to file using exactly the same
syntax, so that you can use WinDiff to easily compare them.
Do not print out timeGetTime() because that will be
different.
--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
date: Wed, 16 Jul 2008 14:28:53 -0400
author: Alessandro Angeli
Re: WMV 9 DMO Encoder/Decoder usage with live stream
Just to confirm I was doing things correctly when setting the time on the
receiver side.
I did the following
CRefTime myTime;
m_pFilter->StreamTime(myTime);
firstClockTime = myTime.m_time;
Thanks,
Kristine
"Alessandro Angeli" wrote:
> From: "Kris"
>
> > The packets are reassembled ... and given to the decoder
> > as one frame. When I was sending RAW data .. there is was
> > 80 packets per frame being disassembled and reassembled
> > The RTP filter being the problem is very low.
> >
> > This is what I have now with your requested time changes.
> > Same results as before. Below are logs.
> [...]
>
> I am out of ideas. I suggest you do the following:
>
> - prefix each sample you transmit with the following header
> (or equivalent, since you are already doing most of this):
>
> #pragma pack(4)
> struct {
> LONGLONG start;
> LONGLONG stop;
> LONGLONG index;
> DWORD size;
> DWORD flags;
> #define FLAG_SYNC 1
> #define FLAG_PREROLL 2
> #define FLAG_DISC 4
> DWORD checksum;
> };
> #pragma pack()
>
> start and stop are normalized to zero by subtracting the
> start time of the first sample. index is the zero-based
> frame index. checksum is any checksum you like, for example
> the 16-bit Internet checksum is easy to compute, but a
> stronger checksum (e.g. CRC-16 or CRC-32 ot Adler-32) would
> be better:
>
> /// THIS IS NOT REALLY THE INTERNET CHECKSUM
> DWORD checksum(DWORD size, LPBYTE data)
> {
> DWORD s = 0;
> WORD* p = (WORD*)data;
> WORD* q = p + (size >> 1);
> while(p < q) s += *p++;
> return s;
> }
>
> On both sides, for each sample print out the header and the
> first and last 8 BYTEs of the data (or more, even all of
> them). If the send and receive sequences are not identical,
> something is wrong. If they are, I am at a loss.
>
> I suggest you print the info to file using exactly the same
> syntax, so that you can use WinDiff to easily compare them.
> Do not print out timeGetTime() because that will be
> different.
>
> --
> // Alessandro Angeli
> // MVP :: DirectShow / MediaFoundation
> // mvpnews at riseoftheants dot com
> // http://www.riseoftheants.com/mmx/faq.htm
>
>
>
>
date: Wed, 16 Jul 2008 19:55:02 -0700
author: Kris
Re: WMV 9 DMO Encoder/Decoder usage with live stream
Hi Alessandro,
I was away on vacation ... I have noticed that when I set the timestamp in
the FillBuffer method, only the first frame renders. When I do not set the
timestamp, I get the decoding errors. Also when I move my camera around, the
frames that have to deal with the movement usually renders properly, it seems
the non keyframes are the ones with the decoding errors.
from the sender
hr = sample->GetTime(&rStart, &rEnd);
rStart = rStart - firstStartTime;
rEnd = rEnd - firstStartTime;
from the receiver
on the first sample
hr = m_pFilter->StreamTime(mytime);
streamTime = mytime.m_time; (this is a large number)
rStart = rStart+ streamTime ; (rStart and rEnd came from the sender)
rEnd = rEnd+ streamTime ;
hr = sample->SetTime(&rStart, &rEnd);
Thanks,
Kris
"Kris" wrote:
> Just to confirm I was doing things correctly when setting the time on the
> receiver side.
>
> I did the following
>
> CRefTime myTime;
> m_pFilter->StreamTime(myTime);
> firstClockTime = myTime.m_time;
>
> Thanks,
> Kristine
>
>
> "Alessandro Angeli" wrote:
>
> > From: "Kris"
> >
> > > The packets are reassembled ... and given to the decoder
> > > as one frame. When I was sending RAW data .. there is was
> > > 80 packets per frame being disassembled and reassembled
> > > The RTP filter being the problem is very low.
> > >
> > > This is what I have now with your requested time changes.
> > > Same results as before. Below are logs.
> > [...]
> >
> > I am out of ideas. I suggest you do the following:
> >
> > - prefix each sample you transmit with the following header
> > (or equivalent, since you are already doing most of this):
> >
> > #pragma pack(4)
> > struct {
> > LONGLONG start;
> > LONGLONG stop;
> > LONGLONG index;
> > DWORD size;
> > DWORD flags;
> > #define FLAG_SYNC 1
> > #define FLAG_PREROLL 2
> > #define FLAG_DISC 4
> > DWORD checksum;
> > };
> > #pragma pack()
> >
> > start and stop are normalized to zero by subtracting the
> > start time of the first sample. index is the zero-based
> > frame index. checksum is any checksum you like, for example
> > the 16-bit Internet checksum is easy to compute, but a
> > stronger checksum (e.g. CRC-16 or CRC-32 ot Adler-32) would
> > be better:
> >
> > /// THIS IS NOT REALLY THE INTERNET CHECKSUM
> > DWORD checksum(DWORD size, LPBYTE data)
> > {
> > DWORD s = 0;
> > WORD* p = (WORD*)data;
> > WORD* q = p + (size >> 1);
> > while(p < q) s += *p++;
> > return s;
> > }
> >
> > On both sides, for each sample print out the header and the
> > first and last 8 BYTEs of the data (or more, even all of
> > them). If the send and receive sequences are not identical,
> > something is wrong. If they are, I am at a loss.
> >
> > I suggest you print the info to file using exactly the same
> > syntax, so that you can use WinDiff to easily compare them.
> > Do not print out timeGetTime() because that will be
> > different.
> >
> > --
> > // Alessandro Angeli
> > // MVP :: DirectShow / MediaFoundation
> > // mvpnews at riseoftheants dot com
> > // http://www.riseoftheants.com/mmx/faq.htm
> >
> >
> >
> >
date: Tue, 5 Aug 2008 11:26:02 -0700
author: Kris
Re: WMV 9 DMO Encoder/Decoder usage with live stream
Hi Alessandro,
I was away on vacation ... I have noticed that when I set the timestamp in
the FillBuffer method, only the first frame renders. When I do not set the
timestamp, I get the decoding errors. Also when I move my camera around, the
frames that have to deal with the movement usually renders properly, it seems
the non keyframes are the ones with the decoding errors.
from the sender
hr = sample->GetTime(&rStart, &rEnd);
rStart = rStart - firstStartTime;
rEnd = rEnd - firstStartTime;
from the receiver
on the first sample
hr = m_pFilter->StreamTime(mytime);
streamTime = mytime.m_time; (this is a large number)
rStart = rStart+ streamTime ; (rStart and rEnd came from the sender)
rEnd = rEnd+ streamTime ;
hr = sample->SetTime(&rStart, &rEnd);
Thanks,
Kris
"Alessandro Angeli" wrote:
> From: "Kris"
>
> > The packets are reassembled ... and given to the decoder
> > as one frame. When I was sending RAW data .. there is was
> > 80 packets per frame being disassembled and reassembled
> > The RTP filter being the problem is very low.
> >
> > This is what I have now with your requested time changes.
> > Same results as before. Below are logs.
> [...]
>
> I am out of ideas. I suggest you do the following:
>
> - prefix each sample you transmit with the following header
> (or equivalent, since you are already doing most of this):
>
> #pragma pack(4)
> struct {
> LONGLONG start;
> LONGLONG stop;
> LONGLONG index;
> DWORD size;
> DWORD flags;
> #define FLAG_SYNC 1
> #define FLAG_PREROLL 2
> #define FLAG_DISC 4
> DWORD checksum;
> };
> #pragma pack()
>
> start and stop are normalized to zero by subtracting the
> start time of the first sample. index is the zero-based
> frame index. checksum is any checksum you like, for example
> the 16-bit Internet checksum is easy to compute, but a
> stronger checksum (e.g. CRC-16 or CRC-32 ot Adler-32) would
> be better:
>
> /// THIS IS NOT REALLY THE INTERNET CHECKSUM
> DWORD checksum(DWORD size, LPBYTE data)
> {
> DWORD s = 0;
> WORD* p = (WORD*)data;
> WORD* q = p + (size >> 1);
> while(p < q) s += *p++;
> return s;
> }
>
> On both sides, for each sample print out the header and the
> first and last 8 BYTEs of the data (or more, even all of
> them). If the send and receive sequences are not identical,
> something is wrong. If they are, I am at a loss.
>
> I suggest you print the info to file using exactly the same
> syntax, so that you can use WinDiff to easily compare them.
> Do not print out timeGetTime() because that will be
> different.
>
> --
> // Alessandro Angeli
> // MVP :: DirectShow / MediaFoundation
> // mvpnews at riseoftheants dot com
> // http://www.riseoftheants.com/mmx/faq.htm
>
>
>
>
date: Tue, 5 Aug 2008 11:31:01 -0700
author: Kris
|
|