+++ /dev/null
-/*
- * 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();
- }
- }
-}
-
-