我是否错误地设置了 avi 信息以在 C++ 中保存文件? vfw?
我正在使用专门的网络流媒体摄像机,并且尝试将视频流保存在文件中。目前,代码保存了视频,但采用了一种粗俗的 RGB 格式,这种格式会搞乱颜色,然后使用 VFW 保存它。我这样做是否正确,这应该会创建颜色不匹配的 avi,还是我在 BITMAPINFOHEADER 区域设置了错误?
void PvSbProUISampleDlg::OnBnClickedSave()
{
// TODO: Add your control notification handler code here
CString StringValue;
mMovieSave.GetWindowTextW(StringValue);
if (StringValue == L"Save")
{
CString codecValue;
mMovieCodecSelected.GetWindowTextW(codecValue);
if (codecValue.IsEmpty()){
MessageBox( L"Please select a codec before saving to file",
L"Select Codec!",
MB_OK | MB_ICONEXCLAMATION );
return;
}
CString fileNameValue;
mFileName.GetWindowTextW(fileNameValue);
if (fileNameValue.IsEmpty()){
MessageBox( L"Please select a file location",
L"Select File!",
MB_OK | MB_ICONEXCLAMATION );
return;
}
if (!StartMovie())
return;
mSavingMovie = true;
mMovieSave.SetWindowTextW(L"Saving");
}
else
{
mVideoMutex.Lock();
PvResult aResult = mVideoCompressor->Stop();
mSavingMovie = false;
mVideoMutex.Unlock();
if (!aResult.IsOK())
{
MessageBox( mLocation,
L"Can't Stop Video Compressor!",
MB_OK | MB_ICONEXCLAMATION );
return;
}
mMovieSave.SetWindowTextW(L"Save");
}
}
我设置了视频流并为我的编解码器选择了未压缩的 AVI。我单击“保存”按钮,然后调用该函数下面的函数
bool PvSbProUISampleDlg::StartMovie()
{
if ( !mDevice.IsConnected() )
{
MessageBox( L"Need to connect to device",
L"Cannot start Video Compressor!",
MB_OK | MB_ICONEXCLAMATION );
return false;
}
if (!mPipeline.IsStarted() )
{
return false;
}
if (mSavingMovie)
return false;
PvInt64 width;
PvInt64 height;
PvInt64 bitCount;
if (!GetImageWidth(width).IsOK())
return false;
if (!GetImageHeight(height).IsOK())
return false;
if (!GetPixelBitCount(bitCount).IsOK())
return false;
// Start the movie compressor
if ( !mVideoCompressor->Start( mLocation,
width,
height,
bitCount/8,
59).IsOK())
{
MessageBox( mLocation,
L"Cannot start Video Compressor!",
MB_OK | MB_ICONEXCLAMATION );
return false;
}
return true;
}
获取视频大小信息,然后调用实际压缩来启动
PvResult VideoCompressor::Start(const CString& aFileName, unsigned short aSizeX, unsigned short aSizeY, unsigned short aBPP, double aFPS)
{
IAVIFile *lAVIFile = NULL;
IAVIStream *lAVIStream = NULL;
IAVIStream *lAVICompressedStream = NULL;
AVISTREAMINFO lAVISTREAMINFO;
AVICOMPRESSOPTIONS lAVICOMPRESSOPTIONS;
// Try to match the image format with the Video Compressor capabilities
BITMAPINFO lTempBI;
lTempBI.bmiHeader.biSize = sizeof( BITMAPINFO );
lTempBI.bmiHeader.biWidth = aSizeX;
lTempBI.bmiHeader.biHeight = aSizeY;
lTempBI.bmiHeader.biPlanes = 1;
lTempBI.bmiHeader.biBitCount = aBPP * 8;
lTempBI.bmiHeader.biCompression = BI_RGB;
lTempBI.bmiHeader.biSizeImage = aSizeX * aSizeY * aBPP;
lTempBI.bmiHeader.biXPelsPerMeter = 1280;
lTempBI.bmiHeader.biYPelsPerMeter = 720;
lTempBI.bmiHeader.biClrUsed = 0;
lTempBI.bmiHeader.biClrImportant = 0;
//lTempBI.bmiHeader.
if( ( mCOMPVARS.hic != NULL ) && // if not the "Full Frames (uncompressed)"
( ICCompressQuery( mCOMPVARS.hic, &lTempBI, NULL ) != ICERR_OK ) )
{
mLastVideoError = "Image format not accepted by compressor!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
// Try to open the stream for writing
if( mTempBuffer )
delete [] mTempBuffer;
mTempBuffer = new unsigned char[ aSizeX * aSizeY * aBPP ];
if( mTempBuffer == NULL )
{
mLastVideoError = "Cannot allocate memory for a temporary buffer!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
if( AVIFileOpen( &lAVIFile, aFileName, OF_CREATE | OF_WRITE, NULL ) != 0 )
{
mLastVideoError = "Cannot open movie file for writing!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
// Fill out AVIStream information
memset( &lAVISTREAMINFO, 0, sizeof( AVISTREAMINFO ) );
lAVISTREAMINFO.fccType = streamtypeVIDEO;
lAVISTREAMINFO.fccHandler = mCOMPVARS.fccHandler;
lAVISTREAMINFO.dwFlags = 0;
lAVISTREAMINFO.dwCaps = 0;
lAVISTREAMINFO.wPriority = 0;
lAVISTREAMINFO.wLanguage = 0;
lAVISTREAMINFO.dwScale = 100;
lAVISTREAMINFO.dwRate = (unsigned long)( aFPS * 100.0 );
lAVISTREAMINFO.dwStart = 0;
lAVISTREAMINFO.dwLength = 0;
lAVISTREAMINFO.dwInitialFrames = 0;
lAVISTREAMINFO.dwQuality = mCOMPVARS.lQ;
lAVISTREAMINFO.dwSuggestedBufferSize = aSizeX * aSizeY * aBPP;
lAVISTREAMINFO.dwSampleSize = aSizeX * aSizeY * aBPP;
SetRect(&lAVISTREAMINFO.rcFrame, 0, aSizeY, aSizeX, 0);
// Convert to a wchar_t*
char *orig = "Video Stream";
size_t origsize = strlen(orig) + 1;
const size_t newsize = 64;
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, lAVISTREAMINFO.szName, origsize, orig, _TRUNCATE);
if( AVIFileCreateStream( lAVIFile, &lAVIStream, &lAVISTREAMINFO ) != 0 )
{
mLastVideoError = "Cannot create video stream!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
BITMAPINFOHEADER lBIH;
lBIH.biSize = sizeof( BITMAPINFOHEADER );
lBIH.biWidth = aSizeX;
lBIH.biHeight = aSizeY;
lBIH.biPlanes = 1;
lBIH.biBitCount = aBPP * 8;
lBIH.biCompression = BI_RGB;
lBIH.biSizeImage = aSizeX * aSizeY * aBPP;
lBIH.biXPelsPerMeter = 1280;
lBIH.biYPelsPerMeter = 720;
lBIH.biClrUsed = 0;
lBIH.biClrImportant = 0;
memset( &lAVICOMPRESSOPTIONS, 0, sizeof( AVICOMPRESSOPTIONS ) );
lAVICOMPRESSOPTIONS.fccType = streamtypeVIDEO;
lAVICOMPRESSOPTIONS.fccHandler = mCOMPVARS.fccHandler;
lAVICOMPRESSOPTIONS.dwKeyFrameEvery = 15;
lAVICOMPRESSOPTIONS.dwQuality = mCOMPVARS.lQ;
lAVICOMPRESSOPTIONS.dwBytesPerSecond = 0;
lAVICOMPRESSOPTIONS.dwFlags = AVICOMPRESSF_KEYFRAMES; //| AVICOMPRESSF_VALID;//|AVICOMPRESSF_DATARATE;
lAVICOMPRESSOPTIONS.lpFormat = &lBIH;
lAVICOMPRESSOPTIONS.cbFormat = sizeof( lBIH );
lAVICOMPRESSOPTIONS.lpParms = 0;
lAVICOMPRESSOPTIONS.cbParms = 0;
lAVICOMPRESSOPTIONS.dwInterleaveEvery = 0;
HRESULT lR = AVIMakeCompressedStream( &lAVICompressedStream, lAVIStream, &lAVICOMPRESSOPTIONS, NULL);
if( lR == AVIERR_NOCOMPRESSOR )
{
mLastVideoError = "Cannot find a suitable compressor!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
else if( lR == AVIERR_MEMORY )
{
mLastVideoError = "Not enough memory to start the compressor!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
else if( lR == AVIERR_UNSUPPORTED )
{
mLastVideoError = "Compression is not supported for this image buffer!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
if( AVIStreamSetFormat( lAVICompressedStream, 0, &lBIH, sizeof( lBIH ) ) != 0 )
{
mLastVideoError = "Cannot set stream format. It probably isn't supported by the Codec!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
///////////////////
HRESULT hr;
//IBaseFilter mux = Null;
//IFileSinkFilter sink = null;
// Guid x = new Guid( 0xe436eb88, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
//ICaptureGraphBuilder2::SetOutputFileName(
//////////////////
// finishing up
mAVIFile = lAVIFile;
mAVIStream = lAVIStream;
mAVICompressedStream = lAVICompressedStream;
mSizeX = aSizeX;
mSizeY = aSizeY;
mBPP = aBPP;
mImageSize = aSizeX * aSizeY * aBPP;
mLastSample = 0;
mCompressing = true;
return PvResult::Code::OK;
}
此压缩流,
PvResult VideoCompressor::Compress(PvBuffer *aPvBuffer)
{
if (!mCompressing)
return PvResult::Code::GENERIC_ERROR;
ASSERT( mTempBuffer != NULL );
long lSamplesWritten, lBytesWritten;
int numberOfLines = 0;
PvUInt8 * aBuffer = aPvBuffer->GetDataPointer();
for( unsigned short lLine = 0; lLine < mSizeY; lLine++ )
{
numberOfLines = lLine;
unsigned char *lCurLine = (unsigned char *)aBuffer + (lLine ) * mSizeX * mBPP;
unsigned char *lCurLineInv = mTempBuffer + (mSizeY - lLine - 1) * mSizeX * mBPP;
::memcpy( lCurLineInv, lCurLine, mSizeX * mBPP );
}
if( AVIStreamWrite( mAVICompressedStream, mLastSample, 1, mTempBuffer, mImageSize, 0,
&lSamplesWritten, &lBytesWritten ) != 0 ||
lSamplesWritten < 1 ||
lBytesWritten < 1 )
{
mLastVideoError = "Cannot compress image!";
return PvResult::Code::GENERIC_ERROR;
}
mLastSample ++;
return PvResult::Code::OK;
}
这应该是这样的: http://i13.photobucket.com/albums/a269/Masterg_/Untitled -16.png
这是它保存的内容(减去那个家伙): http://i13.photobucket.com/albums/a269/Masterg_/vlcsnap-2011-06-07-13h11m34s97.png
I am using a specialized network streaming camera and I am trying to save the video stream off in a file. at the moment the code saves the video but in an ackward RGB format which screws up the color and then saves it using VFW. Am i doing this correctly and this is supposed to create avi with mismatched colors or did i setup something wrong in the BITMAPINFOHEADER areas?
void PvSbProUISampleDlg::OnBnClickedSave()
{
// TODO: Add your control notification handler code here
CString StringValue;
mMovieSave.GetWindowTextW(StringValue);
if (StringValue == L"Save")
{
CString codecValue;
mMovieCodecSelected.GetWindowTextW(codecValue);
if (codecValue.IsEmpty()){
MessageBox( L"Please select a codec before saving to file",
L"Select Codec!",
MB_OK | MB_ICONEXCLAMATION );
return;
}
CString fileNameValue;
mFileName.GetWindowTextW(fileNameValue);
if (fileNameValue.IsEmpty()){
MessageBox( L"Please select a file location",
L"Select File!",
MB_OK | MB_ICONEXCLAMATION );
return;
}
if (!StartMovie())
return;
mSavingMovie = true;
mMovieSave.SetWindowTextW(L"Saving");
}
else
{
mVideoMutex.Lock();
PvResult aResult = mVideoCompressor->Stop();
mSavingMovie = false;
mVideoMutex.Unlock();
if (!aResult.IsOK())
{
MessageBox( mLocation,
L"Can't Stop Video Compressor!",
MB_OK | MB_ICONEXCLAMATION );
return;
}
mMovieSave.SetWindowTextW(L"Save");
}
}
I set up the video stream and select uncompressed AVI for my codec. I click "save" button which then calls the function below
bool PvSbProUISampleDlg::StartMovie()
{
if ( !mDevice.IsConnected() )
{
MessageBox( L"Need to connect to device",
L"Cannot start Video Compressor!",
MB_OK | MB_ICONEXCLAMATION );
return false;
}
if (!mPipeline.IsStarted() )
{
return false;
}
if (mSavingMovie)
return false;
PvInt64 width;
PvInt64 height;
PvInt64 bitCount;
if (!GetImageWidth(width).IsOK())
return false;
if (!GetImageHeight(height).IsOK())
return false;
if (!GetPixelBitCount(bitCount).IsOK())
return false;
// Start the movie compressor
if ( !mVideoCompressor->Start( mLocation,
width,
height,
bitCount/8,
59).IsOK())
{
MessageBox( mLocation,
L"Cannot start Video Compressor!",
MB_OK | MB_ICONEXCLAMATION );
return false;
}
return true;
}
the function gets the video size info and then calls the actually compression to start
PvResult VideoCompressor::Start(const CString& aFileName, unsigned short aSizeX, unsigned short aSizeY, unsigned short aBPP, double aFPS)
{
IAVIFile *lAVIFile = NULL;
IAVIStream *lAVIStream = NULL;
IAVIStream *lAVICompressedStream = NULL;
AVISTREAMINFO lAVISTREAMINFO;
AVICOMPRESSOPTIONS lAVICOMPRESSOPTIONS;
// Try to match the image format with the Video Compressor capabilities
BITMAPINFO lTempBI;
lTempBI.bmiHeader.biSize = sizeof( BITMAPINFO );
lTempBI.bmiHeader.biWidth = aSizeX;
lTempBI.bmiHeader.biHeight = aSizeY;
lTempBI.bmiHeader.biPlanes = 1;
lTempBI.bmiHeader.biBitCount = aBPP * 8;
lTempBI.bmiHeader.biCompression = BI_RGB;
lTempBI.bmiHeader.biSizeImage = aSizeX * aSizeY * aBPP;
lTempBI.bmiHeader.biXPelsPerMeter = 1280;
lTempBI.bmiHeader.biYPelsPerMeter = 720;
lTempBI.bmiHeader.biClrUsed = 0;
lTempBI.bmiHeader.biClrImportant = 0;
//lTempBI.bmiHeader.
if( ( mCOMPVARS.hic != NULL ) && // if not the "Full Frames (uncompressed)"
( ICCompressQuery( mCOMPVARS.hic, &lTempBI, NULL ) != ICERR_OK ) )
{
mLastVideoError = "Image format not accepted by compressor!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
// Try to open the stream for writing
if( mTempBuffer )
delete [] mTempBuffer;
mTempBuffer = new unsigned char[ aSizeX * aSizeY * aBPP ];
if( mTempBuffer == NULL )
{
mLastVideoError = "Cannot allocate memory for a temporary buffer!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
if( AVIFileOpen( &lAVIFile, aFileName, OF_CREATE | OF_WRITE, NULL ) != 0 )
{
mLastVideoError = "Cannot open movie file for writing!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
// Fill out AVIStream information
memset( &lAVISTREAMINFO, 0, sizeof( AVISTREAMINFO ) );
lAVISTREAMINFO.fccType = streamtypeVIDEO;
lAVISTREAMINFO.fccHandler = mCOMPVARS.fccHandler;
lAVISTREAMINFO.dwFlags = 0;
lAVISTREAMINFO.dwCaps = 0;
lAVISTREAMINFO.wPriority = 0;
lAVISTREAMINFO.wLanguage = 0;
lAVISTREAMINFO.dwScale = 100;
lAVISTREAMINFO.dwRate = (unsigned long)( aFPS * 100.0 );
lAVISTREAMINFO.dwStart = 0;
lAVISTREAMINFO.dwLength = 0;
lAVISTREAMINFO.dwInitialFrames = 0;
lAVISTREAMINFO.dwQuality = mCOMPVARS.lQ;
lAVISTREAMINFO.dwSuggestedBufferSize = aSizeX * aSizeY * aBPP;
lAVISTREAMINFO.dwSampleSize = aSizeX * aSizeY * aBPP;
SetRect(&lAVISTREAMINFO.rcFrame, 0, aSizeY, aSizeX, 0);
// Convert to a wchar_t*
char *orig = "Video Stream";
size_t origsize = strlen(orig) + 1;
const size_t newsize = 64;
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, lAVISTREAMINFO.szName, origsize, orig, _TRUNCATE);
if( AVIFileCreateStream( lAVIFile, &lAVIStream, &lAVISTREAMINFO ) != 0 )
{
mLastVideoError = "Cannot create video stream!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
BITMAPINFOHEADER lBIH;
lBIH.biSize = sizeof( BITMAPINFOHEADER );
lBIH.biWidth = aSizeX;
lBIH.biHeight = aSizeY;
lBIH.biPlanes = 1;
lBIH.biBitCount = aBPP * 8;
lBIH.biCompression = BI_RGB;
lBIH.biSizeImage = aSizeX * aSizeY * aBPP;
lBIH.biXPelsPerMeter = 1280;
lBIH.biYPelsPerMeter = 720;
lBIH.biClrUsed = 0;
lBIH.biClrImportant = 0;
memset( &lAVICOMPRESSOPTIONS, 0, sizeof( AVICOMPRESSOPTIONS ) );
lAVICOMPRESSOPTIONS.fccType = streamtypeVIDEO;
lAVICOMPRESSOPTIONS.fccHandler = mCOMPVARS.fccHandler;
lAVICOMPRESSOPTIONS.dwKeyFrameEvery = 15;
lAVICOMPRESSOPTIONS.dwQuality = mCOMPVARS.lQ;
lAVICOMPRESSOPTIONS.dwBytesPerSecond = 0;
lAVICOMPRESSOPTIONS.dwFlags = AVICOMPRESSF_KEYFRAMES; //| AVICOMPRESSF_VALID;//|AVICOMPRESSF_DATARATE;
lAVICOMPRESSOPTIONS.lpFormat = &lBIH;
lAVICOMPRESSOPTIONS.cbFormat = sizeof( lBIH );
lAVICOMPRESSOPTIONS.lpParms = 0;
lAVICOMPRESSOPTIONS.cbParms = 0;
lAVICOMPRESSOPTIONS.dwInterleaveEvery = 0;
HRESULT lR = AVIMakeCompressedStream( &lAVICompressedStream, lAVIStream, &lAVICOMPRESSOPTIONS, NULL);
if( lR == AVIERR_NOCOMPRESSOR )
{
mLastVideoError = "Cannot find a suitable compressor!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
else if( lR == AVIERR_MEMORY )
{
mLastVideoError = "Not enough memory to start the compressor!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
else if( lR == AVIERR_UNSUPPORTED )
{
mLastVideoError = "Compression is not supported for this image buffer!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
if( AVIStreamSetFormat( lAVICompressedStream, 0, &lBIH, sizeof( lBIH ) ) != 0 )
{
mLastVideoError = "Cannot set stream format. It probably isn't supported by the Codec!";
CleanUp(lAVIFile, lAVIStream ,lAVICompressedStream);
return PvResult::Code::GENERIC_ERROR;
}
///////////////////
HRESULT hr;
//IBaseFilter mux = Null;
//IFileSinkFilter sink = null;
// Guid x = new Guid( 0xe436eb88, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
//ICaptureGraphBuilder2::SetOutputFileName(
//////////////////
// finishing up
mAVIFile = lAVIFile;
mAVIStream = lAVIStream;
mAVICompressedStream = lAVICompressedStream;
mSizeX = aSizeX;
mSizeY = aSizeY;
mBPP = aBPP;
mImageSize = aSizeX * aSizeY * aBPP;
mLastSample = 0;
mCompressing = true;
return PvResult::Code::OK;
}
this compresses the stream
PvResult VideoCompressor::Compress(PvBuffer *aPvBuffer)
{
if (!mCompressing)
return PvResult::Code::GENERIC_ERROR;
ASSERT( mTempBuffer != NULL );
long lSamplesWritten, lBytesWritten;
int numberOfLines = 0;
PvUInt8 * aBuffer = aPvBuffer->GetDataPointer();
for( unsigned short lLine = 0; lLine < mSizeY; lLine++ )
{
numberOfLines = lLine;
unsigned char *lCurLine = (unsigned char *)aBuffer + (lLine ) * mSizeX * mBPP;
unsigned char *lCurLineInv = mTempBuffer + (mSizeY - lLine - 1) * mSizeX * mBPP;
::memcpy( lCurLineInv, lCurLine, mSizeX * mBPP );
}
if( AVIStreamWrite( mAVICompressedStream, mLastSample, 1, mTempBuffer, mImageSize, 0,
&lSamplesWritten, &lBytesWritten ) != 0 ||
lSamplesWritten < 1 ||
lBytesWritten < 1 )
{
mLastVideoError = "Cannot compress image!";
return PvResult::Code::GENERIC_ERROR;
}
mLastSample ++;
return PvResult::Code::OK;
}
this is what it should look like:
http://i13.photobucket.com/albums/a269/Masterg_/Untitled-16.png
this is what it saves as ( minus the guy):
http://i13.photobucket.com/albums/a269/Masterg_/vlcsnap-2011-06-07-13h11m34s97.png
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从 MSDN 我们有:
我可能是错的,但在我看来,您试图“强制”此输入格式,而不考虑您作为输入传递的实际格式。如果您的输入格式与“强制”格式不匹配,则必然会出现奇怪的结果。
如果您的实际输入格式与您的压缩器不兼容,您可以尝试使用 ColorSpace 转换器过滤器 在压缩器之前。
From MSDN we have:
I might be wrong, but it seems to me that you are trying to "force" this input format whitout taking into account the actual format you are passing as input. If your input format does not match the "forced" one, weird result must be expected.
If your actual input format is not compatible with your compressor, you could try usign a ColorSpace converter filter before your compressor.