📄 ds_videodecoder.c
字号:
/******************************************************** DirectShow Video decoder implementation Copyright 2000 Eugene Kuznetsov (divx@euro.ru)*********************************************************/#include "config.h"#include "guids.h"#include "interfaces.h"#include "registry.h"#include "libwin32.h"#include "DS_Filter.h"struct DS_VideoDecoder{ IVideoDecoder iv; DS_Filter* m_pDS_Filter; AM_MEDIA_TYPE m_sOurType, m_sDestType; VIDEOINFOHEADER* m_sVhdr; VIDEOINFOHEADER2* m_sVhdr2; int m_Caps;//CAPS m_Caps; // capabilities of DirectShow decoder int m_iLastQuality; // remember last quality as integer int m_iMinBuffers; int m_iMaxAuto; int m_bIsDivX; // for speed int m_bIsDivX4; // for speed};static SampleProcUserData sampleProcData;static int discontinuity = 1;#include "DS_VideoDecoder.h"#include "wine/winerror.h"#ifdef WIN32_LOADER#include "ldt_keeper.h"#endif#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <sys/types.h>#include <stdio.h>#include <stdlib.h> // labs// strcmp((const char*)info.dll,...) is used instead of (... == ...)// so Arpi could use char* pointer in his simplified DS_VideoDecoder class#define false 0#define true 1int DS_VideoDecoder_GetCapabilities(DS_VideoDecoder *this){return this->m_Caps;} typedef struct ct ct;struct ct { unsigned int bits; fourcc_t fcc; const GUID *subtype; int cap; }; static ct check[] = { {16, fccYUY2, &MEDIASUBTYPE_YUY2, CAP_YUY2}, {12, fccIYUV, &MEDIASUBTYPE_IYUV, CAP_IYUV}, {16, fccUYVY, &MEDIASUBTYPE_UYVY, CAP_UYVY}, {12, fccYV12, &MEDIASUBTYPE_YV12, CAP_YV12}, //{16, fccYV12, &MEDIASUBTYPE_YV12, CAP_YV12}, {16, fccYVYU, &MEDIASUBTYPE_YVYU, CAP_YVYU}, {12, fccI420, &MEDIASUBTYPE_I420, CAP_I420}, {9, fccYVU9, &MEDIASUBTYPE_YVU9, CAP_YVU9}, {0, 0, 0, 0}, };#define AV_RB16(x) ((((const uint8_t*)(x))[0] << 8) | ((const uint8_t*)(x))[1])DWORD avc_quant(BYTE *src, BYTE *dst, int len){ //Stolen from libavcodec h264.c BYTE *p = src, *d = dst; int cnt; cnt = *(p+5) & 0x1f; // Number of sps if(src[0] != 0x01 || cnt > 1) { memcpy(dst, src, len); return len; } p += 6; //cnt > 1 not supported? cnt = AV_RB16(p) + 2; memcpy(d, p, cnt); d+=cnt; p+=cnt; //assume pps cnt == 1 too p++; cnt = AV_RB16(p) + 2; memcpy(d, p, cnt); return d + cnt - dst; }#define is_avc(cc) (cc == mmioFOURCC('A', 'V', 'C', '1') || \ cc == mmioFOURCC('a', 'v', 'c', '1'))char *ConvertVIHtoMPEG2VI(VIDEOINFOHEADER *vih, int *size){ struct VIDEOINFOHEADER2 { RECT32 rcSource; RECT32 rcTarget; DWORD dwBitRate; DWORD dwBitErrorRate; REFERENCE_TIME AvgTimePerFrame; DWORD dwInterlaceFlags; DWORD dwCopyProtectFlags; DWORD dwPictAspectRatioX; DWORD dwPictAspectRatioY; union { DWORD dwControlFlags; DWORD dwReserved1; }; DWORD dwReserved2; BITMAPINFOHEADER bmiHeader; }; struct MPEG2VIDEOINFO { struct VIDEOINFOHEADER2 hdr; DWORD dwStartTimeCode; DWORD cbSequenceHeader; DWORD dwProfile; DWORD dwLevel; DWORD dwFlags; DWORD dwSequenceHeader[1]; } *mp2vi; int extra = 0; if(vih->bmiHeader.biSize > sizeof(BITMAPINFOHEADER)) { extra = vih->bmiHeader.biSize-sizeof(BITMAPINFOHEADER); } mp2vi = (struct MPEG2VIDEOINFO *)malloc(sizeof(struct MPEG2VIDEOINFO)+extra-4); memset(mp2vi, 0, sizeof(struct MPEG2VIDEOINFO)); mp2vi->hdr.rcSource = vih->rcSource; mp2vi->hdr.rcTarget = vih->rcTarget; mp2vi->hdr.dwBitRate = vih->dwBitRate; mp2vi->hdr.dwBitErrorRate = vih->dwBitErrorRate; mp2vi->hdr.AvgTimePerFrame = vih->AvgTimePerFrame; mp2vi->hdr.dwPictAspectRatioX = vih->bmiHeader.biWidth; mp2vi->hdr.dwPictAspectRatioY = vih->bmiHeader.biHeight; memcpy(&mp2vi->hdr.bmiHeader, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); mp2vi->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); if(extra) { if(is_avc(vih->bmiHeader.biCompression)) { mp2vi->dwFlags = 4; //What does this mean? mp2vi->cbSequenceHeader = avc_quant( (BYTE *)(&vih->bmiHeader) + sizeof(BITMAPINFOHEADER), (BYTE *)(&mp2vi->dwSequenceHeader[0]), extra); } else { mp2vi->cbSequenceHeader = extra; memcpy(&mp2vi->dwSequenceHeader[0], (BYTE *)(&vih->bmiHeader) + sizeof(BITMAPINFOHEADER), extra); } } // The '4' is from the allocated space of dwSequenceHeader *size = sizeof(struct MPEG2VIDEOINFO) + mp2vi->cbSequenceHeader - 4; return (char *)mp2vi;}void DS_VideoDecoder_SetInputType(DS_VideoDecoder *this, BITMAPINFOHEADER * format){ unsigned int bihs; bihs = (format->biSize < (int) sizeof(BITMAPINFOHEADER)) ? sizeof(BITMAPINFOHEADER) : format->biSize; this->iv.m_bh = realloc(this->iv.m_bh, bihs); memcpy(this->iv.m_bh, format, bihs); this->iv.m_bh->biSize = bihs; bihs += sizeof(VIDEOINFOHEADER) - sizeof(BITMAPINFOHEADER); this->m_sVhdr = realloc(this->m_sVhdr, bihs); memset(this->m_sVhdr, 0, bihs); memcpy(&this->m_sVhdr->bmiHeader, this->iv.m_bh, this->iv.m_bh->biSize); this->m_sVhdr->rcSource.left = this->m_sVhdr->rcSource.top = 0; this->m_sVhdr->rcSource.right = this->m_sVhdr->bmiHeader.biWidth; this->m_sVhdr->rcSource.bottom = this->m_sVhdr->bmiHeader.biHeight; //this->m_sVhdr->rcSource.right = 0; //this->m_sVhdr->rcSource.bottom = 0; this->m_sVhdr->rcTarget = this->m_sVhdr->rcSource; this->m_sOurType.majortype = MEDIATYPE_Video; this->m_sOurType.subtype = MEDIATYPE_Video; this->m_sOurType.subtype.f1 = this->m_sVhdr->bmiHeader.biCompression; this->m_sOurType.formattype = FORMAT_VideoInfo; this->m_sOurType.bFixedSizeSamples = false; this->m_sOurType.bTemporalCompression = true; this->m_sOurType.pUnk = 0; this->m_sOurType.cbFormat = bihs; this->m_sOurType.pbFormat = (char*)this->m_sVhdr; if(is_avc(this->m_sVhdr->bmiHeader.biCompression)) { int size; this->m_sOurType.formattype = FORMAT_MPEG2Video; this->m_sOurType.pbFormat = (char*)ConvertVIHtoMPEG2VI(this->m_sVhdr, &size); this->m_sOurType.cbFormat = size; }}DS_VideoDecoder * DS_VideoDecoder_Open(char* dllname, GUID* guid, BITMAPINFOHEADER * format, int flip, int maxauto){ DS_VideoDecoder *this; HRESULT result; ct* c; this = malloc(sizeof(DS_VideoDecoder)); memset( this, 0, sizeof(DS_VideoDecoder)); this->m_iMaxAuto = maxauto;#ifdef WIN32_LOADER Setup_LDT_Keeper();#endif //memset(&m_obh, 0, sizeof(m_obh)); //m_obh.biSize = sizeof(m_obh); /*try*/ { this->iv.m_State = STOP; //this->iv.m_pFrame = 0; this->iv.m_Mode = DIRECT; this->iv.m_iDecpos = 0; this->iv.m_iPlaypos = -1; this->iv.m_fQuality = 0.0f; this->iv.m_bCapable16b = true; DS_VideoDecoder_SetInputType(this, format); this->m_sVhdr2 = malloc(sizeof(VIDEOINFOHEADER2)+12); memset((char*)this->m_sVhdr2, 0, sizeof(VIDEOINFOHEADER2)+12); this->m_sVhdr2->rcSource = this->m_sVhdr->rcSource; this->m_sVhdr2->rcTarget = this->m_sVhdr->rcTarget; this->m_sVhdr2->dwBitRate = this->m_sVhdr->dwBitRate; this->m_sVhdr2->dwBitErrorRate = this->m_sVhdr->dwBitErrorRate; this->m_sVhdr2->bmiHeader = this->m_sVhdr->bmiHeader; this->m_sVhdr2->bmiHeader.biCompression = 0; this->m_sVhdr2->bmiHeader.biBitCount = 24; memset(&this->m_sDestType, 0, sizeof(this->m_sDestType)); this->m_sDestType.majortype = MEDIATYPE_Video; this->m_sDestType.subtype = MEDIASUBTYPE_RGB24; this->m_sDestType.formattype = FORMAT_VideoInfo2; this->m_sDestType.bFixedSizeSamples = true; this->m_sDestType.bTemporalCompression = false; this->m_sDestType.lSampleSize = labs(this->m_sVhdr2->bmiHeader.biWidth*this->m_sVhdr2->bmiHeader.biHeight * ((this->m_sVhdr2->bmiHeader.biBitCount + 7) / 8)); this->m_sVhdr2->bmiHeader.biSizeImage = this->m_sDestType.lSampleSize; this->m_sDestType.pUnk = 0; this->m_sDestType.cbFormat = sizeof(VIDEOINFOHEADER2); this->m_sDestType.pbFormat = (char*)this->m_sVhdr2; memset(&this->iv.m_obh, 0, sizeof(this->iv.m_obh)); memcpy(&this->iv.m_obh, this->iv.m_bh, sizeof(this->iv.m_obh) < (unsigned) this->iv.m_bh->biSize ? sizeof(this->iv.m_obh) : (unsigned) this->iv.m_bh->biSize); this->iv.m_obh.biBitCount=24; this->iv.m_obh.biSize = sizeof(BITMAPINFOHEADER); this->iv.m_obh.biCompression = 0; //BI_RGB //this->iv.m_obh.biHeight = labs(this->iv.m_obh.biHeight); this->iv.m_obh.biSizeImage = labs(this->iv.m_obh.biWidth * this->iv.m_obh.biHeight) * ((this->iv.m_obh.biBitCount + 7) / 8); memset(&sampleProcData, 0, sizeof(sampleProcData)); this->m_pDS_Filter = DS_FilterCreate(dllname, guid, &this->m_sOurType, &this->m_sDestType,&sampleProcData); if (!this->m_pDS_Filter) { printf("Failed to create DirectShow filter\n"); return 0; } if (!flip) { this->iv.m_obh.biHeight *= -1; this->m_sVhdr2->bmiHeader.biHeight = this->iv.m_obh.biHeight; result = this->m_pDS_Filter->m_pOutputPin->vt->QueryAccept(this->m_pDS_Filter->m_pOutputPin, &this->m_sDestType); if (result) { printf("Decoder does not support upside-down RGB frames\n"); this->iv.m_obh.biHeight *= -1; this->m_sVhdr2->bmiHeader.biHeight = this->iv.m_obh.biHeight; } } memcpy( &this->iv.m_decoder, &this->iv.m_obh, sizeof(this->iv.m_obh) ); switch (this->iv.m_bh->biCompression) {#if 0 case fccDIV3: case fccDIV4: case fccDIV5: case fccDIV6: case fccMP42: case fccWMV2: //YV12 seems to be broken for DivX :-) codec// case fccIV50: //produces incorrect picture //m_Caps = (CAPS) (m_Caps & ~CAP_YV12); //m_Caps = CAP_UYVY;//CAP_YUY2; // | CAP_I420; //m_Caps = CAP_I420; this->m_Caps = (CAP_YUY2 | CAP_UYVY); break;#endif default: this->m_Caps = CAP_NONE; printf("Decoder supports the following YUV formats: "); for (c = check; c->bits; c++) { this->m_sVhdr2->bmiHeader.biBitCount = c->bits; this->m_sVhdr2->bmiHeader.biCompression = c->fcc; this->m_sDestType.subtype = *c->subtype; result = this->m_pDS_Filter->m_pOutputPin->vt->QueryAccept(this->m_pDS_Filter->m_pOutputPin, &this->m_sDestType); if (!result) { this->m_Caps = (this->m_Caps | c->cap); printf("%.4s ", (char *)&c->fcc); } } printf("\n"); } if (this->m_Caps != CAP_NONE) printf("Decoder is capable of YUV output (flags 0x%x)\n", (int)this->m_Caps); this->m_sVhdr2->bmiHeader.biBitCount = 24; this->m_sVhdr2->bmiHeader.biCompression = 0; this->m_sDestType.subtype = MEDIASUBTYPE_RGB24; this->m_iMinBuffers = this->iv.VBUFSIZE; this->m_bIsDivX = (strcmp(dllname, "divxcvki.ax") == 0 || strcmp(dllname, "divx_c32.ax") == 0 || strcmp(dllname, "wmvds32.ax") == 0 || strcmp(dllname, "wmv8ds32.ax") == 0); this->m_bIsDivX4 = (strcmp(dllname, "divxdec.ax") == 0); if (this->m_bIsDivX) this->iv.VBUFSIZE += 7; else if (this->m_bIsDivX4) this->iv.VBUFSIZE += 9; } /*catch (FatalError& error) { delete[] m_sVhdr; delete[] m_sVhdr2; delete m_pDS_Filter; throw; }*/ return this;}static int framecount, framecount_in;void DS_VideoDecoder_Destroy(DS_VideoDecoder *this){ DS_VideoDecoder_StopInternal(this); this->iv.m_State = STOP; free(this->m_sVhdr); free(this->m_sVhdr2); DS_Filter_Destroy(this->m_pDS_Filter); printf("************\nin-frames: %d out-frames: %d\n************\n", framecount_in, framecount);}void DS_VideoDecoder_StartInternal(DS_VideoDecoder *this)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -