Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.0 / plugins / interpolatevideo / interpolatevideo.C
diff --git a/cinelerra-5.0/plugins/interpolatevideo/interpolatevideo.C b/cinelerra-5.0/plugins/interpolatevideo/interpolatevideo.C
deleted file mode 100644 (file)
index c70d6ad..0000000
+++ /dev/null
@@ -1,1005 +0,0 @@
-/*
- * CINELERRA
- * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- * 
- */
-
-#include "bcsignals.h"
-#include "clip.h"
-#include "filexml.h"
-#include "interpolatevideo.h"
-#include "interpolatewindow.h"
-#include "language.h"
-#include "motionscan.h"
-#include "opticflow.h"
-#include "transportque.inc"
-#include <unistd.h>
-
-
-
-
-
-
-
-
-
-InterpolateVideoConfig::InterpolateVideoConfig()
-{
-       input_rate = (double)30000 / 1001;
-       use_keyframes = 0;
-       optic_flow = 1;
-       draw_vectors = 1;
-       search_radius = 16;
-       macroblock_size = 16;
-}
-
-void InterpolateVideoConfig::copy_from(InterpolateVideoConfig *config)
-{
-       this->input_rate = config->input_rate;
-       this->use_keyframes = config->use_keyframes;
-       this->optic_flow = config->optic_flow;
-       this->draw_vectors = config->draw_vectors;
-       this->search_radius = config->search_radius;
-       this->macroblock_size = config->macroblock_size;
-}
-
-int InterpolateVideoConfig::equivalent(InterpolateVideoConfig *config)
-{
-       return EQUIV(this->input_rate, config->input_rate) &&
-               (this->use_keyframes == config->use_keyframes) &&
-               this->optic_flow == config->optic_flow &&
-               this->draw_vectors == config->draw_vectors &&
-               this->search_radius == config->search_radius &&
-               this->macroblock_size == config->macroblock_size;
-}
-
-
-
-
-
-
-
-
-REGISTER_PLUGIN(InterpolateVideo)
-
-
-
-
-
-
-
-InterpolateVideo::InterpolateVideo(PluginServer *server)
- : PluginVClient(server)
-{
-       optic_flow_engine = 0;
-       warp_engine = 0;
-       blend_engine = 0;
-       bzero(frames, sizeof(VFrame*) * 2);
-       for(int i = 0; i < 2; i++)
-               frame_number[i] = -1;
-       last_position = -1;
-       last_rate = -1;
-       last_macroblock_size = 0;
-       last_search_radius = 0;
-       total_macroblocks = 0;
-}
-
-
-InterpolateVideo::~InterpolateVideo()
-{
-       delete optic_flow_engine;
-       delete warp_engine;
-       delete blend_engine;
-       if(frames[0]) delete frames[0];
-       if(frames[1]) delete frames[1];
-       macroblocks.remove_all_objects();
-}
-
-
-void InterpolateVideo::fill_border(double frame_rate, int64_t start_position)
-{
-// A border frame changed or the start position is not identical to the last 
-// start position.
-
-       int64_t frame_start = range_start + (get_direction() == PLAY_REVERSE ? 1 : 0); 
-       int64_t frame_end = range_end + (get_direction() == PLAY_REVERSE ? 1 : 0); 
-
-       if( last_position == start_position && EQUIV(last_rate, frame_rate) &&
-               frame_number[0] >= 0 && frame_number[0] == frame_start &&
-               frame_number[1] >= 0 && frame_number[1] == frame_end ) return;
-
-       if( frame_start == frame_number[1] || frame_end == frame_number[0] )
-       {
-               int64_t n = frame_number[0];
-               frame_number[0] = frame_number[1];
-               frame_number[1] = n;
-               VFrame *f = frames[0];
-               frames[0] = frames[1];
-               frames[1] = f;
-       }
-
-       if( frame_start != frame_number[0] )
-       {
-//printf("InterpolateVideo::fill_border 1 %lld\n", range_start);
-               read_frame(frames[0], 0, frame_start, active_input_rate, 0);
-               frame_number[0] = frame_start;
-       }
-
-       if( frame_end != frame_number[1] )
-       {
-//printf("InterpolateVideo::fill_border 2 %lld\n", range_start);
-               read_frame(frames[1], 0, frame_end, active_input_rate, 0);
-               frame_number[1] = frame_end;
-       }
-
-       last_position = start_position;
-       last_rate = frame_rate;
-}
-
-
-
-
-
-void InterpolateVideo::draw_pixel(VFrame *frame, int x, int y)
-{
-       if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return;
-
-#define DRAW_PIXEL(x, y, components, do_yuv, max, type) \
-{ \
-       type **rows = (type**)frame->get_rows(); \
-       rows[y][x * components] = max - rows[y][x * components]; \
-       if(!do_yuv) \
-       { \
-               rows[y][x * components + 1] = max - rows[y][x * components + 1]; \
-               rows[y][x * components + 2] = max - rows[y][x * components + 2]; \
-       } \
-       else \
-       { \
-               rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \
-               rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \
-       } \
-       if(components == 4) \
-               rows[y][x * components + 3] = max; \
-}
-
-
-       switch(frame->get_color_model())
-       {
-               case BC_RGB888:
-                       DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char);
-                       break;
-               case BC_RGBA8888:
-                       DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char);
-                       break;
-               case BC_RGB_FLOAT:
-                       DRAW_PIXEL(x, y, 3, 0, 1.0, float);
-                       break;
-               case BC_RGBA_FLOAT:
-                       DRAW_PIXEL(x, y, 4, 0, 1.0, float);
-                       break;
-               case BC_YUV888:
-                       DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char);
-                       break;
-               case BC_YUVA8888:
-                       DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char);
-                       break;
-               case BC_RGB161616:
-                       DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t);
-                       break;
-               case BC_YUV161616:
-                       DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t);
-                       break;
-               case BC_RGBA16161616:
-                       DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t);
-                       break;
-               case BC_YUVA16161616:
-                       DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t);
-                       break;
-       }
-}
-
-
-void InterpolateVideo::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
-{
-       int w = labs(x2 - x1);
-       int h = labs(y2 - y1);
-//printf("InterpolateVideo::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
-
-       if(!w && !h)
-       {
-               draw_pixel(frame, x1, y1);
-       }
-       else
-       if(w > h)
-       {
-// Flip coordinates so x1 < x2
-               if(x2 < x1)
-               {
-                       y2 ^= y1;
-                       y1 ^= y2;
-                       y2 ^= y1;
-                       x1 ^= x2;
-                       x2 ^= x1;
-                       x1 ^= x2;
-               }
-               int numerator = y2 - y1;
-               int denominator = x2 - x1;
-               for(int i = x1; i < x2; i++)
-               {
-                       int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator;
-                       draw_pixel(frame, i, y);
-               }
-       }
-       else
-       {
-// Flip coordinates so y1 < y2
-               if(y2 < y1)
-               {
-                       y2 ^= y1;
-                       y1 ^= y2;
-                       y2 ^= y1;
-                       x1 ^= x2;
-                       x2 ^= x1;
-                       x1 ^= x2;
-               }
-               int numerator = x2 - x1;
-               int denominator = y2 - y1;
-               for(int i = y1; i < y2; i++)
-               {
-                       int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator;
-                       draw_pixel(frame, x, i);
-               }
-       }
-//printf("InterpolateVideo::draw_line 2\n");
-}
-
-#define ARROW_SIZE 10
-void InterpolateVideo::draw_arrow(VFrame *frame, 
-       int x1, 
-       int y1, 
-       int x2, 
-       int y2)
-{
-       double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
-       double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
-       double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
-       int x3;
-       int y3;
-       int x4;
-       int y4;
-       if(x2 < x1)
-       {
-               x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
-               y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
-               x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
-               y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
-       }
-       else
-       {
-               x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
-               y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
-               x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
-               y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
-       }
-
-// Main vector
-       draw_line(frame, x1, y1, x2, y2);
-//     draw_line(frame, x1, y1 + 1, x2, y2 + 1);
-
-// Arrow line
-       if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x3, y3);
-//     draw_line(frame, x2, y2 + 1, x3, y3 + 1);
-// Arrow line
-       if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x4, y4);
-//     draw_line(frame, x2, y2 + 1, x4, y4 + 1);
-}
-
-void InterpolateVideo::draw_rect(VFrame *frame, 
-       int x1, 
-       int y1, 
-       int x2, 
-       int y2)
-{
-       draw_line(frame, x1, y1, x2, y1);
-       draw_line(frame, x2, y1, x2, y2);
-       draw_line(frame, x2, y2, x1, y2);
-       draw_line(frame, x1, y2, x1, y1);
-}
-
-
-void InterpolateVideo::create_macroblocks()
-{
-// Get macroblock size
-       x_macroblocks = frames[0]->get_w() / config.macroblock_size;
-       y_macroblocks = frames[0]->get_h() / config.macroblock_size;
-
-       if(config.macroblock_size * x_macroblocks < frames[0]->get_w())
-       {
-               x_macroblocks++;
-       }
-       
-       if(config.macroblock_size * y_macroblocks < frames[0]->get_h())
-       {
-               y_macroblocks++;
-       }
-       
-       total_macroblocks = x_macroblocks * y_macroblocks;
-
-       if(total_macroblocks != macroblocks.size())
-       {
-               macroblocks.remove_all_objects();
-       }
-
-       for(int i = 0; i < total_macroblocks; i++)
-       {
-               OpticFlowMacroblock *mb = 0;
-               if(macroblocks.size() > i) 
-               {
-                       mb = macroblocks.get(i);
-               }
-               else
-               {
-                       mb = new OpticFlowMacroblock;
-                       macroblocks.append(mb);
-               }
-
-               mb->x = (i % x_macroblocks) * config.macroblock_size + config.macroblock_size / 2;
-               mb->y = (i / x_macroblocks) * config.macroblock_size + config.macroblock_size / 2;
-       }
-}
-
-
-void InterpolateVideo::draw_vectors(int processed)
-{
-// Draw arrows
-       if(config.draw_vectors)
-       {
-               create_macroblocks();
-
-               for(int i = 0; i < total_macroblocks; i++)
-               {
-                       OpticFlowMacroblock *mb = macroblocks.get(i);
-//                 printf("InterpolateVideo::optic_flow %d x=%d y=%d dx=%d dy=%d\n",
-//                         __LINE__,
-//                         mb->x,
-//                         mb->y,
-//                         mb->dx / OVERSAMPLE,
-//                         mb->dy / OVERSAMPLE);
-
-                       if(processed)
-                       {
-                               draw_arrow(get_output(),
-                                       mb->x,
-                                       mb->y,
-                                       mb->x - mb->dx / OVERSAMPLE,
-                                       mb->y - mb->dy / OVERSAMPLE);
-
-// debug
-//                             if(mb->is_valid && mb->visible)
-//                             {
-//                                     draw_arrow(get_output(),
-//                                             mb->x + 1,
-//                                             mb->y + 1,
-//                                             mb->x - mb->dx / OVERSAMPLE + 1,
-//                                             mb->y - mb->dy / OVERSAMPLE + 1);
-//                             }
-                       }
-                       else
-                       {
-                               draw_pixel(get_output(),
-                                       mb->x,
-                                       mb->y);
-                       }
-               }
-               
-// Draw center macroblock
-               OpticFlowMacroblock *mb = macroblocks.get(
-                       x_macroblocks / 2 + y_macroblocks / 2 * x_macroblocks);
-               draw_rect(get_output(),
-                       mb->x - config.macroblock_size / 2,
-                       mb->y - config.macroblock_size / 2,
-                       mb->x + config.macroblock_size / 2,
-                       mb->y + config.macroblock_size / 2);
-               draw_rect(get_output(),
-                       mb->x - config.macroblock_size / 2 - config.search_radius,
-                       mb->y - config.macroblock_size / 2 - config.search_radius,
-                       mb->x + config.macroblock_size / 2 + config.search_radius,
-                       mb->y + config.macroblock_size / 2 + config.search_radius);
-       }
-}
-
-
-int InterpolateVideo::angles_overlap(float dst2_angle1, 
-       float dst2_angle2,
-       float dst1_angle1,
-       float dst1_angle2)
-{
-       if(dst2_angle1 < 0 || dst2_angle2 < 0)
-       {
-               dst2_angle1 += 2 * M_PI;
-               dst2_angle2 += 2 * M_PI;
-       }
-
-       if(dst1_angle1 < 0 || dst1_angle2 < 0)
-       {
-               dst1_angle1 += 2 * M_PI;
-               dst1_angle2 += 2 * M_PI;
-       }
-
-       if(dst1_angle1 < dst2_angle2 && 
-               dst1_angle2 > dst2_angle1) return 1;
-
-       return 0;
-}
-
-
-
-void InterpolateVideo::blend_macroblock(int number)
-{
-       OpticFlowMacroblock *src = macroblocks.get(number);
-       struct timeval start_time;
-       gettimeofday(&start_time, 0);
-//     printf("InterpolateVideo::blend_macroblock %d %d\n",
-//     __LINE__,
-//     src->is_valid);
-
-
-// Copy macroblock table to local thread
-       ArrayList<OpticFlowMacroblock*> local_macroblocks;
-       for(int i = 0; i < macroblocks.size(); i++)
-       {
-               OpticFlowMacroblock *mb = new OpticFlowMacroblock;
-               mb->copy_from(macroblocks.get(i));
-               local_macroblocks.append(mb);
-       }
-
-// Get nearest macroblocks
-       for(int i = 0; i < local_macroblocks.size(); i++)
-       {
-               OpticFlowMacroblock *dst = local_macroblocks.get(i);
-               if(i != number && dst->is_valid)
-               {
-
-// rough estimation of angle coverage
-                       float angle = atan2(dst->y - src->y, dst->x - src->x);
-                       float dist = sqrt(SQR(dst->y - src->y) + SQR(dst->x - src->x));
-                       float span = sin((float)config.macroblock_size / dist);
-                       dst->angle1 = angle - span / 2;
-                       dst->angle2 = angle + span / 2;
-                       dst->dist = dist;
-// All macroblocks start as visible
-                       dst->visible = 1;
-
-// printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d span=%f angle1=%f angle2=%f dist=%f\n", 
-// __LINE__, 
-// i,
-// dst->x, 
-// dst->y, 
-// span * 360 / 2 / M_PI,
-// dst->angle1 * 360 / 2 / M_PI, 
-// dst->angle2 * 360 / 2 / M_PI,
-// dst->dist);
-               }
-       }
-       
-       for(int i = 0; i < local_macroblocks.size(); i++)
-       {
-// Conceil macroblocks which are hidden
-               OpticFlowMacroblock *dst1 = local_macroblocks.get(i);
-               if(i != number && dst1->is_valid && dst1->visible)
-               {
-// Find macroblock which is obstructing
-                       for(int j = 0; j < local_macroblocks.size(); j++)
-                       {
-                               OpticFlowMacroblock *dst2 = local_macroblocks.get(j);
-                               if(j != number && 
-                                       dst2->is_valid && 
-                                       dst2->dist < dst1->dist &&
-                                       angles_overlap(dst2->angle1, 
-                                               dst2->angle2,
-                                               dst1->angle1,
-                                               dst1->angle2))
-                               {
-                                       dst1->visible = 0;
-                                       j = local_macroblocks.size();
-                               }
-                       }
-               }
-       }
-
-// Blend all visible macroblocks
-// Get distance metrics
-       float total = 0;
-       float min = 0;
-       float max = 0;
-       int first = 1;
-       for(int i = 0; i < local_macroblocks.size(); i++)
-       {
-               OpticFlowMacroblock *dst = local_macroblocks.get(i);
-               if(i != number && dst->is_valid && dst->visible)
-               {
-                       total += dst->dist;
-                       if(first)
-                       {
-                               min = max = dst->dist;
-                               first = 0;
-                       }
-                       else
-                       {
-                               min = MIN(dst->dist, min);
-                               max = MAX(dst->dist, max);
-                       }
-// printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n", 
-// __LINE__, 
-// i,
-// dst->x, 
-// dst->y, 
-// dst->dist);
-
-               }
-       }
-
-// Invert distances to convert to weights
-       total = 0;
-       for(int i = 0; i < local_macroblocks.size(); i++)
-       {
-               OpticFlowMacroblock *dst = local_macroblocks.get(i);
-               if(i != number && dst->is_valid && dst->visible)
-               {
-                       dst->dist = max - dst->dist + min;
-                       total += dst->dist;
-// printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n", 
-// __LINE__, 
-// i,
-// dst->x, 
-// dst->y, 
-// max - dst->dist + min);
-
-               }
-       }
-
-// Add weighted vectors
-       float dx = 0;
-       float dy = 0;
-       if(total > 0)
-       {
-               for(int i = 0; i < local_macroblocks.size(); i++)
-               {
-                       OpticFlowMacroblock *dst = local_macroblocks.get(i);
-                       if(i != number && dst->is_valid && dst->visible)
-                       {
-                               dx += dst->dist * dst->dx / total;
-                               dy += dst->dist * dst->dy / total;
-                               src->dx = dx;
-                               src->dy = dy;
-// printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n", 
-// __LINE__, 
-// i,
-// dst->x, 
-// dst->y, 
-// max - dst->dist + min);
-
-                       }
-               }
-       }
-
-       local_macroblocks.remove_all_objects();
-       
-// printf("InterpolateVideo::blend_macroblock %d total=%f\n", 
-// __LINE__, 
-// total);
-       struct timeval end_time;
-       gettimeofday(&end_time, 0);
-//     printf("InterpolateVideo::blend_macroblock %d %d\n",
-//             __LINE__,
-//             end_time.tv_sec * 1000 + end_time.tv_usec / 1000 -
-//             start_time.tv_sec * 1000 - start_time.tv_usec / 1000);
-}
-
-
-
-void InterpolateVideo::optic_flow()
-{
-
-       create_macroblocks();
-       int need_motion = 0;
-
-// New engine
-       if(!optic_flow_engine)
-       {
-               optic_flow_engine = new OpticFlow(this,
-                       PluginClient::get_project_smp() + 1, 
-                       PluginClient::get_project_smp() + 1);
-               need_motion = 1;
-       }
-       else
-// Reuse old vectors
-       if(motion_number[0] == frame_number[0] &&
-               motion_number[1] == frame_number[1] &&
-               last_macroblock_size == config.macroblock_size &&
-               last_search_radius == config.search_radius)
-       {
-               ;
-       }
-       else
-// Calculate new vectors
-       {
-               need_motion = 1;
-       }
-
-       if(need_motion)
-       {
-               optic_flow_engine->set_package_count(MIN(MAX_PACKAGES, total_macroblocks));
-               optic_flow_engine->process_packages();
-
-// Fill in failed macroblocks
-               invalid_blocks.remove_all();
-               for(int i = 0; i < macroblocks.size(); i++)
-               {
-                       if(!macroblocks.get(i)->is_valid 
-// debug
-//                              && i >= 30 * x_macroblocks)
-                               )
-                       {
-                               invalid_blocks.append(i);
-                       }
-               }
-
-               if(invalid_blocks.size())
-               {
-                       if(!blend_engine)
-                       {
-                               blend_engine = new BlendMacroblock(this,
-                                       PluginClient::get_project_smp() + 1, 
-                                       PluginClient::get_project_smp() + 1);
-                       }
-
-                       blend_engine->set_package_count(MIN(PluginClient::get_project_smp() + 1, 
-                               invalid_blocks.size()));
-                       blend_engine->process_packages();
-               }
-       }
-
-
-
-// for(int i = 0; i < total_macroblocks; i++)
-// {
-//     OpticFlowPackage *pkg = (OpticFlowPackage*)optic_flow_engine->get_package(
-//             i);
-//     if((i / x_macroblocks) % 2)
-//     {
-//             pkg->dx = 0;
-//             pkg->dy = 0;
-//     }
-//     else
-//     {
-//             pkg->dx = -32;
-//             pkg->dy = 0;
-//     }
-// }
-
-
-       if(!warp_engine)
-       {
-               warp_engine = new Warp(this,
-                       PluginClient::get_project_smp() + 1, 
-                       PluginClient::get_project_smp() + 1);
-       }
-       
-       warp_engine->process_packages();
-
-       motion_number[0] = frame_number[0];
-       motion_number[1] = frame_number[1];
-       last_macroblock_size = config.macroblock_size;
-       last_search_radius = config.search_radius;
-
-
-// Debug
-//     get_output()->copy_from(frames[1]);
-
-
-       draw_vectors(1);
-}
-
-
-#define AVERAGE(type, temp_type,components, max) \
-{ \
-       temp_type fraction0 = (temp_type)(lowest_fraction * max); \
-       temp_type fraction1 = (temp_type)(max - fraction0); \
- \
-       for(int i = 0; i < h; i++) \
-       { \
-               type *prev_row0 = (type*)frames[0]->get_rows()[i]; \
-               type *next_row0 = (type*)frames[1]->get_rows()[i]; \
-               type *out_row = (type*)frame->get_rows()[i]; \
-               for(int j = 0; j < w * components; j++) \
-               { \
-                       *out_row++ = (*prev_row0++ * fraction0 + *next_row0++ * fraction1) / max; \
-               } \
-       } \
-}
-
-
-void InterpolateVideo::average()
-{
-       VFrame *frame = get_output();
-       int w = frame->get_w();
-       int h = frame->get_h();
-
-       switch(frame->get_color_model())
-       {
-               case BC_RGB_FLOAT:
-                       AVERAGE(float, float, 3, 1);
-                       break;
-               case BC_RGB888:
-               case BC_YUV888:
-                       AVERAGE(unsigned char, int, 3, 0xff);
-                       break;
-               case BC_RGBA_FLOAT:
-                       AVERAGE(float, float, 4, 1);
-                       break;
-               case BC_RGBA8888:
-               case BC_YUVA8888:
-                       AVERAGE(unsigned char, int, 4, 0xff);
-                       break;
-       }
-}
-
-
-int InterpolateVideo::process_buffer(VFrame *frame,
-       int64_t start_position,
-       double frame_rate)
-{
-       if(get_direction() == PLAY_REVERSE) start_position--;
-       load_configuration();
-
-       if(!frames[0])
-       {
-               for(int i = 0; i < 2; i++)
-               {
-                       frames[i] = new VFrame(0,
-                               -1,
-                               frame->get_w(),
-                               frame->get_h(),
-                               frame->get_color_model(),
-                               -1);
-               }
-       }
-//printf("InterpolateVideo::process_buffer 1 %lld %lld\n", range_start, range_end);
-
-// Fraction of lowest frame in output
-       int64_t requested_range_start = (int64_t)((double)range_start * 
-               frame_rate / active_input_rate);
-       int64_t requested_range_end = (int64_t)((double)range_end * 
-               frame_rate / active_input_rate);
-       if(requested_range_start == requested_range_end)
-       {
-               read_frame(frame, 0, range_start, active_input_rate, 0);
-        }
-        else
-        {
-
-// Fill border frames
-               fill_border(frame_rate, start_position);
-
-               float highest_fraction = (float)(start_position - requested_range_start) /
-                       (requested_range_end - requested_range_start);
-
-// Fraction of highest frame in output
-               lowest_fraction = 1.0 - highest_fraction;
-
-               CLAMP(highest_fraction, 0, 1);
-               CLAMP(lowest_fraction, 0, 1);
-
-// printf("InterpolateVideo::process_buffer %lld %lld %lld %f %f %lld %lld %f %f\n",
-// range_start,
-// range_end,
-// requested_range_start,
-// requested_range_end,
-// start_position,
-// config.input_rate,
-// frame_rate,
-// lowest_fraction,
-// highest_fraction);
-
-               if(start_position == (int64_t)(range_start * frame_rate / active_input_rate))
-               {
-//printf("InterpolateVideo::process_buffer %d\n", __LINE__);
-                       frame->copy_from(frames[0]);
-                       
-                       if(config.optic_flow)
-                       {
-                               draw_vectors(0);
-                       }
-               }
-               else
-               if(config.optic_flow)
-               {
-//printf("InterpolateVideo::process_buffer %d\n", __LINE__);
-                       optic_flow();
-               }
-               else
-               {
-                       average();
-               }
-       }
-       return 0;
-}
-
-
-
-
-NEW_WINDOW_MACRO(InterpolateVideo, InterpolateVideoWindow)
-const char* InterpolateVideo::plugin_title() { return _("Interpolate Video"); }
-int InterpolateVideo::is_realtime() { return 1; }
-
-int InterpolateVideo::load_configuration()
-{
-       KeyFrame *prev_keyframe, *next_keyframe;
-       InterpolateVideoConfig old_config;
-       old_config.copy_from(&config);
-
-       next_keyframe = get_next_keyframe(get_source_position());
-       prev_keyframe = get_prev_keyframe(get_source_position());
-// Previous keyframe stays in config object.
-       read_data(prev_keyframe);
-
-
-       int64_t prev_position = edl_to_local(prev_keyframe->position);
-       int64_t next_position = edl_to_local(next_keyframe->position);
-       if(prev_position == 0 && next_position == 0)
-       {
-               next_position = prev_position = get_source_start();
-       }
-// printf("InterpolateVideo::load_configuration 1 %lld %lld %lld %lld\n",
-// prev_keyframe->position,
-// next_keyframe->position,
-// prev_position,
-// next_position);
-
-// Get range to average in requested rate
-       range_start = prev_position;
-       range_end = next_position;
-
-
-// Use keyframes to determine range
-       if(config.use_keyframes)
-       {
-               active_input_rate = get_framerate();
-// Between keyframe and edge of range or no keyframes
-               if(range_start == range_end)
-               {
-// Between first keyframe and start of effect
-                       if(get_source_position() >= get_source_start() &&
-                               get_source_position() < range_start)
-                       {
-                               range_start = get_source_start();
-                       }
-                       else
-// Between last keyframe and end of effect
-                       if(get_source_position() >= range_start &&
-                               get_source_position() < get_source_start() + get_total_len())
-                       {
-// Last frame should be inclusive of current effect
-                               range_end = get_source_start() + get_total_len() - 1;
-                       }
-                       else
-                       {
-// Should never get here
-                               ;
-                       }
-               }
-
-
-// Make requested rate equal to input rate for this mode.
-
-// Convert requested rate to input rate
-// printf("InterpolateVideo::load_configuration 2 %lld %lld %f %f\n", 
-// range_start, 
-// range_end,
-// get_framerate(),
-// config.input_rate);
-//             range_start = (int64_t)((double)range_start / get_framerate() * active_input_rate + 0.5);
-//             range_end = (int64_t)((double)range_end / get_framerate() * active_input_rate + 0.5);
-       }
-       else
-// Use frame rate
-       {
-               active_input_rate = config.input_rate;
-// Convert to input frame rate
-               range_start = (int64_t)(get_source_position() / 
-                       get_framerate() *
-                       active_input_rate);
-               range_end = (int64_t)(get_source_position() / 
-                       get_framerate() *
-                       active_input_rate) + 1;
-       }
-
-// printf("InterpolateVideo::load_configuration 1 %lld %lld %lld %lld %lld %lld\n",
-// prev_keyframe->position,
-// next_keyframe->position,
-// prev_position,
-// next_position,
-// range_start,
-// range_end);
-
-
-       return !config.equivalent(&old_config);
-}
-
-
-void InterpolateVideo::save_data(KeyFrame *keyframe)
-{
-       FileXML output;
-
-// cause data to be stored directly in text
-       output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
-       output.tag.set_title("INTERPOLATEVIDEO");
-       output.tag.set_property("INPUT_RATE", config.input_rate);
-       output.tag.set_property("USE_KEYFRAMES", config.use_keyframes);
-       output.tag.set_property("OPTIC_FLOW", config.optic_flow);
-       output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
-       output.tag.set_property("SEARCH_RADIUS", config.search_radius);
-       output.tag.set_property("MACROBLOCK_SIZE", config.macroblock_size);
-       output.append_tag();
-       output.tag.set_title("/INTERPOLATEVIDEO");
-       output.append_tag();
-       output.append_newline();
-       output.terminate_string();
-}
-
-void InterpolateVideo::read_data(KeyFrame *keyframe)
-{
-       FileXML input;
-
-       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
-
-       while(!input.read_tag())
-       {
-               if(input.tag.title_is("INTERPOLATEVIDEO"))
-               {
-                       config.input_rate = input.tag.get_property("INPUT_RATE", config.input_rate);
-                       config.input_rate = Units::fix_framerate(config.input_rate);
-                       config.use_keyframes = input.tag.get_property("USE_KEYFRAMES", config.use_keyframes);
-                       config.optic_flow = input.tag.get_property("OPTIC_FLOW", config.optic_flow);
-                       config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
-                       config.search_radius = input.tag.get_property("SEARCH_RADIUS", config.search_radius);
-                       config.macroblock_size = input.tag.get_property("MACROBLOCK_SIZE", config.macroblock_size);
-               }
-       }
-}
-
-void InterpolateVideo::update_gui()
-{
-       if(thread)
-       {
-               if(load_configuration())
-               {
-                       thread->window->lock_window("InterpolateVideo::update_gui");
-                       ((InterpolateVideoWindow*)thread->window)->rate->update((float)config.input_rate);
-                       ((InterpolateVideoWindow*)thread->window)->keyframes->update(config.use_keyframes);
-                       ((InterpolateVideoWindow*)thread->window)->flow->update(config.optic_flow);
-                       ((InterpolateVideoWindow*)thread->window)->vectors->update(config.draw_vectors);
-                       ((InterpolateVideoWindow*)thread->window)->radius->update(config.search_radius);
-                       ((InterpolateVideoWindow*)thread->window)->size->update(config.macroblock_size);
-                       ((InterpolateVideoWindow*)thread->window)->update_enabled();
-                       thread->window->unlock_window();
-               }
-       }
-}
-
-