$ git clone http://tcclient.ion.nu/tc_client.git
commit da5cc62be0d5a4a2e789e0178e7a5c9ac5345cce
Author: Alicia <...>
Date: Sun Sep 25 15:14:08 2016 +0200
tc_client-gtk: changed camera input for broadcasting from using a thread to using g_timeout.
diff --git a/ChangeLog b/ChangeLog
index 3ade7d4..4cd4e95 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@ tc_client-gtk: merged camera_remove() and camera_removebynick() into a single fu
tc_client-gtk: moved the postprocessing code into its own source file.
tc_client-gtk: added greenscreen postprocessor.
tc_client-gtk: added GTK+2 compatibility code related to the greenscreen postprocessor.
+tc_client-gtk: changed camera input for broadcasting from using a thread to using g_timeout.
tc_client-gtk and camviewer: updated to libavcodec's avcodec_{send,receive}_{frame,packet} API.
0.39:
Added a /closecam command to stop receiving a cam stream.
diff --git a/Makefile b/Makefile
index ac68cc2..d4c5f0e 100644
--- a/Makefile
+++ b/Makefile
@@ -52,7 +52,7 @@ ifdef SWSCALE_LIBS
else
CONFINFO+=| escapi windows camera support will not be enabled
endif
- windowstargets: camviewer tc_client-gtk tc_client-gtk-camthread
+ windowstargets: camviewer tc_client-gtk
@echo
@echo 'To build the core (tc_client.exe), enter this directory from cygwin (or MSYS2 non-MinGW shell) and type make'
endif
@@ -118,30 +118,12 @@ tc_client-gtk: $(TC_CLIENT_GTK_OBJ) camplaceholder.gif
camplaceholder.gif: utilities/gtk/gencamplaceholder.sh utilities/gtk/camplaceholder.xcf utilities/gtk/spinnerdot.xcf
utilities/gtk/gencamplaceholder.sh
-# Workaround for windows' lack of fork() and inflexibility of having or not having a terminal
-utilities/gtk/camthread.gen.c: utilities/gtk/media.c
- sed -n -e '/^ *#/p' utilities/gtk/media.c > $@
- echo 'int main(int argc, char** argv){' >> $@
- echo 'avcodec_register_all();' >> $@
- echo 'AVCodec* vencoder=avcodec_find_encoder(AV_CODEC_ID_FLV1);' >> $@
- echo 'cam_img_filepicker=camselect_file;' >> $@
- echo 'gtk_init(&argc, &argv);' >> $@
- echo 'int campipe[]={0,1};' >> $@
- echo 'setmode(1, O_BINARY);' >> $@
- echo 'CAM* cam=cam_open(argv[1]);' >> $@
- echo 'unsigned int delay=atoi(argv[2]);' >> $@
- echo 'struct size camsize_out={.width=320, .height=240};' >> $@
- sed -n -e '/if(!camproc)$$/,/^ }/p' utilities/gtk/media.c | sed -e '1,3d' >> $@
- sed -n -e '/ camselect_file/,/^}/p' utilities/gtk/media.c >> $@
-tc_client-gtk-camthread: utilities/gtk/camthread.gen.o utilities/compat.o libcamera.a
- $(CC) $^ $(LIBS) $(GTK_LIBS) $(AVCODEC_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(AVRESAMPLE_LIBS) -o $@
-
libcamera.a: $(LIBCAMERA_OBJ)
$(AR) cru $@ $^
$(RANLIB) $@
clean:
- rm -f $(OBJ) $(IRCHACK_OBJ) $(MODBOT_OBJ) $(CAMVIEWER_OBJ) $(CURSEDCHAT_OBJ) $(TC_CLIENT_GTK_OBJ) $(LIBCAMERA_OBJ) tc_client irchack modbot camviewer cursedchat tc_client-gtk camplaceholder.gif utilities/gtk/camthread.gen.c utilities/gtk/camthread.gen.o tc_client-gtk-camthread
+ rm -f $(OBJ) $(IRCHACK_OBJ) $(MODBOT_OBJ) $(CAMVIEWER_OBJ) $(CURSEDCHAT_OBJ) $(TC_CLIENT_GTK_OBJ) $(LIBCAMERA_OBJ) tc_client irchack modbot camviewer cursedchat tc_client-gtk camplaceholder.gif
SOURCES=Makefile client.c amfparser.c rtmp.c numlist.c amfwriter.c idlist.c colors.c endian.c media.c amfparser.h rtmp.h numlist.h amfwriter.h idlist.h colors.h endian.h media.h LICENSE README ChangeLog crossbuild.sh testbuilds.sh configure
SOURCES+=utilities/irchack/irchack.c
diff --git a/utilities/gtk/camviewer.c b/utilities/gtk/camviewer.c
index daa6ab1..c9c2a94 100644
--- a/utilities/gtk/camviewer.c
+++ b/utilities/gtk/camviewer.c
@@ -522,7 +522,6 @@ gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer data
idend[0]=0;
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);
avcodec_open2(cam->vctx, data->vdecoder, 0);
#if defined(HAVE_AVRESAMPLE) || defined(HAVE_SWRESAMPLE)
@@ -568,11 +567,10 @@ gboolean handledata(GIOChannel* iochannel, GIOCondition condition, gpointer data
if(!strcmp(buf, "Server disconnected"))
{
printchat(buf, 0);
- if(camproc)
+ if(camout_cam)
{
- g_source_remove(cameventsource);
- kill(camproc, SIGINT);
- camproc=0;
+ cam_close(camout_cam);
+ camout_cam=0;
}
return 1;
}
@@ -603,27 +601,27 @@ void audiothread(int fd)
}
#endif
+void togglecam_cancel(void)
+{
+ GtkCheckMenuItem* item=GTK_CHECK_MENU_ITEM(gtk_builder_get_object(gui, "menuitem_broadcast_camera"));
+ gtk_check_menu_item_set_active(item, 0);
+}
+
void togglecam(GtkCheckMenuItem* item, struct viddata* data)
{
if(!gtk_check_menu_item_get_active(item))
{
- g_source_remove(cameventsource);
- kill(camproc, SIGINT);
- camproc=0;
+ if(!camout_cam){return;}
+ cam_close(camout_cam);
+ camout_cam=0;
if(camera_find("out"))
{
dprintf(tc_client_in[1], "/camdown\n");
- dprintf(tc_client[1], "VideoEnd: out\n"); // Close our local display
+ camera_remove("out", 0); // Close our local display
}
return;
}
- GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "camselection"));
- gtk_widget_show_all(window);
-
- // Start a cam thread for the selected cam
- GtkComboBox* combo=GTK_COMBO_BOX(gtk_builder_get_object(gui, "camselect_combo"));
- GIOChannel* channel=camthread(gtk_combo_box_get_active_id(combo), data->vencoder, 100000);
- cameventsource=g_io_add_watch(channel, G_IO_IN, cam_encode, 0);
+ camselect_open(startcamout, togglecam_cancel);
}
gboolean handleresize(GtkWidget* widget, GdkEventConfigure* event, struct viddata* data)
@@ -957,7 +955,7 @@ int main(int argc, char** argv)
campreview.frame=av_frame_alloc();
campreview.frame->data[0]=0;
GtkComboBox* combo=GTK_COMBO_BOX(gtk_builder_get_object(gui, "camselect_combo"));
- g_signal_connect(combo, "changed", G_CALLBACK(camselect_change), data->vencoder);
+ g_signal_connect(combo, "changed", G_CALLBACK(camselect_change), 0);
// Signals for cancelling
item=GTK_WIDGET(gtk_builder_get_object(gui, "camselection"));
g_signal_connect(item, "delete-event", G_CALLBACK(camselect_cancel), 0);
@@ -965,7 +963,7 @@ int main(int argc, char** argv)
g_signal_connect(item, "clicked", G_CALLBACK(camselect_cancel), 0);
// Signals for switching from preview to streaming
item=GTK_WIDGET(gtk_builder_get_object(gui, "camselect_ok"));
- g_signal_connect(item, "clicked", G_CALLBACK(camselect_accept), data->vencoder);
+ g_signal_connect(item, "clicked", G_CALLBACK(camselect_accept), 0);
// Enable the "img" camera
cam_img_filepicker=camselect_file;
// Populate list of cams
diff --git a/utilities/gtk/media.c b/utilities/gtk/media.c
index 78b2f27..427e833 100644
--- a/utilities/gtk/media.c
+++ b/utilities/gtk/media.c
@@ -18,9 +18,6 @@
#include <string.h>
#include <gtk/gtk.h>
#include <libavcodec/avcodec.h>
-#ifndef _WIN32
-#include <sys/prctl.h>
-#endif
#include <libswscale/swscale.h>
#if LIBAVUTIL_VERSION_MAJOR>50 || (LIBAVUTIL_VERSION_MAJOR==50 && LIBAVUTIL_VERSION_MINOR>37)
#include <libavutil/imgutils.h>
@@ -44,11 +41,6 @@ struct camera campreview={
};
struct camera* cams=0;
unsigned int camcount=0;
-#ifdef _WIN32
- PROCESS_INFORMATION camprocess={.hProcess=0};
-#else
- pid_t camproc=0;
-#endif
struct size camsize_out={.width=320, .height=240};
struct size camsize_scale={.width=320, .height=240};
GtkWidget* cambox;
@@ -56,6 +48,7 @@ GtkWidget** camrows=0;
unsigned int camrowcount=0;
GdkPixbufAnimation* camplaceholder=0;
GdkPixbufAnimationIter* camplaceholder_iter=0;
+CAM* camout_cam=0;
#if defined(HAVE_AVRESAMPLE) || defined(HAVE_SWRESAMPLE)
// Experimental mixer, not sure if it really works
@@ -163,6 +156,7 @@ struct camera* camera_new(const char* nick, const char* id)
gtk_box_pack_start(GTK_BOX(cam->box), eventbox, 0, 0, 0);
gtk_box_pack_start(GTK_BOX(cam->box), cam->label, 0, 0, 0);
g_signal_connect(eventbox, "button-release-event", G_CALLBACK(gui_show_cam_menu), cam->id);
+ cam->placeholder=g_timeout_add(100, camplaceholder_update, (char*)id);
// Initialize postprocessing values
postproc_init(&cam->postproc);
return cam;
@@ -180,24 +174,36 @@ void camera_cleanup(void)
void freebuffer(guchar* pixels, gpointer data){free(pixels);}
-gboolean cam_encode(GIOChannel* iochannel, GIOCondition condition, gpointer datap)
+unsigned int camout_delay;
+void startcamout(CAM* cam)
+{
+ dprintf(tc_client_in[1], "/camup\n");
+ camout_cam=cam;
+ camout_delay=500;
+ camsize_out.width=320;
+ camsize_out.height=240;
+ cam_resolution(cam, (unsigned int*)&camsize_out.width, (unsigned int*)&camsize_out.height);
+ g_timeout_add(camout_delay, cam_encode, cam);
+}
+
+gboolean cam_encode(void* camera_)
{
+ CAM* camera=camera_;
+ if(camera!=camout_cam){return G_SOURCE_REMOVE;}
struct camera* cam=camera_find("out");
- char preview=0;
- if(!cam)
+ if(cam->placeholder) // Remove the placeholder animation if it has it
{
- cam=&campreview;
- preview=1;
- }else{
- cam->vctx->width=camsize_out.width;
- cam->vctx->height=camsize_out.height;
- if(!cam->dstframe->data[0])
- {
- cam->dstframe->format=AV_PIX_FMT_YUV420P;
- cam->dstframe->width=camsize_out.width;
- cam->dstframe->height=camsize_out.height;
- av_image_alloc(cam->dstframe->data, cam->dstframe->linesize, camsize_out.width, camsize_out.height, cam->dstframe->format, 1);
- }
+ g_source_remove(cam->placeholder);
+ cam->placeholder=0;
+ }
+ cam->vctx->width=camsize_out.width;
+ cam->vctx->height=camsize_out.height;
+ if(!cam->dstframe->data[0])
+ {
+ cam->dstframe->format=AV_PIX_FMT_YUV420P;
+ cam->dstframe->width=camsize_out.width;
+ cam->dstframe->height=camsize_out.height;
+ av_image_alloc(cam->dstframe->data, cam->dstframe->linesize, camsize_out.width, camsize_out.height, cam->dstframe->format, 1);
}
if(cam->frame->width!=camsize_out.width || cam->frame->height!=camsize_out.height)
{
@@ -208,28 +214,15 @@ gboolean cam_encode(GIOChannel* iochannel, GIOCondition condition, gpointer data
av_freep(cam->frame->data);
av_image_alloc(cam->frame->data, cam->frame->linesize, camsize_out.width, camsize_out.height, cam->frame->format, 1);
}
- g_io_channel_read_chars(iochannel, (void*)cam->frame->data[0], camsize_out.width*camsize_out.height*3, 0, 0);
+ cam_getframe(camera, cam->frame->data[0]);
postprocess(&cam->postproc, cam->frame->data[0], cam->frame->width, cam->frame->height);
// Update our local display
GdkPixbuf* oldpixbuf=gtk_image_get_pixbuf(GTK_IMAGE(cam->cam));
GdkPixbuf* gdkframe=gdk_pixbuf_new_from_data(cam->frame->data[0], GDK_COLORSPACE_RGB, 0, 8, cam->frame->width, cam->frame->height, cam->frame->linesize[0], 0, 0);
- if(!preview) // Scale, unless we're previewing
- {
- gdkframe=gdk_pixbuf_scale_simple(gdkframe, camsize_scale.width, camsize_scale.height, GDK_INTERP_BILINEAR);
- }else if(gdk_pixbuf_get_height(gdkframe)>PREVIEW_MAX_HEIGHT || gdk_pixbuf_get_width(gdkframe)>PREVIEW_MAX_WIDTH) // Scale anyway if the input is huge
- {
- unsigned int width=gdk_pixbuf_get_width(gdkframe);
- unsigned int height=gdk_pixbuf_get_height(gdkframe);
- if(height*PREVIEW_MAX_WIDTH/width>PREVIEW_MAX_HEIGHT)
- {
- gdkframe=gdk_pixbuf_scale_simple(gdkframe, width*PREVIEW_MAX_HEIGHT/height, PREVIEW_MAX_HEIGHT, GDK_INTERP_BILINEAR);
- }else{
- gdkframe=gdk_pixbuf_scale_simple(gdkframe, PREVIEW_MAX_WIDTH, height*PREVIEW_MAX_WIDTH/width, GDK_INTERP_BILINEAR);
- }
- }
+ // Scale to fit
+ gdkframe=gdk_pixbuf_scale_simple(gdkframe, camsize_scale.width, camsize_scale.height, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(cam->cam), gdkframe);
g_object_unref(oldpixbuf);
- if(preview){return 1;}
// Encode
struct SwsContext* swsctx=sws_getContext(cam->frame->width, cam->frame->height, cam->frame->format, cam->frame->width, cam->frame->height, AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, 0, 0, 0);
sws_scale(swsctx, (const uint8_t*const*)cam->frame->data, cam->frame->linesize, 0, cam->frame->height, cam->dstframe->data, cam->dstframe->linesize);
@@ -247,7 +240,7 @@ gboolean cam_encode(GIOChannel* iochannel, GIOCondition condition, gpointer data
av_init_packet(&packet);
avcodec_send_frame(cam->vctx, cam->dstframe);
gotpacket=avcodec_receive_packet(cam->vctx, &packet);
- if(gotpacket){return 1;}
+ if(gotpacket){return G_SOURCE_CONTINUE;}
unsigned char frameinfo=0x22; // Note: differentiating between keyframes and non-keyframes seems to break stuff, so let's just go with all being interframes (1=keyframe, 2=interframe, 3=disposable interframe)
// Send video
dprintf(tc_client_in[1], "/video %i\n", packet.size+1);
@@ -256,98 +249,98 @@ gboolean cam_encode(GIOChannel* iochannel, GIOCondition condition, gpointer data
if(w!=packet.size){printf("Error: wrote %li of %i bytes\n", w, packet.size);}
av_packet_unref(&packet);
- return 1;
+ if(camout_delay>100) // Slowly speed up to 10fps, otherwise the flash client won't show it.
+ {
+ camout_delay-=50;
+ g_timeout_add(camout_delay, cam_encode, camera_);
+ return G_SOURCE_REMOVE;
+ }
+ return G_SOURCE_CONTINUE;
}
-unsigned int* camthread_delay;
-void camthread_resetdelay(int x)
+struct
{
- *camthread_delay=500000;
-}
-extern unsigned int cameventsource;
-GIOChannel* camthread(const char* name, AVCodec* vencoder, unsigned int delay)
+ void(*callback)(CAM* cam);
+ void(*cancelcallback)(void);
+ unsigned int eventsource;
+ CAM* current;
+ struct size size;
+} camselect={.eventsource=0, .current=0};
+
+gboolean camselect_frame(void* x)
{
- if(camproc)
- {
- g_source_remove(cameventsource);
- kill(camproc, SIGINT);
- usleep(200000); // Give the previous process some time to shut down
- }
- // Set up a pipe to be handled by cam_encode()
- int campipe[2];
-#ifndef _WIN32
- CAM* cam=cam_open(name); // Opening here in case of GUI callbacks
- if(cam){cam_resolution(cam, (unsigned int*)&camsize_out.width, (unsigned int*)&camsize_out.height);}
- pipe(campipe);
- camproc=fork();
- if(!camproc)
+ if(!camselect.current){return G_SOURCE_CONTINUE;}
+ void* buf=malloc(camselect.size.width*camselect.size.height*3);
+ cam_getframe(camselect.current, buf);
+ GdkPixbuf* oldpixbuf=gtk_image_get_pixbuf(GTK_IMAGE(campreview.cam));
+ GdkPixbuf* gdkframe=gdk_pixbuf_new_from_data(buf, GDK_COLORSPACE_RGB, 0, 8, camselect.size.width, camselect.size.height, camselect.size.width*3, 0, freebuffer);
+ if(gdk_pixbuf_get_height(gdkframe)>PREVIEW_MAX_HEIGHT || gdk_pixbuf_get_width(gdkframe)>PREVIEW_MAX_WIDTH) // Scale if the input is huge
{
- close(campipe[0]);
- unsigned char img[camsize_out.width*camsize_out.height*3];
- if(!cam) // If it failed to open, just give some grey before quitting
- {
- memset(img, 0x7f, camsize_out.width*camsize_out.height*3);
- write(campipe[1], img, camsize_out.width*camsize_out.height*3);
- _exit(1);
- }
-#ifndef _WIN32
- prctl(PR_SET_PDEATHSIG, SIGHUP);
- camthread_delay=&delay;
- signal(SIGUSR1, camthread_resetdelay);
-#endif
- while(1)
+ unsigned int width=gdk_pixbuf_get_width(gdkframe);
+ unsigned int height=gdk_pixbuf_get_height(gdkframe);
+ if(height*PREVIEW_MAX_WIDTH/width>PREVIEW_MAX_HEIGHT)
{
- usleep(delay);
- if(delay>100000){delay-=50000;}
- cam_getframe(cam, img);
- write(campipe[1], img, camsize_out.width*camsize_out.height*3);
+ gdkframe=gdk_pixbuf_scale_simple(gdkframe, width*PREVIEW_MAX_HEIGHT/height, PREVIEW_MAX_HEIGHT, GDK_INTERP_BILINEAR);
+ }else{
+ gdkframe=gdk_pixbuf_scale_simple(gdkframe, PREVIEW_MAX_WIDTH, height*PREVIEW_MAX_WIDTH/width, GDK_INTERP_BILINEAR);
}
- _exit(0);
}
- if(cam){cam_close(cam);} // Leave the cam to the child process
- close(campipe[1]);
-#else
- char cmd[snprintf(0,0, "./tc_client-gtk-camthread %s %u", name, delay)+1];
- sprintf(cmd, "./tc_client-gtk-camthread %s %u", name, delay);
- w32_runcmdpipes(cmd, ((int*)0), campipe, camprocess);
-#endif
- GIOChannel* channel=g_io_channel_unix_new(campipe[0]);
- g_io_channel_set_encoding(channel, 0, 0);
- return channel;
+ gtk_image_set_from_pixbuf(GTK_IMAGE(campreview.cam), gdkframe);
+ g_object_unref(oldpixbuf);
+ return G_SOURCE_CONTINUE;
}
-void camselect_change(GtkComboBox* combo, AVCodec* vencoder)
+void camselect_open(void(*cb)(CAM*), void(*ccb)(void))
{
- if(!camproc){return;} // If there isn't a camthread already, it will be started elsewhere
- GIOChannel* channel=camthread(gtk_combo_box_get_active_id(combo), vencoder, 100000);
- cameventsource=g_io_add_watch(channel, G_IO_IN, cam_encode, 0);
+ camselect.callback=cb;
+ camselect.cancelcallback=ccb;
+ // Start the preview
+ if(!camselect.eventsource)
+ {
+ camselect.eventsource=g_timeout_add(100, camselect_frame, 0);
+ }
+ // Open the currently selected camera (usually starting with the top alternative)
+ if(camselect.current){cam_close(camselect.current);}
+ GtkComboBox* combo=GTK_COMBO_BOX(gtk_builder_get_object(gui, "camselect_combo"));
+ camselect_change(combo, 0);
+ GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "camselection"));
+ gtk_widget_show_all(window);
+}
+
+void camselect_change(GtkComboBox* combo, void* x)
+{
+ if(!camselect.eventsource){return;} // Haven't opened the cam selection window yet (happens at startup)
+ if(camselect.current){cam_close(camselect.current);}
+ camselect.current=cam_open(gtk_combo_box_get_active_id(combo));
+ if(!camselect.current){return;}
+ camselect.size.width=320;
+ camselect.size.height=240;
+ cam_resolution(camselect.current, (unsigned int*)&camselect.size.width, (unsigned int*)&camselect.size.height);
}
gboolean camselect_cancel(GtkWidget* widget, void* x1, void* x2)
{
GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "camselection"));
gtk_widget_hide(window);
- // Note: unchecking the menu item kills the cam thread for us
- GtkCheckMenuItem* item=GTK_CHECK_MENU_ITEM(gtk_builder_get_object(gui, "menuitem_broadcast_camera"));
- gtk_check_menu_item_set_active(item, 0);
+ g_source_remove(camselect.eventsource);
+ camselect.eventsource=0;
+ if(camselect.cancelcallback){camselect.cancelcallback();}
return 1;
}
-extern int tc_client_in[];
-void camselect_accept(GtkWidget* widget, AVCodec* vencoder)
+void camselect_accept(GtkWidget* widget, void* x)
{
GtkWidget* window=GTK_WIDGET(gtk_builder_get_object(gui, "camselection"));
gtk_widget_hide(window);
-#ifndef _WIN32
- // Tell the camthread to reset the delay to 500000 as a workaround for a quirk in the flash client
- kill(camproc, SIGUSR1);
-#else
- // For platforms without proper signals, resort to restarting the camthread with the new delay
- GtkComboBox* combo=GTK_COMBO_BOX(gtk_builder_get_object(gui, "camselect_combo"));
- GIOChannel* channel=camthread(gtk_combo_box_get_active_id(combo), vencoder, 500000);
- cameventsource=g_io_add_watch(channel, G_IO_IN, cam_encode, 0);
-#endif
- dprintf(tc_client_in[1], "/camup\n");
+ g_source_remove(camselect.eventsource);
+ camselect.eventsource=0;
+ if(camselect.callback)
+ {
+ camselect.callback(camselect.current);
+ }else{
+ cam_close(camselect.current);
+ }
+ camselect.current=0;
}
void camselect_file_preview(GtkFileChooser* dialog, gpointer data)
diff --git a/utilities/gtk/media.h b/utilities/gtk/media.h
index 58197bc..788b36b 100644
--- a/utilities/gtk/media.h
+++ b/utilities/gtk/media.h
@@ -15,6 +15,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libavcodec/avcodec.h>
+#include "../libcamera/camera.h"
#include "postproc.h"
struct camera
{
@@ -40,17 +41,12 @@ struct size
extern struct camera campreview;
extern struct camera* cams;
extern unsigned int camcount;
-#ifdef _WIN32
- extern PROCESS_INFORMATION camprocess;
- #define camproc camprocess.hProcess
-#else
- extern pid_t camproc;
-#endif
extern struct size camsize_out;
extern struct size camsize_scale;
extern GtkWidget* cambox;
extern GdkPixbufAnimation* camplaceholder;
extern GdkPixbufAnimationIter* camplaceholder_iter;
+extern CAM* camout_cam;
#if defined(HAVE_AVRESAMPLE) || defined(HAVE_SWRESAMPLE)
extern void camera_playsnd(int audiopipe, struct camera* cam, short* samples, unsigned int samplecount);
@@ -61,11 +57,12 @@ extern struct camera* camera_findbynick(const char* nick);
extern struct camera* camera_new(const char* nick, const char* id);
extern void camera_cleanup(void);
extern void freebuffer(guchar* pixels, gpointer data);
-extern gboolean cam_encode(GIOChannel* iochannel, GIOCondition condition, gpointer datap);
-extern GIOChannel* camthread(const char* name, AVCodec* vencoder, unsigned int delay);
-extern void camselect_change(GtkComboBox* combo, AVCodec* vencoder);
+extern void startcamout(CAM* cam);
+extern gboolean cam_encode(void* camera_);
+extern void camselect_open(void(*cb)(CAM*), void(*ccb)(void));
+extern void camselect_change(GtkComboBox* combo, void* x);
extern gboolean camselect_cancel(GtkWidget* widget, void* x1, void* x2);
-extern void camselect_accept(GtkWidget* widget, AVCodec* vencoder);
+extern void camselect_accept(GtkWidget* widget, void* x);
extern const char* camselect_file(void);
extern void camera_postproc(struct camera* cam, unsigned char* buf, unsigned int width, unsigned int height);
extern void updatescaling(unsigned int width, unsigned int height, char changedcams);
diff --git a/utilities/libcamera/camera.h b/utilities/libcamera/camera.h
index 8ec37bc..6cf4776 100644
--- a/utilities/libcamera/camera.h
+++ b/utilities/libcamera/camera.h
@@ -14,6 +14,8 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifndef CAMERA_H
+#define CAMERA_H
enum{
CAMTYPE_V4L2,
CAMTYPE_ESCAPI,
@@ -28,3 +30,4 @@ extern void cam_resolution(CAM* cam, unsigned int* width, unsigned int* height);
extern void cam_getframe(CAM* cam, void* pixmap);
extern void cam_close(CAM* cam);
extern const char*(*cam_img_filepicker)(void);
+#endif