3

I am stuck since 2 days with a seemingly simple calculation. But I just don't get it.

I am encoding an audio file with a compressing algorithm.

The entire audio file is separated into "chunks" of 960 bytes. Each chunk is compressed to 60 bytes.

My uncompressed file is 1480320 bytes long. My encoded file is 46320 bytes long.

Something seems to be wrong. I tried to calculate the theoretic uncompressed file size from the file size of the encoded audio.

Here is how the file is encoded:

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);
 }

The compression ratio seems to be 960/60 = 16

So I calculated 46320 bytes * 16. But that gets me to 741120 bytes. And that doesn't fit. I expected it to be 1480320 bytes.

I am trying to find the error in my calculation, but I just don't manage.

Does anybody see where I went wrong?

Thank you very much for any help!

tmighty
  • 10,734
  • 21
  • 104
  • 218
  • The actual compression ratio appears to be 32, not 16. – Robert Harvey May 20 '13 at 15:30
  • 1
    I think I've got some bad news for you, each chuck does not compress to 60 bytes. Either that or each chunk isn't 960 bytes. Well, actually it's good news, since it's less / more (respectively) than that. – Bernhard Barker May 20 '13 at 15:30
  • is it possible different chunks are being compressed to different sizes rather than all being compressed uniformly? Do you know what the compression algorithm is by any chance? – Daniel May 20 '13 at 15:30
  • Actually the compression ratio is 60/960 (see [this](http://en.wikipedia.org/wiki/Data_compression_ratio)), but not that that would get you to the correct result. – Bernhard Barker May 20 '13 at 15:32
  • I have attached the code that is used to compress the audio data. iLen is always 60, so I thought that 960 bytes are compressed to 60 bytes. – tmighty May 20 '13 at 15:34
  • The names of your (undeclared) variables make the code more or less impossible to follow, and it's hard to tell if something in it is going wrong. (Like losing every other chunk of compressed data.) What is the purpose of `m_fbytes`, `s`, `m_data`, `m_enc`, `m_in` supposed to be? You should avoid acronyms or Hungarian for SO code samples, or at least include the variable declarations with comments explaining their purpose. – millimoose May 20 '13 at 15:43
  • @millimoose Sorry, I have added the declarations and initializations. – tmighty May 20 '13 at 15:45
  • (I.e. `m_fbytes` seems like it means "a field that's a file that contains bytes` which says nothing whatsoever since every file contains bytes.) – millimoose May 20 '13 at 15:45
  • Hurrr... `fread(m_fbytes, sizeof(short), 960, fin);` – millimoose May 20 '13 at 15:49
  • 3
    You're reading 960 `short`s, which is `1920` bytes, and then you're presumably ignoring half of every data chunk. Or maybe not ignoring it, but your reading code is still hokey because `fread()` will return the number of bytes read. Either way, if `opus_encode()` returns a size in bytes, that explains the discrepancy. – millimoose May 20 '13 at 15:54
  • @millimoose I copied this sample code from the documentary. Can you "beautify" it and make it more readable? – tmighty May 20 '13 at 16:28
  • @tmighty I've done what I could in [my answer](http://stackoverflow.com/a/16653841/41655), but it's hard to do much else without knowing what's really going on in the code, and thus what the *purpose* of those `short` arrays is. (Which is the important thing in naming.) – millimoose May 20 '13 at 16:30
  • @tmighty I already have. And gessing wildly, I'd propose renamings like `m_fbytes` -> `raw_input_chunk`, `m_in` -> `preprocessed_input_chunk`, `m_data` -> `encoded_output_chunk`, `m_iByteLen1FrameDecoded` -> `UNENCODED_CHUNK_ITEMS`, etc. – millimoose May 20 '13 at 16:34

1 Answers1

1

Right, to expand on my comments. The problem is found here:

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

You're reading 960 shorts, which should be 2 bytes wide, so you're really reading 1920 bytes. If opus_encode() returns the compressed size in bytes, that would make the compression ration 32 as Robert observed.

I'd also simplify the code processing the chunks:

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
}

You get rid of the useless stop flag and a level of nesting, and the construct is idiomatic for "read until you can't." (See this SO question.)

I retract what I mentioned about the code being hokey, I thought fread returns the bytes read, not the items read.

Community
  • 1
  • 1
millimoose
  • 39,073
  • 9
  • 82
  • 134