Some streaming sites, in particular YouTube, don't support frame rates much larger than 30 fps. As such, they do a poor job of displaying 30Hz flicker effects present in games such as Super Metroid and the Mega Man X series.
To combat this, creaothceann proposed some frame blending techniques. The best-received of these has been one which combines pairs of frames in a 33%/67% ratio, with which frame in a pair being more visible alternating for every pair (thus, 33%/67% for one pair, 67%/33% for the following pair, and so on). This technique has come to be known as TASBlend.
Some implementations of TASBlend follow.
``````function TASBlend(clip c, float "ratio")  {
# reduces framerate to 1/2 but leaves flicker effects partly visible
# blends frame pairs with alternating opacity (default is 2/3+1/3;1/3+2/3)
# optional "ratio" is the opacity of the first frame out of the four
ratio    = default(ratio, 2.0 / 3)
opacity1 = round((1 - ratio) * 257)
opacity2 = round((    ratio) * 257)
c
Interleave(Layer(SelectEvery(4, 0), SelectEvery(4, 1), level=opacity1),
\          Layer(SelectEvery(4, 2), SelectEvery(4, 3), level=opacity2))
}
``````
If only certain segments of the clip are to be blended, creaothceann suggests using this in the following fashion:
``````function Replace(clip c, int i, int j, clip d)  {
Assert(i >= 0, "Replace: parameter i is negative")
Assert(j >= 0, "Replace: parameter j is negative")
p1 = c.Trim(0    , -i)
p2 = d.Trim(i    ,  j)
p3 = c.Trim(j + 1,  0)
p1 = (i == 0)  ?  c.Trim(0, -1).DeleteFrame(0)  :  p1
p3 = (j == 0)  ?  c.Trim(0, -1).DeleteFrame(0)  :  p3
p1 + p2 + p3
return (c.HasAudio)  ?  last.AudioDub(c)  :  last
}

AVISource("video.avi")

blended = TASBlend
ChangeFPS(FrameRate / 2)

Replace(  500,   999, blended)
Replace( 2000,  2999, blended)
Replace(70000, 71999, blended)
...
``````
sgrunt has written the following filter in the spirit of his duplicate frame filter, which accepts raw RGB24 frames on `stdin` and outputs blended/unblended frames at half the framerate on `stdout`.
Usage is:
```tasblend <width> <height>　<startframe> <endframe> [<startframe> <endframe> [...] ]
```
where
• `<width>` and `<height>` are the height of a frame; and
• each pair of `<startframe>` and `<endframe>` signifies frame ranges from the input to be blended - to blend an entire clip, set `<startframe>` to 0 and `<endframe>` to a value larger than the number of frames in the clip.
This has not been tested thoroughly, so use at your own risk (and report bugs to sgrunt).
A version that has gamma correction is available at http://engelsish.org/tasblend-lookup.c
``````#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv)
{
unsigned char *firstframe, *secondframe, *outframe;
unsigned int width = 0, height = 0, framesize = 0, curarg = 3;
unsigned long startframe = 0, endframe = 0, curframe = 0, i = 0;
unsigned short first33 = 1;
FILE* outfile = 0;
if (argc < 5)
{
fprintf(stderr, "usage: tasblend <width> <height> <startframe> <endframe> [<startframe> <endframe> [...]]\n");
exit(1);
}
width = atoi(argv);
height = atoi(argv);
startframe = atoi(argv);
endframe = atoi(argv);
framesize = width*height*3;
firstframe = (unsigned char *)malloc(sizeof(unsigned char)*framesize);
if (!firstframe)
{
perror("Couldn't malloc firstframe");
exit(2);
}
secondframe = (unsigned char *)malloc(sizeof(unsigned char)*framesize);
if (!secondframe)
{
perror("Couldn't malloc secondframe");
free(firstframe);
exit(3);
}
outframe = (unsigned char *)malloc(sizeof(unsigned char)*framesize);
if (!outframe)
{
perror("Couldn't malloc outframe");
free(firstframe);
free(secondframe);
exit(4);
}
while (!feof(stdin))
{
if (fread(firstframe, sizeof(unsigned char), framesize, stdin) < framesize)
break;
if (fread(secondframe, sizeof(unsigned char), framesize, stdin) < framesize)
{
fwrite(firstframe, sizeof(unsigned char), framesize, stdout);
break;
}
if (curframe >= startframe && curframe < endframe)
{
if (first33 > 0)
{
for (i = 0; i < framesize; i++)
outframe[i] = (firstframe[i] * 33 + secondframe[i] * 67) / 100;
}
else
{
for (i = 0; i < framesize; i++)
outframe[i] = (firstframe[i] * 67 + secondframe[i] * 33) / 100;
}
fwrite(outframe, sizeof(unsigned char), framesize, stdout);
first33 = (first33 > 0) ? 0 : 1;
}
else
{
if (curframe >= endframe && curarg+1 < argc)
{
curarg += 2;
if (curarg+1 < argc)
{
first33 = 1;
startframe = atoi(argv[curarg]);
endframe = atoi(argv[curarg+1]);
}
}
fwrite(firstframe, sizeof(unsigned char), framesize, stdout);
}
curframe += 2;
}
free(firstframe);
free(secondframe);
free(outframe);
return 0;
}
``````

EncodingGuide/Legacy/TASBlend last edited by adelikat on 8/7/2022 8:16 PM