stereo decorrelation support by (Justin Ruggles jruggle earthlink net>)

Originally committed as revision 5528 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Michael Niedermayer 2006-06-26 06:00:07 +00:00
parent 6c35b4dee3
commit f33aa12011
3 changed files with 112 additions and 28 deletions

View File

@ -177,7 +177,12 @@ static int flac_encode_init(AVCodecContext *avctx)
s->blocksize = select_blocksize(s->samplerate);
avctx->frame_size = s->blocksize;
s->max_framesize = 14 + (s->blocksize * s->channels * 2);
/* set maximum encoded frame size in verbatim mode */
if(s->channels == 2) {
s->max_framesize = 14 + ((s->blocksize * 33 + 7) >> 3);
} else {
s->max_framesize = 14 + (s->blocksize * s->channels * 2);
}
streaminfo = av_malloc(FLAC_STREAMINFO_SIZE);
write_streaminfo(s, streaminfo);
@ -192,7 +197,7 @@ static int flac_encode_init(AVCodecContext *avctx)
return 0;
}
static int init_frame(FlacEncodeContext *s)
static void init_frame(FlacEncodeContext *s)
{
int i, ch;
FlacFrame *frame;
@ -221,13 +226,6 @@ static int init_frame(FlacEncodeContext *s)
for(ch=0; ch<s->channels; ch++) {
frame->subframes[ch].obits = 16;
}
if(s->channels == 2) {
frame->ch_mode = FLAC_CHMODE_LEFT_RIGHT;
} else {
frame->ch_mode = FLAC_CHMODE_NOT_STEREO;
}
return 0;
}
/**
@ -246,6 +244,94 @@ static void copy_samples(FlacEncodeContext *s, int16_t *samples)
}
}
static int estimate_stereo_mode(int32_t *left_ch, int32_t *right_ch, int n)
{
int i, best;
int32_t lt, rt;
uint64_t left, right, mid, side;
uint64_t score[4];
/* calculate sum of squares for each channel */
left = right = mid = side = 0;
for(i=2; i<n; i++) {
lt = left_ch[i] - 2*left_ch[i-1] + left_ch[i-2];
rt = right_ch[i] - 2*right_ch[i-1] + right_ch[i-2];
mid += ABS((lt + rt) >> 1);
side += ABS(lt - rt);
left += ABS(lt);
right += ABS(rt);
}
/* calculate score for each mode */
score[0] = left + right;
score[1] = left + side;
score[2] = right + side;
score[3] = mid + side;
/* return mode with lowest score */
best = 0;
for(i=1; i<4; i++) {
if(score[i] < score[best]) {
best = i;
}
}
if(best == 0) {
return FLAC_CHMODE_LEFT_RIGHT;
} else if(best == 1) {
return FLAC_CHMODE_LEFT_SIDE;
} else if(best == 2) {
return FLAC_CHMODE_RIGHT_SIDE;
} else {
return FLAC_CHMODE_MID_SIDE;
}
}
/**
* Perform stereo channel decorrelation
*/
static void channel_decorrelation(FlacEncodeContext *ctx)
{
FlacFrame *frame;
int32_t *left, *right;
int i, n;
frame = &ctx->frame;
n = frame->blocksize;
left = frame->subframes[0].samples;
right = frame->subframes[1].samples;
if(ctx->channels != 2) {
frame->ch_mode = FLAC_CHMODE_NOT_STEREO;
return;
}
frame->ch_mode = estimate_stereo_mode(left, right, n);
/* perform decorrelation and adjust bits-per-sample */
if(frame->ch_mode == FLAC_CHMODE_LEFT_RIGHT) {
return;
}
if(frame->ch_mode == FLAC_CHMODE_MID_SIDE) {
int32_t tmp;
for(i=0; i<n; i++) {
tmp = left[i];
left[i] = (tmp + right[i]) >> 1;
right[i] = tmp - right[i];
}
frame->subframes[1].obits++;
} else if(frame->ch_mode == FLAC_CHMODE_LEFT_SIDE) {
for(i=0; i<n; i++) {
right[i] = left[i] - right[i];
}
frame->subframes[1].obits++;
} else {
for(i=0; i<n; i++) {
left[i] -= right[i];
}
frame->subframes[0].obits++;
}
}
static void encode_residual_verbatim(FlacEncodeContext *s, int ch)
{
FlacFrame *frame;
@ -359,19 +445,15 @@ output_frame_header(FlacEncodeContext *s)
put_bits(&s->pb, 3, 4); /* bits-per-sample code */
put_bits(&s->pb, 1, 0);
write_utf8(&s->pb, s->frame_count);
if(frame->bs_code[1] > 0) {
if(frame->bs_code[1] < 256) {
put_bits(&s->pb, 8, frame->bs_code[1]);
} else {
put_bits(&s->pb, 16, frame->bs_code[1]);
}
if(frame->bs_code[0] == 6) {
put_bits(&s->pb, 8, frame->bs_code[1]);
} else if(frame->bs_code[0] == 7) {
put_bits(&s->pb, 16, frame->bs_code[1]);
}
if(s->sr_code[1] > 0) {
if(s->sr_code[1] < 256) {
put_bits(&s->pb, 8, s->sr_code[1]);
} else {
put_bits(&s->pb, 16, s->sr_code[1]);
}
if(s->sr_code[0] == 12) {
put_bits(&s->pb, 8, s->sr_code[1]);
} else if(s->sr_code[0] > 12) {
put_bits(&s->pb, 16, s->sr_code[1]);
}
flush_put_bits(&s->pb);
crc = av_crc(av_crc07, 0, s->pb.buf, put_bits_count(&s->pb)>>3);
@ -493,12 +575,12 @@ static int flac_encode_frame(AVCodecContext *avctx, uint8_t *frame,
s = avctx->priv_data;
s->blocksize = avctx->frame_size;
if(init_frame(s)) {
return 0;
}
init_frame(s);
copy_samples(s, samples);
channel_decorrelation(s);
for(ch=0; ch<s->channels; ch++) {
encode_residual(s, ch);
}
@ -532,6 +614,8 @@ static int flac_encode_frame(AVCodecContext *avctx, uint8_t *frame,
static int flac_encode_close(AVCodecContext *avctx)
{
av_freep(&avctx->extradata);
avctx->extradata_size = 0;
av_freep(&avctx->coded_frame);
return 0;
}

View File

@ -176,7 +176,7 @@ stddev:1050.18 PSNR:35.89 bytes:1054720
264236 ./data/a-adpcm_yam.wav
e92cec8c07913ffb91ad2b11f79cdc00 *./data/out.wav
stddev:18312.68 PSNR:11.06 bytes:1056768
7bcc7daf968fc489c9b4b7aca5ae380d *./data/a-flac.flac
799336 ./data/a-flac.flac
9ed4957501a56ce9d4e6a6611553a45f *./data/a-flac.flac
801577 ./data/a-flac.flac
0116cdcefd0aeae3ab8e5140c19c725d *./data/out.wav
stddev: 51.59 PSNR:62.07 bytes:1032192

View File

@ -176,7 +176,7 @@ stddev:1050.18 PSNR:35.89 bytes:1054720
264236 ./data/a-adpcm_yam.wav
e92cec8c07913ffb91ad2b11f79cdc00 *./data/out.wav
stddev:18312.68 PSNR:11.06 bytes:1056768
7bcc7daf968fc489c9b4b7aca5ae380d *./data/a-flac.flac
799336 ./data/a-flac.flac
9ed4957501a56ce9d4e6a6611553a45f *./data/a-flac.flac
801577 ./data/a-flac.flac
0116cdcefd0aeae3ab8e5140c19c725d *./data/out.wav
stddev: 51.59 PSNR:62.07 bytes:1032192