83ff93b6a4beecbbfc0b58f999ff69909a31aee6
[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-hv.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 // printf("InterpolateVideo::create_macroblocks %d %d %d %d\n", 
330 // __LINE__, 
331 // config.macroblock_size,
332 // x_macroblocks,
333 // y_macroblocks);
334
335         if(config.macroblock_size * x_macroblocks < frames[0]->get_w())
336         {
337                 x_macroblocks++;
338         }
339
340         if(config.macroblock_size * y_macroblocks < frames[0]->get_h())
341         {
342                 y_macroblocks++;
343         }
344
345         total_macroblocks = x_macroblocks * y_macroblocks;
346
347         if(total_macroblocks != macroblocks.size())
348         {
349                 macroblocks.remove_all_objects();
350         }
351
352         for(int i = 0; i < total_macroblocks; i++)
353         {
354                 OpticFlowMacroblock *mb = 0;
355                 if(macroblocks.size() > i)
356                 {
357                         mb = macroblocks.get(i);
358                 }
359                 else
360                 {
361                         mb = new OpticFlowMacroblock;
362                         macroblocks.append(mb);
363                 }
364
365                 mb->x = (i % x_macroblocks) * config.macroblock_size + config.macroblock_size / 2;
366                 mb->y = (i / x_macroblocks) * config.macroblock_size + config.macroblock_size / 2;
367         }
368 }
369
370
371 void InterpolateVideo::draw_vectors(int processed)
372 {
373 // Draw arrows
374         if(config.draw_vectors)
375         {
376                 create_macroblocks();
377
378                 for(int i = 0; i < total_macroblocks; i++)
379                 {
380                         OpticFlowMacroblock *mb = macroblocks.get(i);
381 //                  printf("InterpolateVideo::optic_flow %d x=%d y=%d dx=%d dy=%d\n",
382 //                          __LINE__,
383 //                          mb->x,
384 //                          mb->y,
385 //                          mb->dx / OVERSAMPLE,
386 //                          mb->dy / OVERSAMPLE);
387
388                         if(processed)
389                         {
390                                 draw_arrow(get_output(),
391                                         mb->x,
392                                         mb->y,
393                                         mb->x - mb->dx / OVERSAMPLE,
394                                         mb->y - mb->dy / OVERSAMPLE);
395
396 // debug
397 //                              if(mb->is_valid && mb->visible)
398 //                              {
399 //                                      draw_arrow(get_output(),
400 //                                              mb->x + 1,
401 //                                              mb->y + 1,
402 //                                              mb->x - mb->dx / OVERSAMPLE + 1,
403 //                                              mb->y - mb->dy / OVERSAMPLE + 1);
404 //                              }
405                         }
406                         else
407                         {
408                                 draw_pixel(get_output(),
409                                         mb->x,
410                                         mb->y);
411                         }
412                 }
413
414 // Draw center macroblock
415                 OpticFlowMacroblock *mb = macroblocks.get(
416                         x_macroblocks / 2 + y_macroblocks / 2 * x_macroblocks);
417                 draw_rect(get_output(),
418                         mb->x - config.macroblock_size / 2,
419                         mb->y - config.macroblock_size / 2,
420                         mb->x + config.macroblock_size / 2,
421                         mb->y + config.macroblock_size / 2);
422                 draw_rect(get_output(),
423                         mb->x - config.macroblock_size / 2 - config.search_radius,
424                         mb->y - config.macroblock_size / 2 - config.search_radius,
425                         mb->x + config.macroblock_size / 2 + config.search_radius,
426                         mb->y + config.macroblock_size / 2 + config.search_radius);
427         }
428 }
429
430
431 int InterpolateVideo::angles_overlap(float dst2_angle1,
432         float dst2_angle2,
433         float dst1_angle1,
434         float dst1_angle2)
435 {
436         if(dst2_angle1 < 0 || dst2_angle2 < 0)
437         {
438                 dst2_angle1 += 2 * M_PI;
439                 dst2_angle2 += 2 * M_PI;
440         }
441
442         if(dst1_angle1 < 0 || dst1_angle2 < 0)
443         {
444                 dst1_angle1 += 2 * M_PI;
445                 dst1_angle2 += 2 * M_PI;
446         }
447
448         if(dst1_angle1 < dst2_angle2 &&
449                 dst1_angle2 > dst2_angle1) return 1;
450
451         return 0;
452 }
453
454
455
456 void InterpolateVideo::blend_macroblock(int number)
457 {
458         OpticFlowMacroblock *src = macroblocks.get(number);
459         struct timeval start_time;
460         gettimeofday(&start_time, 0);
461 //      printf("InterpolateVideo::blend_macroblock %d %d\n",
462 //      __LINE__,
463 //      src->is_valid);
464
465
466 // Copy macroblock table to local thread
467         ArrayList<OpticFlowMacroblock*> local_macroblocks;
468         for(int i = 0; i < macroblocks.size(); i++)
469         {
470                 OpticFlowMacroblock *mb = new OpticFlowMacroblock;
471                 mb->copy_from(macroblocks.get(i));
472                 local_macroblocks.append(mb);
473         }
474
475 // Get nearest macroblocks
476         for(int i = 0; i < local_macroblocks.size(); i++)
477         {
478                 OpticFlowMacroblock *dst = local_macroblocks.get(i);
479                 if(i != number && dst->is_valid)
480                 {
481
482 // rough estimation of angle coverage
483                         float angle = atan2(dst->y - src->y, dst->x - src->x);
484                         float dist = sqrt(SQR(dst->y - src->y) + SQR(dst->x - src->x));
485                         float span = sin((float)config.macroblock_size / dist);
486                         dst->angle1 = angle - span / 2;
487                         dst->angle2 = angle + span / 2;
488                         dst->dist = dist;
489 // All macroblocks start as visible
490                         dst->visible = 1;
491
492 // printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d span=%f angle1=%f angle2=%f dist=%f\n",
493 // __LINE__,
494 // i,
495 // dst->x,
496 // dst->y,
497 // span * 360 / 2 / M_PI,
498 // dst->angle1 * 360 / 2 / M_PI,
499 // dst->angle2 * 360 / 2 / M_PI,
500 // dst->dist);
501                 }
502         }
503
504         for(int i = 0; i < local_macroblocks.size(); i++)
505         {
506 // Conceil macroblocks which are hidden
507                 OpticFlowMacroblock *dst1 = local_macroblocks.get(i);
508                 if(i != number && dst1->is_valid && dst1->visible)
509                 {
510 // Find macroblock which is obstructing
511                         for(int j = 0; j < local_macroblocks.size(); j++)
512                         {
513                                 OpticFlowMacroblock *dst2 = local_macroblocks.get(j);
514                                 if(j != number &&
515                                         dst2->is_valid &&
516                                         dst2->dist < dst1->dist &&
517                                         angles_overlap(dst2->angle1,
518                                                 dst2->angle2,
519                                                 dst1->angle1,
520                                                 dst1->angle2))
521                                 {
522                                         dst1->visible = 0;
523                                         j = local_macroblocks.size();
524                                 }
525                         }
526                 }
527         }
528
529 // Blend all visible macroblocks
530 // Get distance metrics
531         float total = 0;
532         float min = 0;
533         float max = 0;
534         int first = 1;
535         for(int i = 0; i < local_macroblocks.size(); i++)
536         {
537                 OpticFlowMacroblock *dst = local_macroblocks.get(i);
538                 if(i != number && dst->is_valid && dst->visible)
539                 {
540                         total += dst->dist;
541                         if(first)
542                         {
543                                 min = max = dst->dist;
544                                 first = 0;
545                         }
546                         else
547                         {
548                                 min = MIN(dst->dist, min);
549                                 max = MAX(dst->dist, max);
550                         }
551 // printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n",
552 // __LINE__,
553 // i,
554 // dst->x,
555 // dst->y,
556 // dst->dist);
557
558                 }
559         }
560
561 // Invert distances to convert to weights
562         total = 0;
563         for(int i = 0; i < local_macroblocks.size(); i++)
564         {
565                 OpticFlowMacroblock *dst = local_macroblocks.get(i);
566                 if(i != number && dst->is_valid && dst->visible)
567                 {
568                         dst->dist = max - dst->dist + min;
569                         total += dst->dist;
570 // printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n",
571 // __LINE__,
572 // i,
573 // dst->x,
574 // dst->y,
575 // max - dst->dist + min);
576
577                 }
578         }
579
580 // Add weighted vectors
581         float dx = 0;
582         float dy = 0;
583         if(total > 0)
584         {
585                 for(int i = 0; i < local_macroblocks.size(); i++)
586                 {
587                         OpticFlowMacroblock *dst = local_macroblocks.get(i);
588                         if(i != number && dst->is_valid && dst->visible)
589                         {
590                                 dx += dst->dist * dst->dx / total;
591                                 dy += dst->dist * dst->dy / total;
592                                 src->dx = dx;
593                                 src->dy = dy;
594 // printf("InterpolateVideo::blend_macroblock %d %d x=%d y=%d dist=%f\n",
595 // __LINE__,
596 // i,
597 // dst->x,
598 // dst->y,
599 // max - dst->dist + min);
600
601                         }
602                 }
603         }
604
605         local_macroblocks.remove_all_objects();
606
607 // printf("InterpolateVideo::blend_macroblock %d total=%f\n",
608 // __LINE__,
609 // total);
610         struct timeval end_time;
611         gettimeofday(&end_time, 0);
612 //      printf("InterpolateVideo::blend_macroblock %d %d\n",
613 //              __LINE__,
614 //              end_time.tv_sec * 1000 + end_time.tv_usec / 1000 -
615 //              start_time.tv_sec * 1000 - start_time.tv_usec / 1000);
616 }
617
618
619
620 void InterpolateVideo::optic_flow()
621 {
622
623         create_macroblocks();
624         int need_motion = 0;
625
626 // New engine
627         if(!optic_flow_engine)
628         {
629                 optic_flow_engine = new OpticFlow(this,
630                         PluginClient::get_project_smp() + 1,
631                         PluginClient::get_project_smp() + 1);
632                 need_motion = 1;
633         }
634         else
635 // Reuse old vectors
636         if(motion_number[0] == frame_number[0] &&
637                 motion_number[1] == frame_number[1] &&
638                 last_macroblock_size == config.macroblock_size &&
639                 last_search_radius == config.search_radius)
640         {
641                 ;
642         }
643         else
644 // Calculate new vectors
645         {
646                 need_motion = 1;
647         }
648
649         if(need_motion)
650         {
651                 optic_flow_engine->set_package_count(MIN(MAX_PACKAGES, total_macroblocks));
652                 optic_flow_engine->process_packages();
653
654 // Fill in failed macroblocks
655                 invalid_blocks.remove_all();
656                 for(int i = 0; i < macroblocks.size(); i++)
657                 {
658                         if(!macroblocks.get(i)->is_valid
659 // debug
660 //                               && i >= 30 * x_macroblocks)
661                                 )
662                         {
663                                 invalid_blocks.append(i);
664                         }
665                 }
666
667 //printf("InterpolateVideo::optic_flow %d %d\n", __LINE__, invalid_blocks.size());
668                 if(invalid_blocks.size())
669                 {
670                         if(!blend_engine)
671                         {
672                                 blend_engine = new BlendMacroblock(this,
673                                         PluginClient::get_project_smp() + 1,
674                                         PluginClient::get_project_smp() + 1);
675                         }
676
677                         blend_engine->set_package_count(MIN(PluginClient::get_project_smp() + 1,
678                                 invalid_blocks.size()));
679                         blend_engine->process_packages();
680                 }
681         }
682
683
684
685 // for(int i = 0; i < total_macroblocks; i++)
686 // {
687 //      OpticFlowPackage *pkg = (OpticFlowPackage*)optic_flow_engine->get_package(
688 //              i);
689 //      if((i / x_macroblocks) % 2)
690 //      {
691 //              pkg->dx = 0;
692 //              pkg->dy = 0;
693 //      }
694 //      else
695 //      {
696 //              pkg->dx = -32;
697 //              pkg->dy = 0;
698 //      }
699 // }
700
701
702         if(!warp_engine)
703         {
704                 warp_engine = new Warp(this,
705                         PluginClient::get_project_smp() + 1,
706                         PluginClient::get_project_smp() + 1);
707         }
708
709         warp_engine->process_packages();
710
711         motion_number[0] = frame_number[0];
712         motion_number[1] = frame_number[1];
713         last_macroblock_size = config.macroblock_size;
714         last_search_radius = config.search_radius;
715
716
717 // Debug
718 //      get_output()->copy_from(frames[1]);
719
720
721         draw_vectors(1);
722 }
723
724
725 #define AVERAGE(type, temp_type,components, max) \
726 { \
727         temp_type fraction0 = (temp_type)(lowest_fraction * max); \
728         temp_type fraction1 = (temp_type)(max - fraction0); \
729  \
730         for(int i = 0; i < h; i++) \
731         { \
732                 type *prev_row0 = (type*)frames[0]->get_rows()[i]; \
733                 type *next_row0 = (type*)frames[1]->get_rows()[i]; \
734                 type *out_row = (type*)frame->get_rows()[i]; \
735                 for(int j = 0; j < w * components; j++) \
736                 { \
737                         *out_row++ = (*prev_row0++ * fraction0 + *next_row0++ * fraction1) / max; \
738                 } \
739         } \
740 }
741
742
743 void InterpolateVideo::average()
744 {
745         VFrame *frame = get_output();
746         int w = frame->get_w();
747         int h = frame->get_h();
748
749         switch(frame->get_color_model())
750         {
751                 case BC_RGB_FLOAT:
752                         AVERAGE(float, float, 3, 1);
753                         break;
754                 case BC_RGB888:
755                 case BC_YUV888:
756                         AVERAGE(unsigned char, int, 3, 0xff);
757                         break;
758                 case BC_RGBA_FLOAT:
759                         AVERAGE(float, float, 4, 1);
760                         break;
761                 case BC_RGBA8888:
762                 case BC_YUVA8888:
763                         AVERAGE(unsigned char, int, 4, 0xff);
764                         break;
765         }
766 }
767
768
769 int InterpolateVideo::process_buffer(VFrame *frame,
770         int64_t start_position,
771         double frame_rate)
772 {
773         if(get_direction() == PLAY_REVERSE) start_position--;
774         load_configuration();
775
776         if(!frames[0])
777         {
778                 for(int i = 0; i < 2; i++)
779                 {
780                         frames[i] = new VFrame(frame->get_w(), frame->get_h(),
781                                 frame->get_color_model(), 0);
782                 }
783         }
784 //printf("InterpolateVideo::process_buffer 1 %lld %lld\n", range_start, range_end);
785
786 // Fraction of lowest frame in output
787         int64_t requested_range_start = (int64_t)((double)range_start *
788                 frame_rate / active_input_rate);
789         int64_t requested_range_end = (int64_t)((double)range_end *
790                 frame_rate / active_input_rate);
791         if(requested_range_start == requested_range_end)
792         {
793                 read_frame(frame, 0, range_start, active_input_rate, 0);
794         }
795         else
796         {
797
798 // Fill border frames
799                 fill_border(frame_rate, start_position);
800
801                 float highest_fraction = (float)(start_position - requested_range_start) /
802                         (requested_range_end - requested_range_start);
803
804 // Fraction of highest frame in output
805                 lowest_fraction = 1.0 - highest_fraction;
806
807                 CLAMP(highest_fraction, 0, 1);
808                 CLAMP(lowest_fraction, 0, 1);
809
810 // printf("InterpolateVideo::process_buffer %lld %lld %lld %f %f %lld %lld %f %f\n",
811 // range_start,
812 // range_end,
813 // requested_range_start,
814 // requested_range_end,
815 // start_position,
816 // config.input_rate,
817 // frame_rate,
818 // lowest_fraction,
819 // highest_fraction);
820
821                 if(start_position == (int64_t)(range_start * frame_rate / active_input_rate))
822                 {
823 //printf("InterpolateVideo::process_buffer %d\n", __LINE__);
824                         frame->copy_from(frames[0]);
825
826                         if(config.optic_flow)
827                         {
828                                 draw_vectors(0);
829                         }
830                 }
831                 else
832                 if(config.optic_flow)
833                 {
834 //printf("InterpolateVideo::process_buffer %d\n", __LINE__);
835                         optic_flow();
836                 }
837                 else
838                 {
839                         average();
840                 }
841         }
842         return 0;
843 }
844
845
846
847
848 NEW_WINDOW_MACRO(InterpolateVideo, InterpolateVideoWindow)
849 const char* InterpolateVideo::plugin_title() { return _("Interpolate Video"); }
850 int InterpolateVideo::is_realtime() { return 1; }
851
852 int InterpolateVideo::load_configuration()
853 {
854         KeyFrame *prev_keyframe, *next_keyframe;
855         InterpolateVideoConfig old_config;
856         old_config.copy_from(&config);
857
858         next_keyframe = get_next_keyframe(get_source_position());
859         prev_keyframe = get_prev_keyframe(get_source_position());
860 // Previous keyframe stays in config object.
861         read_data(prev_keyframe);
862
863
864         int64_t prev_position = edl_to_local(prev_keyframe->position);
865         int64_t next_position = edl_to_local(next_keyframe->position);
866         if(prev_position == 0 && next_position == 0)
867         {
868                 next_position = prev_position = get_source_start();
869         }
870 // printf("InterpolateVideo::load_configuration 1 %lld %lld %lld %lld\n",
871 // prev_keyframe->position,
872 // next_keyframe->position,
873 // prev_position,
874 // next_position);
875
876 // Get range to average in requested rate
877         range_start = prev_position;
878         range_end = next_position;
879
880
881 // Use keyframes to determine range
882         if(config.use_keyframes)
883         {
884                 active_input_rate = get_framerate();
885 // Between keyframe and edge of range or no keyframes
886                 if(range_start == range_end)
887                 {
888 // Between first keyframe and start of effect
889                         if(get_source_position() >= get_source_start() &&
890                                 get_source_position() < range_start)
891                         {
892                                 range_start = get_source_start();
893                         }
894                         else
895 // Between last keyframe and end of effect
896                         if(get_source_position() >= range_start &&
897                                 get_source_position() < get_source_start() + get_total_len())
898                         {
899 // Last frame should be inclusive of current effect
900                                 range_end = get_source_start() + get_total_len() - 1;
901                         }
902                         else
903                         {
904 // Should never get here
905                                 ;
906                         }
907                 }
908
909
910 // Make requested rate equal to input rate for this mode.
911
912 // Convert requested rate to input rate
913 // printf("InterpolateVideo::load_configuration 2 %lld %lld %f %f\n",
914 // range_start,
915 // range_end,
916 // get_framerate(),
917 // config.input_rate);
918 //              range_start = (int64_t)((double)range_start / get_framerate() * active_input_rate + 0.5);
919 //              range_end = (int64_t)((double)range_end / get_framerate() * active_input_rate + 0.5);
920         }
921         else
922 // Use frame rate
923         {
924                 active_input_rate = config.input_rate;
925 // Convert to input frame rate
926                 range_start = (int64_t)(get_source_position() /
927                         get_framerate() *
928                         active_input_rate);
929                 range_end = (int64_t)(get_source_position() /
930                         get_framerate() *
931                         active_input_rate) + 1;
932         }
933
934 // printf("InterpolateVideo::load_configuration 1 %lld %lld %lld %lld %lld %lld\n",
935 // prev_keyframe->position,
936 // next_keyframe->position,
937 // prev_position,
938 // next_position,
939 // range_start,
940 // range_end);
941
942
943         return !config.equivalent(&old_config);
944 }
945
946
947 void InterpolateVideo::save_data(KeyFrame *keyframe)
948 {
949         FileXML output;
950
951 // cause data to be stored directly in text
952         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
953         output.tag.set_title("INTERPOLATEVIDEO");
954         output.tag.set_property("INPUT_RATE", config.input_rate);
955         output.tag.set_property("USE_KEYFRAMES", config.use_keyframes);
956         output.tag.set_property("OPTIC_FLOW", config.optic_flow);
957         output.tag.set_property("DRAW_VECTORS", config.draw_vectors);
958         output.tag.set_property("SEARCH_RADIUS", config.search_radius);
959         output.tag.set_property("MACROBLOCK_SIZE", config.macroblock_size);
960         output.append_tag();
961         output.tag.set_title("/INTERPOLATEVIDEO");
962         output.append_tag();
963         output.append_newline();
964         output.terminate_string();
965 }
966
967 void InterpolateVideo::read_data(KeyFrame *keyframe)
968 {
969         FileXML input;
970
971         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
972
973         while(!input.read_tag())
974         {
975                 if(input.tag.title_is("INTERPOLATEVIDEO"))
976                 {
977                         config.input_rate = input.tag.get_property("INPUT_RATE", config.input_rate);
978                         config.input_rate = Units::fix_framerate(config.input_rate);
979                         config.use_keyframes = input.tag.get_property("USE_KEYFRAMES", config.use_keyframes);
980                         config.optic_flow = input.tag.get_property("OPTIC_FLOW", config.optic_flow);
981                         config.draw_vectors = input.tag.get_property("DRAW_VECTORS", config.draw_vectors);
982                         config.search_radius = input.tag.get_property("SEARCH_RADIUS", config.search_radius);
983                         config.macroblock_size = input.tag.get_property("MACROBLOCK_SIZE", config.macroblock_size);
984                 }
985         }
986 }
987
988 void InterpolateVideo::update_gui()
989 {
990         if(thread)
991         {
992                 if(load_configuration())
993                 {
994                         thread->window->lock_window("InterpolateVideo::update_gui");
995                         ((InterpolateVideoWindow*)thread->window)->rate->update((float)config.input_rate);
996                         ((InterpolateVideoWindow*)thread->window)->keyframes->update(config.use_keyframes);
997                         ((InterpolateVideoWindow*)thread->window)->flow->update(config.optic_flow);
998                         ((InterpolateVideoWindow*)thread->window)->vectors->update(config.draw_vectors);
999                         ((InterpolateVideoWindow*)thread->window)->radius->update(config.search_radius);
1000                         ((InterpolateVideoWindow*)thread->window)->size->update(config.macroblock_size);
1001                         ((InterpolateVideoWindow*)thread->window)->update_enabled();
1002                         thread->window->unlock_window();
1003                 }
1004         }
1005 }
1006
1007