Beispiel #1
0
boolean lives_yuv_stream_start_write(lives_yuv4m_t *yuv4mpeg, const char *filename, int hsize, int vsize, double fps) {
  int i;

  if (mainw->fixed_fpsd>-1.&&mainw->fixed_fpsd!=fps) {
    do_error_dialog(lives_strdup_printf(_("Unable to set display framerate to %.3f fps.\n\n"),fps));
    return FALSE;
  }
  mainw->fixed_fpsd=fps;

  if (filename==NULL) filename=lives_strdup_printf("%s/streamout.yuv",prefs->tmpdir);

  // TODO - do_threaded_dialog
  if ((yuvout=creat(filename,O_CREAT))<0) {
    do_error_dialog(lives_strdup_printf(_("Unable to open yuv4mpeg out stream %s\n"),filename));
    return FALSE;
  }

  if (mainw->fixed_fpsd>23.9999&&mainw->fixed_fpsd<24.0001) {
    y4m_si_set_framerate(&(yuv4mpeg->streaminfo),y4m_fps_FILM);
  } else return FALSE;
  y4m_si_set_interlace(&(yuv4mpeg->streaminfo), Y4M_ILACE_NONE);

  y4m_si_set_width(&(yuv4mpeg->streaminfo), (hsize_out=hsize));
  y4m_si_set_height(&(yuv4mpeg->streaminfo), (vsize_out=vsize));
  y4m_si_set_sampleaspect(&(yuv4mpeg->streaminfo), yuv4mpeg->sar);

  i = y4m_write_stream_header(yuvout, &(yuv4mpeg->streaminfo));

  if (i != Y4M_OK) return FALSE;

  return TRUE;
}
Beispiel #2
0
void del_frame_index(lives_clip_t *sfile) {
  // physically delete the frame_index for a clip
  // only done once all

  char *idxfile;
  char *com;

  register int i;

  // cannot call check_if_non_virtual() else we end up recursing

  if (sfile->frame_index!=NULL) {
    for (i=1; i<=sfile->frames; i++) {
      if (sfile->frame_index[i-1]!=-1) {
        LIVES_ERROR("deleting frame_index with virtual frames in it !");
        return;
      }
    }
  }

  if (sfile!=clipboard) {
    idxfile=lives_build_filename(prefs->tmpdir,sfile->handle,"file_index",NULL);

#ifndef IS_MINGW
    com=lives_strdup_printf("/bin/rm -f \"%s\"",idxfile);
#else
    com=lives_strdup_printf("rm.exe -f \"%s\"",idxfile);
#endif

    lives_system(com,FALSE);
    lives_free(com);

    lives_free(idxfile);
  }

  if (sfile->frame_index!=NULL) lives_free(sfile->frame_index);
  sfile->frame_index=NULL;
}
Beispiel #3
0
void clean_images_from_virtual(lives_clip_t *sfile, int oldframes) {
  // remove images on disk where the frame_index points to a frame in
  // the original clip

  // only needed if frames were reordered when rendered and the process is
  // then undone

  // in future, a smarter function could trace the images back to their
  // original source frames, and just rename them


  // should be threadsafe

  register int i;
  char *iname=NULL,*com;

  if (sfile==NULL||sfile->frame_index==NULL) return;

  for (i=0; i<oldframes; i++) {
    threaded_dialog_spin();
    lives_widget_context_update();
    threaded_dialog_spin();

    if ((i<sfile->frames&&sfile->frame_index[i]!=-1)||i>=sfile->frames) {
      iname=lives_strdup_printf("%s/%s/%08d.%s",prefs->tmpdir,sfile->handle,i,get_image_ext_for_type(sfile->img_type));

#ifndef IS_MINGW
      com=lives_strdup_printf("/bin/rm -f \"%s\"",iname);
#else
      com=lives_strdup_printf("rm.exe -f \"%s\"",iname);
#endif
      lives_system(com,FALSE);
      lives_free(com);
    }
  }
}
Beispiel #4
0
static void start_preview(LiVESButton *button, lives_rfx_t *rfx) {
  int i;
  char *com;

  lives_widget_set_sensitive(mainw->framedraw_preview,FALSE);
  lives_widget_context_update();

  if (mainw->did_rfx_preview) {
    lives_kill_subprocesses(cfile->handle,TRUE);

    if (cfile->start==0) {
      cfile->start=1;
      cfile->end=cfile->frames;
    }

    do_rfx_cleanup(rfx);
  }

  com=lives_strdup_printf("%s clear_pre_files \"%s\" 2>%s",prefs->backend_sync,cfile->handle,LIVES_DEVNULL);
  lives_system(com,TRUE); // clear any .pre files from before

  for (i=0; i<rfx->num_params; i++) {
    rfx->params[i].changed=FALSE;
  }

  mainw->cancelled=CANCEL_NONE;
  mainw->error=FALSE;

  // within do_effect() we check and if
  do_effect(rfx,TRUE); // actually start effect processing in the background

  lives_widget_set_sensitive(mainw->framedraw_spinbutton,TRUE);
  lives_widget_set_sensitive(mainw->framedraw_scale,TRUE);

  if (mainw->framedraw_frame>cfile->start&&!(cfile->start==0&&mainw->framedraw_frame==1))
    lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->framedraw_spinbutton),cfile->start);
  else {
    load_rfx_preview(rfx);
  }

  mainw->did_rfx_preview=TRUE;
}
Beispiel #5
0
boolean virtual_to_images(int sfileno, int sframe, int eframe, boolean update_progress, LiVESPixbuf **pbr) {
  // pull frames from a clip to images
  // from sframe to eframe inclusive (first frame is 1)

  // if update_progress, set mainw->msg with number of frames pulled

  // should be threadsafe apart from progress update

  // if pbr is non-null, it will be set to point to the pulled pixbuf (

  // return FALSE on write error

  register int i;
  lives_clip_t *sfile=mainw->files[sfileno];
  LiVESPixbuf *pixbuf=NULL;
  LiVESError *error=NULL;
  char *oname;
  int retval;

  int progress=1;

  if (sframe<1) sframe=1;

  for (i=sframe; i<=eframe; i++) {
    if (i>sfile->frames) break;

    if (sfile->frame_index[i-1]>=0) {
      oname=NULL;

      if (update_progress) {
        threaded_dialog_spin();
        lives_widget_context_update();
      }

      if (pbr!=NULL&&pixbuf!=NULL) lives_object_unref(pixbuf);

      pixbuf=pull_lives_pixbuf_at_size(sfileno,i,get_image_ext_for_type(sfile->img_type),
                                       q_gint64((i-1.)/sfile->fps,sfile->fps),sfile->hsize,sfile->vsize,LIVES_INTERP_BEST);

      oname=lives_strdup_printf("%s/%s/%08d.%s",prefs->tmpdir,sfile->handle,i,get_image_ext_for_type(sfile->img_type));

      do {
        retval=0;
        lives_pixbuf_save(pixbuf, oname, sfile->img_type, 100-prefs->ocp, TRUE, &error);
        if (error!=NULL&&pbr==NULL) {
          retval=do_write_failed_error_s_with_retry(oname,error->message,NULL);
          lives_error_free(error);
          error=NULL;
        }
      } while (retval==LIVES_RESPONSE_RETRY);

      if (oname!=NULL) lives_free(oname);

      if (pbr==NULL) {
        if (pixbuf!=NULL) lives_object_unref(pixbuf);
        pixbuf=NULL;
      }

      if (retval==LIVES_RESPONSE_CANCEL) return FALSE;


      // another thread may have called check_if_non_virtual - TODO : use a mutex
      if (sfile->frame_index==NULL) break;
      sfile->frame_index[i-1]=-1;

      if (update_progress) {
        // sig_progress...
        lives_snprintf(mainw->msg,256,"%d",progress++);
        threaded_dialog_spin();
        lives_widget_context_update();
      }

      if (mainw->cancelled!=CANCEL_NONE) {
        if (!check_if_non_virtual(sfileno,1,sfile->frames)) save_frame_index(sfileno);
        if (pbr!=NULL) *pbr=pixbuf;
        return TRUE;
      }
    }
  }

  if (pbr!=NULL) *pbr=pixbuf;

  if (!check_if_non_virtual(sfileno,1,sfile->frames)) if (!save_frame_index(sfileno)) return FALSE;

  return TRUE;
}
Beispiel #6
0
boolean check_clip_integrity(int fileno, const lives_clip_data_t *cdata) {
  lives_clip_t *sfile=mainw->files[fileno];

  lives_image_type_t empirical_img_type=sfile->img_type;

  int first_real_frame=0;

  register int i;

  // check clip integrity upon loading

  // check that cached values match with sfile (on disk) values
  // TODO: also check sfile->frame_index to make sure all frames are present


  // return FALSE if we find any omissions/inconsistencies


  // check the image type
  for (i=0; i<sfile->frames; i++) {
    if (sfile->frame_index[i]==-1) {
      // this is a non-virtual frame
      char *frame=lives_strdup_printf("%s/%s/%08d.png",prefs->tmpdir,sfile->handle,i+1);
      if (lives_file_test(frame,LIVES_FILE_TEST_EXISTS)) empirical_img_type=IMG_TYPE_PNG;
      else empirical_img_type=IMG_TYPE_JPEG;
      lives_free(frame);
      first_real_frame=i+1;
      break;
    }
  }

  // TODO *** check frame count

  if (sfile->frames>0&&(sfile->hsize*sfile->vsize==0)) {
    if (first_real_frame>0) {
      sfile->img_type=empirical_img_type;
      get_frames_sizes(fileno,first_real_frame);
    } else {
      if (!prefs->auto_nobord) {
        sfile->hsize=cdata->frame_width*weed_palette_get_pixels_per_macropixel(cdata->current_palette);
        sfile->vsize=cdata->frame_height;
      } else {
        sfile->hsize=cdata->width*weed_palette_get_pixels_per_macropixel(cdata->current_palette);
        sfile->vsize=cdata->height;
      }
    }
    goto mismatch;
  }

  if (sfile->fps!=cdata->fps) goto mismatch;

  if (sfile->img_type!=empirical_img_type) sfile->img_type=empirical_img_type;

  // and all else are equal
  return TRUE;

mismatch:
  // something mismatched - trust the disk version
  ((lives_clip_data_t *)cdata)->fps=sfile->pb_fps=sfile->fps;

  sfile->img_type=empirical_img_type;

  return FALSE;
}
Beispiel #7
0
void on_live_fw_activate(LiVESMenuItem *menuitem, livespointer user_data) {

  char *com,*tmp;
  int cardno;
  int cache=1024;

  int new_file=mainw->first_free_file;

  int response;

  char *fifofile=lives_strdup_printf("%s/firew.%d",prefs->tmpdir,capable->mainpid);
  char *fname;

  LiVESWidget *card_dialog;

  mainw->open_deint=FALSE;

  card_dialog=create_cdtrack_dialog(5,NULL);
  response=lives_dialog_run(LIVES_DIALOG(card_dialog));
  if (response==LIVES_RESPONSE_CANCEL) {
    lives_widget_destroy(card_dialog);
    lives_free(fifofile);
    return;
  }

  cardno=(int)mainw->fx1_val;

  lives_widget_destroy(card_dialog);

  if (lives_list_find(fw_cards,LIVES_INT_TO_POINTER(cardno))) {
    lives_free(fifofile);
    do_card_in_use_error();
    return;
  }

  fname=lives_strdup_printf(_("Firewire card %d"),cardno);

  if (!get_new_handle(new_file,fname)) {
    lives_free(fifofile);
    lives_free(fname);
    return;
  }

  fw_cards=lives_list_append(fw_cards,LIVES_INT_TO_POINTER(cardno));

  mainw->current_file=new_file;
  cfile->deinterlace=mainw->open_deint;

  unlink(fifofile);
  mkfifo(fifofile,S_IRUSR|S_IWUSR);

  com=lives_strdup_printf("%s open_fw_card \"%s\" %d %d \"%s\"",prefs->backend,cfile->handle,cardno,cache,fifofile);
  mainw->com_failed=FALSE;
  lives_system(com,FALSE);
  lives_free(com);

  if (mainw->com_failed) {
    mainw->com_failed=FALSE;
    lives_free(fname);
    lives_free(fifofile);
    return;
  }

  if (!open_yuv4m_inner(fifofile,fname,new_file,YUV4_TYPE_FW,cardno)) {
    lives_free(fname);
    lives_free(fifofile);
    return;
  }

  lives_snprintf(cfile->type,40,"%s",fname);

  d_print((tmp=lives_strdup_printf(_("Opened firewire card %d"),cardno)));

  lives_free(tmp);
  lives_free(fname);
  lives_free(fifofile);

}
Beispiel #8
0
void on_live_tvcard_activate(LiVESMenuItem *menuitem, livespointer user_data) {
  int cardno=0;

  int new_file=mainw->first_free_file;

  int response;

  char *com,*tmp;
  char *fifofile=lives_strdup_printf("%s/tvpic.%d",prefs->tmpdir,capable->mainpid);

  char *chanstr;
  char *devstr;

  char *fname;

  LiVESWidget *card_dialog;

  lives_tvcardw_t *tvcardw;

  mainw->open_deint=FALSE;

  card_dialog=create_cdtrack_dialog(4,NULL);

  tvcardw=(lives_tvcardw_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(card_dialog),"tvcard_data");


  response=lives_dialog_run(LIVES_DIALOG(card_dialog));
  if (response==LIVES_RESPONSE_CANCEL) {
    lives_widget_destroy(card_dialog);
    lives_free(fifofile);
    lives_free(tvcardw);
    return;
  }

  cardno=(int)mainw->fx1_val;
  chanstr=lives_strdup_printf("%d",(int)mainw->fx2_val);

  if (lives_list_find(mainw->videodevs,LIVES_INT_TO_POINTER(cardno))) {
    lives_widget_destroy(card_dialog);
    do_card_in_use_error();
    lives_free(chanstr);
    lives_free(fifofile);
    lives_free(tvcardw);
    return;
  }

  fname=lives_strdup_printf(_("TV card %d"),cardno);

  if (!get_new_handle(new_file,fname)) {
    lives_widget_destroy(card_dialog);
    lives_free(chanstr);
    lives_free(fifofile);
    lives_free(fname);
    lives_free(tvcardw);
    return;
  }

  devstr=lives_strdup_printf("/dev/video%d",cardno);

  if (!check_dev_busy(devstr)) {
    lives_widget_destroy(card_dialog);
    do_dev_busy_error(fname);
    lives_free(devstr);
    lives_free(chanstr);
    lives_free(fifofile);
    lives_free(fname);
    lives_free(tvcardw);
    return;
  }

  mainw->videodevs=lives_list_append(mainw->videodevs,LIVES_INT_TO_POINTER(cardno));

  mainw->current_file=new_file;

  cfile->deinterlace=mainw->open_deint;

  unlink(fifofile);
  mkfifo(fifofile,S_IRUSR|S_IWUSR);

  if (!tvcardw->use_advanced) {
    com=lives_strdup_printf("%s open_tv_card \"%s\" \"%s\" \"%s\" \"%s\"",prefs->backend,cfile->handle,chanstr,
                            devstr,fifofile);
  } else {
    double fps=0.;
    char *driver=NULL,*outfmt=NULL;
    int width=0,height=0;
    int input=lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(tvcardw->spinbuttoni));

    if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(tvcardw->radiobuttond))) {
      width=lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(tvcardw->spinbuttonw));
      height=lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(tvcardw->spinbuttonh));
      fps=lives_spin_button_get_value(LIVES_SPIN_BUTTON(tvcardw->spinbuttonf));
    }

    driver=lives_combo_get_active_text(LIVES_COMBO(tvcardw->combod));
    outfmt=lives_combo_get_active_text(LIVES_COMBO(tvcardw->comboo));

    com=lives_strdup_printf("%s open_tv_card \"%s\" \"%s\" \"%s\" \"%s\" %d %d %d %.3f \"%s\" \"%s\"",
                            prefs->backend,cfile->handle,chanstr,
                            devstr,fifofile,input,width,height,fps,driver,outfmt);
    lives_free(driver);
    lives_free(outfmt);

  }
  lives_widget_destroy(card_dialog);
  lives_free(tvcardw);

  mainw->com_failed=FALSE;
  lives_system(com,FALSE);
  lives_free(com);

  if (mainw->com_failed) {
    mainw->com_failed=FALSE;
    lives_free(fname);
    lives_free(chanstr);
    lives_free(fifofile);
    lives_free(devstr);
    return;
  }

  if (!open_yuv4m_inner(fifofile,fname,new_file,YUV4_TYPE_TV,cardno)) {
    lives_free(fname);
    lives_free(chanstr);
    lives_free(fifofile);
    lives_free(devstr);
    return;
  }

  lives_snprintf(cfile->type,40,"%s",fname);

  d_print((tmp=lives_strdup_printf(_("Opened TV card %d (%s)"),cardno,devstr)));

  lives_free(tmp);
  lives_free(fname);
  lives_free(chanstr);
  lives_free(devstr);
  lives_free(fifofile);

}
Beispiel #9
0
void on_open_yuv4m_activate(LiVESMenuItem *menuitem, livespointer user_data) {
  // open a general yuvmpeg stream
  // start "playing" but open frames in yuv4mpeg format on stdin

  int old_file=mainw->current_file,new_file=mainw->first_free_file;
  char *tmp;
  char *filename;
  char *fname;

  char *audio_real,*audio_fake;

  if (menuitem && !do_yuv4m_open_warning()) return;

  fname=lives_strdup(_("yuv4mpeg stream"));

  if (!get_new_handle(new_file,fname)) {
    lives_free(fname);
    return;
  }

  mainw->current_file=new_file;

  if (!strlen(prefs->yuvin))
    filename=lives_build_filename(prefs->tmpdir,"stream.yuv",NULL);
  else
    filename=lives_strdup(prefs->yuvin);

  mkfifo(filename,S_IRUSR|S_IWUSR);

  if (!open_yuv4m_inner(filename,fname,new_file,YUV4_TYPE_GENERIC,0)) {
    close_current_file(old_file);
    lives_free(filename);
    lives_free(fname);
    return;
  }

  lives_free(fname);

  if (!lives_yuv_stream_start_read(cfile)) {
    close_current_file(old_file);
    lives_free(filename);
    return;
  }

  new_file=mainw->current_file;

  lives_snprintf(cfile->type,40,"%s",_("yu4mpeg stream in"));

  d_print((tmp=lives_strdup_printf(_("Opened yuv4mpeg stream on %s"),filename)));
  lives_free(tmp);
  lives_free(filename);

  d_print(_("Audio: "));

  if (cfile->achans==0) {
    d_print(_("none\n"));
  } else {
    d_print((tmp=lives_strdup_printf(P_("%d Hz %d channel %d bps\n","%d Hz %d channels %d bps\n",cfile->achans),
                                     cfile->arate,cfile->achans,cfile->asampsize)));
    lives_free(tmp);
  }

  // if not playing, start playing
  if (mainw->playing_file==-1) {

    // temp kludge, symlink audiodump.pcm to wav file, then pretend we are playing
    // an opening preview . Doesn't work with fifo.
    // and we dont really care if it doesnt work

    // but what it means is, if we have an audio file or stream at
    // "prefs->tmpdir/audiodump.pcm" we will try to play it



    // real is tmpdir/audiodump.pcm
    audio_real=lives_build_filename(prefs->tmpdir,"audiodump.pcm",NULL);
    // fake is tmpdir/handle/audiodump.pcm
    audio_fake=lives_build_filename(prefs->tmpdir,cfile->handle,"audiodump.pcm",NULL);


#ifndef IS_MINGW
    // fake file will go away when we close the current clip
    lives_system((tmp=lives_strdup_printf("/bin/ln -s \"%s\" \"%s\" >/dev/null 2>&1",
                                          audio_real,audio_fake)),TRUE);
#else
    // TODO
#endif

    lives_free(audio_real);
    lives_free(audio_fake);

    lives_free(tmp);

    // start playing
    play_file();

    mainw->noswitch=FALSE;
  }
  // TODO - else...

  if (mainw->current_file!=old_file&&mainw->current_file!=new_file)
    old_file=mainw->current_file; // we could have rendered to a new file

  mainw->current_file=new_file;

  // close this temporary clip
  close_current_file(old_file);

}
Beispiel #10
0
static boolean lives_yuv_stream_start_read(lives_clip_t *sfile) {
  double ofps=sfile->fps;

  lives_yuv4m_t *yuv4mpeg=(lives_yuv4m_t *)sfile->ext_src;

  pthread_t y4thread;

  char *filename=yuv4mpeg->filename,*tmp;

  int alarm_handle=0;

  int ohsize=sfile->hsize;
  int ovsize=sfile->vsize;

  y4data thread_data;

  register int i;


  if (filename==NULL) return FALSE;

  if (yuv4mpeg->fd==-1) {
    // create a thread to open the fifo

    thread_data.filename=filename;

    pthread_create(&y4thread,NULL,y4open_thread,(void *)&thread_data);

    alarm_handle=lives_alarm_set(YUV4_O_TIME);

    d_print("");
    d_print(_("Waiting for yuv4mpeg frames..."));

    while (!lives_alarm_get(alarm_handle)&&!pthread_kill(y4thread,0)) {
      // wait for thread to complete or timeout
      lives_usleep(prefs->sleep_time);
      lives_widget_context_update();
    }

    if (lives_alarm_get(alarm_handle)) {
      // timeout - kill thread and wait for it to terminate
      pthread_cancel(y4thread);
      pthread_join(y4thread,NULL);
      lives_alarm_clear(alarm_handle);

      d_print_failed();
      d_print(_("Unable to open the incoming video stream\n"));

      yuv4mpeg->fd=thread_data.fd;

      if (yuv4mpeg->fd>=0) {
        close(yuv4mpeg->fd);
        yuv4mpeg->fd=-1;
      }

      return FALSE;
    }

    pthread_join(y4thread,NULL);
    lives_alarm_clear(alarm_handle);

    yuv4mpeg->fd=thread_data.fd;

    if (yuv4mpeg->fd<0) {
      return FALSE;
    }
  }

  // create a thread to open the stream header
  thread_data.yuv4mpeg=yuv4mpeg;
  pthread_create(&y4thread,NULL,y4header_thread,&thread_data);
  alarm_handle=lives_alarm_set(YUV4_H_TIME);

  while (!lives_alarm_get(alarm_handle)&&!pthread_kill(y4thread,0)) {
    // wait for thread to complete or timeout
    lives_usleep(prefs->sleep_time);
    lives_widget_context_update();
  }

  if (lives_alarm_get(alarm_handle)) {
    // timeout - kill thread and wait for it to terminate
    pthread_cancel(y4thread);
    pthread_join(y4thread,NULL);
    lives_alarm_clear(alarm_handle);
    d_print(_("Unable to read the stream header\n"));
    return FALSE;
  }

  pthread_join(y4thread,NULL);
  lives_alarm_clear(alarm_handle);

  i=thread_data.i;

  if (i != Y4M_OK) {
    char *tmp;
    d_print((tmp=lives_strdup_printf("yuv4mpeg: %s\n", y4m_strerr(i))));
    lives_free(tmp);
    return FALSE;
  }

  d_print(_("got header\n"));

  sfile->hsize = yuv4mpeg->hsize = y4m_si_get_width(&(yuv4mpeg->streaminfo));
  sfile->vsize = yuv4mpeg->vsize = y4m_si_get_height(&(yuv4mpeg->streaminfo));

  sfile->fps=cfile->pb_fps=lives_strtod(lives_strdup_printf("%.8f",Y4M_RATIO_DBL
                                        (y4m_si_get_framerate(&(yuv4mpeg->streaminfo)))),NULL);

  if (!(sfile->hsize*sfile->vsize)) {
    do_error_dialog(lives_strdup_printf(_("Video dimensions: %d x %d are invalid. Stream cannot be opened"),
                                        sfile->hsize,sfile->vsize));
    return FALSE;
  }

  if (sfile->hsize!=ohsize||sfile->vsize!=ovsize||sfile->fps!=ofps) {
    set_main_title(sfile->file_name,0);
  }

  d_print((tmp=lives_strdup_printf(_("Reset clip values for %s: size=%dx%d fps=%.3f\n"),yuv4mpeg->name,
                                   cfile->hsize,yuv4mpeg->vsize,cfile->bpp,cfile->fps)));
  lives_free(tmp);

  yuv4mpeg->ready=TRUE;

  return TRUE;
}
Beispiel #11
0
static void start_preview(LiVESButton *button, lives_rfx_t *rfx) {
  int i;
  char *com;

  lives_widget_set_sensitive(mainw->framedraw_preview,FALSE);
  lives_widget_context_update();

  if (mainw->did_rfx_preview) {
#ifndef IS_MINGW
    com=lives_strdup_printf("%s stopsubsub \"%s\" 2>/dev/null",prefs->backend_sync,cfile->handle);
    lives_system(com,TRUE); // try to stop any in-progress preview
#else
    // get pid from backend
    FILE *rfile;
    ssize_t rlen;
    char val[16];
    int pid;
    com=lives_strdup_printf("%s get_pid_for_handle \"%s\"",prefs->backend_sync,cfile->handle);
    rfile=popen(com,"r");
    rlen=fread(val,1,16,rfile);
    pclose(rfile);
    memset(val+rlen,0,1);
    pid=atoi(val);

    lives_win32_kill_subprocesses(pid,TRUE);
#endif
    lives_free(com);

    if (cfile->start==0) {
      cfile->start=1;
      cfile->end=cfile->frames;
    }

    do_rfx_cleanup(rfx);
  }

#ifndef IS_MINGW
  com=lives_strdup_printf("%s clear_pre_files \"%s\" 2>/dev/null",prefs->backend_sync,cfile->handle);
#else
  com=lives_strdup_printf("%s clear_pre_files \"%s\" 2>NUL",prefs->backend_sync,cfile->handle);
#endif
  lives_system(com,TRUE); // clear any .pre files from before

  for (i=0; i<rfx->num_params; i++) {
    rfx->params[i].changed=FALSE;
  }

  mainw->cancelled=CANCEL_NONE;
  mainw->error=FALSE;

  // within do_effect() we check and if
  do_effect(rfx,TRUE); // actually start effect processing in the background

  lives_widget_set_sensitive(mainw->framedraw_spinbutton,TRUE);
  lives_widget_set_sensitive(mainw->framedraw_scale,TRUE);

  if (mainw->framedraw_frame>cfile->start&&!(cfile->start==0&&mainw->framedraw_frame==1))
    lives_spin_button_set_value(LIVES_SPIN_BUTTON(mainw->framedraw_spinbutton),cfile->start);
  else {
    load_rfx_preview(rfx);
  }

  mainw->did_rfx_preview=TRUE;
}