1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-22 20:33:02 +01:00

Fixed v4l2 capture crash, and refactored to prepare for new features

This commit is contained in:
cnhenry 2015-08-08 21:21:23 -05:00
parent d359ba6a54
commit c2c612b85a
8 changed files with 171 additions and 123 deletions

21
cfg/checks/audio.mk Normal file
View File

@ -0,0 +1,21 @@
# Variables for audio call support
AUDIO_LIBS = libtoxav openal
AUDIO_CFLAGS = -DAUDIO
ifneq (, $(findstring audio_device.o, $(OBJ)))
AUDIO_OBJ = audio_call.o
else
AUDIO_OBJ = audio_call.o audio_device.o
endif
# Check if we can build audio support
CHECK_AUDIO_LIBS = $(shell pkg-config --exists $(AUDIO_LIBS) || echo -n "error")
ifneq ($(CHECK_AUDIO_LIBS), error)
LIBS += $(AUDIO_LIBS)
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
endif

View File

@ -1,43 +0,0 @@
# Variables for audio call support
AUDIO_LIBS = libtoxav openal
AUDIO_CFLAGS = -DAUDIO
ifneq (, $(findstring audio_device.o, $(OBJ)))
AUDIO_OBJ = audio_call.o
else
AUDIO_OBJ = audio_call.o audio_device.o
endif
# Variables for video call support
VIDEO_LIBS = libtoxav vpx x11
VIDEO_CFLAGS = -DVIDEO
ifneq (, $(findstring video_device.o, $(OBJ)))
VIDEO_OBJ = video_call.o
else
VIDEO_OBJ = video_call.o video_device.o
endif
# Check if we can build audio support
CHECK_AUDIO_LIBS = $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
ifneq ($(CHECK_AUDIO_LIBS), error)
LIBS += $(AUDIO_LIBS)
CFLAGS += $(AUDIO_CFLAGS)
OBJ += $(AUDIO_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_AUDIO_LIBS = $(shell for lib in $(AUDIO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without audio support)
$(warning WARNING -- You need these libraries for audio support)
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
endif
# Check if we can build video support
CHECK_VIDEO_LIBS = $(shell pkg-config --exists $(VIDEO_LIBS) || echo -n "error")
ifneq ($(CHECK_VIDEO_LIBS), error)
LIBS += $(VIDEO_LIBS)
CFLAGS += $(VIDEO_CFLAGS)
OBJ += $(VIDEO_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without video support)
$(warning WARNING -- You will need these libraries for video support)
$(warning WARNING -- $(MISSING_VIDEO_LIBS))
endif

View File

@ -9,7 +9,15 @@ endif
# Check if we want build audio support
AUDIO = $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(AUDIO), disabled)
-include $(CHECKS_DIR)/av.mk
-include $(CHECKS_DIR)/audio.mk
endif
# Check if we want build video support
VIDEO = $*shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
ifneq ($(AUDIO), disabled)
ifneq ($(VIDEO), disabled)
-include $(CHECKS_DIR)/video.mk
endif
endif
# Check if we want build sound notifications support

21
cfg/checks/video.mk Normal file
View File

@ -0,0 +1,21 @@
# Variables for video call support
VIDEO_LIBS = libtoxav vpx x11
VIDEO_CFLAGS = -DVIDEO
ifneq (, $(findstring video_device.o, $(OBJ)))
VIDEO_OBJ = video_call.o
else
VIDEO_OBJ = video_call.o video_device.o
endif
# Check if we can build video support
CHECK_VIDEO_LIBS = $(shell pkg-config --exists $(VIDEO_LIBS) || echo -n "error")
ifneq ($(CHECK_VIDEO_LIBS), error)
LIBS += $(VIDEO_LIBS)
CFLAGS += $(VIDEO_CFLAGS)
OBJ += $(VIDEO_OBJ)
else ifneq ($(MAKECMDGOALS), clean)
MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! pkg-config --exists $$lib ; then echo $$lib ; fi ; done)
$(warning WARNING -- Toxic will be compiled without video support)
$(warning WARNING -- You will need these libraries for video support)
$(warning WARNING -- $(MISSING_VIDEO_LIBS))
endif

View File

@ -167,6 +167,15 @@ static void help_draw_global(ToxWindow *self)
wprintw(win, " /sdev <type> <id> : Set active device\n");
#endif /* AUDIO */
#ifdef VIDEO
wattron(win, A_BOLD);
wprintw(win, "\n Video:\n");
wattroff(win, A_BOLD);
wprintw(win, " /lsvdev <type> : List video devices where type: in|out\n");
wprintw(win, " /svdev <type> <id> : Set active video device\n");
#endif /* VIDEO */
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
@ -203,6 +212,14 @@ static void help_draw_chat(ToxWindow *self)
wprintw(win, " /sense <n> : VAD sensitivity threshold\n");
#endif /* AUDIO */
#ifdef VIDEO
wattron(win, A_BOLD);
wprintw(win, "\n Video:\n");
wattroff(win, A_BOLD);
wprintw(win, " /video : Send video capture\n");
wprintw(win, " /endvideo : Close all video windows\n");
#endif /* VIDEO */
help_draw_bottom_menu(win);
box(win, ACS_VLINE, ACS_HLINE);
@ -282,7 +299,9 @@ void help_onKey(ToxWindow *self, wint_t key)
break;
case 'c':
#ifdef AUDIO
#ifdef VIDEO
help_init_window(self, 23, 80);
#elif AUDIO
help_init_window(self, 19, 80);
#else
help_init_window(self, 9, 80);
@ -291,7 +310,9 @@ void help_onKey(ToxWindow *self, wint_t key)
break;
case 'g':
#ifdef AUDIO
#ifdef VIDEO
help_init_window(self, 28, 80);
#elif AUDIO
help_init_window(self, 24, 80);
#else
help_init_window(self, 20, 80);

View File

@ -80,11 +80,11 @@ void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_
int32_t ystride, int32_t ustride, int32_t vstride,
void *user_data)
{
CallControl* cc = (CallControl*)user_data;
Call* this_call = &cc->calls[friend_number];
Call* this_call = &CallContrl.calls[friend_number];
if(write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data) == vde_DeviceNotActive)
callback_recv_video_starting(cc->av, friend_number, cc);
if(write_video_out(width, height, y, u, v, ystride, ustride, vstride, user_data) == vde_DeviceNotActive) {
callback_recv_video_starting(CallContrl.av, friend_number, &CallContrl);
}
}
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
@ -155,7 +155,7 @@ void callback_recv_video_starting(void* av, uint32_t friend_number, void *arg)
Call* this_call = &cc->calls[friend_number];
open_primary_video_device(vdt_output, &this_call->out_idx);
CallContrl.video_call = true;
cc->video_call = true;
}
void callback_video_starting(void* av, uint32_t friend_number, void *arg)
@ -167,16 +167,18 @@ void callback_video_starting(void* av, uint32_t friend_number, void *arg)
int i;
for (i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i].is_call && windows[i].num == friend_number) {
cc->video_call = true;
if(0 != start_video_transmission(&windows[i], av, this_call)) {
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Error starting transmission!");
cc->video_call = false;
return;
}
line_info_add(&windows[i], NULL, NULL, NULL, SYS_MSG, 0, 0, "Video capture starting.");
cc->video_call = true;
}
}
}
void callback_video_ending(void* av, uint32_t friend_number, void *arg)
{
CallControl *cc = (CallControl*)arg;
@ -191,8 +193,11 @@ void callback_video_ending(void* av, uint32_t friend_number, void *arg)
}
}
for (i = 0; i < MAX_CALLS; ++i)
stop_video_transmission(&CallContrl.calls[i], i);
cc->video_call = false;
terminate_video();
}
/*
* End of Callbacks

View File

@ -113,6 +113,54 @@ static int xioctl(int fh, unsigned long request, void *arg)
return r;
}
static void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
const uint8_t *u, const uint8_t *v, unsigned int ystride,
unsigned int ustride, unsigned int vstride, uint8_t *out)
{
unsigned long int i, j;
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
uint8_t *point = out + 4 * ((i * width) + j);
int t_y = y[((i * ystride) + j)];
int t_u = u[(((i / 2) * ustride) + (j / 2))];
int t_v = v[(((i / 2) * vstride) + (j / 2))];
t_y = t_y < 16 ? 16 : t_y;
int r = (298 * (t_y - 16) + 409 * (t_v - 128) + 128) >> 8;
int g = (298 * (t_y - 16) - 100 * (t_u - 128) - 208 * (t_v - 128) + 128) >> 8;
int b = (298 * (t_y - 16) + 516 * (t_u - 128) + 128) >> 8;
point[2] = r>255? 255 : r<0 ? 0 : r;
point[1] = g>255? 255 : g<0 ? 0 : g;
point[0] = b>255? 255 : b<0 ? 0 : b;
point[3] = ~0;
}
}
}
static void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
uint8_t *input, uint16_t width, uint16_t height)
{
uint8_t *end = input + width * height * 2;
while(input != end) {
uint8_t *line_end = input + width * 2;
while(input != line_end) {
*plane_y++ = *input++;
*plane_u++ = *input++;
*plane_y++ = *input++;
*plane_v++ = *input++;
}
line_end = input + width * 2;
while(input != line_end) {
*plane_y++ = *input++;
input++;//u
*plane_y++ = *input++;
input++;//v
}
}
}
/* Meet devices */
#ifdef VIDEO
VideoDeviceError init_video_devices(ToxAV* av_)
@ -124,7 +172,6 @@ VideoDeviceError init_video_devices()
#ifdef __linux__
for(; size[vdt_input] <= MAX_DEVICES; ++size[vdt_input]) {
//size[vdt_input] = i;
int fd;
char device_address[] = "/dev/videoXX";
snprintf(device_address + 10, sizeof(char) * strlen(device_address) - 10, "%i", size[vdt_input]);
@ -199,6 +246,7 @@ VideoDeviceError register_video_device_callback(int32_t friend_number, uint32_t
VideoDeviceError set_primary_video_device(VideoDeviceType type, int32_t selection)
{
if (size[type] <= selection || selection < 0) return vde_InvalidSelection;
primary_video_device[type] = selection;
return vde_None;
@ -247,6 +295,8 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
}
if (type == vdt_input) {
video_thread_paused = true;
#ifdef __linux__
char device_address[] = "/dev/videoXX";
snprintf(device_address + 10 , sizeof(device_address) - 10, "%i", selection);
@ -259,7 +309,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
/* Obtain video device capabilities */
struct v4l2_capability cap;
if (-1 == xioctl(device->fd, VIDIOC_QUERYCAP, &cap)) {
return vde_UnsupportedMode;
return vde_FailedStart;
}
/* Setup video format */
@ -269,30 +319,29 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
if(-1 == xioctl(device->fd, VIDIOC_G_FMT, &fmt)) {
return vde_UnsupportedMode;
return vde_FailedStart;
}
device->video_width = fmt.fmt.pix.width;
device->video_height = fmt.fmt.pix.height;
/* Request buffers */
struct v4l2_requestbuffers req;
memset(&(req), 0, sizeof(req));
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(device->fd, VIDIOC_REQBUFS, &req)) {
assert(0);
return vde_UnsupportedMode;
return vde_FailedStart;
}
if(req.count < 2) {
return vde_UnsupportedMode;
return vde_FailedStart;
}
device->buffers = calloc(req.count, sizeof(*device->buffers));
device->buffers = calloc(req.count, sizeof(struct VideoBuffer));
for(i = 0; i < req.count; ++i) {
struct v4l2_buffer buf;
@ -300,11 +349,10 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = device->n_buffers;
device->n_buffers = i;
buf.index = i;
if (-1 == xioctl(device->fd, VIDIOC_QUERYBUF, &buf)) {
return vde_UnsupportedMode;
return vde_FailedStart;
}
device->buffers[i].length = buf.length;
@ -315,14 +363,16 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
device->fd, buf.m.offset);
if(MAP_FAILED == device->buffers[i].start) {
return vde_UnsupportedMode;
return vde_FailedStart;
}
}
device->n_buffers = i;
enum v4l2_buf_type type;
for (i = 0; i < device->n_buffers; ++i) {
struct v4l2_buffer buf;
memset(&(buf), 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
@ -353,7 +403,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
if ((device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen),
0, 0, device->video_width, device->video_height, 0,
BlackPixel(device->x_display, screen),
WhitePixel(device->x_display, screen))) == NULL) {
BlackPixel(device->x_display, screen))) == NULL) {
return vde_FailedStart;
}
@ -383,7 +433,7 @@ VideoDeviceError open_video_device(VideoDeviceType type, int32_t selection, uint
if ((device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen),
0, 0, 100, 100, 0,
BlackPixel(device->x_display, screen),
WhitePixel(device->x_display, screen))) == NULL) {
BlackPixel(device->x_display, screen))) == NULL) {
return vde_FailedStart;
}
@ -419,6 +469,20 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
pthread_mutex_lock(device->mutex);
int screen = DefaultScreen(device->x_display);
/* Recreate missing window */
if(!device->x_window) {
device->x_window = XCreateSimpleWindow(device->x_display, RootWindow(device->x_display, screen),
0, 0, device->video_width, device->video_height, 0,
BlackPixel(device->x_display, screen),
BlackPixel(device->x_display, screen));
XMapWindow(device->x_display, device->x_window);
XClearWindow(device->x_display, device->x_window);
XMapRaised(device->x_display, device->x_window);
XFlush(device->x_display);
}
/* Resize X11 window to correct size */
if(device->video_width != width || device->video_height != height) {
device->video_width = width;
@ -427,13 +491,11 @@ __inline VideoDeviceError write_video_out(uint16_t width, uint16_t height,
vpx_img_free(&device->input);
vpx_img_alloc(&device->input, VPX_IMG_FMT_I420, width, height, 1);
}
int screen = DefaultScreen(device->x_display);
/* Display video image */
ystride = abs(ystride);
ustride = abs(ustride);
vstride = abs(vstride);
line_info_add(CallContrl.window, NULL, NULL, NULL, SYS_MSG, 0, 0, "ystride: %i ustride: %i vstride: %i", ystride, ustride, vstride);
uint8_t *img_data = malloc(width * height * 4);
yuv420tobgr(width, height, y, u, v, ystride, ustride, vstride, img_data);
@ -558,7 +620,7 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
if (device_idx >= MAX_DEVICES) return vde_InvalidSelection;
lock;
VideoDevice* device = video_devices_running[type][device_idx];
VideoDevice *device = video_devices_running[type][device_idx];
VideoDeviceError rc = vde_None;
if (!device) {
@ -571,17 +633,16 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
if ( !device->ref_count ) {
if (type == vdt_input) {
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(-1 == xioctl(device->fd, VIDIOC_STREAMOFF, &buf_type)) {}
int i;
for(i = 0; i < device->n_buffers; ++i) {
if (-1 == munmap(device->buffers[i].start, device->buffers[i].length)) {}
if (-1 == munmap(device->buffers[i].start, device->buffers[i].length)) {
}
}
close(device->fd);
vpx_img_free(&device->input);
//vpx_img_free(&device->input);
XDestroyWindow(device->x_display, device->x_window);
XFlush(device->x_display);
XCloseDisplay(device->x_display);
@ -604,54 +665,6 @@ VideoDeviceError close_video_device(VideoDeviceType type, uint32_t device_idx)
return rc;
}
void yuv420tobgr(uint16_t width, uint16_t height, const uint8_t *y,
const uint8_t *u, const uint8_t *v, unsigned int ystride,
unsigned int ustride, unsigned int vstride, uint8_t *out)
{
unsigned long int i, j;
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
uint8_t *point = out + 4 * ((i * width) + j);
int t_y = y[((i * ystride) + j)];
int t_u = u[(((i / 2) * ustride) + (j / 2))];
int t_v = v[(((i / 2) * vstride) + (j / 2))];
t_y = t_y < 16 ? 16 : t_y;
int r = (298 * (t_y - 16) + 409 * (t_v - 128) + 128) >> 8;
int g = (298 * (t_y - 16) - 100 * (t_u - 128) - 208 * (t_v - 128) + 128) >> 8;
int b = (298 * (t_y - 16) + 516 * (t_u - 128) + 128) >> 8;
point[2] = r>255? 255 : r<0 ? 0 : r;
point[1] = g>255? 255 : g<0 ? 0 : g;
point[0] = b>255? 255 : b<0 ? 0 : b;
point[3] = ~0;
}
}
}
void yuv422to420(uint8_t *plane_y, uint8_t *plane_u, uint8_t *plane_v,
uint8_t *input, uint16_t width, uint16_t height)
{
uint8_t *end = input + width * height * 2;
while(input != end) {
uint8_t *line_end = input + width * 2;
while(input != line_end) {
*plane_y++ = *input++;
*plane_u++ = *input++;
*plane_y++ = *input++;
*plane_v++ = *input++;
}
line_end = input + width * 2;
while(input != line_end) {
*plane_y++ = *input++;
input++;//u
*plane_y++ = *input++;
input++;//v
}
}
}
void print_video_devices(ToxWindow* self, VideoDeviceType type)
{
int i;

View File

@ -153,7 +153,9 @@ struct ToxWindow {
int ringing_sound;
#ifdef VIDEO
int video_device_selection[2]; /* -1 if not set, if set uses these selections instead of primary video device */
#endif /* VIDEO */
#endif /* AUDIO */