1 /********************************************************
3 DirectShow Video decoder implementation
4 Copyright 2000 Eugene Kuznetsov (divx@euro.ru)
6 *********************************************************/
8 #include "loader/dshow/guids.h"
9 #include "loader/dshow/interfaces.h"
10 #include "loader/registry.h"
12 #include "loader/ldt_keeper.h"
15 #include "loader/dshow/libwin32.h"
16 #include "DMO_Filter.h"
18 #include "DMO_VideoDecoder.h"
20 struct DMO_VideoDecoder
24 DMO_Filter
* m_pDMO_Filter
;
25 AM_MEDIA_TYPE m_sOurType
, m_sDestType
;
26 VIDEOINFOHEADER
* m_sVhdr
;
27 VIDEOINFOHEADER
* m_sVhdr2
;
28 int m_Caps
;//CAPS m_Caps; // capabilities of DirectShow decoder
29 int m_iLastQuality
; // remember last quality as integer
34 //#include "DMO_VideoDecoder.h"
36 #include "loader/wine/winerror.h"
41 #include <sys/types.h>
42 #ifdef HAVE_SYS_MMAN_H
46 #include <stdlib.h> // labs
48 // strcmp((const char*)info.dll,...) is used instead of (... == ...)
49 // so Arpi could use char* pointer in his simplified DMO_VideoDecoder class
55 //int DMO_VideoDecoder_GetCapabilities(DMO_VideoDecoder *this){return this->m_Caps;}
68 { fccI420
, 12, &MEDIASUBTYPE_I420
, CAP_I420
, NULL
},
69 { fccYV12
, 12, &MEDIASUBTYPE_YV12
, CAP_YV12
, NULL
},
70 { fccYUY2
, 16, &MEDIASUBTYPE_YUY2
, CAP_YUY2
, NULL
},
71 { fccUYVY
, 16, &MEDIASUBTYPE_UYVY
, CAP_UYVY
, NULL
},
72 { fccYVYU
, 16, &MEDIASUBTYPE_YVYU
, CAP_YVYU
, NULL
},
73 { fccIYUV
, 24, &MEDIASUBTYPE_IYUV
, CAP_IYUV
, NULL
},
75 { 8, 8, &MEDIASUBTYPE_RGB8
, CAP_NONE
, "RGB8" },
76 { 15, 16, &MEDIASUBTYPE_RGB555
, CAP_NONE
, "RGB555" },
77 { 16, 16, &MEDIASUBTYPE_RGB565
, CAP_NONE
, "RGB565" },
78 { 24, 24, &MEDIASUBTYPE_RGB24
, CAP_NONE
, "RGB24" },
79 { 32, 32, &MEDIASUBTYPE_RGB32
, CAP_NONE
, "RGB32" },
84 DMO_VideoDecoder
* DMO_VideoDecoder_Open(char* dllname
, GUID
* guid
, BITMAPINFOHEADER
* format
, int flip
, int maxauto
)
86 DMO_VideoDecoder
*this;
90 this = malloc(sizeof(DMO_VideoDecoder
));
91 memset( this, 0, sizeof(DMO_VideoDecoder
));
94 this->m_iLastQuality
= -1;
95 this->m_iMaxAuto
= maxauto
;
101 //memset(&m_obh, 0, sizeof(m_obh));
102 //m_obh.biSize = sizeof(m_obh);
107 bihs
= (format
->biSize
< (int) sizeof(BITMAPINFOHEADER
)) ?
108 sizeof(BITMAPINFOHEADER
) : format
->biSize
;
110 this->iv
.m_bh
= malloc(bihs
);
111 memcpy(this->iv
.m_bh
, format
, bihs
);
112 this->iv
.m_bh
->biSize
= bihs
;
114 this->iv
.m_State
= STOP
;
115 //this->iv.m_pFrame = 0;
116 this->iv
.m_Mode
= DIRECT
;
117 this->iv
.m_iDecpos
= 0;
118 this->iv
.m_iPlaypos
= -1;
119 this->iv
.m_fQuality
= 0.0f
;
120 this->iv
.m_bCapable16b
= true;
122 bihs
+= sizeof(VIDEOINFOHEADER
) - sizeof(BITMAPINFOHEADER
);
123 this->m_sVhdr
= malloc(bihs
);
124 memset(this->m_sVhdr
, 0, bihs
);
125 memcpy(&this->m_sVhdr
->bmiHeader
, this->iv
.m_bh
, this->iv
.m_bh
->biSize
);
126 this->m_sVhdr
->rcSource
.left
= this->m_sVhdr
->rcSource
.top
= 0;
127 this->m_sVhdr
->rcSource
.right
= this->m_sVhdr
->bmiHeader
.biWidth
;
128 this->m_sVhdr
->rcSource
.bottom
= this->m_sVhdr
->bmiHeader
.biHeight
;
129 //this->m_sVhdr->rcSource.right = 0;
130 //this->m_sVhdr->rcSource.bottom = 0;
131 this->m_sVhdr
->rcTarget
= this->m_sVhdr
->rcSource
;
133 this->m_sOurType
.majortype
= MEDIATYPE_Video
;
134 this->m_sOurType
.subtype
= MEDIATYPE_Video
;
135 this->m_sOurType
.subtype
.f1
= this->m_sVhdr
->bmiHeader
.biCompression
;
136 this->m_sOurType
.formattype
= FORMAT_VideoInfo
;
137 this->m_sOurType
.bFixedSizeSamples
= false;
138 this->m_sOurType
.bTemporalCompression
= true;
139 this->m_sOurType
.pUnk
= 0;
140 this->m_sOurType
.cbFormat
= bihs
;
141 this->m_sOurType
.pbFormat
= (char*)this->m_sVhdr
;
143 this->m_sVhdr2
= (VIDEOINFOHEADER
*)(malloc(sizeof(VIDEOINFOHEADER
)+12));
144 memcpy(this->m_sVhdr2
, this->m_sVhdr
, sizeof(VIDEOINFOHEADER
));
145 memset((char*)this->m_sVhdr2
+ sizeof(VIDEOINFOHEADER
), 0, 12);
146 this->m_sVhdr2
->bmiHeader
.biCompression
= 0;
147 this->m_sVhdr2
->bmiHeader
.biBitCount
= 24;
149 // memset((char*)this->m_sVhdr2, 0, sizeof(VIDEOINFOHEADER)+12);
150 this->m_sVhdr2
->rcTarget
= this->m_sVhdr
->rcTarget
;
151 // this->m_sVhdr2->rcSource = this->m_sVhdr->rcSource;
153 memset(&this->m_sDestType
, 0, sizeof(this->m_sDestType
));
154 this->m_sDestType
.majortype
= MEDIATYPE_Video
;
155 this->m_sDestType
.subtype
= MEDIASUBTYPE_RGB24
;
156 this->m_sDestType
.formattype
= FORMAT_VideoInfo
;
157 this->m_sDestType
.bFixedSizeSamples
= true;
158 this->m_sDestType
.bTemporalCompression
= false;
159 this->m_sDestType
.lSampleSize
= labs(this->m_sVhdr2
->bmiHeader
.biWidth
*this->m_sVhdr2
->bmiHeader
.biHeight
160 * ((this->m_sVhdr2
->bmiHeader
.biBitCount
+ 7) / 8));
161 this->m_sVhdr2
->bmiHeader
.biSizeImage
= this->m_sDestType
.lSampleSize
;
162 this->m_sDestType
.pUnk
= 0;
163 this->m_sDestType
.cbFormat
= sizeof(VIDEOINFOHEADER
);
164 this->m_sDestType
.pbFormat
= (char*)this->m_sVhdr2
;
166 memset(&this->iv
.m_obh
, 0, sizeof(this->iv
.m_obh
));
167 memcpy(&this->iv
.m_obh
, this->iv
.m_bh
, sizeof(this->iv
.m_obh
) < (unsigned) this->iv
.m_bh
->biSize
168 ? sizeof(this->iv
.m_obh
) : (unsigned) this->iv
.m_bh
->biSize
);
169 this->iv
.m_obh
.biBitCount
=24;
170 this->iv
.m_obh
.biSize
= sizeof(BITMAPINFOHEADER
);
171 this->iv
.m_obh
.biCompression
= 0; //BI_RGB
172 //this->iv.m_obh.biHeight = labs(this->iv.m_obh.biHeight);
173 this->iv
.m_obh
.biSizeImage
= labs(this->iv
.m_obh
.biWidth
* this->iv
.m_obh
.biHeight
)
174 * ((this->iv
.m_obh
.biBitCount
+ 7) / 8);
177 this->m_pDMO_Filter
= DMO_FilterCreate(dllname
, guid
, &this->m_sOurType
, &this->m_sDestType
);
179 if (!this->m_pDMO_Filter
)
181 printf("Failed to create DMO filter\n");
187 this->iv
.m_obh
.biHeight
*= -1;
188 this->m_sVhdr2
->bmiHeader
.biHeight
= this->iv
.m_obh
.biHeight
;
189 // result = this->m_pDMO_Filter->m_pOutputPin->vt->QueryAccept(this->m_pDMO_Filter->m_pOutputPin, &this->m_sDestType);
190 result
= this->m_pDMO_Filter
->m_pMedia
->vt
->SetOutputType(this->m_pDMO_Filter
->m_pMedia
, 0, &this->m_sDestType
, DMO_SET_TYPEF_TEST_ONLY
);
193 printf("Decoder does not support upside-down RGB frames\n");
194 this->iv
.m_obh
.biHeight
*= -1;
195 this->m_sVhdr2
->bmiHeader
.biHeight
= this->iv
.m_obh
.biHeight
;
199 memcpy( &this->iv
.m_decoder
, &this->iv
.m_obh
, sizeof(this->iv
.m_obh
) );
201 switch (this->iv
.m_bh
->biCompression
)
210 //YV12 seems to be broken for DivX :-) codec
212 //produces incorrect picture
213 //m_Caps = (CAPS) (m_Caps & ~CAP_YV12);
214 //m_Caps = CAP_UYVY;//CAP_YUY2; // | CAP_I420;
216 this->m_Caps
= (CAP_YUY2
| CAP_UYVY
);
221 this->m_Caps
= CAP_NONE
;
223 printf("Decoder supports the following formats: ");
224 for (c
= check
; c
->bits
; c
++)
226 this->m_sVhdr2
->bmiHeader
.biBitCount
= c
->bits
;
227 this->m_sVhdr2
->bmiHeader
.biCompression
= c
->fcc
;
228 this->m_sDestType
.subtype
= *c
->subtype
;
229 //result = this->m_pDMO_Filter->m_pOutputPin->vt->QueryAccept(this->m_pDMO_Filter->m_pOutputPin, &this->m_sDestType);
230 result
= this->m_pDMO_Filter
->m_pMedia
->vt
->SetOutputType(this->m_pDMO_Filter
->m_pMedia
, 0, &this->m_sDestType
, DMO_SET_TYPEF_TEST_ONLY
);
233 this->m_Caps
= (this->m_Caps
| c
->cap
);
235 printf("%s ", c
->name
);
237 printf("%.4s ", (char*) &c
->fcc
);
243 if (this->m_Caps
!= CAP_NONE
)
244 printf("Decoder is capable of YUV output (flags 0x%x)\n", (int)this->m_Caps
);
246 this->m_sVhdr2
->bmiHeader
.biBitCount
= 24;
247 this->m_sVhdr2
->bmiHeader
.biCompression
= 0;
248 this->m_sDestType
.subtype
= MEDIASUBTYPE_RGB24
;
250 this->m_iMinBuffers
= this->iv
.VBUFSIZE
;
252 /*catch (FatalError& error)
256 delete m_pDMO_Filter;
262 void DMO_VideoDecoder_Destroy(DMO_VideoDecoder
*this)
264 DMO_VideoDecoder_StopInternal(this);
265 this->iv
.m_State
= STOP
;
267 free(this->m_sVhdr2
);
268 DMO_Filter_Destroy(this->m_pDMO_Filter
);
271 void DMO_VideoDecoder_StartInternal(DMO_VideoDecoder
*this)
274 ALLOCATOR_PROPERTIES props
, props1
;
275 Debug
printf("DMO_VideoDecoder_StartInternal\n");
276 //cout << "DSSTART" << endl;
277 this->m_pDMO_Filter
->Start(this->m_pDMO_Filter
);
280 props
.cbBuffer
= this->m_sDestType
.lSampleSize
;
284 this->m_pDMO_Filter
->m_pAll
->vt
->SetProperties(this->m_pDMO_Filter
->m_pAll
, &props
, &props1
);
285 this->m_pDMO_Filter
->m_pAll
->vt
->Commit(this->m_pDMO_Filter
->m_pAll
);
287 this->iv
.m_State
= START
;
290 void DMO_VideoDecoder_StopInternal(DMO_VideoDecoder
*this)
292 // this->m_pDMO_Filter->Stop(this->m_pDMO_Filter);
293 //??? why was this here ??? m_pOurOutput->SetFramePointer(0);
296 int DMO_VideoDecoder_DecodeInternal(DMO_VideoDecoder
*this, const void* src
, int size
, int is_keyframe
, char* imdata
)
298 // IMediaSample* sample = 0;
300 unsigned long status
; // to be ignored by M$ specs
301 DMO_OUTPUT_DATA_BUFFER db
;
302 CMediaBuffer
* bufferin
;
303 //+ uint8_t* imdata = dest ? dest->Data() : 0;
305 Debug
printf("DMO_VideoDecoder_DecodeInternal(%p,%p,%d,%d,%p)\n",this,src
,size
,is_keyframe
,imdata
);
307 // this->m_pDMO_Filter->m_pAll->vt->GetBuffer(this->m_pDMO_Filter->m_pAll, &sample, 0, 0, 0);
310 // Debug printf("ERROR: null sample\n");
318 bufferin
= CMediaBufferCreate(size
, (void*)src
, size
, 0);
319 result
= this->m_pDMO_Filter
->m_pMedia
->vt
->ProcessInput(this->m_pDMO_Filter
->m_pMedia
, 0,
320 (IMediaBuffer
*)bufferin
,
321 DMO_INPUT_DATA_BUFFERF_SYNCPOINT
,
323 ((IMediaBuffer
*)bufferin
)->vt
->Release((IUnknown
*)bufferin
);
327 /* something for process */
328 if (result
!= S_FALSE
)
329 printf("ProcessInputError r:0x%x=%d (keyframe: %d)\n", result
, result
, is_keyframe
);
331 printf("ProcessInputError FALSE ?? (keyframe: %d)\n", is_keyframe
);
338 db
.pBuffer
= (IMediaBuffer
*) CMediaBufferCreate(this->m_sDestType
.lSampleSize
,
340 result
= this->m_pDMO_Filter
->m_pMedia
->vt
->ProcessOutput(this->m_pDMO_Filter
->m_pMedia
,
341 (imdata
) ? 0 : DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER
,
343 //m_pDMO_Filter->m_pMedia->vt->Lock(m_pDMO_Filter->m_pMedia, 0);
344 if ((unsigned)result
== DMO_E_NOTACCEPTING
)
345 printf("ProcessOutputError: Not accepting\n");
347 printf("ProcessOutputError: r:0x%x=%d %ld stat:%ld\n", result
, result
, status
, db
.dwStatus
);
349 ((IMediaBuffer
*)db
.pBuffer
)->vt
->Release((IUnknown
*)db
.pBuffer
);
351 //int r = m_pDMO_Filter->m_pMedia->vt->Flush(m_pDMO_Filter->m_pMedia);
352 //printf("FLUSH %d\n", r);
358 * bits == 0 - leave unchanged
360 //int SetDestFmt(DMO_VideoDecoder * this, int bits = 24, fourcc_t csp = 0);
361 int DMO_VideoDecoder_SetDestFmt(DMO_VideoDecoder
*this, int bits
, unsigned int csp
)
366 Debug
printf("DMO_VideoDecoder_SetDestFmt (%p, %d, %d)\n",this,bits
,(int)csp
);
368 /* if (!CImage::Supported(csp, bits))
371 // BitmapInfo temp = m_obh;
380 this->m_sDestType
.subtype
= MEDIASUBTYPE_RGB555
;
383 this->m_sDestType
.subtype
= MEDIASUBTYPE_RGB565
;
386 this->m_sDestType
.subtype
= MEDIASUBTYPE_RGB24
;
389 this->m_sDestType
.subtype
= MEDIASUBTYPE_RGB32
;
397 this->iv
.m_obh
.biBitCount
=bits
;
398 if( bits
== 15 || bits
== 16 ) {
399 this->iv
.m_obh
.biSize
=sizeof(BITMAPINFOHEADER
)+12;
400 this->iv
.m_obh
.biCompression
=3;//BI_BITFIELDS
401 this->iv
.m_obh
.biSizeImage
=abs((int)(2*this->iv
.m_obh
.biWidth
*this->iv
.m_obh
.biHeight
));
405 this->iv
.m_obh
.colors
[0]=0xF800;
406 this->iv
.m_obh
.colors
[1]=0x07E0;
407 this->iv
.m_obh
.colors
[2]=0x001F;
408 } else if ( bits
== 15 ) {
409 this->iv
.m_obh
.colors
[0]=0x7C00;
410 this->iv
.m_obh
.colors
[1]=0x03E0;
411 this->iv
.m_obh
.colors
[2]=0x001F;
413 this->iv
.m_obh
.biSize
= sizeof(BITMAPINFOHEADER
);
414 this->iv
.m_obh
.biCompression
= 0; //BI_RGB
415 //this->iv.m_obh.biHeight = labs(this->iv.m_obh.biHeight);
416 this->iv
.m_obh
.biSizeImage
= labs(this->iv
.m_obh
.biWidth
* this->iv
.m_obh
.biHeight
)
417 * ((this->iv
.m_obh
.biBitCount
+ 7) / 8);
420 //.biSizeImage=abs(temp.biWidth*temp.biHeight*((temp.biBitCount+7)/8));
427 this->m_sDestType
.subtype
= MEDIASUBTYPE_YUY2
;
430 this->m_sDestType
.subtype
= MEDIASUBTYPE_YV12
;
433 this->m_sDestType
.subtype
= MEDIASUBTYPE_IYUV
;
436 this->m_sDestType
.subtype
= MEDIASUBTYPE_I420
;
439 this->m_sDestType
.subtype
= MEDIASUBTYPE_UYVY
;
442 this->m_sDestType
.subtype
= MEDIASUBTYPE_YVYU
;
445 this->m_sDestType
.subtype
= MEDIASUBTYPE_YVU9
;
452 if (csp
!= 0 && csp
!= 3 && this->iv
.m_obh
.biHeight
> 0)
453 this->iv
.m_obh
.biHeight
*= -1; // YUV formats uses should have height < 0
454 this->iv
.m_obh
.biSize
= sizeof(BITMAPINFOHEADER
);
455 this->iv
.m_obh
.biCompression
=csp
;
456 this->iv
.m_obh
.biBitCount
=bits
;
458 this->iv
.m_obh
.biSizeImage
= labs(this->iv
.m_obh
.biWidth
* this->iv
.m_obh
.biHeight
)
459 * ((this->iv
.m_obh
.biBitCount
+ 7) / 8);
462 this->m_sDestType
.lSampleSize
= this->iv
.m_obh
.biSizeImage
;
463 memcpy(&(this->m_sVhdr2
->bmiHeader
), &this->iv
.m_obh
, sizeof(this->iv
.m_obh
));
464 this->m_sVhdr2
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
465 if (this->m_sVhdr2
->bmiHeader
.biCompression
== 3)
466 this->m_sDestType
.cbFormat
= sizeof(VIDEOINFOHEADER
) + 12;
468 this->m_sDestType
.cbFormat
= sizeof(VIDEOINFOHEADER
);
474 if(!(this->m_Caps
& CAP_YUY2
))
478 if(!(this->m_Caps
& CAP_YV12
))
482 if(!(this->m_Caps
& CAP_IYUV
))
486 if(!(this->m_Caps
& CAP_I420
))
490 if(!(this->m_Caps
& CAP_UYVY
))
494 if(!(this->m_Caps
& CAP_YVYU
))
498 if(!(this->m_Caps
& CAP_YVU9
))
508 // result = this->m_pDMO_Filter->m_pOutputPin->vt->QueryAccept(this->m_pDMO_Filter->m_pOutputPin, &this->m_sDestType);
513 if(!this->m_pDMO_Filter
) return 0;
514 result
= this->m_pDMO_Filter
->m_pMedia
->vt
->SetOutputType(this->m_pDMO_Filter
->m_pMedia
, 0, &this->m_sDestType
, DMO_SET_TYPEF_TEST_ONLY
);
519 printf("Warning: unsupported color space\n");
521 printf("Warning: unsupported bit depth\n");
523 this->m_sDestType
.lSampleSize
= this->iv
.m_decoder
.biSizeImage
;
524 memcpy(&(this->m_sVhdr2
->bmiHeader
), &this->iv
.m_decoder
, sizeof(this->iv
.m_decoder
));
525 this->m_sVhdr2
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
526 if (this->m_sVhdr2
->bmiHeader
.biCompression
== 3)
527 this->m_sDestType
.cbFormat
= sizeof(VIDEOINFOHEADER
) + 12;
529 this->m_sDestType
.cbFormat
= sizeof(VIDEOINFOHEADER
);
534 memcpy( &this->iv
.m_decoder
, &this->iv
.m_obh
, sizeof(this->iv
.m_obh
));
538 // m_obh.biBitCount=BitmapInfo::BitCount(csp);
539 this->iv
.m_bh
->biBitCount
= bits
;
541 //DMO_VideoDecoder_Restart(this);
543 this->m_pDMO_Filter
->m_pMedia
->vt
->SetOutputType(this->m_pDMO_Filter
->m_pMedia
, 0, &this->m_sDestType
, 0);
549 int DMO_VideoDecoder_SetDirection(DMO_VideoDecoder
*this, int d
)
551 this->iv
.m_obh
.biHeight
= (d
) ? this->iv
.m_bh
->biHeight
: -this->iv
.m_bh
->biHeight
;
552 this->m_sVhdr2
->bmiHeader
.biHeight
= this->iv
.m_obh
.biHeight
;