cosmopolitan/dsp/mpeg/macroblock.c

172 lines
6.6 KiB
C

/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
│ Dominic Szablewski - https://phoboslab.org │
│ │
│ The MIT License(MIT) │
│ Copyright(c) 2019 Dominic Szablewski │
│ │
│ Permission is hereby granted, free of charge, to any person obtaining │
│ a copy of this software and associated documentation files(the │
│ "Software"), to deal in the Software without restriction, including │
│ without limitation the rights to use, copy, modify, merge, publish, │
│ distribute, sublicense, and / or sell copies of the Software, and to │
│ permit persons to whom the Software is furnished to do so, subject to │
│ the following conditions: │
│ │
│ The above copyright notice and this permission notice shall be │
│ included in all copies or substantial portions of the Software. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND │
│ NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE │
│ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN │
│ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN │
│ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE │
│ SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "dsp/mpeg/mpeg.h"
#include "dsp/mpeg/video.h"
#include "libc/log/check.h"
forceinline void plm_video_process_macroblock(plm_video_t *self,
uint8_t *restrict d,
uint8_t *restrict s, int motion_h,
int motion_v, bool interpolate,
unsigned BW) {
unsigned si, di, max_address;
int y, x, dest_scan, source_scan, dw, hp, vp, odd_h, odd_v;
dw = self->mb_width * BW;
hp = motion_h >> 1;
vp = motion_v >> 1;
odd_h = (motion_h & 1) == 1;
odd_v = (motion_v & 1) == 1;
si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
di = (self->mb_row * dw + self->mb_col) * BW;
max_address = (dw * (self->mb_height * BW - BW + 1) - BW);
if (si > max_address || di > max_address) return;
d += di;
s += si;
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {
case 0:
dest_scan = dw - BW;
source_scan = dw - BW;
for (y = 0; y < BW; y++) {
for (x = 0; x < BW; x++) {
*d++ = *s++;
}
s += source_scan;
d += dest_scan;
}
break;
case 1:
dest_scan = dw - BW;
source_scan = dw - BW;
for (y = 0; y < BW; y++) {
for (x = 0; x < BW; x++) {
*d++ = (s[0] + s[dw] + 1) >> 1;
s++;
}
s += source_scan;
d += dest_scan;
}
break;
case 2:
dest_scan = dw - BW;
source_scan = dw - BW;
for (y = 0; y < BW; y++) {
for (x = 0; x < BW; x++) {
*d++ = (s[0] + s[1] + 1) >> 1;
s++;
}
s += source_scan;
d += dest_scan;
}
break;
case 3:
dest_scan = dw - BW;
source_scan = dw - BW;
for (y = 0; y < BW; y++) {
for (x = 0; x < BW; x++) {
*d++ = (s[0] + s[1] + s[dw] + s[dw + 1] + 2) >> 2;
s++;
}
s += source_scan;
d += dest_scan;
}
break;
case 4:
dest_scan = dw - BW;
source_scan = dw - BW;
for (y = 0; y < BW; y++) {
for (x = 0; x < BW; x++) {
d[0] = (d[0] + (s[0]) + 1) >> 1;
d++;
s++;
}
s += source_scan;
d += dest_scan;
}
break;
case 5:
dest_scan = dw - BW;
source_scan = dw - BW;
for (y = 0; y < BW; y++) {
for (x = 0; x < BW; x++) {
d[0] = (d[0] + ((s[0] + s[dw] + 1) >> 1) + 1) >> 1;
d++;
s++;
}
s += source_scan;
d += dest_scan;
}
break;
case 6:
dest_scan = dw - BW;
source_scan = dw - BW;
for (y = 0; y < BW; y++) {
for (x = 0; x < BW; x++) {
d[0] = (d[0] + ((s[0] + s[1] + 1) >> 1) + 1) >> 1;
d++;
s++;
}
s += source_scan;
d += dest_scan;
}
break;
case 7:
dest_scan = dw - BW;
source_scan = dw - BW;
for (y = 0; y < BW; y++) {
for (x = 0; x < BW; x++) {
d[0] = (d[0] + ((s[0] + s[1] + s[dw] + s[dw + 1] + 2) >> 2) + 1) >> 1;
d++;
s++;
}
s += source_scan;
d += dest_scan;
}
break;
default:
break;
}
}
void plm_video_process_macroblock_8(plm_video_t *self, uint8_t *restrict d,
uint8_t *restrict s, int motion_h,
int motion_v, bool interpolate) {
DCHECK_ALIGNED(8, d);
DCHECK_ALIGNED(8, s);
plm_video_process_macroblock(self, d, s, motion_h, motion_v, interpolate, 8);
}
void plm_video_process_macroblock_16(plm_video_t *self, uint8_t *restrict d,
uint8_t *restrict s, int motion_h,
int motion_v, bool interpolate) {
DCHECK_ALIGNED(16, d);
DCHECK_ALIGNED(16, s);
plm_video_process_macroblock(self, d, s, motion_h, motion_v, interpolate, 16);
}