mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 10:40:34 +00:00
1cf3cae5e1
Add an element that converts AYUV video frames to a DVB subpicture stream. It's fairly simple for now. Later it would be good to support input via a stream that contains only GstVideoOverlayComposition meta. The element searches each input video frame for the largest sub-region containing non-transparent pixels and encodes that as a single DVB subpicture region. It can also do palette reduction of the input frames using code taken from libimagequant. There are various FIXME for potential improvements for now, but it works. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1227>
131 lines
3.3 KiB
C
131 lines
3.3 KiB
C
|
|
#include "libimagequant.h"
|
|
#include "pam.h"
|
|
#include "blur.h"
|
|
|
|
/*
|
|
Blurs image horizontally (width 2*size+1) and writes it transposed to dst (called twice gives 2d blur)
|
|
*/
|
|
static void
|
|
transposing_1d_blur (unsigned char *restrict src, unsigned char *restrict dst,
|
|
unsigned int width, unsigned int height, const unsigned int size)
|
|
{
|
|
for (unsigned int j = 0; j < height; j++) {
|
|
unsigned char *restrict row = src + j * width;
|
|
|
|
// accumulate sum for pixels outside line
|
|
unsigned int sum;
|
|
sum = row[0] * size;
|
|
for (unsigned int i = 0; i < size; i++) {
|
|
sum += row[i];
|
|
}
|
|
|
|
// blur with left side outside line
|
|
for (unsigned int i = 0; i < size; i++) {
|
|
sum -= row[0];
|
|
sum += row[i + size];
|
|
|
|
dst[i * height + j] = sum / (size * 2);
|
|
}
|
|
|
|
for (unsigned int i = size; i < width - size; i++) {
|
|
sum -= row[i - size];
|
|
sum += row[i + size];
|
|
|
|
dst[i * height + j] = sum / (size * 2);
|
|
}
|
|
|
|
// blur with right side outside line
|
|
for (unsigned int i = width - size; i < width; i++) {
|
|
sum -= row[i - size];
|
|
sum += row[width - 1];
|
|
|
|
dst[i * height + j] = sum / (size * 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Picks maximum of neighboring pixels (blur + lighten)
|
|
*/
|
|
LIQ_PRIVATE void
|
|
liq_max3 (unsigned char *src, unsigned char *dst, unsigned int width,
|
|
unsigned int height)
|
|
{
|
|
unsigned int i, j;
|
|
|
|
for (j = 0; j < height; j++) {
|
|
const unsigned char *row = src + j * width;
|
|
unsigned char t1, t2;
|
|
unsigned char prev, curr, next;
|
|
|
|
const unsigned char *prevrow = src + (j > 1 ? j - 1 : 0) * width;
|
|
const unsigned char *nextrow = src + MIN (height - 1, j + 1) * width;
|
|
|
|
curr = row[0];
|
|
next = row[0];
|
|
|
|
for (i = 0; i < width - 1; i++) {
|
|
prev = curr;
|
|
curr = next;
|
|
next = row[i + 1];
|
|
|
|
t1 = MAX (prev, next);
|
|
t2 = MAX (nextrow[i], prevrow[i]);
|
|
*dst++ = MAX (curr, MAX (t1, t2));
|
|
}
|
|
|
|
t1 = MAX (curr, next);
|
|
t2 = MAX (nextrow[width - 1], prevrow[width - 1]);
|
|
*dst++ = MAX (t1, t2);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Picks minimum of neighboring pixels (blur + darken)
|
|
*/
|
|
LIQ_PRIVATE void
|
|
liq_min3 (unsigned char *src, unsigned char *dst, unsigned int width,
|
|
unsigned int height)
|
|
{
|
|
unsigned int j;
|
|
|
|
for (j = 0; j < height; j++) {
|
|
unsigned char t1, t2;
|
|
const unsigned char *row = src + j * width,
|
|
*prevrow = src + (j > 1 ? j - 1 : 0) * width,
|
|
*nextrow = src + MIN (height - 1, j + 1) * width;
|
|
|
|
unsigned char prev, curr = row[0], next = row[0];
|
|
|
|
for (unsigned int i = 0; i < width - 1; i++) {
|
|
prev = curr;
|
|
curr = next;
|
|
next = row[i + 1];
|
|
|
|
t1 = MIN (prev, next);
|
|
t2 = MIN (nextrow[i], prevrow[i]);
|
|
*dst++ = MIN (curr, MIN (t1, t2));
|
|
}
|
|
|
|
t1 = MIN (curr, next);
|
|
t2 = MIN (nextrow[width - 1], prevrow[width - 1]);
|
|
*dst++ = MIN (t1, t2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Filters src image and saves it to dst, overwriting tmp in the process.
|
|
Image must be width*height pixels high. Size controls radius of box blur.
|
|
*/
|
|
LIQ_PRIVATE void
|
|
liq_blur (unsigned char *src, unsigned char *tmp, unsigned char *dst,
|
|
unsigned int width, unsigned int height, unsigned int size)
|
|
{
|
|
assert (size > 0);
|
|
if (width < 2 * size + 1 || height < 2 * size + 1) {
|
|
return;
|
|
}
|
|
transposing_1d_blur (src, tmp, width, height, size);
|
|
transposing_1d_blur (tmp, dst, height, width, size);
|
|
}
|