C++算法压缩比计算

3

我已经卡了两天,这个计算似乎很简单,但我就是不明白。

我正在使用压缩算法对音频文件进行编码。

整个音频文件被分成了每个960字节的"块"。每个块被压缩为60字节。

我的未压缩文件长度为1480320字节。我的编码文件长度为46320字节。

似乎有些不对劲。我试图从已编码音频的文件大小中计算理论上的未压缩文件大小。

以下是文件的编码方式:

short *m_in;
short *m_out;
unsigned char *m_data;
unsigned char *m_fbytes;
int m_max_frame_size;
int m_frame_size;
int m_sampling_rate;
int m_max_payload_bytes;
int m_bitrate_bps;
int m_iByteLen1FrameEncoded;
int m_iByteLen1FrameDecoded;


m_sampling_rate=48000;
m_max_frame_size = 960*6;
m_max_payload_bytes=1500;
m_bitrate_bps= 24000;
m_iByteLen1FrameEncoded=60;
m_iByteLen1FrameDecoded=960;

m_in = (short*)malloc(m_max_frame_size*sizeof(short));
m_out = (short*)malloc(m_max_frame_size*sizeof(short));
m_data = (unsigned char*)calloc(m_max_payload_bytes,sizeof(char));
m_fbytes = (unsigned char*)malloc(m_iByteLen1FrameDecoded*sizeof(short));

FILE *fin= fopen(uPathInput.c_str(), "rb");
FILE *fout=fopen(uPathOutput.c_str(), "wb");

int curr_read=0;
int stop=0;

    while (!stop)
    {
    int err;
    err = fread(m_fbytes, sizeof(short), 960, fin);
    curr_read = err;
    for(int i=0;i<curr_read;i++)
    {
        opus_int32 s;
        s=m_fbytes[2*i+1]<<8|m_fbytes[2*i];
        s=((s&0xFFFF)^0x8000)-0x8000;
        m_in[i]=s;
    }
    if (curr_read < 960)
    {
        for (int i=curr_read;i<960;i++)
        {
            m_in[i] = 0;
        }
        stop = 1;
    }
            //iLen will always return 60, so I guess the 960 bytes are compressed to 60 bytes, right?
    int iLen = opus_encode(m_enc, m_in, m_iByteLen1FrameDecoded, m_data, m_max_payload_bytes);
    if (fwrite(m_data, 1, iLen, fout) !=iLen) 
    {
        fprintf(stderr, "Error writing.\n");
    }     
}

    fclose(fin);
    fclose(fout);
 }

压缩比似乎是960/60 = 16

所以我计算了46320字节*16。 但这让我得到741120字节。 而那不合适。我预期它应该是1480320字节。

我试图找出我的计算错误,但我就是做不到。

有人看到我哪里错了吗?

非常感谢您的任何帮助!


实际压缩比似乎是32,而不是16。 - Robert Harvey
1
我想我有一些坏消息要告诉你,每个块不会压缩到60字节。或者每个块不是960字节。嗯,实际上这是好消息,因为它比那少/多(分别)。 - Bernhard Barker
我已经附上了用于压缩音频数据的代码。iLen始终为60,因此我认为960字节被压缩为60字节。 - tmighty
你(未声明的)变量的名称使代码难以理解,很难判断其中是否出现了问题(例如丢失每个压缩数据块)。m_fbytessm_datam_encm_in 的目的是什么?在 SO 代码示例中应避免使用缩写或匈牙利命名法,或者至少包括带有说明其目的的注释的变量声明。 - millimoose
3
你正在读取960个“short”,这相当于1920个字节,然后你可能会忽略每个数据块的一半。或者也许不是忽略了它,但是你的读取代码很奇怪,因为"fread()"会返回读取的字节数。无论哪种方式,如果“opus_encode()”返回的是字节大小,那么就可以解释其中的差异。 - millimoose
显示剩余8条评论
1个回答

1

好的,为了进一步说明我的评论。问题出在这里:

fread(m_fbytes, sizeof(short), 960, fin);

你正在阅读960个2字节宽的short,因此实际上你正在读取1920个字节。如果opus_encode()以字节为单位返回压缩大小,则压缩比率将为32,正如Robert所观察到的那样。
我还将简化处理块的代码:
size_t ITEM_SIZE = sizeof(short);
int ITEM_COUNT = 960;

// fread should first return a short item count, then zero
size_t shorts_read = 0;
while (shorts_read = fread(m_fbytes, ITEM_SIZE, ITEM_COUNT, fin)) {
    size_t i = 0;
    for (; i<read; i++) {
        opus_int32 s;
        // etc.
    }
    for (; i < ITEM_COUNT; i++) {
        m_in[i] = 0;
    }
    // opus_encode() etc
}

你可以去掉无用的停止标志和一层嵌套,这个结构是惯用语,表示“读到不能再读”。(参见这个stackoverflow问题
我撤回了对代码不合适的评论,我之前认为fread返回的是字节数而不是项目数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接