Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / vicon.C
index 296b3b08f7b4205974552e0ffaada438215fa74e..e0b4d1b8f7eb1b57e210b894a97d287262601761 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * CINELERRA
+ * Copyright (C) 2016-2020 William Morrow
+ *
+ * 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 "vicon.h"
 
 #include "bctimer.h"
 #include "condition.h"
 
 VIcon::
-VIcon(int vw, int vh, double rate)
+VIcon(int w, int h, double rate)
 {
-       this->vw = vw;
-       this->vh = vh;
+       this->w = w;
+       this->h = h;
        this->frame_rate = rate;
 
        cycle_start = 0;
@@ -35,8 +56,7 @@ void VIcon::
 add_image(VFrame *frm, int ww, int hh, int vcmdl)
 {
        VIFrame *vifrm = new VIFrame(ww, hh, vcmdl);
-       VFrame *img = *vifrm;
-       img->transfer_from(frm);
+       vifrm->vfrm->transfer_from(frm);
        images.append(vifrm);
 }
 
@@ -47,12 +67,12 @@ draw_vframe(VIconThread *vt, BC_WindowBase *wdw, int x, int y)
        if( !vfrm ) return;
        int sx0 = 0, sx1 = sx0 + vt->vw;
        int sy0 = 0, sy1 = sy0 + vt->vh;
-       int dx0 = x, dx1 = dx0 + vw;
-       int dy0 = y, dy1 = dy0 + vh;
-       if( (x=vt->draw_x0-dx0) > 0 ) { sx0 += (x*vt->vw)/vw;  dx0 = vt->draw_x0; }
-       if( (x=dx1-vt->draw_x1) > 0 ) { sx1 -= (x*vt->vw)/vw;  dx1 = vt->draw_x1; }
-       if( (y=vt->draw_y0-dy0) > 0 ) { sy0 += (y*vt->vh)/vh;  dy0 = vt->draw_y0; }
-       if( (y=dy1-vt->draw_y1) > 0 ) { sy1 -= (y*vt->vh)/vh;  dy1 = vt->draw_y1; }
+       int dx0 = x, dx1 = dx0 + w;
+       int dy0 = y, dy1 = dy0 + h;
+       if( (x=vt->draw_x0-dx0) > 0 ) { sx0 += (x*vt->vw)/w;  dx0 = vt->draw_x0; }
+       if( (x=dx1-vt->draw_x1) > 0 ) { sx1 -= (x*vt->vw)/w;  dx1 = vt->draw_x1; }
+       if( (y=vt->draw_y0-dy0) > 0 ) { sy0 += (y*vt->vh)/h;  dy0 = vt->draw_y0; }
+       if( (y=dy1-vt->draw_y1) > 0 ) { sy1 -= (y*vt->vh)/h;  dy1 = vt->draw_y1; }
        int sw = sx1 - sx0, sh = sy1 - sy0;
        int dw = dx1 - dx0, dh = dy1 - dy0;
        if( dw > 0 && dh > 0 && sw > 0 && sh > 0 )
@@ -87,6 +107,7 @@ VIcon *VIconThread::low_vicon()
 
 void VIconThread::remove_vicon(int i)
 {
+       if( t_heap[i] == solo ) solo = 0;
        int sz = t_heap.size();
        for( int k; (k=2*(i+1)) < sz; i=k ) {
                if( t_heap[k]->age > t_heap[k-1]->age ) --k;
@@ -108,12 +129,16 @@ VIconThread(BC_WindowBase *wdw, int vw, int vh, int view_w, int view_h)
        this->wdw = wdw;
        this->vw = vw;         this->vh = vh;
        this->view_w = view_w; this->view_h = view_h;
-       this->view_win = 0;    this->vicon = 0;    this->viewing = 0;
+       this->view_win = 0;    this->vicon = 0;
+       this->viewing = 0;     this->solo = 0;
        this->draw_x0 = 0;     this->draw_x1 = wdw->get_w();
        this->draw_y0 = 0;     this->draw_y1 = wdw->get_h();
        draw_lock = new Condition(0, "VIconThread::draw_lock", 1);
        timer = new Timer();
        this->refresh_rate = VICON_RATE;
+       this->draw_flash = 0;
+       this->seq_no = 0;
+       this->now = 0;
        done = 0;
        interrupted = -1;
        stop_age = 0;
@@ -179,9 +204,9 @@ bool VIconThread::
 visible(VIcon *vicon, int x, int y)
 {
        if( vicon->hidden ) return false;
-       if( y+vicon->vh <= draw_y0 ) return false;
+       if( y+vicon->h <= draw_y0 ) return false;
        if( y >= draw_y1 ) return false;
-       if( x+vicon->vw <= draw_x0 ) return false;
+       if( x+vicon->w <= draw_x0 ) return false;
        if( x >= draw_x1 ) return false;
        return true;
 }
@@ -193,7 +218,7 @@ int ViewPopup::keypress_event()
 }
 
 
-ViewPopup::ViewPopup(VIconThread *vt, VFrame *frame, int x, int y, int w, int h)
+ViewPopup::ViewPopup(VIconThread *vt, int x, int y, int w, int h)
  : BC_Popup(vt->wdw, x, y, w, h, BLACK)
 {
        this->vt = vt;
@@ -204,7 +229,7 @@ ViewPopup::~ViewPopup()
        vt->wdw->set_active_subwindow(0);
 }
 
-ViewPopup *VIconThread::new_view_window(VFrame *frame)
+ViewPopup *VIconThread::new_view_window(ViewPopup *vpopup)
 {
        BC_WindowBase *parent = wdw->get_parent();
        XineramaScreenInfo *info = parent->get_xinerama_info(-1);
@@ -213,21 +238,14 @@ ViewPopup *VIconThread::new_view_window(VFrame *frame)
        int vx = viewing->get_vx(), rx = 0;
        int vy = viewing->get_vy(), ry = 0;
        wdw->get_root_coordinates(vx, vy, &rx, &ry);
-       rx += (rx >= cx ? -view_w : viewing->vw);
-       ry += (ry >= cy ? -view_h : viewing->vh);
-       ViewPopup *vwin = new ViewPopup(this, frame, rx, ry, view_w, view_h);
-       wdw->set_active_subwindow(vwin);
-       return vwin;
-}
-
-int ViewPopup::zoom_scale(int dir)
-{
-       int view_h = vt->view_h + dir*vt->view_h/10 + dir;
-       bclamp(view_h, 16,512);
-       vt->view_h = view_h;
-       vt->view_w = view_h * vt->vw/vt->vh;
-       vt->stop_viewing();
-       return 1;
+       rx += (rx >= cx ? -view_w+viewing->w/4 : viewing->w-viewing->w/4);
+       ry += (ry >= cy ? -view_h+viewing->h/4 : viewing->h-viewing->h/4);
+       if( vpopup )
+               vpopup->reposition_window(rx, ry, view_w, view_h);
+       else
+               vpopup = new ViewPopup(this, rx, ry, view_w, view_h);
+       wdw->set_active_subwindow(vpopup);
+       return vpopup;
 }
 
 
@@ -265,7 +283,10 @@ void ViewPopup::draw_vframe(VFrame *frame)
 
 void VIconThread::set_view_popup(VIcon *vicon)
 {
+       if( viewing == vicon && !this->vicon ) return;
        this->vicon = vicon;
+       if( interrupted ) update_view(vicon ? 1 : 0);
+
 }
 
 void VIconThread::close_view_popup()
@@ -274,20 +295,37 @@ void VIconThread::close_view_popup()
 }
 
 int VIconThread::
-update_view()
+update_view(int do_audio)
 {
        if( viewing ) viewing->stop_audio();
        delete view_win;  view_win = 0;
-       if( (viewing=vicon) != 0 ) {
-               VFrame *frame = viewing->frame();
-               view_win = new_view_window(frame);
+       VFrame *vfrm;
+       if( (viewing=vicon) != 0 && (vfrm=viewing->frame()) != 0 ) {
+               view_win = new_view_window(0);
+               view_win->draw_vframe(vfrm);
+               view_win->flash(0);
                view_win->show_window();
-               vicon->start_audio();
+               if( do_audio ) vicon->start_audio();
        }
        wdw->set_active_subwindow(view_win);
        return 1;
 }
 
+int VIconThread::zoom_scale(int dir)
+{
+       VFrame *vfrm;
+       if( !viewing || !view_win || !(vfrm=viewing->frame()) ) return 0;
+       int view_h = this->view_h;
+       view_h += dir*view_h/10 + dir;
+       bclamp(view_h, 16,512);
+       this->view_h = view_h;
+       this->view_w = view_h * vw/vh;
+       new_view_window(view_win);
+       view_win->draw_vframe(vfrm);
+       view_win->flash(1);
+       return 1;
+}
+
 
 void VIconThread::
 draw_images()
@@ -312,13 +350,14 @@ draw(VIcon *vicon)
        int draw_img = visible(vicon, x, y);
        int draw_win = view_win && viewing == vicon ? 1 : 0;
        if( !draw_img && !draw_win ) return 0;
-       if( !vicon->frame() ) return 0;
+       VFrame *vfrm = vicon->frame();
+       if( !vfrm ) return 0;
        if( draw_img ) {
                vicon->draw_vframe(this, wdw, x, y);
                img_dirty = 1;
        }
        if( draw_win ) {
-               view_win->draw_vframe(vicon->frame());
+               view_win->draw_vframe(vfrm);
                win_dirty = 1;
        }
        return 1;
@@ -332,6 +371,26 @@ void VIconThread::hide_vicons(int v)
        }
 }
 
+int VIconThread::show_vicon(VIcon *next)
+{
+       now = timer->get_difference();
+       if( now >= draw_flash ) return 1;
+       draw(next);
+       if( !next->seq_no ) {
+               next->cycle_start = now;
+               if( next->playing_audio > 0 )
+                       next->start_audio();
+       }
+       int64_t ref_no = (now - next->cycle_start) / 1000. * refresh_rate;
+       int count = ref_no - next->seq_no;
+       if( count < 1 ) count = 1;
+       ref_no = next->seq_no + count;
+       next->age =  next->cycle_start + 1000. * ref_no / refresh_rate;
+       if( !next->set_seq_no(ref_no) )
+               next->age = now + 1000.;
+       return 0;
+}
+
 void VIconThread::
 run()
 {
@@ -341,35 +400,25 @@ run()
                wdw->lock_window("BC_WindowBase::run 1");
                drawing_started();
                reset_images();
-               int64_t seq_no = 0, now = 0;
-               int64_t draw_flash = 1000 / refresh_rate;
+               draw_flash = 1000 / refresh_rate;
+               seq_no = 0;  now = 0;
                while( !interrupted ) {
                        if( viewing != vicon )
-                               update_view();
-                       VIcon *next = low_vicon();
-                       while( next && next->age < draw_flash ) {
-                               now = timer->get_difference();
-                               if( now >= draw_flash ) break;
-                               draw(next);
-                               if( !next->seq_no ) {
-                                       next->cycle_start = now;
-                                       if( next->playing_audio > 0 )
-                                               next->start_audio();
+                               update_view(1);
+                       if( !solo ) {
+                               VIcon *next = low_vicon();
+                               while( !interrupted && next && next->age < draw_flash ) {
+                                       if( show_vicon(next) ) break;
+                                       add_vicon(next);
+                                       next = low_vicon();
                                }
-                               int64_t ref_no = (now - next->cycle_start) / 1000. * refresh_rate;
-                               int count = ref_no - next->seq_no;
-                               if( count < 1 ) count = 1;
-                               ref_no = next->seq_no + count;
-                               next->age =  next->cycle_start + 1000. * ref_no / refresh_rate;
-                               if( !next->set_seq_no(ref_no) )
-                                       next->age = now + 1000.;
+                               if( !next ) break;
                                add_vicon(next);
-                               next = low_vicon();
+                               if( draw_flash < now+1 )
+                                       draw_flash = now+1;
                        }
-                       if( !next ) break;
-                       add_vicon(next);
-                       if( draw_flash < now+1 )
-                               draw_flash = now+1;
+                       else
+                               show_vicon(solo);
                        wdw->unlock_window();
                        while( !interrupted ) {
                                now = timer->get_difference();
@@ -389,7 +438,7 @@ run()
                        draw_flash = seq_no * 1000. / refresh_rate;
                }
                if( viewing != vicon )
-                       update_view();
+                       update_view(1);
                drawing_stopped();
                interrupted = -1;
                wdw->unlock_window();
@@ -408,10 +457,11 @@ void VIcon::dump(const char *dir)
 {
        mkdir(dir,0777);
        for( int i=0; i<images.size(); ++i ) {
+               VFrame *vfrm = images[i]->vfrm;
+               if( !vfrm ) continue;
                char fn[1024];  sprintf(fn,"%s/img%05d.png",dir,i);
                printf("\r%s",fn);
-               VFrame *img = *images[i];
-               img->write_png(fn);
+               vfrm->write_png(fn);
        }
        printf("\n");
 }