📄 misc.cpp
字号:
class StackHorizontal : public VideoFilterWithRefcount {
const PVideoFilter child1, child2;
VideoInfo vi1, vi2;
unsigned char *mybuffer1, *mybuffer2;
public:
StackHorizontal(PVideoFilter _child1, PVideoFilter _child2) : child1(_child1), child2(_child2), mybuffer1(0), mybuffer2(0) {
child1->GetVideoInfo(&vi1);
child2->GetVideoInfo(&vi2);
if (vi1.height != vi2.height)
throw FilterChainError("StackHorizontal: image heights don't match");
if (vi1.pixel_type != vi2.pixel_type)
throw FilterChainError("StackHorizontal: image formats don't match");
}
void GetFrame(int n, unsigned char* buf) {
if (!mybuffer1) {
mybuffer1 = new unsigned char[vi1.ImageSize()];
mybuffer2 = new unsigned char[vi2.ImageSize()];
}
child1->GetFrame(n, mybuffer1);
child2->GetFrame(n, mybuffer2);
int row_size_1 = vi1.RowSize(), row_size_2 = vi2.RowSize();
int row_size = row_size_1 + row_size_2;
for (int y=0; y<vi1.height; ++y) {
memcpy(buf+y*row_size, mybuffer1+y*row_size_1, row_size_1);
memcpy(buf+y*row_size+row_size_1, mybuffer2+y*row_size_2, row_size_2);
}
}
void GetAudio(void* buf, int start, int count) { child1->GetAudio(buf, start, count); }
void GetVideoInfo(VideoInfo* pvi) {
*pvi = vi1;
pvi->width += vi2.width;
pvi->num_frames = max(pvi->num_frames, vi2.num_frames);
pvi->num_audio_samples = max(pvi->num_audio_samples, vi2.num_audio_samples);
}
bool GetParity(int n) { return child1->GetParity(n); }
~StackHorizontal() {
if (mybuffer1) delete[] mybuffer1;
if (mybuffer2) delete[] mybuffer2;
}
static PVideoFilter __cdecl Create(const FilterInfo* self, const Arg* args, const char* arg_types) {
if (arg_types[1])
return new StackHorizontal(args[0].clip, Create(self, args+1, arg_types+1));
else
return args[0].clip;
}
};
/********************************************************************
********************************************************************/
class ShowFiveVersions : public VideoFilterWithRefcount {
PVideoFilter child[5];
VideoInfo vi;
unsigned char* mybuffer;
public:
ShowFiveVersions(PVideoFilter* children) {
mybuffer = 0;
for (int b=0; b<5; ++b)
child[b] = children[b];
child[0]->GetVideoInfo(&vi);
// if any of the VideoInfo structs from the children differ, fail
for (int c=1; c<5; ++c) {
VideoInfo viprime;
child[c]->GetVideoInfo(&viprime);
vi.num_frames = viprime.num_frames = max(vi.num_frames, viprime.num_frames);
if (memcmp(&vi, &viprime, sizeof(VideoInfo)))
throw FilterChainError("ShowFiveVersions: video attributes of all streams must be identical");
}
}
void GetFrame(int n, unsigned char* buf) {
if (!mybuffer)
mybuffer = new unsigned char[vi.ImageSize()];
int src_row_size = vi.RowSize();
int dst_row_size = src_row_size * 3;
for (int c=0; c<5; ++c) {
int dst_base = ((c&1)^vi.IsRGB()) * (vi.height * dst_row_size)
+ c * (src_row_size >> 1); // staggered arrangement
if (dst_base & 3) dst_base += 2;
child[c]->GetFrame(n, mybuffer);
for (int y=0; y<vi.height; ++y)
memcpy(buf+dst_base+y*dst_row_size, mybuffer+y*src_row_size, src_row_size);
}
}
void GetAudio(void* buf, int start, int count) { child[0]->GetAudio(buf, start, count); }
void GetVideoInfo(VideoInfo* pvi) {
*pvi = vi;
pvi->width *= 3;
pvi->height *= 2;
}
bool GetParity(int n) { return child[0]->GetParity(n); }
static PVideoFilter __cdecl Create(const FilterInfo* self, const Arg* args, const char*) {
PVideoFilter children[5];
for (int i=0; i<5; ++i)
children[i] = args[i].clip;
return new ShowFiveVersions(children);
}
};
/********************************************************************
********************************************************************/
class Animate : public VideoFilterWithRefcount {
enum { cache_size = 3 };
PVideoFilter cache[cache_size];
int cache_stage[cache_size];
const int first, last;
Arg *args_before, *args_after, *args_now;
char arg_types[64];
int num_args;
FilterInfo* filter_info;
public:
Animate(int _first, int _last, const char* name, const Arg* _args, const char* _arg_types)
: first(_first), last(_last)
{
if (first >= last)
throw FilterChainError("Animate: final frame number must be greater than initial");
int len = strlen(_arg_types);
num_args = len >> 1;
if ((len & 1) || memcmp(_arg_types, _arg_types+num_args, num_args))
throw FilterChainError("Animate: must have two identical argument lists");
extern FilterInfo* SearchForMatchingFilter(const char* search_name, const char* arg_types);
filter_info = SearchForMatchingFilter(name, _arg_types + num_args);
if (!filter_info)
throw FilterChainError("Animate: no appropriate filter found");
strcpy(arg_types, _arg_types+num_args);
args_before = new Arg[num_args*3];
for (int a=0; a<num_args*2; ++a)
args_before[a] = _args[a];
args_after = args_before + num_args;
args_now = args_after + num_args;
// promote int->float, save strings, and check for unanimatible arguments
for (int i=0; filter_info->param_types[i]; ++i) {
if (filter_info->param_types[i] == 'f' && arg_types[i] == 'i') {
arg_types[i] = 'f';
args_before[i].floating_pt = float(args_before[i].integer);
args_after[i].floating_pt = float(args_after[i].integer);
}
else if (arg_types[i] == 's') {
if (strcmp(args_before[i].string, args_after[i].string))
throw FilterChainError("Animate: string arguments must match before and after");
args_after[i].string = args_before[i].string = MyStrdup(args_before[i].string);
}
}
memset(cache_stage, -1, sizeof(cache_stage));
cache[0] = filter_info->pFilterFactoryFunction(filter_info, args_before, arg_types);
cache_stage[0] = 0;
cache[1] = filter_info->pFilterFactoryFunction(filter_info, args_after, arg_types);
cache_stage[1] = last-first;
VideoInfo vi1, vi2;
cache[0]->GetVideoInfo(&vi1);
cache[1]->GetVideoInfo(&vi2);
if (vi1.width != vi2.width || vi1.height != vi2.height)
throw FilterChainError("Animate: initial and final video frame sizes must match");
}
void GetFrame(int n, unsigned char* buf) {
int stage = min(max(n, first), last) - first;
for (int i=0; i<cache_size; ++i)
if (cache_stage[i] == stage) {
cache[i]->GetFrame(n, buf);
return;
}
// filter not found in cache--create it
int furthest = 0;
for (int j=1; j<cache_size; ++j)
if (abs(stage-cache_stage[j]) > abs(stage-cache_stage[furthest]))
furthest = j;
int scale = last-first;
for (int a=0; a<num_args; ++a) {
switch (arg_types[a]) {
case 'i':
args_now[a].integer = int(((double)args_before[a].integer*(scale-stage) + (double)args_after[a].integer*stage) / scale + 0.5);
break;
case 'f':
args_now[a].floating_pt = float(((double)args_before[a].floating_pt*(scale-stage) + (double)args_after[a].floating_pt*stage) / scale);
break;
case 's':
args_now[a].string = args_before[a].string;
case 'c':
args_now[a].clip = args_before[a].clip;
}
}
cache_stage[furthest] = stage;
cache[furthest] = filter_info->pFilterFactoryFunction(filter_info, args_now, arg_types);
cache[furthest]->GetFrame(n, buf);
}
void GetAudio(void* buf, int start, int count) {
// this could be implemented better...
cache[0]->GetAudio(buf, start, count);
}
void GetVideoInfo(VideoInfo* pvi) {
cache[0]->GetVideoInfo(pvi);
}
bool GetParity(int n) { return cache[0]->GetParity(n); }
~Animate() {
for (int i=0; i<num_args; ++i)
if (arg_types[i] == 's')
delete[] const_cast<char*>(args_before[i].string);
delete[] args_before;
}
static PVideoFilter __cdecl Create(const FilterInfo*, const Arg* args, const char* arg_types) {
return new Animate(args[0].integer, args[1].integer, args[2].string, args+3, arg_types+3);
}
};
/********************************************************************
********************************************************************/
FilterInfo misc_filters[] = {
{ "ConvertToRGB", "c", ConvertToRGB::Create },
{ "ConvertToYUY2", "c", ConvertToYUY2::Create },
{ "Subtract", "cc", Subtract::Create },
{ "StackVertical", "cc+", StackVertical::Create },
{ "StackHorizontal", "cc+", StackHorizontal::Create },
{ "ShowFiveVersions", "ccccc", ShowFiveVersions::Create },
{ "Animate", "iis*", Animate::Create },
{ 0,0,0 }
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -