$ git clone http://tcclient.ion.nu/tc_client.git
commit 18c46c3e71ccce5d531166b3a2e892bbe5df933e
Author: Alicia <...>
Date:   Wed Sep 21 19:39:54 2016 +0200

    tc_client-gtk: merged camera_remove() and camera_removebynick() into a single function, merged the deallocation of camera data into camera_free()

diff --git a/ChangeLog b/ChangeLog
index b2fcada..e01e13d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,5 @@
+0.40:
+tc_client-gtk: merged camera_remove() and camera_removebynick() into a single function, merged the deallocation of camera data into camera_free()
 0.39:
 Added a /closecam command to stop receiving a cam stream.
 Use uintX_t for endianness functions instead of unsigned long*x int.
diff --git a/Makefile b/Makefile
index baa4d10..8e38889 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.39
+VERSION=0.40pre
 CFLAGS=-g3 -Wall $(shell curl-config --cflags)
 LDFLAGS=-g3
 PREFIX=/usr/local
diff --git a/utilities/gtk/camviewer.c b/utilities/gtk/camviewer.c
index 18f8e56..58167bc 100644
--- a/utilities/gtk/camviewer.c
+++ b/utilities/gtk/camviewer.c
@@ -442,7 +442,7 @@ gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer data
       {
         space[0]=0;
         removeuser(nick);
-        camera_removebynick(nick);
+        camera_remove(nick, 1);
       }
       else if(!strncmp(space, " changed nickname to ", 21))
       {
@@ -517,7 +517,7 @@ gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer data
     char* idend=strchr(id, ')');
     if(!idend){return 1;}
     idend[0]=0;
-    camera_removebynick(nick); // Remove any duplicates
+    camera_remove(nick, 1); // Remove any duplicates
     struct camera* cam=camera_new(nick, id);
     cam->placeholder=g_timeout_add(100, camplaceholder_update, cam->id);
     cam->vctx=avcodec_alloc_context3(data->vdecoder);
@@ -553,7 +553,7 @@ gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer data
   }
   if(!strncmp(buf, "VideoEnd: ", 10))
   {
-    camera_remove(&buf[10]);
+    camera_remove(&buf[10], 0);
     return 1;
   }
   if(!strncmp(buf, "Room topic: ", 12) ||
diff --git a/utilities/gtk/gui.c b/utilities/gtk/gui.c
index 136c846..836fa0a 100644
--- a/utilities/gtk/gui.c
+++ b/utilities/gtk/gui.c
@@ -550,5 +550,5 @@ void gui_hide_cam(GtkMenuItem* menuitem, void* x)
   struct camera* cam=camera_find(menu_context_cam);
   if(!cam){return;}
   dprintf(tc_client_in[1], "/closecam %s\n", cam->nick);
-  camera_remove(menu_context_cam);
+  camera_remove(menu_context_cam, 0);
 }
diff --git a/utilities/gtk/media.c b/utilities/gtk/media.c
index 4076382..6ba2304 100644
--- a/utilities/gtk/media.c
+++ b/utilities/gtk/media.c
@@ -87,48 +87,30 @@ void camera_playsnd(int audiopipe, struct camera* cam, short* samples, unsigned
 }
 #endif
 
-void camera_remove(const char* id)
+void camera_free(struct camera* cam)
 {
-  unsigned int i;
-  for(i=0; i<camcount; ++i)
-  {
-    if(!strcmp(cams[i].id, id))
-    {
-      if(cams[i].placeholder) // Remove the placeholder animation if it has it
-      {
-        g_source_remove(cams[i].placeholder);
-      }
-      gtk_widget_destroy(cams[i].box);
-      av_frame_free(&cams[i].frame);
-      avcodec_free_context(&cams[i].vctx);
+  if(cam->placeholder){g_source_remove(cam->placeholder);}
+  av_frame_free(&cam->frame);
+  avcodec_free_context(&cam->vctx);
 #if defined(HAVE_AVRESAMPLE) || defined(HAVE_SWRESAMPLE)
-      avcodec_free_context(&cams[i].actx);
+  avcodec_free_context(&cam->actx);
 #endif
-      free(cams[i].id);
-      free(cams[i].nick);
-      --camcount;
-      memmove(&cams[i], &cams[i+1], (camcount-i)*sizeof(struct camera));
-      break;
-    }
-  }
-  updatescaling(0, 0, 1);
+  free(cam->id);
+  free(cam->nick);
+
+  if(cam->postproc.greenscreen){img_free(cam->postproc.greenscreen);}
+  free((void*)cam->postproc.greenscreen_filename);
 }
 
-void camera_removebynick(const char* nick)
+void camera_remove(const char* id, char isnick)
 {
   unsigned int i;
   for(i=0; i<camcount; ++i)
   {
-    if(!strcmp(cams[i].nick, nick))
+    if(!strcmp(isnick?cams[i].nick:cams[i].id, id))
     {
       gtk_widget_destroy(cams[i].box);
-      av_frame_free(&cams[i].frame);
-      avcodec_free_context(&cams[i].vctx);
-#if defined(HAVE_AVRESAMPLE) || defined(HAVE_SWRESAMPLE)
-      avcodec_free_context(&cams[i].actx);
-#endif
-      free(cams[i].id);
-      free(cams[i].nick);
+      camera_free(&cams[i]);
       --camcount;
       memmove(&cams[i], &cams[i+1], (camcount-i)*sizeof(struct camera));
       break;
@@ -195,13 +177,7 @@ void camera_cleanup(void)
   unsigned int i;
   for(i=0; i<camcount; ++i)
   {
-    av_frame_free(&cams[i].frame);
-    avcodec_free_context(&cams[i].vctx);
-#if defined(HAVE_AVRESAMPLE) || defined(HAVE_SWRESAMPLE)
-    avcodec_free_context(&cams[i].actx);
-#endif
-    free(cams[i].id);
-    free(cams[i].nick);
+    camera_free(&cams[i]);
   }
   free(cams);
 }
diff --git a/utilities/gtk/media.h b/utilities/gtk/media.h
index b61eaaf..15ad786 100644
--- a/utilities/gtk/media.h
+++ b/utilities/gtk/media.h
@@ -61,8 +61,7 @@ extern GdkPixbufAnimationIter* camplaceholder_iter;
 #if defined(HAVE_AVRESAMPLE) || defined(HAVE_SWRESAMPLE)
 extern void camera_playsnd(int audiopipe, struct camera* cam, short* samples, unsigned int samplecount);
 #endif
-extern void camera_remove(const char* nick);
-extern void camera_removebynick(const char* nick);
+extern void camera_remove(const char* id, char isnick);
 extern struct camera* camera_find(const char* id);
 extern struct camera* camera_findbynick(const char* nick);
 extern struct camera* camera_new(const char* nick, const char* id);