remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / plugins / interpolatevideo / interpolatevideo.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2016 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "bcsignals.h"
22 #include "clip.h"
23 #include "filexml.h"
24 #include "interpolatevideo.h"
25 #include "interpolatewindow.h"
26 #include "language.h"
27 #include "motionscan.h"
28 #include "opticflow.h"
29 #include "transportque.inc"
30 #include <unistd.h>
31
32
33
34
35
36
37
38
39
40 InterpolateVideoConfig::InterpolateVideoConfig()
41 {
42         input_rate = (double)30000 / 1001;
43         use_keyframes = 0;
44         optic_flow = 1;
45         draw_vectors = 1;
46         search_radius = 16;
47         macroblock_size = 16;
48 }
49
50 void InterpolateVideoConfig::copy_from(InterpolateVideoConfig *config)
51 {
52         this->input_rate = config->input_rate;
53         this->use_keyframes = config->use_keyframes;
54         this->optic_flow = config->optic_flow;
55         this->draw_vectors = config->draw_vectors;
56         this->search_radius = config->search_radius;
57         this->macroblock_size = config->macroblock_size;
58 }
59
60 int InterpolateVideoConfig::equivalent(InterpolateVideoConfig *config)
61 {
62         return EQUIV(this->input_rate, config->input_rate) &&
63                 (this->use_keyframes == config->use_keyframes) &&
64                 this->optic_flow == config->optic_flow &&
65                 this->draw_vectors == config->draw_vectors &&
66                 this->search_radius == config->search_radius &&
67                 this->macroblock_size == config->macroblock_size;
68 }
69
70
71
72
73
74
75
76
77 REGISTER_PLUGIN(InterpolateVideo)
78
79
80
81
82
83
84
85 InterpolateVideo::InterpolateVideo(PluginServer *server)
86  : PluginVClient(server)
87 {
88         optic_flow_engine = 0;
89         warp_engine = 0;
90         blend_engine = 0;
91         bzero(frames, sizeof(VFrame*) * 2);
92         for(int i = 0; i < 2; i++)
93                 frame_number[i] = -1;
94         last_position = -1;
95         last_rate = -1;
96         last_macroblock_size = 0;
97         last_search_radius = 0;
98         total_macroblocks = 0;
99 }
100
101
102 InterpolateVideo::~InterpolateVideo()
103 {
104         delete optic_flow_engine;
105         delete warp_engine;
106         delete blend_engine;
107         if(frames[0]) delete frames[0];
108         if(frames[1]) delete frames[1];
109         macroblocks.remove_all_objects();
110 }
111
112
113 void InterpolateVideo::fill_border(double frame_rate, int64_t start_position)
114 {
115 // A border frame changed or the start position is not identical to the last
116 // start position.
117
118         int64_t frame_start = range_start + (get_direction() == PLAY_REVERSE ? 1 : 0);
119         int64_t frame_end = range_end + (get_direction() == PLAY_REVERSE ? 1 : 0);
120
121         if( last_position == start_position && EQUIV(last_rate, frame_rate) &&
122                 frame_number[0] >= 0 && frame_number[0] == frame_start &&
123                 frame_number[1] >= 0 && frame_number[1] == frame_end ) return;
124
125         if( frame_start == frame_number[1] || frame_end == frame_number[0] )
126         {
127                 int64_t n = frame_number[0];
128                 frame_number[0] = frame_number[1];
129                 frame_number[1] = n;
130                 VFrame *f = frames[0];
131                 frames[0] = frames[1];
132                 frames[1] = f;
133         }
134
135         if( frame_start != frame_number[0] )
136         {
137 //printf("InterpolateVideo::fill_border 1 %lld\n", range_start);
138                 read_frame(frames[0], 0, frame_start, active_input_rate, 0);
139                 frame_number[0] = frame_start;
140         }
141
142         if( frame_end != frame_number[1] )
143         {
144 //printf("InterpolateVideo::fill_border 2 %lld\n", range_start);
145                 read_frame(frames[1], 0, frame_end, active_input_rate, 0);
146                 frame_number[1] = frame_end;
147         }
148
149         last_position = start_position;
150         last_rate = frame_rate;
151 }
152
153
154
155
156
157 void InterpolateVideo::draw_pixel(VFrame *frame, int x, int y)
158 {
159         if(!(x >= 0 && y >= 0 && x < frame->get_w() && y < frame->get_h())) return;
160
161 #define DRAW_PIXEL(x, y, components, do_yuv, max, type) \
162 { \
163         type **rows = (type**)frame->get_rows(); \
164         rows[y][x * components] = max - rows[y][x * components]; \
165         if(!do_yuv) \
166         { \
167                 rows[y][x * components + 1] = max - rows[y][x * components + 1]; \
168                 rows[y][x * components + 2] = max - rows[y][x * components + 2]; \
169         } \
170         else \
171         { \
172                 rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \
173                 rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \
174         } \
175         if(components == 4) \
176                 rows[y][x * components + 3] = max; \
177 }
178
179
180         switch(frame->get_color_model())
181         {
182                 case BC_RGB888:
183                         DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char);
184                         break;
185                 case BC_RGBA8888:
186                         DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char);
187                         break;
188                 case BC_RGB_FLOAT:
189                         DRAW_PIXEL(x, y, 3, 0, 1.0, float);
190                         break;
191                 case BC_RGBA_FLOAT:
192                         DRAW_PIXEL(x, y, 4, 0, 1.0, float);
193                         break;
194                 case BC_YUV888:
195                         DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char);
196                         break;
197                 case BC_YUVA8888:
198                         DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char);
199                         break;
200                 case BC_RGB161616:
201                         DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t);
202                         break;
203                 case BC_YUV161616:
204                         DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t);
205                         break;
206                 case BC_RGBA16161616:
207                         DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t);
208                         break;
209                 case BC_YUVA16161616:
210                         DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t);
211                         break;
212         }
213 }
214
215
216 void InterpolateVideo::draw_line(VFrame *frame, int x1, int y1, int x2, int y2)
217 {
218         int w = labs(x2 - x1);
219         int h = labs(y2 - y1);
220 //printf("InterpolateVideo::draw_line 1 %d %d %d %d\n", x1, y1, x2, y2);
221
222         if(!w && !h)
223         {
224                 draw_pixel(frame, x1, y1);
225         }
226         else
227         if(w > h)
228         {
229 // Flip coordinates so x1 < x2
230                 if(x2 < x1)
231                 {
232                         y2 ^= y1;
233                         y1 ^= y2;
234                         y2 ^= y1;
235                         x1 ^= x2;
236                         x2 ^= x1;
237                         x1 ^= x2;
238                 }
239                 int numerator = y2 - y1;
240                 int denominator = x2 - x1;
241                 for(int i = x1; i < x2; i++)
242                 {
243                         int y = y1 + (int64_t)(i - x1) * (int64_t)numerator / (int64_t)denominator;
244                         draw_pixel(frame, i, y);
245                 }
246         }
247         else
248         {
249 // Flip coordinates so y1 < y2
250                 if(y2 < y1)
251                 {
252                         y2 ^= y1;
253                         y1 ^= y2;
254                         y2 ^= y1;
255                         x1 ^= x2;
256                         x2 ^= x1;
257                         x1 ^= x2;
258                 }
259                 int numerator = x2 - x1;
260                 int denominator = y2 - y1;
261                 for(int i = y1; i < y2; i++)
262                 {
263                         int x = x1 + (int64_t)(i - y1) * (int64_t)numerator / (int64_t)denominator;
264                         draw_pixel(frame, x, i);
265                 }
266         }
267 //printf("InterpolateVideo::draw_line 2\n");
268 }
269
270 #define ARROW_SIZE 10
271 void InterpolateVideo::draw_arrow(VFrame *frame,
272         int x1,
273         int y1,
274         int x2,
275         int y2)
276 {
277         double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
278         double angle1 = angle + (float)145 / 360 * 2 * 3.14159265;
279         double angle2 = angle - (float)145 / 360 * 2 * 3.14159265;
280         int x3;
281         int y3;
282         int x4;
283         int y4;
284         if(x2 < x1)
285         {
286                 x3 = x2 - (int)(ARROW_SIZE * cos(angle1));
287                 y3 = y2 - (int)(ARROW_SIZE * sin(angle1));
288                 x4 = x2 - (int)(ARROW_SIZE * cos(angle2));
289                 y4 = y2 - (int)(ARROW_SIZE * sin(angle2));
290         }
291         else
292         {
293                 x3 = x2 + (int)(ARROW_SIZE * cos(angle1));
294                 y3 = y2 + (int)(ARROW_SIZE * sin(angle1));
295                 x4 = x2 + (int)(ARROW_SIZE * cos(angle2));
296                 y4 = y2 + (int)(ARROW_SIZE * sin(angle2));
297         }
298
299 // Main vector
300         draw_line(frame, x1, y1, x2, y2);
301 //      draw_line(frame, x1, y1 + 1, x2, y2 + 1);
302
303 // Arrow line
304         if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x3, y3);
305 //      draw_line(frame, x2, y2 + 1, x3, y3 + 1);
306 // Arrow line
307         if(abs(y2 - y1) || abs(x2 - x1)) draw_line(frame, x2, y2, x4, y4);
308 //      draw_line(frame, x2, y2 + 1, x4, y4 + 1);
309 }
310
311 void InterpolateVideo::draw_rect(VFrame *frame,
312         int x1,
313         int y1,
314         int x2,
315         int y2)
316 {
317         draw_line(frame, x1, y1, x2, y1);
318         draw_line(frame, x2, y1, x2, y2);
319         draw_line(frame, x2, y2, x1, y2);
320         draw_line(frame, x1, y2, x1, y1);
321 }
322
323
324 void InterpolateVideo::create_macroblocks()
325 {
326 // Get macroblock size
327         x_macroblocks = frames[0]->get_w() / config.macroblock_size;
328         y_macroblocks = frames[0]->get_h() / config.macroblock_size;
329
330         if(config.macroblock_size * x_macroblocks < frames[0]->get_w())
331         {
332                 x_macroblocks++;
333         }
334
335         if(config.macroblock_size * y_macroblocks < frames[0]->get_h())
336         {
337                 y_macroblocks++;
338         }
339
340         total_macroblocks = x_macroblocks * y_macroblocks;
341
342         if(total_macroblocks != macroblocks.size())
343         {
344                 macroblocks.remove_all_objects();
345         }
346
347         for(int i = 0; i < total_macroblocks; i++)
348         {
349                 OpticFlowMacroblock *mb = 0;
350                 if(macroblocks.size() > i)
351                 {
352                         mb = macroblocks.get(i);
353                 }
354                 else
355                 {
356                         mb = new OpticFlowMacroblock;
357                         macroblocks.append(mb);
358                 }
359
360                 mb->x = (i % x_macroblocks) * config.macroblock_size + config.macroblock_size / 2;
361                 mb->y = (i / x_macroblocks) * config.macroblock_size + config.macroblock_size / 2;
362         }
363 }
364
365
366 void InterpolateVideo::draw_vectors(int processed)
367 {
368 // Draw arrows
369         if(config.draw_vectors)
370         {
371                 create_macroblocks();
372
373                 for(int i = 0; i < total_macroblocks; i++)
374                 {
375                         OpticFlowMacroblock *mb = macroblocks.get(i);
376 //                  printf("InterpolateVideo::optic_flow %d x=%d y=%d dx=%d dy=%d\n",
377 //                          __LINE__,
378 //                          mb->x,
379 //                          mb->y,
380 //                          mb->dx / OVERSAMPLE,
381 //                          mb->dy / OVERSAMPLE);
382
383                         if(processed)
384                         {
385                                 draw_arrow(get_output(),
386                                         mb->x,
387                                         mb->y,
388                                         mb->x - mb->dx / OVERSAMPLE,
389                                         mb->y - mb->dy / OVERSAMPLE);
390
391 // debug
392 //                              if(mb->is_valid && mb->visible)
393 //                              {
394 //                                      draw_arrow(get_output(),
395 //                                              mb->x + 1,
396 //                                              mb->y + 1,
397 //                                              mb->x - mb->dx / OVERSAMPLE + 1,
398 //                                              mb->y - mb->dy / OVERSAMPLE + 1);
399 //                              }
400                         }
401                         else
402                         {
403                                 draw_pixel(get_output(),
404                                         mb->x,
405                                         mb->y);
406                         }
407                 }
408
409 // Draw center macroblock
410                 OpticFlowMacroblock *mb = macroblocks.get(
411                         x_macroblocks / 2 + y_macroblocks / 2 * x_macroblocks);
412                 draw_rect(get_output(),
413                         mb->x - config.macroblock_size / 2,
414                         mb->y - config.macroblock_size / 2,
415                         mb->x + config.macroblock_size / 2,
416                         mb->y + config.macroblock_size / 2);
417                 draw_rect(get_output(),
418                         mb->x - config.macroblock_size / 2 - config.search_radius,
419                         mb->y - config.macroblock_size / 2 - config.search_radius,
420                         mb->x + config.macroblock_size / 2 + config.search_radius,
421                         mb->y + config.macroblock_size / 2 + config.search_radius);
422         }
423 }
424
425
426 int InterpolateVideo::angles_overlap(float dst2_angle1,
427         float dst2_angle2,
428         float dst1_angle1,
429         float dst1_angle2)
430 {
431         if(dst2_angle1 < 0 || dst2_angle2 < 0)
432         {
433                 dst2_angle1 += 2 * M_PI;
434                 dst2_angle2 += 2 * M_PI;
435         }
436
437         if(dst1_angle1 < 0 || dst1_angle2 < 0)
438         {
439                 dst1_angle1 += 2 * M_PI;
440                 dst1_angle2 += 2 * M_PI;
441         }
442
443         if(dst1_angle1 < dst2_angle2 &&
444                 dst1_angle2 > dst2_angle1) return 1;
445
446         return 0;
447 }
448
449
450
451 void InterpolateVideo::blend_macroblock(int number)
452 {
453         OpticFlowMacroblock *src = macroblocks.get(number);
454         struct timeval start_time;
455         gettimeofday(&start_time, 0);
456 //      printf("InterpolateVideo::blend_macroblock %d %d\n",
457 //      __LINE__,
458 //      src->is_valid);
459
460
461 // Copy macroblock table to local thread
462         ArrayList<OpticFlowMacroblock*> local_macroblocks;
463         for(int i = 0; i < macroblocks.size(); i++)
464         {
465                 OpticFlowMacroblock *mb = new OpticFlowMacroblock;
466                 mb->copy_from(macroblocks.get(i));
467                 local_macroblocks.append(mb);
468         }
469
470 // Get nearest macroblocks
471         for(int i = 0; i < local_macroblocks.size(); i++)
472         {
473                 OpticFlowMacroblock *dst = local_macroblocks.get(i);
474                 if(i != number && dst->is_valid)
475                 {
476
477 // rough estimation of angle coverage
478                         float angle = atan2(dst->y - src->y, dst->x - src->x);
479                         float dist = sqrt(SQR(dst->y - src->y) + SQR(dst->x - src->x));
480                         float span = sin((float)config.macroblock_size / dist);
481                         dst->angle1 = angle - span / 2;
482                         dst->angle2 = angle + span / 2;
483                         dst->dist = dist;
484 // All macroblocks start as visible
485                         dst->visible = 1;
486
487 // printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d span=%f angle1=%f angle2=%f dist=%f\n",
488 // __LINE__,
489 // i,
490 // dst->x,
491 // dst->y,
492 // span * 360 / 2 / M_PI,
493 // dst->angle1 * 360 / 2 / M_PI,
494 // dst->angle2 * 360 / 2 / M_PI,
495 // dst->dist);
496                 }
497         }
498
499         for(int i = 0; i < local_macroblocks.size(); i++)
500         {
501 // Conceil macroblocks which are hidden
502                 OpticFlowMacroblock *dst1 = local_macroblocks.get(i);
503                 if(i != number && dst1->is_valid && dst1->visible)
504                 {
505 // Find macroblock which is obstructing
506                         for(int j = 0; j < local_macroblocks.size(); j++)
507                         {
508                                 OpticFlowMacroblock *dst2 = local_macroblocks.get(j);
509                                 if(j != number &&
510                                         dst2->is_valid &&
511                                         dst2->dist < dst1->dist &&
512                                         angles_overlap(dst2->angle1,
513                                                 dst2->angle2,
514                                                 dst1->angle1,
515                                                 dst1->angle2))
516                                 {
517                                         dst1->visible = 0;
518                                         j = local_macroblocks.size();
519                                 }
520                         }
521                 }
522         }
523
524 // Blend all visible macroblocks
525 // Get distance metrics
526         float total = 0;
527         float min = 0;
528         float max = 0;
529         int first = 1;
530         for(int i = 0; i < local_macroblocks.size(); i++)
531         {
532                 OpticFlowMacroblock *dst = local_macroblocks.get(i);
533                 if(i != number && dst->is_valid && dst->visible)
534                 {
535                         total += dst->dist;
536                         if(first)
537                         {
538                                 min = max = dst->dist;
539                                 first = 0;
540                         }
541                         else
542                         {
543                                 min = MIN(dst->dist, min);
544                                 max = MAX(dst->dist, max);
545                         }
546 // printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n",
547 // __LINE__,
548 // i,
549 // dst->x,
550 // dst->y,
551 // dst->dist);
552
553                 }
554         }
555
556 // Invert distances to convert to weights
557         total = 0;
558         for(int i = 0; i < local_macroblocks.size(); i++)
559         {
560                 OpticFlowMacroblock *dst = local_macroblocks.get(i);
561                 if(i != number && dst->is_valid && dst->visible)
562                 {
563                         dst->dist = max - dst->dist + min;
564                         total += dst->dist;
565 // printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n",
566 // __LINE__,
567 // i,
568 // dst->x,
569 // dst->y,
570 // max - dst->dist + min);
571
572                 }
573         }
574
575 // Add weighted vectors
576         float dx = 0;
577         float dy = 0;
578         if(total > 0)
579         {
580                 for(int i = 0; i < local_macroblocks.size(); i++)
581                 {
582                         OpticFlowMacroblock *dst = local_macroblocks.get(i);
583                         if(i != number && dst->is_valid && dst->visible)
584                         {
585                                 dx += dst->dist * dst->dx / total;
586                                 dy += dst->dist * dst->dy / total;
587                                 src->dx = dx;
588                                 src->dy = dy;
589 // printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n",
590 // __LINE__,
591 // i,
592 // dst->x,
593 // dst->y,
594 // max - dst->dist + min);
595
596                         }
597                 }
598         }
599
600         local_macroblocks.remove_all_objects();
601
602 // printf("InterpolateVideo::blend_macroblock %d total=%f\n",
603 // __LINE__,
604 // total);
605         struct timeval end_time;
606         gettimeofday(&end_time, 0);
607 //      printf("InterpolateVideo::blend_macroblock %d %d\n",
608 //              __LINE__,
609 //              end_time.tv_sec * 1000 + end_time.tv_usec / 1000 -
610 //              start_time.tv_sec * 1000 - start_time.tv_usec / 1000);
611 }
612
613
614
615 void InterpolateVideo::optic_flow()
616 {
617
618         create_macroblocks();
619         int need_motion = 0;
620
621 // New engine
622         if(!optic_flow_engine)
623         {
624                 optic_flow_engine = new OpticFlow(this,
625                         PluginClient::get_project_smp() + 1,
626                         PluginClient::get_project_smp() + 1);
627                 need_motion = 1;
628         }
629         else
630 // Reuse old vectors
631         if(motion_number[0] == frame_number[0] &&
632                 motion_number[1] == frame_number[1] &&
633                 last_macroblock_size == config.macroblock_size &&
634                 last_search_radius == config.search_radius)
635         {
636                 ;
637         }
638         else
639 // Calculate new vectors
640         {
641                 need_motion = 1;
642         }
643
644         if(need_motion)
645         {
646                 optic_flow_engine->set_package_count(MIN(MAX_PACKAGES, total_macroblocks));
647                 optic_flow_engine->process_packages();
648
649 // Fill in failed macroblocks
650                 invalid_blocks.remove_all();
651                 for(int i = 0; i < macroblocks.size(); i++)
652                 {
653                         if(!macroblocks.get(i)->is_valid
654 // debug
655 //                               && i >= 30 * x_macroblocks)
656                                 )
657                         {
658                                 invalid_blocks.append(i);
659                         }
660                 }
661
662 //printf("InterpolateVideo::optic_flow %d %d\n", __LINE__, invalid_blocks.size());
663                 if(invalid_blocks.size())
664                 {
665                         if(!blend_engine)
666                         {
667                                 blend_engine = new BlendMacroblock(this,
668                                         PluginClient::get_project_smp() + 1,
669                                         PluginClient::get_project_smp() + 1);
670                         }
671
672                         blend_engine->set_package_count(MIN(PluginClient::get_project_smp() + 1,
673                                 invalid_blocks.size()));
674                         blend_engine->process_packages();
675                 }
676         }
677
678
679
680 // for(int i = 0; i < total_macroblocks; i++)
681 // {
682 //      OpticFlowPackage *pkg = (OpticFlowPackage*)optic_flow_engine->get_package(
683 //              i);
684 //      if((i / x_macroblocks) % 2)
685 //      {
686 //              pkg->dx = 0;
687 //              pkg->dy = 0;
688 //      }
689 //      else
690 //      {
691 //              pkg->dx = -32;
692 //              pkg->dy = 0;
693 //      }
694 // }
695
696
697         if(!warp_engine)
698         {
699                 warp_engine = new Warp(this,
700                         PluginClient::get_project_smp() + 1,
701                         PluginClient::get_project_smp() + 1);
702         }
703
704         warp_engine->process_packages();
705
706         motion_number[0] = frame_number[0];
707         motion_number[1] = frame_number[1];
708         last_macroblock_size = config.macroblock_size;
709         last_search_radius = config.search_radius;
710
711
712 // Debug
713 //      get_output()->copy_from(frames[1]);
714
715
716         draw_vectors(1);
717 }
718
719
720 #define AVERAGE(type, temp_type,components, max) \
721 { \
722         temp_type fraction0 = (temp_type)(lowest_fraction * max); \
723         temp_type fraction1 = (temp_type)(max - fraction0); \
724  \
725         for(int i = 0; i < h; i++) \
726         { \
727                 type *prev_row0 = (type*)frames[0]->get_rows()[i]; \
728                 type *next_row0 = (type*)frames[1]->get_rows()[i]; \
729                 type *out_row = (type*)frame->get_rows()[i]; \
730                 for(int j = 0; j < w * components; j++) \
731                 { \
732                         *out_row++ = (*prev_row0++ * fraction0 + *next_row0++ * fraction1) / max; \
733                 } \
734         } \
735 }
736
737
738 void InterpolateVideo::average()
739 {
740         VFrame *frame = get_output();
741         int w = frame->get_w();
742         int h = frame->get_h();
743
744         switch(frame->get_color_model())
745         {
746                 case BC_RGB_FLOAT:
747                         AVERAGE(float, float, 3, 1);
748                         break;
749                 case BC_RGB888:
750                 case BC_YUV888:
751                         AVERAGE(unsigned char, int, 3, 0xff);
752                         break;
753                 case BC_RGBA_FLOAT:
754                         AVERAGE(float, float, 4, 1);
755                         break;
756                 case BC_RGBA8888:
757                 case BC_YUVA8888:
758                         AVERAGE(unsigned char, int, 4, 0xff);
759                         break;
760         }
761 }
762
763
764 int InterpolateVideo::process_buffer(VFrame *frame,
765         int64_t start_position,
766         double frame_rate)
767 {
768         if(get_direction() == PLAY_REVERSE) start_position--;
769         load_configuration();
770
771         if(!frames[0])
772         {
773                 for(int i = 0; i < 2; i++)
774                 {
775                         frames[i] = new VFrame(0,
776                                 -1,
777                                 frame->get_w(),
778                                 frame->get_h(),
779                                 frame->get_color_model(),
780                                 -1);
781                 }
782         }
783 //printf("InterpolateVideo::process_buffer 1 %lld %lld\n", range_start, range_end);
784
785 // Fraction of lowest frame in output
786         int64_t requested_range_start = (int64_t)((double)range_start *
787                 frame_rate / active_input_rate);
788         int64_t requested_range_end = (int64_t)((double)range_end *
789                 frame_rate / active_input_rate);
790         if(requested_range_start == requested_range_end)
791         {
792                 read_frame(frame, 0, range_start, active_input_rate, 0);
793         }
794         else
795         {
796
797 // Fill border frames
798                 fill_border(frame_rate, start_position);
799
800                 float highest_fraction = (float)(start_position - requested_range_start) /
801                         (requested_range_end - requested_range_start);
802
803 // Fraction of highest frame in output
804                 lowest_fraction = 1.0 - highest_fraction;
805
806                 CLAMP(highest_fraction, 0, 1);
807                 CLAMP(lowest_fraction, 0, 1);
808
809 // printf("InterpolateVideo::process_buffer %lld %lld %lld %f %f %lld %lld %f %f\n",
810 // range_start,
811 // range_end,
812 // requested_range_start,
813 // requested_range_end,
814 // start_position,
815 // config.input_rate,
816 // frame_rate,
817 // lowest_fraction,
818 // highest_fraction);
819
820                 if(start_position == (int64_t)(range_start * frame_rate / active_input_rate))
821                 {
822 //printf("InterpolateVideo::process_buffer %d\n", __LINE__);
823                         frame->copy_from(frames[0]);
824
825                         if(config.optic_flow)
826                         {
827                                 draw_vectors(0);
828                         }
829                 }
830                 else
831                 if(config.optic_flow)
832                 {
833 //printf("InterpolateVideo::process_buffer %d\n", __LINE__);
834                         optic_flow();
835                 }
836                 else
837                 {
838                         average();
839                 }
840         }
841         return 0;
842 }
843
844
845
846
847 NEW_WINDOW_MACRO(InterpolateVideo, InterpolateVideoWindow)
848 const char* InterpolateVideo::plugin_title() { return _("Interpolate Video"); }
849 int InterpolateVideo::is_realtime() { return 1; }
850
851 int InterpolateVideo::load_configuration()
852 {
853         KeyFrame *prev_keyframe, *next_keyframe;
854         InterpolateVideoConfig old_config;
855         old_config.copy_from(&config);
856
857         next_keyframe = get_next_keyframe(get_source_position());
858         prev_keyframe = get_prev_keyframe(get_source_position());
859 // Previous keyframe stays in config object.
860         read_data(prev_keyframe);
861
862
863         int64_t prev_position = edl_to_local(prev_keyframe->position);
864         int64_t next_position = edl_to_local(next_keyframe->position);
865         if(prev_position == 0 && next_position == 0)
866         {
867                 next_position = prev_position = get_source_start();
868         }
869 // printf("InterpolateVideo::load_configuration 1 %lld %lld %lld %lld\n",
870 // prev_keyframe->position,
871 // next_keyframe->position,
872 // prev_position,
873 // next_position);
874
875 // Get range to average in requested rate
876         range_start = prev_position;
877         range_end = next_position;
878
879
880 // Use keyframes to determine range
881         if(config.use_keyframes)
882         {
883                 active_input_rate = get_framerate();
884 // Between keyframe and edge of range or no keyframes
885                 if(range_start == range_end)
886                 {
887 // Between first keyframe and start of effect
888                         if(get_source_position() >= get_source_start() &&
889                                 get_source_position() < range_start)
890                         {
891                                 range_start = get_source_start();
892                         }
893                         else
894 // Between last keyframe and end of effect
895                         if(get_source_position() >= range_start &&
896                                 get_source_position() < get_source_start() + get_total_len())
897                         {
898 // Last frame should be inclusive of current effect
899                                 range_end = get_source_start() + get_total_len() - 1;
900                         }
901                         else
902                         {
903 // Should never get here
904                                 ;
905                         }
906                 }
907
908
909 // Make requested rate equal to input rate for this mode.
910
911 // Convert requested rate to input rate
912 // printf("InterpolateVideo::load_configuration 2 %lld %lld %f %f\n",
913 // range_start,
914 // range_end,
915 // get_framerate(),
916 // config.input_rate);
917 //              range_start = (int64_t)((double)range_start / get_framerate() * active_input_rate + 0.5);
918 //              range_end = (int64_t)((double)range_end / get_framerate() * active_input_rate + 0.5);
919         }
920         else
921 // Use frame rate
922         {
923                 active_input_rate = config.input_rate;
924 // Convert to input frame rate
925                 range_start = (int64_t)(get_source_position() /
926                         get_framerate() *
927                         active_input_rate);
928                 range_end = (int64_t)(get_source_position() /
929                         get_framerate() *
930                         active_input_rate) + 1;
931         }
932
933 // printf("InterpolateVideo::load_configuration 1 %lld %lld %lld %lld %lld %lld\n",
934 // prev_keyframe->position,
935 // next_keyframe->position,
936 // prev_position,
937 // next_position,
938 // range_start,
939 // range_end);
940
941
942         return !config.equivalent(&old_config);
943 }
944
945
946 void InterpolateVideo::save_data(KeyFrame *keyframe)
947 {
948         FileXML output;
949
950 // cause data to be stored directly in text
951         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
952         output.tag.set_title("INTERPOLATEVIDEO");
953         output.tag.set_property("INPUT_RATE", config.input_rate);
954         output.tag.set_property("USE_KEYFRAMES", config.use_keyframes);
955         output.tag.set_property("OPTIC_FLOW", config.optic_flow);
956         output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
957         output.tag.set_property("SEARCH_RADIUS", config.search_radius);
958         output.tag.set_property("MACROBLOCK_SIZE", config.macroblock_size);
959         output.append_tag();
960         output.tag.set_title("/INTERPOLATEVIDEO");
961         output.append_tag();
962         output.append_newline();
963         output.terminate_string();
964 }
965
966 void InterpolateVideo::read_data(KeyFrame *keyframe)
967 {
968         FileXML input;
969
970         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
971
972         while(!input.read_tag())
973         {
974                 if(input.tag.title_is("INTERPOLATEVIDEO"))
975                 {
976                         config.input_rate = input.tag.get_property("INPUT_RATE", config.input_rate);
977                         config.input_rate = Units::fix_framerate(config.input_rate);
978                         config.use_keyframes = input.tag.get_property("USE_KEYFRAMES", config.use_keyframes);
979                         config.optic_flow = input.tag.get_property("OPTIC_FLOW", config.optic_flow);
980                         config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
981                         config.search_radius = input.tag.get_property("SEARCH_RADIUS", config.search_radius);
982                         config.macroblock_size = input.tag.get_property("MACROBLOCK_SIZE", config.macroblock_size);
983                 }
984         }
985 }
986
987 void InterpolateVideo::update_gui()
988 {
989         if(thread)
990         {
991                 if(load_configuration())
992                 {
993                         thread->window->lock_window("InterpolateVideo::update_gui");
994                         ((InterpolateVideoWindow*)thread->window)->rate->update((float)config.input_rate);
995                         ((InterpolateVideoWindow*)thread->window)->keyframes->update(config.use_keyframes);
996                         ((InterpolateVideoWindow*)thread->window)->flow->update(config.optic_flow);
997                         ((InterpolateVideoWindow*)thread->window)->vectors->update(config.draw_vectors);
998                         ((InterpolateVideoWindow*)thread->window)->radius->update(config.search_radius);
999                         ((InterpolateVideoWindow*)thread->window)->size->update(config.macroblock_size);
1000                         ((InterpolateVideoWindow*)thread->window)->update_enabled();
1001                         thread->window->unlock_window();
1002                 }
1003         }
1004 }
1005
1006