Winapi 是否可以在Windows 8下的Windows视频上使用MRLE编解码器进行编码? 问题

Winapi 是否可以在Windows 8下的Windows视频上使用MRLE编解码器进行编码? 问题,winapi,vfw,Winapi,Vfw,我有一个旧的应用程序,它使用MRLE编解码器在.avi容器中提供视频。该代码使用Windows API的视频。多年来,这种方法一直运行良好,但我刚刚发现我的代码在Windows8上的行为不正确 在Windows 8上,程序会创建一个.avi文件,但当在例如Windows Media Player中查看该文件时,视频会以正确的持续时间播放,但第一帧会一直显示 我制作了一个SSCCE来演示问题: #include <Windows.h> #include <vfw.h> #i

我有一个旧的应用程序,它使用MRLE编解码器在.avi容器中提供视频。该代码使用Windows API的视频。多年来,这种方法一直运行良好,但我刚刚发现我的代码在Windows8上的行为不正确

在Windows 8上,程序会创建一个.avi文件,但当在例如Windows Media Player中查看该文件时,视频会以正确的持续时间播放,但第一帧会一直显示

我制作了一个SSCCE来演示问题:

#include <Windows.h>
#include <vfw.h>
#include <cstdlib>
#include <iostream>

#pragma comment(lib, "vfw32.lib")

int main()
{
    RECT frame = { 0, 0, 120, 100 };

    AVIFileInit();

    IAVIFile *pFile;
    if (AVIFileOpenA(&pFile, "out.avi", OF_CREATE | OF_WRITE, NULL) != 0)
    {
        std::cout << "AVIFileOpen failed" << std::endl;
        return 1;
    }

    AVISTREAMINFO si = { 0 };
    si.fccType = streamtypeVIDEO;
    si.fccHandler = mmioFOURCC('M', 'R', 'L', 'E');
    si.dwScale = 1;
    si.dwRate = 25;
    si.dwQuality = (DWORD)-1;
    si.rcFrame = frame;
    IAVIStream *pStream;
    if (AVIFileCreateStream(pFile, &pStream, &si) != 0)
    {
        std::cout << "AVIFileCreateStream failed" << std::endl;
        return 1;
    }

    AVICOMPRESSOPTIONS co = { 0 };
    co.fccType = si.fccType;
    co.fccHandler = si.fccHandler;
    co.dwQuality = si.dwQuality;
    IAVIStream *pCompressedStream;
    if (AVIMakeCompressedStream(&pCompressedStream, pStream, &co, NULL) != 0)
    {
        std::cout << "AVIMakeCompressedStream failed" << std::endl;
        return 1;
    }

    size_t bmiSize = sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD);
    BITMAPINFO *bmi = (BITMAPINFO*)std::malloc(bmiSize);
    ZeroMemory(bmi, bmiSize);
    bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi->bmiHeader.biWidth = si.rcFrame.right;
    bmi->bmiHeader.biHeight = si.rcFrame.bottom;
    bmi->bmiHeader.biPlanes = 1;
    bmi->bmiHeader.biBitCount = 8;
    bmi->bmiHeader.biCompression = BI_RGB;
    bmi->bmiHeader.biSizeImage = bmi->bmiHeader.biWidth*bmi->bmiHeader.biHeight;
    bmi->bmiHeader.biClrUsed = 256;
    for (int i = 0; i < 256; i++)
    {
        RGBQUAD col = { i, i, i, 0 };
        bmi->bmiColors[i] = col;
    }
    if (AVIStreamSetFormat(pCompressedStream, 0, bmi, bmiSize) != 0)
    {
        std::cout << "AVIStreamSetFormat failed" << std::endl;
        return 1;
    }

    unsigned char *bits = new unsigned char[bmi->bmiHeader.biSizeImage];
    for (int frame = 0; frame < 256; frame++)
    {
        std::memset(bits, 255-frame, bmi->bmiHeader.biSizeImage);
        if (AVIStreamWrite(pCompressedStream, frame, 1, bits, bmi->bmiHeader.biSizeImage, 0, NULL, NULL) != 0)
        {
            std::cout << "AVIStreamWrite failed" << std::endl;
            return 1;
        }
    }

    if (AVIStreamRelease(pCompressedStream) != 0 || AVIStreamRelease(pStream) != 0)
    {
        std::cout << "AVIStreamRelease failed" << std::endl;
        return 1;
    }
    if (AVIFileRelease(pFile) != 0)
    {
        std::cout << "AVIFileRelease failed" << std::endl;
        return 1;
    }

    std::cout << "Succeeded" << std::endl;
    return 0;
}
#包括
#包括
#包括
#包括
#pragma注释(lib,“vfw32.lib”)
int main()
{
矩形帧={0,0,120,100};
AVIFileInit();
IAVIFile*pFile;
if(AVIFileOpenA(&pFile,“out.avi”,OF|CREATE | OF|WRITE,NULL)!=0)
{
std::cout bmiHeader.biCompression=biu RGB;
bmi->bmiHeader.biSizeImage=bmi->bmiHeader.biWidth*bmi->bmiHeader.biHeight;
bmi->bmiHeader.biclrued=256;
对于(int i=0;i<256;i++)
{
RGBQUAD col={i,i,i,0};
bmi->bmiColors[i]=col;
}
如果(AVIStreamSetFormat(pCompressedStream,0,bmi,bmiSize)!=0)
{
标准::cout-bmiHeader.biSizeImage);
if(AVIStreamWrite(pCompressedStream,frame,1,bits,bmi->bmiHeader.biSizeImage,0,NULL,NULL)!=0)
{

std::cout这似乎确实是Windows 8中的一个bug。感谢Roman提出了一些解决问题的想法。我可以确认手动执行RLE编码很容易,而且效果很好

从问题中的代码开始,我们需要保留所有代码,并替换写入帧的for循环的内部。我们仍然需要创建压缩流,但不再向其写入。相反,我们将RLE8编码的数据写入原始流

unsigned char *bits = new unsigned char[bmi->bmiHeader.biHeight*4 + 2];
for (int frame = 0; frame < 256; frame++)
{
    size_t i = 0;
    for (size_t y = 0; y < bmi->bmiHeader.biHeight; y++)
    {
        bits[i++] = bmi->bmiHeader.biWidth;
        bits[i++] = 255-frame; // encoded run
        bits[i++] = 0;
        bits[i++] = 0; // EOL
    }
    bits[i++] = 0;
    bits[i++] = 1; // EOB
    if (AVIStreamWrite(pStream, frame, 1, bits, i, 0, NULL, NULL) != 0)
    {
        std::cout << "AVIStreamWrite failed" << std::endl;
        return 1;
    }
}
unsigned char*bits=新的unsigned char[bmi->bmiHeader.biHeight*4+2];
用于(整数帧=0;帧<256;帧++)
{
尺寸i=0;
对于(大小y=0;ybmiHeader.biHeight;y++)
{
位[i++]=bmi->bmiHeader.biWidth;
位[i++]=255帧;//编码运行
位[i++]=0;
位[i++]=0;//下线
}
位[i++]=0;
位[i++]=1;//EOB
if(流写入(PStreamWrite,帧,1,位,i,0,NULL,NULL)!=0)
{

std::我可以说问题出在编解码器本身——它接受新数据,但提供了一些陈旧的缓冲区。@RomanR。谢谢你的关注。我可以看出这是一个你是专家的主题领域。你认为我有什么希望吗?我的意思是,RLE_8似乎很容易实现。也许我需要做的就是输入RLE_8编码位映射到未压缩的流中。虽然有些东西告诉我它一定比这更复杂。我可以在我的系统上重复这个问题。大概,可以将问题隔离到编解码器上,直接用
ICOpen
打开它,并向它提供几个视频帧以检查输出。或者可能是一些标志缺少,并影响输出。但是,如果这工作正常,则可以获取压缩数据以进行进一步写入,并消除
AVIMakeCompressedStream
,直接绕过压缩写入数据。也就是说,再次尝试使用
ICOpen
可能会建议一种解决方法,并提供更多信息(尽管简单地实现RLE8可能会更容易)@Roman谢谢你的建议。我会试试看的。@Roman。最后,我从来没有达到过
ICOpen
,只是直奔颈静脉。我证明了手动编码的RLE8是可行的,然后继续在我的应用程序中实现了一个编码器。这非常好用。尽管出于某种原因,我的编码器没有MS压缩那么多所以我想我需要研究MS编码的位图,看看是否有明显的改进。非常感谢你的提示和建议,非常有用。