如何缩放视频的输出缓冲区大小? [英] How to scale output buffer size for a video?

查看:116
本文介绍了如何缩放视频的输出缓冲区大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嗨专家,



链接到我的完整源代码:

https://docs.google.com/file/d/0B9qC3OVDGTjuM2xaeGx1Q0NUYWs/edit [ ^ ]

(在Debug文件夹中有Resizer.dll,需要先注册然后再注册在图形编辑中选择任何视频文件(使用文件源文件管理器),然后添加RGB Resizer并使用它来调整视频大小)





我正在创建一个新的缩放器滤镜,我添加了一个属性页面,用户可以选择不同的输出(朋友(720X576),ntsc(720X480)......)



默认情况下选择pal,如果我播放它工作正常。

玩朋友后如果我将输出更改为ntsc视频显示不正确(问题是标题的顶部部分正在崩溃。)

如果我断开输出和输入我的过滤器的引脚,然后更改输出设置,重新连接后它似乎工作正常。



如何解决这个问题?(没有断开引脚我需要更改输出设置)



以下是我的代码(我使用的代码来自我在网上找到的样本,我添加了属性页面)

我想我需要更改ScaleBuf()但我没有任何线索如何解决这个问题。



Hi Experts,

Link to my Full source code:
https://docs.google.com/file/d/0B9qC3OVDGTjuM2xaeGx1Q0NUYWs/edit[^]
(in the Debug folder there is Resizer.dll, and need to register it first then in graph edit select any video file(using file source filer), then add "RGB Resizer" and use it to resize the video)


I am creating a new resizer Filter, I added a property page where user can select different outputs (pal(720X576), ntsc(720X480)...)

By default pal is selected and if i played it working fine.
after playing with pal and if i changed the output to ntsc video is not displaying correctly(problem is top part of the header is getting croped.)
If i disconnect the output and input pins of my filter and then change the output settings and after reconnecting it seems to be working fine.

How to fix this issue?(with out disconnecting the pins i need to change the output settings)

below is my code(the code i am using is from a sample i found online, i added the property page)
I guess i need to change ScaleBuf() but i dont have any clues how to fix this.

HRESULT CResizer::CheckInputType(const CMediaType *mtIn)
{
    // check this is a VIDEOINFOHEADER type and RGB
    GUID subtypeIn = *mtIn->Subtype();
    if( *mtIn->FormatType() == FORMAT_VideoInfo &&
        (subtypeIn == MEDIASUBTYPE_RGB555 || subtypeIn == MEDIASUBTYPE_RGB565 ||
        subtypeIn == MEDIASUBTYPE_RGB24 || subtypeIn == MEDIASUBTYPE_RGB32))
    {
        BITMAPINFOHEADER *pbih = &((VIDEOINFOHEADER*)mtIn->Format())->bmiHeader;
        m_inX = pbih->biWidth;
        m_inY = pbih->biHeight;
        m_bMakeTables = true;
        return S_OK;
    }
    return VFW_E_INVALID_MEDIA_TYPE;
}

HRESULT CResizer::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
{
    GUID subtypeIn = *mtIn->Subtype();
    GUID subtypeOut = *mtOut->Subtype();

    if(subtypeIn == subtypeOut && (subtypeIn == MEDIASUBTYPE_RGB555 || subtypeIn == MEDIASUBTYPE_RGB565 || 
       subtypeIn == MEDIASUBTYPE_RGB24 || subtypeIn == MEDIASUBTYPE_RGB32) )
    return S_OK;

    return VFW_E_INVALID_MEDIA_TYPE;
}


HRESULT CResizer::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties)
{
	if (!m_pInput->IsConnected()) 
        return E_UNEXPECTED;

    //HRESULT hr = NOERROR;

	ALLOCATOR_PROPERTIES InputProps;
	IMemAllocator *pAllocInput = 0;
	HRESULT hr = m_pInput->GetAllocator(&pAllocInput);
	if (FAILED(hr))
	{
		return hr;
	}
	hr = pAllocInput->GetProperties(&InputProps);
	pAllocInput->Release();

	if (FAILED(hr)) 
	{
		return hr;
	}

	if (pProperties->cbAlign == 0)
	{
		pProperties->cbAlign = 1;
	}

	if (pProperties->cbBuffer == 0)
	{
		pProperties->cBuffers = 1;
	}

	pProperties->cbBuffer = max(InputProps.cbBuffer, pProperties->cbBuffer);
	ALLOCATOR_PROPERTIES Actual;
	hr = pAlloc->SetProperties(pProperties, &Actual);
	if (FAILED(hr)) 
	{
		return hr;
	}

	if (InputProps.cbBuffer > Actual.cbBuffer) 
	{
		return E_FAIL;
	}

	return S_OK;
}

HRESULT CResizer::GetMediaType(int iPosition, CMediaType *pMediaType)
{
    // Is the input pin connected
    if (!m_pInput->IsConnected()) 
        return E_UNEXPECTED;

    if (iPosition < 0)
        return E_INVALIDARG;

    // Do we have more items to offer
    if (iPosition > 0)
        return VFW_S_NO_MORE_ITEMS;

	// get input dimensions
	CMediaType *inMediaType = &m_pInput->CurrentMediaType();
    VIDEOINFOHEADER *vihIn = (VIDEOINFOHEADER*)inMediaType->Format();
    m_bytesPerPixel = vihIn->bmiHeader.biBitCount / 8;
	pMediaType->SetFormatType(&FORMAT_VideoInfo);
	pMediaType->SetType(&MEDIATYPE_Video);
	pMediaType->SetSubtype(inMediaType->Subtype());
	pMediaType->SetSampleSize(RowWidth(m_outX) * m_outY * m_bytesPerPixel);
	pMediaType->SetTemporalCompression(FALSE);
	VIDEOINFOHEADER *vihOut = (VIDEOINFOHEADER *)pMediaType->ReallocFormatBuffer(sizeof(VIDEOINFOHEADER));

	// set VIDEOINFOHEADER
	memset(vihOut, 0, sizeof(VIDEOINFOHEADER));
	double frameRate = vihIn->AvgTimePerFrame / 10000000.0;
	vihOut->dwBitRate = (int)(frameRate * m_outY * m_outX * m_bytesPerPixel);
	vihOut->AvgTimePerFrame = vihIn->AvgTimePerFrame;

	// set BITMAPINFOHEADER
	vihOut->bmiHeader.biBitCount = m_bytesPerPixel * 8;
	vihOut->bmiHeader.biCompression = BI_RGB;
	vihOut->bmiHeader.biHeight = m_outY;
    vihOut->bmiHeader.biWidth = m_outX;
	vihOut->bmiHeader.biPlanes = 1;
	vihOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	vihOut->bmiHeader.biSizeImage = RowWidth(m_outX) * m_outY * m_bytesPerPixel;

    return NOERROR;
}

//////////////////////////////////////////////////////////////////////////
// Build the lookup tables used for scaling the input into the output
// For each destination pixel x and y the corresponding offset in the
// source buffer is stored
//////////////////////////////////////////////////////////////////////////
void CResizer::MakeScaleTables()
{
    double xStep = (double)m_inX / m_outX;
    double yStep = (double)m_inY / m_outY;

    int inRowBytes = RowWidth(m_inX * m_bytesPerPixel);
    int inY, inX;
    for(int y = 0; y < m_outY; ++y)    
    {
        inY = y * yStep;
        m_iSrcScanLine[y] = (inY * inRowBytes);
    }

    for(int x = 0; x < m_outX; ++x)
    {
        inX = x * xStep;
        m_iSrcPixelOffset[x] = (inX * m_bytesPerPixel);
    }

}

//////////////////////////////////////////////////////////////////////////
// This method scales the bitmap data from the input to output buffer
// When either of the formats change, the tables are rebuilt
//////////////////////////////////////////////////////////////////////////
void CResizer::ScaleBuf(BYTE *in, BYTE *out)
{
    UCHAR *dstPixel = out;
    UCHAR *srcScanLine, *srcPixel;
    // separate loops for each bpp
    for(int y = 0; y < m_outY; ++y)
    {
        srcScanLine = in + m_iSrcScanLine[y];
        switch(m_bytesPerPixel)
        {
            case 4: 
            for(int x = 0; x < m_outX; ++x)
            {
                srcPixel = srcScanLine + m_iSrcPixelOffset[x];
                *dstPixel++ = *srcPixel++;
                *dstPixel++ = *srcPixel++;
                *dstPixel++ = *srcPixel++;
                *dstPixel++ = *srcPixel++;
            }
            break;

            case 3: 
            for(int x = 0; x < m_outX; ++x)
            {
                srcPixel = srcScanLine + m_iSrcPixelOffset[x];
                *dstPixel++ = *srcPixel++;
                *dstPixel++ = *srcPixel++;
                *dstPixel++ = *srcPixel++;
            }
            break;
                
            case 2: 
            for(int x = 0; x < m_outX; ++x)
            {
                srcPixel = srcScanLine + m_iSrcPixelOffset[x];
                *dstPixel++ = *srcPixel++;
                *dstPixel++ = *srcPixel++;
            }
            break;
                
            case 1: 
            for(int x = 0; x < m_outX; ++x)
            {
                srcPixel = srcScanLine + m_iSrcPixelOffset[x];
                *dstPixel++ = *srcPixel++;
            }
            break;
        }
    }
}

推荐答案

你好,

一次你手动更改输出分辨率,你应该通知输出引脚输出格式已被更改,否则连接的滤波器仍然需要具有先前分辨率的数据:这样做可以简化重新连接输出引脚(如果已连接)。



代码中的问题:

- 您不应该在CheckInputType方法中设置输入宽度和高度,因为它只是计算出接受的类型,并且可以在图形运行期间调用,请改用taht SetMediaType,注意你应该处理pbFormat可以为NULL。

- 您的代码不关心动态格式更改实际上它通过了更改但忽略了(我认为您的问题是bcs of that就像你连接到渲染器一样,它会改变曲面分配的间距)。

- 在代码和动态格式处理中你应该校正输出音高。



此致,

Maxim。
Hello,
Once you change output resolution manually you should notify output pin that output format has been changed, otherwise connected filter still expect data with previous resolution: to do so simplify reconnect ouput pin if it already connected.

Issues in the code:
- You should not set the input width and height in CheckInputType method as it is to just figure out accepted type or not and may be called during graph running, use for taht SetMediaType instead, NOTE you should handle that pbFormat can be NULL.
- Your code not care about dynamic format changes actually it pass the changes but ignore that (I think your issue is bcs of that as if you connected to renderer it performs changing the pitch for surfaces allocating).
- In code along with dynamic format handling you should correct the output pitch.

Regards,
Maxim.


这篇关于如何缩放视频的输出缓冲区大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆