$ git clone http://tcclient.ion.nu/tc_client.git
commit b421fd7a948554773f9f2153acdb0fb7bc027a66
Author: Alicia <...>
Date: Tue Jun 30 10:30:54 2015 +0200
tc_client-gtk and camviewer: added an abstraction library (libcamera) for cam access.
diff --git a/ChangeLog b/ChangeLog
index f6916a2..95f88d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@ Print version info when called with -v/--version (contributed by Jade)
Flush stdout after printing unknown RTMP types, and return upon <1 reads in b_read.
tc_client-gtk: fixed windows compatibility (w32_runcmd and strndup)
tc_client-gtk and camviewer: added some compatibility macros for older libav versions.
+tc_client-gtk and camviewer: added an abstraction library (libcamera) for cam access.
modbot: added an option (--disable-lists) to disable playlist requests, instead only the first video linked to will be added to the queue.
modbot: make a note about skipped videos (!skip) not being marked as bad, and list the skipped videos to make it easier if they were meant to be marked as bad.
modbot: give feedback for !wrongrequest, and if the user is a mod and the dropped video was the last one approved, remove it from goodvids since it was probably requested (and automatically approved) by accident.
diff --git a/Makefile b/Makefile
index 5588e9c..f145209 100644
--- a/Makefile
+++ b/Makefile
@@ -27,15 +27,18 @@ ifdef SWSCALE_LIBS
CFLAGS+=-DHAVE_SWRESAMPLE=1 $(SWRESAMPLE_CFLAGS) $(AO_CFLAGS)
endif
endif
- ifdef LIBV4L2_LIBS
- CFLAGS+=-DHAVE_V4L2 $(LIBV4L2_CFLAGS)
- endif
ifneq ($(findstring MINGW,$(shell uname -s)),)
LDFLAGS+=-mwindows
windowstargets: camviewer tc_client-gtk
@echo
@echo 'To build the core (tc_client.exe), enter this directory from cygwin and type make'
endif
+ ifdef LIBV4L2_LIBS
+ CFLAGS+=-DHAVE_CAM $(LIBV4L2_CFLAGS)
+ LIBCAMERA_OBJ+=utilities/libcamera/camera_v4l2.o
+ CAMVIEWER_OBJ+=libcamera.a
+ TC_CLIENT_GTK_OBJ+=libcamera.a
+ endif
endif
endif
endif
@@ -47,6 +50,12 @@ ifdef READLINE_LIBS
INSTALLDEPS+=cursedchat
endif
endif
+ifeq ($(AR),)
+ AR=ar
+endif
+ifeq ($(RANLIB),)
+ RANLIB=ranlib
+endif
CFLAGS+=-DPREFIX=\"$(PREFIX)\" -DVERSION=\"$(VERSION)\"
INSTALLDEPS=tc_client
@@ -70,8 +79,12 @@ cursedchat: $(CURSEDCHAT_OBJ)
tc_client-gtk: $(TC_CLIENT_GTK_OBJ)
$(CC) $(LDFLAGS) $^ $(LIBS) $(GTK_LIBS) $(AVCODEC_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(AVRESAMPLE_LIBS) $(SWRESAMPLE_LIBS) $(AO_LIBS) $(LIBV4L2_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) tc_client irchack modbot camviewer cursedchat tc_client-gtk
+ 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
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
@@ -80,6 +93,7 @@ SOURCES+=utilities/camviewer/camviewer.c
SOURCES+=utilities/cursedchat/cursedchat.c utilities/cursedchat/buffer.c utilities/cursedchat/buffer.h
SOURCES+=utilities/gtk/camviewer.c utilities/gtk/userlist.c utilities/gtk/media.c utilities/gtk/compat.c utilities/gtk/config.c utilities/gtk/gui.c utilities/gtk/logging.c utilities/gtk/userlist.h utilities/gtk/media.h utilities/gtk/compat.h utilities/gtk/config.h utilities/gtk/gui.h utilities/gtk/logging.h gtkgui.glade
SOURCES+=utilities/compat.c utilities/compat.h utilities/list.c utilities/list.h utilities/stringutils.c utilities/stringutils.h
+SOURCES+=utilities/libcamera/camera.h utilities/libcamera/camera_v4l2.c
tarball:
tar -cJf tc_client-$(VERSION).tar.xz --transform='s|^|tc_client-$(VERSION)/|' $(SOURCES)
diff --git a/utilities/camviewer/camviewer.c b/utilities/camviewer/camviewer.c
index 9bbe689..6a72ea4 100644
--- a/utilities/camviewer/camviewer.c
+++ b/utilities/camviewer/camviewer.c
@@ -41,9 +41,8 @@
#include <ao/ao.h>
#endif
#include <gtk/gtk.h>
-#ifdef HAVE_V4L2
- #include <libv4l2.h>
- #include <linux/videodev2.h>
+#ifdef HAVE_CAM
+ #include "../libcamera/camera.h"
#endif
#include "../compat.h"
@@ -370,7 +369,7 @@ void audiothread(int fd)
}
#endif
-#ifdef HAVE_V4L2
+#ifdef HAVE_CAM
pid_t camproc=0;
void togglecam(GtkButton* button, struct viddata* data)
{
@@ -383,6 +382,9 @@ void togglecam(GtkButton* button, struct viddata* data)
dprintf(tc_client[1], "VideoEnd: out\n"); // Close our local display
return;
}
+ unsigned int count;
+ char** cams=cam_list(&count);
+ if(!count){printf("No camera found\n"); return;}
// Set up a second pipe to be handled by handledata() to avoid overlap with tc_client's output
int campipe[2];
pipe(campipe);
@@ -396,27 +398,19 @@ void togglecam(GtkButton* button, struct viddata* data)
prctl(PR_SET_PDEATHSIG, SIGHUP);
unsigned int delay=500000;
// Set up camera
- int fd=v4l2_open("/dev/video0", O_RDWR);
- struct v4l2_format fmt;
- fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width=320;
- fmt.fmt.pix.height=240;
- fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_RGB24;
- fmt.fmt.pix.field=V4L2_FIELD_NONE;
- fmt.fmt.pix.bytesperline=fmt.fmt.pix.width*3;
- fmt.fmt.pix.sizeimage=fmt.fmt.pix.bytesperline*fmt.fmt.pix.height;
- v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt);
+ CAM* cam=cam_open(cams[0]);
AVCodecContext* ctx=avcodec_alloc_context3(data->vencoder);
- ctx->width=fmt.fmt.pix.width;
- ctx->height=fmt.fmt.pix.height;
+ ctx->width=320;
+ ctx->height=240;
+ cam_resolution(cam, (unsigned int*)&ctx->width, (unsigned int*)&ctx->height);
ctx->pix_fmt=PIX_FMT_YUV420P;
ctx->time_base.num=1;
ctx->time_base.den=10;
avcodec_open2(ctx, data->vencoder, 0);
AVFrame* frame=av_frame_alloc();
frame->format=PIX_FMT_RGB24;
- frame->width=fmt.fmt.pix.width;
- frame->height=fmt.fmt.pix.height;
+ frame->width=ctx->width;
+ frame->height=ctx->height;
av_image_alloc(frame->data, frame->linesize, ctx->width, ctx->height, frame->format, 1);
AVPacket packet;
packet.buf=0;
@@ -438,7 +432,7 @@ void togglecam(GtkButton* button, struct viddata* data)
{
usleep(delay);
if(delay>100000){delay-=50000;}
- v4l2_read(fd, frame->data[0], fmt.fmt.pix.sizeimage);
+ cam_getframe(cam, frame->data[0]);
int gotpacket;
sws_scale(swsctx, (const uint8_t*const*)frame->data, frame->linesize, 0, frame->height, dstframe->data, dstframe->linesize);
av_init_packet(&packet);
@@ -506,7 +500,7 @@ int main(int argc, char** argv)
g_signal_connect(w, "destroy", gtk_main_quit, 0);
data.box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add(GTK_CONTAINER(w), data.box);
-#ifdef HAVE_V4L2
+#ifdef HAVE_CAM
data.vencoder=avcodec_find_encoder(AV_CODEC_ID_FLV1);
GtkWidget* cambutton=gtk_button_new_with_label("Broadcast cam");
g_signal_connect(cambutton, "clicked", G_CALLBACK(togglecam), &data);
diff --git a/utilities/gtk/camviewer.c b/utilities/gtk/camviewer.c
index ac1ba7d..29d049d 100644
--- a/utilities/gtk/camviewer.c
+++ b/utilities/gtk/camviewer.c
@@ -45,9 +45,8 @@
#endif
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
-#ifdef HAVE_V4L2
- #include <libv4l2.h>
- #include <linux/videodev2.h>
+#ifdef HAVE_CAM
+ #include "../libcamera/camera.h"
#endif
#include "userlist.h"
#include "media.h"
@@ -577,7 +576,7 @@ void audiothread(int fd)
}
#endif
-#ifdef HAVE_V4L2
+#ifdef HAVE_CAM
pid_t camproc=0;
unsigned int cameventsource;
void togglecam(GtkCheckMenuItem* item, struct viddata* data)
@@ -591,6 +590,9 @@ void togglecam(GtkCheckMenuItem* item, struct viddata* data)
dprintf(tc_client[1], "VideoEnd: out\n"); // Close our local display
return;
}
+ unsigned int count;
+ char** cams=cam_list(&count);
+ if(!count){printf("No camera found\n"); return;}
// Set up a second pipe to be handled by handledata() to avoid overlap with tc_client's output
int campipe[2];
pipe(campipe);
@@ -603,27 +605,19 @@ void togglecam(GtkCheckMenuItem* item, struct viddata* data)
prctl(PR_SET_PDEATHSIG, SIGHUP);
unsigned int delay=500000;
// Set up camera
- int fd=v4l2_open("/dev/video0", O_RDWR);
- struct v4l2_format fmt;
- fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width=320;
- fmt.fmt.pix.height=240;
- fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_RGB24;
- fmt.fmt.pix.field=V4L2_FIELD_NONE;
- fmt.fmt.pix.bytesperline=fmt.fmt.pix.width*3;
- fmt.fmt.pix.sizeimage=fmt.fmt.pix.bytesperline*fmt.fmt.pix.height;
- v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt);
+ CAM* cam=cam_open(cams[0]);
AVCodecContext* ctx=avcodec_alloc_context3(data->vencoder);
- ctx->width=fmt.fmt.pix.width;
- ctx->height=fmt.fmt.pix.height;
+ ctx->width=320;
+ ctx->height=240;
+ cam_resolution(cam, (unsigned int*)&ctx->width, (unsigned int*)&ctx->height);
ctx->pix_fmt=PIX_FMT_YUV420P;
ctx->time_base.num=1;
ctx->time_base.den=10;
avcodec_open2(ctx, data->vencoder, 0);
AVFrame* frame=av_frame_alloc();
frame->format=PIX_FMT_RGB24;
- frame->width=fmt.fmt.pix.width;
- frame->height=fmt.fmt.pix.height;
+ frame->width=ctx->width;
+ frame->height=ctx->height;
av_image_alloc(frame->data, frame->linesize, ctx->width, ctx->height, frame->format, 1);
AVPacket packet;
packet.buf=0;
@@ -645,7 +639,7 @@ void togglecam(GtkCheckMenuItem* item, struct viddata* data)
{
usleep(delay);
if(delay>100000){delay-=50000;}
- v4l2_read(fd, frame->data[0], fmt.fmt.pix.sizeimage);
+ cam_getframe(cam, frame->data[0]);
int gotpacket;
sws_scale(swsctx, (const uint8_t*const*)frame->data, frame->linesize, 0, frame->height, dstframe->data, dstframe->linesize);
av_init_packet(&packet);
@@ -967,7 +961,7 @@ int main(int argc, char** argv)
}
gtk_builder_connect_signals(gui, 0);
-#ifdef HAVE_V4L2
+#ifdef HAVE_CAM
GtkWidget* item=GTK_WIDGET(gtk_builder_get_object(gui, "menuitem_broadcast_camera"));
g_signal_connect(item, "toggled", G_CALLBACK(togglecam), data);
data->vencoder=avcodec_find_encoder(AV_CODEC_ID_FLV1);
diff --git a/utilities/libcamera/camera.h b/utilities/libcamera/camera.h
new file mode 100644
index 0000000..0d3f9f6
--- /dev/null
+++ b/utilities/libcamera/camera.h
@@ -0,0 +1,24 @@
+/*
+ libcamera, a camera access abstraction library
+ Copyright (C) 2015 alicia@ion.nu
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License.
+
+ 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 Affero General Public License for more details.
+
+ 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/>.
+*/
+struct CAM_t;
+typedef struct CAM_t CAM;
+extern char** cam_list(unsigned int* count);
+extern CAM* cam_open(const char* name);
+// Note: cam_resolution both tries to set the resolution and gets what it set it to
+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);
diff --git a/utilities/libcamera/camera_v4l2.c b/utilities/libcamera/camera_v4l2.c
new file mode 100644
index 0000000..3a488e3
--- /dev/null
+++ b/utilities/libcamera/camera_v4l2.c
@@ -0,0 +1,85 @@
+/*
+ libcamera, a camera access abstraction library
+ Copyright (C) 2015 alicia@ion.nu
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License.
+
+ 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 Affero General Public License for more details.
+
+ 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/>.
+*/
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <libv4l2.h>
+#include <linux/videodev2.h>
+#include "camera.h"
+
+typedef struct CAM_t
+{
+ int fd;
+ unsigned int framesize;
+} CAM;
+
+char** cam_list(unsigned int* count)
+{
+ char** list=0;
+ *count=0;
+ DIR* dir=opendir("/dev");
+ struct dirent* entry;
+ while((entry=readdir(dir)))
+ {
+ if(!strncmp(entry->d_name, "video", 5))
+ {
+ ++*count;
+ list=realloc(list, sizeof(char*)*(*count));
+ char* path=malloc(strlen("/dev/0")+strlen(entry->d_name));
+ sprintf(path, "/dev/%s", entry->d_name);
+ list[(*count)-1]=path;
+ }
+ }
+ return list;
+}
+
+CAM* cam_open(const char* name)
+{
+ CAM* cam=malloc(sizeof(CAM));
+ cam->fd=v4l2_open(name, O_RDWR);
+ return cam;
+}
+
+void cam_resolution(CAM* cam, unsigned int* width, unsigned int* height)
+{
+ struct v4l2_format fmt;
+ fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width=*width;
+ fmt.fmt.pix.height=*height;
+ fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_RGB24;
+ fmt.fmt.pix.field=V4L2_FIELD_NONE;
+ fmt.fmt.pix.bytesperline=fmt.fmt.pix.width*3;
+ fmt.fmt.pix.sizeimage=fmt.fmt.pix.bytesperline*fmt.fmt.pix.height;
+ v4l2_ioctl(cam->fd, VIDIOC_S_FMT, &fmt);
+ v4l2_ioctl(cam->fd, VIDIOC_G_FMT, &fmt);
+ *width=fmt.fmt.pix.width;
+ *height=fmt.fmt.pix.height;
+ cam->framesize=(*width)*(*height)*3;
+}
+
+void cam_getframe(CAM* cam, void* pixmap)
+{
+ v4l2_read(cam->fd, pixmap, cam->framesize);
+}
+
+void cam_close(CAM* cam)
+{
+ v4l2_close(cam->fd);
+ free(cam);
+}