Log in

View Full Version : Ac3


GaveUp
27th March 2005, 07:29
Is there a way to patch/modify AC3 frames to be a higher bitrate than they are without reencoding? I have some AC3's that jump from 448 to 192 to 448 and so on. Decoders seem not to be able to handle this properly, so I need a way to change the 192 to 448, preferably without reencoding to eliminate a loss of quality by reencoding.

GaveUp
27th March 2005, 08:01
Hmmm. After doing a little more testing it seems more so that the decoder isn't what is causing the problem but that it is the container causing the problem. If it is in a mpg container (mpeg2/ac3) the audio decodes fine and stays in sync. If it is in an avi, ogm, or mkv (xvid/ac3) then it has problems when the bitrate changes. So I guess, my initial question still applies, and also if there is another way around this problem.

jsoto
29th March 2005, 22:49
I did a small test "upgrading" from 384 to 448 and seems to work!!

Do you have the ac3 specs?
Simply:
- hack frmsizecod
- add auxdata (zeroes) at the end of the frame. If the last bit of the auxbit block is zero (usually it is) it is enough to add zeroes. If this bit is one, you have to do some extra job, to keep the auxdata, but seems not difficult
- recalculate crc

You're done!

It is so easy I cannot believe it!

May be I'm missing something?

jsoto

GaveUp
29th March 2005, 22:59
Hmmm. I'll have to test this out. You mention there is more work if the auxdata is not 0's already. What sort of work is involved? Can't check the specs right now, myself, as I'm at work.

jsoto
29th March 2005, 23:08
Nah, seems easy.
Auxdata has to be always at the end of the frame, so I believe you have to "move" the aux bits (you get the number of bits from auxdatal, which is always at the same position, starting from the end) from their original position to the "extended" one.

In any case, I do not think auxdata is something usual....May be you can directly forget it.

jsoto

GaveUp
29th March 2005, 23:09
Ok, so I'm bored. I went and grabbed the specs and started looking at the auxdata part. I guess I don't see why that wouldn't work. I also saw the skiple, skipl, skipfld fields. If I'm reading those properly they were designed to padd streams in the event they ended up short of the CBR.

jsoto
29th March 2005, 23:22
Originally posted by GaveUp
I also saw the skiple, skipl, skipfld fields. If I'm reading those properly they were designed to padd streams in the event they ended up short of the CBR. Yes, but they are inside the audio block. There are 6 audio blocks and you have to parse completely the frame to find their positions... Using aux data is so easy..., read the last paragraph of page 47 of the specs. You can decode the auxdata whitout parsing the ac3 frame!, just starting from the end.

BTW, I've double checked my small test in PowerDVD, and yes, it works!

jsoto

GaveUp
29th March 2005, 23:36
Under Section 5.5 it seems to imply this is an illegal way of doing things, even if it does work. By doing this you'd easily have a auxdata greater than 3/8'ths the size of the frame and thus violating the bitstream constraints.

jsoto
29th March 2005, 23:47
I don't think so...
In my understanding, the number of aux data bits will be the same (usually zero), so you are not going to do nothing illegal. I believe when 5.5 says "auxiliary data fields" it is refering to the actual aux data size (auxdatal), which usually is zero.

jsoto

jsoto
29th March 2005, 23:52
Did another small test: From 128k to 448k (2.0)
No problem at all in powerDVD.

jsoto

GaveUp
30th March 2005, 04:20
Well either I've got a bug in my code or this really doesn't work in an avi. Maybe someone here can see something in my code that I'm missing.


int patchFrame(AC3FrameInfo fi, unsigned char *frame, AC3FrameInfo newFrame) {
char temp[3];
int end;
int i;
unsigned int crc_inv;

if(fi.auxdataE != 0)
return -1;
else {
printf("Patching Frame\n");
temp[0] = frame[(fi.size*2)-3];
temp[1] = frame[(fi.size*2)-2];
temp[2] = frame[(fi.size*2)-1];

end = newFrame.size *= 2;
end -= 3;
for(i = ((fi.size * 2) - 3); i <= end; i ++)
frame[i] = 0x00;

frame[i] = temp[0];
frame[i+1] = temp[1];
frame[i+2] = temp[2];

fi.size = newFrame.size;
fi.bitrate = newFrame.bitrate;

fi.actual_crc1 = ac3_crc(frame + 4, 2 * crc1_sizes[fi.samplerate + (2*fi.bitrate & 0x01)][fi.bitrate >> 1] - 4, 0);
crc_inv = pow_poly((CRC16_POLY >> 1), (16 * crc1_sizes[fi.samplerate + (2*fi.bitrate & 0x01)][fi.bitrate >> 1]) - 16, CRC16_POLY);
fi.actual_crc1 = mul_poly(crc_inv, fi.actual_crc1, CRC16_POLY);
fi.actual_crc2 = ac3_crc(frame + (2 * crc1_sizes[fi.samplerate + (2*fi.bitrate & 0x01)][fi.bitrate >> 1]), ((bitrates[fi.samplerate+1][(fi.bitrate >> 1)] + (fi.bitrate & 0x01)) - crc1_sizes[fi.samplerate + (2*fi.bitrate & 0x01)][fi.bitrate >> 1]) * 2 - 2, 0);

return 0;
}

return 0;
}


The AC3FrameInfo type used is:


typedef struct ac3FrameInfo {
unsigned char samplerate;
unsigned char bitrate;
unsigned int crc1;
unsigned int crc2;
unsigned int actual_crc1;
unsigned int actual_crc2;
unsigned long startByte;
unsigned long size;
unsigned short auxdataE;
} AC3FrameInfo;

jsoto
30th March 2005, 07:45
What is the effect?. May be the crc is wrong? Try loading your output in delaycut and see what happen.

Looking in my code

frame_size_58 = (frame_size >> 1) + (frame_size >> 3);
cal_crc1 = ac3_crc(caracter + 4, (2 * frame_size_58) - 4, 0);
crc_inv = pow_poly((CRC16_POLY >> 1), (16 * frame_size_58) - 16, CRC16_POLY);
cal_crc1 = mul_poly(crc_inv, cal_crc1, CRC16_POLY);
cal_crc2 = ac3_crc(caracter + 2 * frame_size_58, (frame_size - frame_size_58) * 2 - 2, 0);


Are you updating your fi.bitrate?

jsoto

jsoto
30th March 2005, 08:21
Ooops, Seems I've found something wrong in your code...

The last two bytes of the frame are the crc.
IIRC (do not have the specs here), the last bit of frame[framesize-3] is a flag of the crc (don't remember the name) and the previous bit is auzdataE. But the other six bits can be part of the last audioblock if auzdataE==0, So you have to keep the byte frame[framesize-3], you cannot put a zero there...

jsoto

GaveUp
30th March 2005, 15:13
I was aware that the CRC was broken. I am not reupdating the packets with the correct CRC's. I also see now the error with the 6 bits in the third byte from the end. However, I made a check and this 3rd from last byte is always 0 in the test files I'm using so this is not an issue. The problem that I'm having is that I run the file through the utility, which should produce a good stream except for the CRC on the frames I patch. Then, I run this fixed ac3 through the program again. What I should see is that all the patched frames are converted to silent frames as the CRCs will be wrong. A bug, yes, but at least it is expected. However, what I get is that every frame patched in the first run is patched again in the second run. This leads me to believe that the frame header, specifically the bitrate field is not being properly patched. The odd thing, though, is that if I print out the values of the bitrate field and the max bitrate in the stream they are identical (ie: they were patched properly). The patch function, however, is still being called. Updating the values of the AC3FrameInfo struct is not enough in patching as these values are not rewritten to the output, they are just used for reference in the program.

I also see that in the code I pasted above there is no patching of the bitrate field. Below is the updated code that fixes some of the bugs I had found after the last post.


int patchFrame(AC3FrameInfo fi, unsigned char *frame, AC3FrameInfo newFrame) {
char temp[3];
int end;
int i;
unsigned int crc_inv;

if(fi.auxdataE != 0)
return -1;
else {
printf("Patching Frame %d\n", fi.bitrate);
temp[0] = frame[(fi.size*2)-3];
temp[1] = frame[(fi.size*2)-2];
temp[2] = frame[(fi.size*2)-1];

end = newFrame.size *= 2;
end -= 3;
for(i = ((fi.size * 2) - 3); i <= end; i ++)
frame[i] = 0x00;

frame[4] = newFrame.byteThree;
printf("\n%d %d\n\n", newFrame.byteThree,frame[4]);
frame[i] = temp[0];
frame[i+1] = temp[1];
frame[i+2] = temp[2];

fi.size = newFrame.size;
fi.bitrate = newFrame.bitrate;

fi.actual_crc1 = ac3_crc(frame + 4, 2 * crc1_sizes[fi.samplerate + (2*fi.bitrate & 0x01)][fi.bitrate >> 1] - 4, 0);
crc_inv = pow_poly((CRC16_POLY >> 1), (16 * crc1_sizes[fi.samplerate + (2*fi.bitrate & 0x01)][fi.bitrate >> 1]) - 16, CRC16_POLY);
fi.actual_crc1 = mul_poly(crc_inv, fi.actual_crc1, CRC16_POLY);
fi.actual_crc2 = ac3_crc(frame + (2 * crc1_sizes[fi.samplerate + (2*fi.bitrate & 0x01)][fi.bitrate >> 1]), ((bitrates[fi.samplerate+1][(fi.bitrate >> 1)] + (fi.bitrate & 0x01)) - crc1_sizes[fi.samplerate + (2*fi.bitrate & 0x01)][fi.bitrate >> 1]) * 2 - 2, 0);

return 0;
}

return 0;
}


and the updated AC3FrameInfo struct:


typedef struct ac3FrameInfo {
unsigned char samplerate;
unsigned char bitrate;
unsigned int crc1;
unsigned int crc2;
unsigned int actual_crc1;
unsigned int actual_crc2;
unsigned long startByte;
unsigned long size;
unsigned short auxdataE;
unsigned char byteThree;
} AC3FrameInfo;