From: libvidcap c. m. <lib...@li...> - 2007-09-06 15:39:55
|
Revision: 4 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=4&view=rev Author: jpgrayson Date: 2007-09-06 08:39:40 -0700 (Thu, 06 Sep 2007) Log Message: ----------- Add pkg-config file. Fix installation directory for header files. No longer use multibyte constants for fourcc values. Add api function for mapping fourcc values to strings. Modified Paths: -------------- trunk/Makefile.am trunk/configure.ac trunk/examples/simplegrab.c trunk/examples/vidcapTester/Grabber.cpp trunk/include/vidcap/Makefile.am trunk/include/vidcap/vidcap.h trunk/src/Makefile.am trunk/src/conv.h trunk/src/directshow/DirectShowSource.cpp trunk/src/sapi_qt.c trunk/src/vidcap.c Added Paths: ----------- trunk/vidcap.pc.in Modified: trunk/Makefile.am =================================================================== --- trunk/Makefile.am 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/Makefile.am 2007-09-06 15:39:40 UTC (rev 4) @@ -1,4 +1,7 @@ SUBDIRS = include src examples +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = vidcap.pc + dist-hook: find $(distdir) -name ".svn" -type d -print0 | xargs -0 rm -rf Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/configure.ac 2007-09-06 15:39:40 UTC (rev 4) @@ -1,11 +1,11 @@ +dnl Copyright (C) 2007 Wimba, Inc. + AC_PREREQ(2.59) dnl package version -m4_define(VC_MAJOR, [0]) -m4_define(VC_MINOR, [1]) -m4_define(VC_MICRO, [0]) +m4_define(VIDCAP_VERSION, [0.1]) -AC_INIT([libvidcap], VC_MAJOR.VC_MINOR.VC_MICRO, [jpgrayson (at) gmail (dot) com]) +AC_INIT([libvidcap], VIDCAP_VERSION, [jpg...@gm...]) AC_CONFIG_SRCDIR([include/vidcap/vidcap.h]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall]) @@ -36,6 +36,14 @@ ACX_PTHREAD +AC_CHECK_PROG(have_pkg_config, pkg-config, yes, no) + +if test x"$have_pkg_config" = "xno"; then + AC_MSG_ERROR(pkg-config is required to install this program) +fi + +PKG_PROG_PKG_CONFIG + AC_CHECK_FUNCS(nanosleep gettimeofday snprintf Sleep) AC_CHECK_HEADER(linux/videodev.h, @@ -63,11 +71,15 @@ AM_CONDITIONAL(HAVE_QUICKTIME, test "x$have_quicktime" = "xyes") AM_CONDITIONAL(HAVE_DIRECTSHOW, test "x$have_directshow" = "xyes") +dnl TODO: how do we make the various quicktime frameworks fit in? +AC_SUBST(PKG_REQUIRES) + AC_CONFIG_FILES([ Makefile include/Makefile include/vidcap/Makefile examples/Makefile + vidcap.pc src/Makefile ]) Modified: trunk/examples/simplegrab.c =================================================================== --- trunk/examples/simplegrab.c 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/examples/simplegrab.c 2007-09-06 15:39:40 UTC (rev 4) @@ -150,13 +150,10 @@ { const int size = 255; char * s = malloc(size); - snprintf(s, size, "%3dx%3d %c%c%c%c %.2f %d/%d", + snprintf(s, size, "%3dx%3d %s %.2f %d/%d", fmt_info->width, fmt_info->height, - (fmt_info->fourcc >> 24) & 0xff, - (fmt_info->fourcc >> 16) & 0xff, - (fmt_info->fourcc >> 8) & 0xff, - (fmt_info->fourcc >> 0) & 0xff, + vidcap_fourcc_string_get(fmt_info->fourcc), (float)fmt_info->fps_numerator / (float)fmt_info->fps_denominator, fmt_info->fps_numerator, Modified: trunk/examples/vidcapTester/Grabber.cpp =================================================================== --- trunk/examples/vidcapTester/Grabber.cpp 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/examples/vidcapTester/Grabber.cpp 2007-09-06 15:39:40 UTC (rev 4) @@ -65,14 +65,10 @@ throw std::runtime_error("failed vidcap_format_info_get()"); qDebug() << " bind fmt:" - << QString("%2x%3 %4%5%6%7 (0x%8) %9 %10/%11") + << QString("%2x%3 %4 %5 %6/%7") .arg(fmt_info.width, 3) .arg(fmt_info.height, 3) - .arg(QChar(static_cast<uchar>(fmt_info.fourcc >> 24))) - .arg(QChar(static_cast<uchar>(fmt_info.fourcc >> 16))) - .arg(QChar(static_cast<uchar>(fmt_info.fourcc >> 8))) - .arg(QChar(static_cast<uchar>(fmt_info.fourcc >> 0))) - .arg(static_cast<uint>(fmt_info.fourcc), 8, 16, QChar('0')) + .arg(vidcap_fourcc_string_get(fmt_info.fourcc)) .arg(static_cast<double>(fmt_info.fps_numerator) / static_cast<double>(fmt_info.fps_denominator), 0, 'f', 2) Modified: trunk/include/vidcap/Makefile.am =================================================================== --- trunk/include/vidcap/Makefile.am 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/include/vidcap/Makefile.am 2007-09-06 15:39:40 UTC (rev 4) @@ -1,3 +1,5 @@ -pkginclude_HEADERS = \ +pkgincludedir = $(includedir)/vidcap + +pkginclude_HEADERS = \ vidcap.h \ converters.h Modified: trunk/include/vidcap/vidcap.h =================================================================== --- trunk/include/vidcap/vidcap.h 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/include/vidcap/vidcap.h 2007-09-06 15:39:40 UTC (rev 4) @@ -33,9 +33,9 @@ #define VIDCAP_NAME_LENGTH 256 enum vidcap_fourccs { - VIDCAP_FOURCC_I420 = 'i420', - VIDCAP_FOURCC_YUY2 = 'yuy2', - VIDCAP_FOURCC_RGB32 = ' rgb', + VIDCAP_FOURCC_I420 = 100, + VIDCAP_FOURCC_YUY2 = 101, + VIDCAP_FOURCC_RGB32 = 102, }; typedef void vidcap_state; @@ -143,6 +143,9 @@ int vidcap_src_capture_stop(vidcap_src *); +const char * +vidcap_fourcc_string_get(int fourcc); + #ifdef __cplusplus } #endif Modified: trunk/src/Makefile.am =================================================================== --- trunk/src/Makefile.am 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/src/Makefile.am 2007-09-06 15:39:40 UTC (rev 4) @@ -3,10 +3,8 @@ lib_LTLIBRARIES = libvidcap.la libvidcap_la_CPPFLAGS = -I$(top_srcdir)/include -libvidcap_la_CFLAGS = -Wall -Wextra -Wno-unused-parameter -Wno-multichar \ - $(PTHREAD_CFLAGS) -libvidcap_la_CXXFLAGS = -Wall -Wextra -Wno-unused-parameter -Wno-multichar \ - $(PTHREAD_CFLAGS) +libvidcap_la_CFLAGS = -Wall -Wextra -Wno-unused-parameter $(PTHREAD_CFLAGS) +libvidcap_la_CXXFLAGS = -Wall -Wextra -Wno-unused-parameter $(PTHREAD_CFLAGS) libvidcap_la_LIBADD = $(PTHREAD_LIBS) Modified: trunk/src/conv.h =================================================================== --- trunk/src/conv.h 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/src/conv.h 2007-09-06 15:39:40 UTC (rev 4) @@ -31,10 +31,10 @@ enum vidcap_fourccs_extra { - VIDCAP_FOURCC_RGB24 = ' r24', - VIDCAP_FOURCC_RGB555 = 'r555', - VIDCAP_FOURCC_YVU9 = 'yvu9', - VIDCAP_FOURCC_2VUY = '2vuy', + VIDCAP_FOURCC_RGB24 = 200, + VIDCAP_FOURCC_RGB555 = 201, + VIDCAP_FOURCC_YVU9 = 202, + VIDCAP_FOURCC_2VUY = 203, }; typedef int (*conv_func)(int width, int height, Modified: trunk/src/directshow/DirectShowSource.cpp =================================================================== --- trunk/src/directshow/DirectShowSource.cpp 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/src/directshow/DirectShowSource.cpp 2007-09-06 15:39:40 UTC (rev 4) @@ -1011,11 +1011,8 @@ data = 0x32595559; break; default: - log_warn("failed to map '%c%c%c%c' to DS media type\n", - (char)((fourcc >> 24) & 0xff), - (char)((fourcc >> 16) & 0xff), - (char)((fourcc >> 8) & 0xff), - (char)((fourcc >> 0) & 0xff)); + log_warn("failed to map '%s' to DS media type\n", + vidcap_fourcc_string_get(fourcc)); return -1; } Modified: trunk/src/sapi_qt.c =================================================================== --- trunk/src/sapi_qt.c 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/src/sapi_qt.c 2007-09-06 15:39:40 UTC (rev 4) @@ -202,19 +202,15 @@ } if ( qt_src_ctx->frame_count == 1 ) - log_info("capture time: %c%c%c%c %c%c%c%c %c%c%c%c %s\n", + log_info("capture time: %c%c%c%c %s %s %s\n", (char)(pixel_format >> 24), (char)(pixel_format >> 16), (char)(pixel_format >> 8), (char)(pixel_format >> 0), - (char)(src_ctx->fmt_native.fourcc >> 24), - (char)(src_ctx->fmt_native.fourcc >> 16), - (char)(src_ctx->fmt_native.fourcc >> 8), - (char)(src_ctx->fmt_native.fourcc >> 0), - (char)(src_ctx->fmt_nominal.fourcc >> 24), - (char)(src_ctx->fmt_nominal.fourcc >> 16), - (char)(src_ctx->fmt_nominal.fourcc >> 8), - (char)(src_ctx->fmt_nominal.fourcc >> 0), + vidcap_fourcc_string_get( + src_ctx->fmt_native.fourcc), + vidcap_fourcc_string_get( + src_ctx->fmt_nominal.fourcc), src_ctx->src_info.identifier); sapi_src_capture_notify(src_ctx, @@ -285,27 +281,19 @@ if ( map_fourcc_to_ostype(src_ctx->fmt_native.fourcc, &pixel_format) ) { - log_error("invalid bound fourcc '%c%c%c%c'\n", - (char)(src_ctx->fmt_native.fourcc >> 24), - (char)(src_ctx->fmt_native.fourcc >> 16), - (char)(src_ctx->fmt_native.fourcc >> 8), - (char)(src_ctx->fmt_native.fourcc >> 0)); + log_error("invalid bound fourcc '%s'\n", + vidcap_fourcc_string_get( + src_ctx->fmt_native.fourcc)); return -1; } - log_info("setup decomp: %c%c%c%c %c%c%c%c %c%c%c%c %s\n", + log_info("setup decomp: %c%c%c%c %s %s %s\n", (char)(pixel_format >> 24), (char)(pixel_format >> 16), (char)(pixel_format >> 8), (char)(pixel_format >> 0), - (char)(src_ctx->fmt_native.fourcc >> 24), - (char)(src_ctx->fmt_native.fourcc >> 16), - (char)(src_ctx->fmt_native.fourcc >> 8), - (char)(src_ctx->fmt_native.fourcc >> 0), - (char)(src_ctx->fmt_nominal.fourcc >> 24), - (char)(src_ctx->fmt_nominal.fourcc >> 16), - (char)(src_ctx->fmt_nominal.fourcc >> 8), - (char)(src_ctx->fmt_nominal.fourcc >> 0), + vidcap_fourcc_string_get(src_ctx->fmt_native.fourcc), + vidcap_fourcc_string_get(src_ctx->fmt_nominal.fourcc), src_ctx->src_info.identifier); n = CFNumberCreate(0, kCFNumberSInt32Type, &pixel_format); @@ -403,12 +391,9 @@ if ( map_fourcc_to_ostype(src_ctx->fmt_native.fourcc, &pixel_format) ) { - log_error("invalid pixel format '%c%c%c%c' (0x%08x)\n", - (char)(src_ctx->fmt_native.fourcc >> 24), - (char)(src_ctx->fmt_native.fourcc >> 16), - (char)(src_ctx->fmt_native.fourcc >> 8), - (char)(src_ctx->fmt_native.fourcc >> 0), - src_ctx->fmt_native.fourcc); + log_error("invalid pixel format '%s'\n", + vidcap_fourcc_string_get( + src_ctx->fmt_native.fourcc)); return (void *)-1; } Modified: trunk/src/vidcap.c =================================================================== --- trunk/src/vidcap.c 2007-09-03 20:34:33 UTC (rev 3) +++ trunk/src/vidcap.c 2007-09-06 15:39:40 UTC (rev 4) @@ -369,12 +369,9 @@ if ( !src_ctx->format_validate(src_ctx, fmt_info, &fmt_native) ) { - log_error("invalid format %dx%d %c%c%c%c %d/%d\n", + log_error("invalid format %dx%d %s %d/%d\n", fmt_info->width, fmt_info->height, - (char)(fmt_info->fourcc >> 24), - (char)(fmt_info->fourcc >> 16), - (char)(fmt_info->fourcc >> 8), - (char)(fmt_info->fourcc >> 0), + vidcap_fourcc_string_get(fmt_info->fourcc), fmt_info->fps_numerator, fmt_info->fps_denominator); return -1; @@ -405,11 +402,9 @@ if ( !src_ctx->fmt_conv_buf_size ) { - log_error("failed to get buffer size for %c%c%c%c\n", - (char)(fmt_info->fourcc >> 24), - (char)(fmt_info->fourcc >> 16), - (char)(fmt_info->fourcc >> 8), - (char)(fmt_info->fourcc >> 0)); + log_error("failed to get buffer size for %s\n", + vidcap_fourcc_string_get( + fmt_info->fourcc)); return -1; } @@ -492,3 +487,26 @@ return ret; } +const char * +vidcap_fourcc_string_get(int fourcc) +{ + switch ( fourcc ) + { + case VIDCAP_FOURCC_I420: + return "i420"; + case VIDCAP_FOURCC_YUY2: + return "yuy2"; + case VIDCAP_FOURCC_RGB32: + return " rgb"; + case VIDCAP_FOURCC_RGB24: + return " r24"; + case VIDCAP_FOURCC_RGB555: + return "r555"; + case VIDCAP_FOURCC_YVU9: + return "yvu9"; + case VIDCAP_FOURCC_2VUY: + return "2vuy"; + default: + return "????"; + } +} Added: trunk/vidcap.pc.in =================================================================== --- trunk/vidcap.pc.in (rev 0) +++ trunk/vidcap.pc.in 2007-09-06 15:39:40 UTC (rev 4) @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=${prefix}/include + +Name: vidcap +Description: Cross-platform video capture library +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lvidcap @PTHREAD_LIBS@ +Libs.private: +Cflags: -I${includedir} +Requires.private: @PKG_REQUIRES@ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. m. <lib...@li...> - 2007-09-11 15:31:21
|
Revision: 14 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=14&view=rev Author: bcholew Date: 2007-09-11 08:31:16 -0700 (Tue, 11 Sep 2007) Log Message: ----------- Remove all destination buffer size checks in conversion functions. Replace with notices for each class of conversion function. Modified Paths: -------------- trunk/examples/vidcapTester/Grabber.cpp trunk/include/vidcap/converters.h trunk/src/conv.c trunk/src/conv.h trunk/src/conv_to_i420.c trunk/src/conv_to_rgb.c trunk/src/conv_to_yuy2.c trunk/src/sapi.c Modified: trunk/examples/vidcapTester/Grabber.cpp =================================================================== --- trunk/examples/vidcapTester/Grabber.cpp 2007-09-11 14:46:28 UTC (rev 13) +++ trunk/examples/vidcapTester/Grabber.cpp 2007-09-11 15:31:16 UTC (rev 14) @@ -134,13 +134,13 @@ rgb_buf.resize(width_ * height_ * 4); vidcap_i420_to_rgb32(width_, height_, cap_info->video_data, - rgb_buf.data(), rgb_buf.size()); + rgb_buf.data()); break; case VIDCAP_FOURCC_YUY2: rgb_buf.resize(width_ * height_ * 4); vidcap_yuy2_to_rgb32(width_, height_, cap_info->video_data, - rgb_buf.data(), rgb_buf.size()); + rgb_buf.data()); break; Modified: trunk/include/vidcap/converters.h =================================================================== --- trunk/include/vidcap/converters.h 2007-09-11 14:46:28 UTC (rev 13) +++ trunk/include/vidcap/converters.h 2007-09-11 15:31:16 UTC (rev 14) @@ -32,27 +32,27 @@ int vidcap_i420_to_rgb32(int width, int height, const char * src, - char * dest, int dest_size); + char * dest); int vidcap_i420_to_yuy2(int width, int height, const char * src, - char * dest, int dest_size); + char * dest); int vidcap_yuy2_to_i420(int width, int height, const char * src, - char * dest, int dest_size); + char * dest); int vidcap_yuy2_to_rgb32(int width, int height, const char * src, - char * dest, int dest_size); + char * dest); int vidcap_rgb32_to_i420(int width, int height, const char * src, - char * dest, int dest_size); + char * dest); int vidcap_rgb32_to_yuy2(int width, int height, const char * src, - char * dest, int dest_size); + char * dest); #ifdef __cplusplus } Modified: trunk/src/conv.c =================================================================== --- trunk/src/conv.c 2007-09-11 14:46:28 UTC (rev 13) +++ trunk/src/conv.c 2007-09-11 15:31:16 UTC (rev 14) @@ -25,11 +25,11 @@ #include "conv.h" -int conv_2vuy_to_i420(int w, int h, const char * s, char * d, int ds); -int conv_2vuy_to_yuy2(int w, int h, const char * s, char * d, int ds); -int conv_rgb24_to_rgb32(int w, int h, const char * s, char * d, int ds); -int conv_yvu9_to_i420(int w, int h, const char * s, char * d, int ds); -int conv_bottom_up_rgb24_to_rgb32(int w, int h, const char * s, char * d, int ds); +int conv_2vuy_to_i420(int w, int h, const char * s, char * d); +int conv_2vuy_to_yuy2(int w, int h, const char * s, char * d); +int conv_rgb24_to_rgb32(int w, int h, const char * s, char * d); +int conv_yvu9_to_i420(int w, int h, const char * s, char * d); +int conv_bottom_up_rgb24_to_rgb32(int w, int h, const char * s, char * d); struct conv_info { Modified: trunk/src/conv.h =================================================================== --- trunk/src/conv.h 2007-09-11 14:46:28 UTC (rev 13) +++ trunk/src/conv.h 2007-09-11 15:31:16 UTC (rev 14) @@ -39,7 +39,7 @@ }; typedef int (*conv_func)(int width, int height, - const char * src, char * dst, int dst_size); + const char * src, char * dst); #ifdef __cplusplus extern "C" { Modified: trunk/src/conv_to_i420.c =================================================================== --- trunk/src/conv_to_i420.c 2007-09-11 14:46:28 UTC (rev 13) +++ trunk/src/conv_to_i420.c 2007-09-11 15:31:16 UTC (rev 14) @@ -27,10 +27,13 @@ #include <vidcap/converters.h> #include "logging.h" +/* NOTE: size of dest must be >= width * height * 3 / 2 + */ + int vidcap_rgb32_to_i420(int width, int height, const char * src, - char * dst, int dest_size) + char * dst) { log_error("vidcap_rgb32_to_i420() not implemented\n"); return -1; @@ -39,7 +42,7 @@ int vidcap_yuy2_to_i420(int width, int height, const char * src, - char * dst, int dest_size) + char * dst) { /* convert from a packed structure to a planar structure */ char * dst_y_even = dst; @@ -51,9 +54,6 @@ int i, j; - if ( dest_size < width * height * 3 / 2 ) - return -1; - /* yuy2 has a vertical sampling period (for u and v) * half that for i420. Will toss half of the * U and V data during repackaging. @@ -88,7 +88,7 @@ int conv_2vuy_to_i420(int width, int height, const char * src, - char * dst, int dest_size) + char * dst) { char * dst_y_even = dst; char * dst_y_odd = dst + width; @@ -99,9 +99,6 @@ int i, j; - if ( dest_size < width * height * 3 / 2 ) - return -1; - for ( i = 0; i < height / 2; ++i ) { for ( j = 0; j < width / 2; ++j ) @@ -132,7 +129,7 @@ int conv_yvu9_to_i420(int width, int height, const char * src, - char * dst, int dest_size) + char * dst) { char * dst_y = dst; char * dst_u_even = dst + width * height; @@ -145,9 +142,6 @@ int i, j; - if ( dest_size < width * height * 3 / 2 ) - return -1; - memcpy(dst_y, src_y, height * width); for ( i = 0; i < height / 4; ++i ) Modified: trunk/src/conv_to_rgb.c =================================================================== --- trunk/src/conv_to_rgb.c 2007-09-11 14:46:28 UTC (rev 13) +++ trunk/src/conv_to_rgb.c 2007-09-11 15:31:16 UTC (rev 14) @@ -23,7 +23,6 @@ * */ -//#include <string.h> #include <vidcap/converters.h> enum { @@ -98,9 +97,13 @@ * * Based on the formulas found at http://en.wikipedia.org/wiki/YUV */ + +/* NOTE: size of dest buffer must be >= width * height * 4 + */ + int vidcap_i420_to_rgb32(int width, int height, const char * src, - char * dest, int dest_size) + char * dest) { const unsigned char * y_even; const unsigned char * y_odd; @@ -110,9 +113,6 @@ unsigned int *dst_odd; int i, j; - if ( dest_size < width * height * 4 ) - return -1; - if ( !tables_initialized ) init_yuv2rgb_tables(); @@ -159,14 +159,11 @@ * chroma (Cr and Cb aka v and u) sample use for both pixels. */ int vidcap_yuy2_to_rgb32(int width, int height, const char * src, - char * dest, int dest_size) + char * dest) { unsigned int * d = (unsigned int *)dest; int i, j; - if ( dest_size < width * height * 4 ) - return -1; - if ( !tables_initialized ) init_yuv2rgb_tables(); @@ -193,14 +190,11 @@ } int conv_rgb24_to_rgb32(int width, int height, const char * src, - char * dest, int dest_size) + char * dest) { int i; unsigned int * d = (unsigned int *)dest; - if ( dest_size < width * height * 4 ) - return -1; - for ( i = 0; i < width * height; ++i ) { *d = 0xff000000; @@ -214,15 +208,12 @@ int conv_bottom_up_rgb24_to_rgb32(int width, int height, const char * src, - char * dest, int dest_size) + char * dest) { int i; unsigned int * d = (unsigned int *)dest; const unsigned char *src_end = src - 1 + width * height * 3; - if ( dest_size < width * height * 4 ) - return -1; - for ( i = 0; i < width * height; ++i ) { *d = 0xff000000; Modified: trunk/src/conv_to_yuy2.c =================================================================== --- trunk/src/conv_to_yuy2.c 2007-09-11 14:46:28 UTC (rev 13) +++ trunk/src/conv_to_yuy2.c 2007-09-11 15:31:16 UTC (rev 14) @@ -26,9 +26,12 @@ #include <vidcap/converters.h> #include "logging.h" +/* NOTE: size of dest buffer must be >= width * height * 2 + */ + int vidcap_rgb32_to_yuy2(int width, int height, const char * src, - char * dest, int dest_size) + char * dest) { log_error("vidcap_rgb32_to_yuy2() not implemented\n"); return -1; @@ -36,7 +39,7 @@ int vidcap_i420_to_yuy2(int width, int height, const char * src, - char * dest, int dest_size) + char * dest) { log_error("vidcap_i420_to_yuy2() not implemented\n"); return -1; @@ -44,15 +47,12 @@ int conv_2vuy_to_yuy2(int width, int height, const char * src, - char * dest, int dest_size) + char * dest) { int i; unsigned int * d = (unsigned int *)dest; const unsigned int * s = (const unsigned int *)src; - if ( dest_size < width * height * 2 ) - return -1; - for ( i = 0; i < width * height / 2; ++i ) { *d++ = ((*s & 0xff000000) >> 8) | Modified: trunk/src/sapi.c =================================================================== --- trunk/src/sapi.c 2007-09-11 14:46:28 UTC (rev 13) +++ trunk/src/sapi.c 2007-09-11 15:31:16 UTC (rev 14) @@ -236,8 +236,7 @@ src_ctx->fmt_nominal.width, src_ctx->fmt_nominal.height, video_data, - src_ctx->fmt_conv_buf, - src_ctx->fmt_conv_buf_size) ) + src_ctx->fmt_conv_buf) ) { log_error("failed format conversion\n"); cap_info.error_status = -1; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. m. <lib...@li...> - 2007-10-06 19:10:19
|
Revision: 40 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=40&view=rev Author: jpgrayson Date: 2007-10-06 12:10:17 -0700 (Sat, 06 Oct 2007) Log Message: ----------- Fixup 'make dist'. vidcapTester makes it into source tarball. directshow sources fixed-up in Makefile.am. Modified Paths: -------------- trunk/examples/Makefile.am trunk/src/Makefile.am Modified: trunk/examples/Makefile.am =================================================================== --- trunk/examples/Makefile.am 2007-10-01 21:47:31 UTC (rev 39) +++ trunk/examples/Makefile.am 2007-10-06 19:10:17 UTC (rev 40) @@ -16,3 +16,4 @@ -framework QuickTime endif +EXTRA_DIST = vidcapTester Modified: trunk/src/Makefile.am =================================================================== --- trunk/src/Makefile.am 2007-10-01 21:47:31 UTC (rev 39) +++ trunk/src/Makefile.am 2007-10-06 19:10:17 UTC (rev 40) @@ -51,15 +51,18 @@ endif if HAVE_DIRECTSHOW -libvidcap_la_SOURCES += \ - sapi_dshow.cpp \ - directshow/DShowSrcManager.cpp \ - directshow/DShowSrcManager.h \ - directshow/DevMonitor.cpp \ - directshow/DevMonitor.h \ - directshow/DirectShowSource.cpp \ - directshow/DirectShowSource.h \ - directshow/GraphMonitor.cpp \ - directshow/GraphMonitor.h \ - directshow/LocklessQueue.h +libvidcap_la_SOURCES += \ + directshow/DShowSrcManager.cpp \ + directshow/DShowSrcManager.h \ + directshow/DevMonitor.cpp \ + directshow/DevMonitor.h \ + directshow/DirectShowObject.cpp \ + directshow/DirectShowObject.h \ + directshow/DirectShowSource.cpp \ + directshow/DirectShowSource.h \ + directshow/GraphMonitor.cpp \ + directshow/GraphMonitor.h \ + directshow/SourceStateMachine.cpp \ + directshow/SourceStateMachine.h \ + sapi_dshow.cpp endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. m. <lib...@li...> - 2007-10-06 19:43:25
|
Revision: 41 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=41&view=rev Author: jpgrayson Date: 2007-10-06 12:43:23 -0700 (Sat, 06 Oct 2007) Log Message: ----------- Add vidcap_log_level_set() function to the api. Set the default log level to VIDCAP_LOG_INFO. Change some quicktime messages to debug level. Modified Paths: -------------- trunk/include/vidcap/vidcap.h trunk/src/logging.c trunk/src/quicktime/sg_source.c trunk/src/sapi_qt.c trunk/src/vidcap.c Modified: trunk/include/vidcap/vidcap.h =================================================================== --- trunk/include/vidcap/vidcap.h 2007-10-06 19:10:17 UTC (rev 40) +++ trunk/include/vidcap/vidcap.h 2007-10-06 19:43:23 UTC (rev 41) @@ -38,6 +38,14 @@ VIDCAP_FOURCC_RGB32 = 102, }; +enum vidcap_log_level { + VIDCAP_LOG_NONE = 0, + VIDCAP_LOG_ERROR = 10, + VIDCAP_LOG_WARN = 20, + VIDCAP_LOG_INFO = 30, + VIDCAP_LOG_DEBUG = 40 +}; + typedef void vidcap_state; typedef void vidcap_sapi; typedef void vidcap_src; @@ -83,6 +91,9 @@ vidcap_destroy(vidcap_state *); int +vidcap_log_level_set(enum vidcap_log_level level); + +int vidcap_sapi_enumerate(vidcap_state *, int index, struct vidcap_sapi_info *); Modified: trunk/src/logging.c =================================================================== --- trunk/src/logging.c 2007-10-06 19:10:17 UTC (rev 40) +++ trunk/src/logging.c 2007-10-06 19:43:23 UTC (rev 41) @@ -38,7 +38,7 @@ static FILE * logging_file = 0; -static enum log_level logging_level = log_level_debug; +static enum log_level logging_level = log_level_info; static void do_log(enum log_level level, const char * fmt, va_list ap) { Modified: trunk/src/quicktime/sg_source.c =================================================================== --- trunk/src/quicktime/sg_source.c 2007-10-06 19:10:17 UTC (rev 40) +++ trunk/src/quicktime/sg_source.c 2007-10-06 19:43:23 UTC (rev 41) @@ -149,7 +149,7 @@ src->native_pixel_format = (*compression_list)->cType; - log_info("native pixel format %c%c%c%c\n", + log_debug("native pixel format %c%c%c%c\n", (char)(src->native_pixel_format >> 24), (char)(src->native_pixel_format >> 16), (char)(src->native_pixel_format >> 8), Modified: trunk/src/sapi_qt.c =================================================================== --- trunk/src/sapi_qt.c 2007-10-06 19:10:17 UTC (rev 40) +++ trunk/src/sapi_qt.c 2007-10-06 19:43:23 UTC (rev 41) @@ -202,7 +202,7 @@ } if ( qt_src_ctx->frame_count == 1 ) - log_info("capture time: %c%c%c%c %s %s %s\n", + log_debug("capture time: %c%c%c%c %s %s %s\n", (char)(pixel_format >> 24), (char)(pixel_format >> 16), (char)(pixel_format >> 8), @@ -287,7 +287,7 @@ return -1; } - log_info("setup decomp: %c%c%c%c %s %s %s\n", + log_debug("setup decomp: %c%c%c%c %s %s %s\n", (char)(pixel_format >> 24), (char)(pixel_format >> 16), (char)(pixel_format >> 8), Modified: trunk/src/vidcap.c =================================================================== --- trunk/src/vidcap.c 2007-10-06 19:10:17 UTC (rev 40) +++ trunk/src/vidcap.c 2007-10-06 19:43:23 UTC (rev 41) @@ -133,6 +133,36 @@ } int +vidcap_log_level_set(enum vidcap_log_level level) +{ + int log_level; + + switch ( level ) + { + case VIDCAP_LOG_NONE: + log_level = log_level_none; + break; + case VIDCAP_LOG_ERROR: + log_level = log_level_error; + break; + case VIDCAP_LOG_WARN: + log_level = log_level_warn; + break; + case VIDCAP_LOG_INFO: + log_level = log_level_info; + break; + case VIDCAP_LOG_DEBUG: + log_level = log_level_debug; + default: + return -1; + } + + log_level_set(log_level); + + return 0; +} + +int vidcap_sapi_enumerate(vidcap_state * state, int index, struct vidcap_sapi_info * sapi_info) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. m. <lib...@li...> - 2007-10-09 14:30:42
|
Revision: 42 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=42&view=rev Author: jpgrayson Date: 2007-10-09 07:30:40 -0700 (Tue, 09 Oct 2007) Log Message: ----------- Whitespace, comments Modified Paths: -------------- trunk/include/vidcap/converters.h trunk/src/sapi.c Modified: trunk/include/vidcap/converters.h =================================================================== --- trunk/include/vidcap/converters.h 2007-10-06 19:43:23 UTC (rev 41) +++ trunk/include/vidcap/converters.h 2007-10-09 14:30:40 UTC (rev 42) @@ -31,28 +31,22 @@ #endif int -vidcap_i420_to_rgb32(int width, int height, const char * src, - char * dest); +vidcap_i420_to_rgb32(int width, int height, const char * src, char * dest); int -vidcap_i420_to_yuy2(int width, int height, const char * src, - char * dest); +vidcap_i420_to_yuy2(int width, int height, const char * src, char * dest); int -vidcap_yuy2_to_i420(int width, int height, const char * src, - char * dest); +vidcap_yuy2_to_i420(int width, int height, const char * src, char * dest); int -vidcap_yuy2_to_rgb32(int width, int height, const char * src, - char * dest); +vidcap_yuy2_to_rgb32(int width, int height, const char * src, char * dest); int -vidcap_rgb32_to_i420(int width, int height, const char * src, - char * dest); +vidcap_rgb32_to_i420(int width, int height, const char * src, char * dest); int -vidcap_rgb32_to_yuy2(int width, int height, const char * src, - char * dest); +vidcap_rgb32_to_yuy2(int width, int height, const char * src, char * dest); #ifdef __cplusplus } Modified: trunk/src/sapi.c =================================================================== --- trunk/src/sapi.c 2007-10-06 19:43:23 UTC (rev 41) +++ trunk/src/sapi.c 2007-10-09 14:30:40 UTC (rev 42) @@ -217,9 +217,10 @@ { struct vidcap_capture_info cap_info; - // NOTE: We may be called here by a notification thread while - // the main thread is clearing the src_ctx ->capture_data and - // ->capture_callback from within vidcap_src_capture_stop() + /* NOTE: We may be called here by a notification thread while the + * main thread is clearing capture_data and capture_callback from + * within vidcap_src_capture_stop(). + */ vidcap_src_capture_callback cap_callback = src_ctx->capture_callback; void * cap_data = src_ctx->capture_data; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. m. <lib...@li...> - 2007-10-09 16:28:31
|
Revision: 43 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=43&view=rev Author: bcholew Date: 2007-10-09 09:28:27 -0700 (Tue, 09 Oct 2007) Log Message: ----------- Added vcproj file. Added Paths: ----------- trunk/contrib/ trunk/contrib/win/ trunk/contrib/win/vs2005/ trunk/contrib/win/vs2005/libvidcap.vcproj Added: trunk/contrib/win/vs2005/libvidcap.vcproj =================================================================== --- trunk/contrib/win/vs2005/libvidcap.vcproj (rev 0) +++ trunk/contrib/win/vs2005/libvidcap.vcproj 2007-10-09 16:28:27 UTC (rev 43) @@ -0,0 +1,372 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="libvidcap" + ProjectGUID="{F5166D99-32BB-40D5-BE95-6F97F72C44CE}" + RootNamespace="libvidcap" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="..\..\..\..\build-win32\$(ProjectName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)" + ConfigurationType="4" + UseOfATL="0" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\directshow;..\..\..\include;"$(DXSDK_DIR)\Include"" + PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_DIRECTSHOW;HAVE_SLEEP" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + CompileAs="1" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="..\..\..\..\build-win32\$(ProjectName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)" + ConfigurationType="4" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\..\src;..\..\..\src\directshow;..\..\..\include;"$(DXSDK_DIR)\Include"" + PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;HAVE_DIRECTSHOW;HAVE_SLEEP" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CompileAs="1" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\..\src\conv.c" + > + </File> + <File + RelativePath="..\..\..\src\conv_to_i420.c" + > + </File> + <File + RelativePath="..\..\..\src\conv_to_rgb.c" + > + </File> + <File + RelativePath="..\..\..\src\conv_to_yuy2.c" + > + </File> + <File + RelativePath="..\..\..\src\directshow\DevMonitor.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\src\directshow\DirectShowSource.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\src\directshow\DShowSrcManager.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\src\directshow\GraphMonitor.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\src\hotlist.c" + > + </File> + <File + RelativePath="..\..\..\src\logging.c" + > + </File> + <File + RelativePath="..\..\..\src\sapi.c" + > + </File> + <File + RelativePath="..\..\..\src\sapi_dshow.cpp" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + CompileAs="2" + /> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\src\sliding_window.c" + > + </File> + <File + RelativePath="..\..\..\src\vidcap.c" + > + <FileConfiguration + Name="Debug|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + > + <Tool + Name="VCCLCompilerTool" + ObjectFile="$(IntDir)\$(InputName)1.obj" + XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc" + /> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath="..\..\..\src\conv.h" + > + </File> + <File + RelativePath="..\..\..\include\vidcap\converters.h" + > + </File> + <File + RelativePath="..\..\..\src\directshow\DevMonitor.h" + > + </File> + <File + RelativePath="..\..\..\src\directshow\DirectShowSource.h" + > + </File> + <File + RelativePath="..\..\..\src\directshow\DShowSrcManager.h" + > + </File> + <File + RelativePath="..\..\..\src\directshow\GraphMonitor.h" + > + </File> + <File + RelativePath="..\..\..\src\hotlist.h" + > + </File> + <File + RelativePath="..\..\..\src\logging.h" + > + </File> + <File + RelativePath="..\..\..\src\sapi.h" + > + </File> + <File + RelativePath="..\..\..\src\sapi_context.h" + > + </File> + <File + RelativePath="..\..\..\src\sliding_window.h" + > + </File> + <File + RelativePath="..\..\..\include\vidcap\vidcap.h" + > + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> Property changes on: trunk/contrib/win/vs2005/libvidcap.vcproj ___________________________________________________________________ Name: svn:executable + * This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. <lib...@li...> - 2007-11-26 17:59:41
|
Revision: 65 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=65&view=rev Author: bcholew Date: 2007-11-26 09:59:33 -0800 (Mon, 26 Nov 2007) Log Message: ----------- Add a capture timer thread to strictly enforce framerate (but preserve code for use without this thread). Add a double buffer to pass frames between threads. Abstract threading and mutexes for linux, mac and windows. Add new double_buffer and os_funcs files to vcproj and Makefiles. Simplify and rearrange some includes. Modified Paths: -------------- trunk/contrib/win/vs2005/libvidcap.vcproj trunk/src/Makefile.am trunk/src/directshow/DShowSrcManager.cpp trunk/src/directshow/DevMonitor.cpp trunk/src/directshow/DevMonitor.h trunk/src/directshow/DirectShowSource.cpp trunk/src/directshow/SourceStateMachine.cpp trunk/src/sapi.c trunk/src/sapi_context.h trunk/src/sapi_dshow.cpp trunk/src/vidcap.c Added Paths: ----------- trunk/src/double_buffer.c trunk/src/double_buffer.h trunk/src/os_funcs.h Modified: trunk/contrib/win/vs2005/libvidcap.vcproj =================================================================== --- trunk/contrib/win/vs2005/libvidcap.vcproj 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/contrib/win/vs2005/libvidcap.vcproj 2007-11-26 17:59:33 UTC (rev 65) @@ -228,6 +228,10 @@ </FileConfiguration> </File> <File + RelativePath="..\..\..\src\double_buffer.c" + > + </File> + <File RelativePath="..\..\..\src\directshow\DShowSrcManager.cpp" > <FileConfiguration @@ -372,6 +376,10 @@ > </File> <File + RelativePath="..\..\..\src\double_buffer.h" + > + </File> + <File RelativePath="..\..\..\src\directshow\DShowSrcManager.h" > </File> @@ -388,6 +396,10 @@ > </File> <File + RelativePath="..\..\..\src\os_funcs.h" + > + </File> + <File RelativePath="..\..\..\src\sapi.h" > </File> Modified: trunk/src/Makefile.am =================================================================== --- trunk/src/Makefile.am 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/Makefile.am 2007-11-26 17:59:33 UTC (rev 65) @@ -19,10 +19,13 @@ conv_to_rgb.c \ conv_to_i420.c \ conv_to_yuy2.c \ + double_buffer.c \ + double_buffer.h \ hotlist.c \ hotlist.h \ logging.c \ logging.h \ + os_funcs.h \ sapi.c \ sapi.h \ sapi_context.h \ Modified: trunk/src/directshow/DShowSrcManager.cpp =================================================================== --- trunk/src/directshow/DShowSrcManager.cpp 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/directshow/DShowSrcManager.cpp 2007-11-26 17:59:33 UTC (rev 65) @@ -22,7 +22,7 @@ // <http://www.gnu.org/licenses/>. // -#include <windows.h> +#include "os_funcs.h" #include <cstring> #include <cstdio> #include <cwchar> Modified: trunk/src/directshow/DevMonitor.cpp =================================================================== --- trunk/src/directshow/DevMonitor.cpp 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/directshow/DevMonitor.cpp 2007-11-26 17:59:33 UTC (rev 65) @@ -22,11 +22,12 @@ // <http://www.gnu.org/licenses/>. // -#include "DevMonitor.h" +#include "os_funcs.h" #include <dbt.h> #include <process.h> #include <string> #include "sapi_context.h" +#include "DevMonitor.h" #include "logging.h" DevMonitor::DevMonitor() Modified: trunk/src/directshow/DevMonitor.h =================================================================== --- trunk/src/directshow/DevMonitor.h 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/directshow/DevMonitor.h 2007-11-26 17:59:33 UTC (rev 65) @@ -25,21 +25,8 @@ #ifndef _DEVMONITOR_H_ #define _DEVMONITOR_H_ -#include <windows.h> #include <vidcap/vidcap.h> -// Allow use of features specific to Windows XP or later. -#ifndef _WIN32_WINNT - -// Change this to the appropriate value to target other versions of Windows. -// see: http://msdn2.microsoft.com/en-us/library/aa383745.aspx -#define _WIN32_WINNT 0x0501 - -#endif - -// Exclude rarely-used stuff from Windows headers -#define WIN32_LEAN_AND_MEAN - class DevMonitor { Modified: trunk/src/directshow/DirectShowSource.cpp =================================================================== --- trunk/src/directshow/DirectShowSource.cpp 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/directshow/DirectShowSource.cpp 2007-11-26 17:59:33 UTC (rev 65) @@ -22,7 +22,7 @@ // <http://www.gnu.org/licenses/>. // -#include <windows.h> +#include "os_funcs.h" #include <cstring> #include <cstdio> #include <cwchar> @@ -686,6 +686,9 @@ static_cast<double>(fmtNominal->fps_denominator); // check framerate + // TODO: a timer thread could enforce this framerate, + // but would need to pass src_ctx->use_timer_thread here + // to know that if ( fps > fpsMax ) { freeMediaType(*pMediaType); Modified: trunk/src/directshow/SourceStateMachine.cpp =================================================================== --- trunk/src/directshow/SourceStateMachine.cpp 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/directshow/SourceStateMachine.cpp 2007-11-26 17:59:33 UTC (rev 65) @@ -22,11 +22,9 @@ // <http://www.gnu.org/licenses/>. // -#include <windows.h> - +#include "sapi.h" #include "hotlist.h" #include "logging.h" -#include "sapi.h" #include "SourceStateMachine.h" SourceStateMachine::SourceStateMachine(struct sapi_src_context *src, Added: trunk/src/double_buffer.c =================================================================== --- trunk/src/double_buffer.c (rev 0) +++ trunk/src/double_buffer.c 2007-11-26 17:59:33 UTC (rev 65) @@ -0,0 +1,200 @@ +/* + * libvidcap - a cross-platform video capture library + * + * Copyright 2007 Wimba, Inc. + * + * Contributors: + * Peter Grayson <jpg...@gm...> + * Bill Cholewka <bc...@gm...> + * + * libvidcap is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libvidcap 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <stdlib.h> +#include <string.h> + +#include "double_buffer.h" + +#include "logging.h" + +/* The write thread inserts (and frees) objects. + * The read thread reads (copies) objects + * + * It is the responsibility of the read thread's 'application' to + * free the copied objects. + * + * If the read thread 'application' blocks for too long (doesn't + * read often enough), the write thread will free a buffered object + * to make room for an incoming object + */ + +/* NOTE: This function is passed function pointers to call when + * necessary to free or copy an object + */ +struct double_buffer * +double_buffer_create( void (*free_me)(void *), void * (*copy_me)(void *) ) +{ + + struct double_buffer * db_buff; + + if ( !free_me || !copy_me ) + return 0; + + db_buff = calloc(1, sizeof(*db_buff)); + + if ( !db_buff ) + { + log_oom(__FILE__, __LINE__); + return 0; + } + + db_buff->read_count = 0; + db_buff->write_count = 0; + db_buff->count[0] = -1; + db_buff->count[1] = -1; + db_buff->objects[0] = 0; + db_buff->objects[1] = 0; + + db_buff->free_object = free_me; + db_buff->copy_object = copy_me; + + vc_mutex_init(&db_buff->locks[0]); + vc_mutex_init(&db_buff->locks[1]); + + /* TODO: remove this (debug) counter */ + db_buff->num_insert_too_far_failures = 0; + + return db_buff; +} + +void +double_buffer_destroy(struct double_buffer * db_buff) +{ + vc_mutex_destroy(&db_buff->locks[1]); + vc_mutex_destroy(&db_buff->locks[0]); + + if ( db_buff->write_count > 0 ) + db_buff->free_object(db_buff->objects[0]); + + if ( db_buff->write_count > 1 ) + db_buff->free_object(db_buff->objects[1]); + + free(db_buff); +} + +void +double_buffer_insert(struct double_buffer * db_buff, void * new_object) +{ + const int insertion_index = db_buff->write_count % 2; + + /* TODO: we could eliminate a copy by having the reader free + * all buffered objects. This would require that a failed + * check below result in the object being freed. This + * would ensure that the reader sees all BUFFERED objects. + * + * The reader would then need to take care to free objects + * as they become outdated. + * + * The tradeoff is the occasional dropped object when + * the writer gets ahead a little. The counter can help + * to evaluate the cost of this tradeoff + */ + /* don't get far ahead of the reader*/ + if ( db_buff->write_count > ( db_buff->read_count + 2 ) ) + { + db_buff->num_insert_too_far_failures++; + /* return; */ + } + + /* get exclusive access to the correct buffer */ + if ( vc_mutex_trylock(&db_buff->locks[insertion_index] )) + { + /* failed to obtain lock */ + /* drop incoming object */ + db_buff->free_object(new_object); + return; + } + + /* free the slot object if something is already there */ + if ( db_buff->write_count > 1 ) + db_buff->free_object(db_buff->objects[insertion_index]); + + /* insert object */ + db_buff->objects[insertion_index] = new_object; + + /* stamp the buffer with the write count */ + db_buff->count[insertion_index] = db_buff->write_count; + + /* advance the write count */ + ++db_buff->write_count; + + /* unlock the correct lock */ + vc_mutex_unlock(&db_buff->locks[insertion_index]); +} + +void * +double_buffer_read(struct double_buffer * db_buff) +{ + int copy_index = 1; + void * buff; + + if ( db_buff->write_count < 1 ) + return 0; + + /* NOTE: Try the newest buffer first + * IF that lock fails THEN try other + */ + if ( db_buff->count[0] > db_buff->count[1] ) + copy_index = 0; + + if ( vc_mutex_trylock(&db_buff->locks[copy_index] ) ) + { + /* failed to obtain lock */ + /* try the other (older) slot? */ + if ( db_buff->write_count < 2 ) + return 0; + + copy_index = 1 - copy_index; + + /* Failed to obtain other lock? */ + /* This should be pretty rare */ + if ( vc_mutex_trylock(&db_buff->locks[copy_index] ) ) + return 0; + } + + /* Is this buffer older than the last-read? + * TODO: could this happen? + */ + if ( db_buff->count[copy_index] < db_buff->read_count ) + { + vc_mutex_unlock(&db_buff->locks[copy_index]); + return 0; + } + + buff = db_buff->copy_object(db_buff->objects[copy_index]); + + db_buff->read_count = db_buff->count[copy_index]; + + vc_mutex_unlock(&db_buff->locks[copy_index]); + + return buff; +} + +int +double_buffer_count(struct double_buffer * db_buff) +{ + return db_buff->write_count; +} Property changes on: trunk/src/double_buffer.c ___________________________________________________________________ Name: svn:executable + * Added: trunk/src/double_buffer.h =================================================================== --- trunk/src/double_buffer.h (rev 0) +++ trunk/src/double_buffer.h 2007-11-26 17:59:33 UTC (rev 65) @@ -0,0 +1,65 @@ +/* + * libvidcap - a cross-platform video capture library + * + * Copyright 2007 Wimba, Inc. + * + * Contributors: + * Peter Grayson <jpg...@gm...> + * Bill Cholewka <bc...@gm...> + * + * libvidcap is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libvidcap 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _DOUBLE_BUFFER_H +#define _DOUBLE_BUFFER_H + +#include "os_funcs.h" + +#define _DOUBLE_MEANS_TWO_ 2 + +struct double_buffer +{ + int read_count; + int write_count; + void * objects[_DOUBLE_MEANS_TWO_]; + vc_mutex locks[_DOUBLE_MEANS_TWO_]; + + int count[_DOUBLE_MEANS_TWO_]; + + void * (*copy_object)(void *); + void (*free_object)(void *); + + /* TODO: remove */ + int num_insert_too_far_failures; +}; + +struct double_buffer * +double_buffer_create( void (*free_obj_func)(void *), + void * (*copy_object)(void *)); + +void +double_buffer_destroy(struct double_buffer * db_buff); + +void +double_buffer_insert(struct double_buffer * db_buff, void * object); + +void * +double_buffer_read(struct double_buffer * db_buff); + +int +double_buffer_count(struct double_buffer * db_buff); + +#endif Property changes on: trunk/src/double_buffer.h ___________________________________________________________________ Name: svn:executable + * Added: trunk/src/os_funcs.h =================================================================== --- trunk/src/os_funcs.h (rev 0) +++ trunk/src/os_funcs.h 2007-11-26 17:59:33 UTC (rev 65) @@ -0,0 +1,219 @@ +/* + * libvidcap - a cross-platform video capture library + * + * Copyright 2007 Wimba, Inc. + * + * Contributors: + * Peter Grayson <jpg...@gm...> + * Bill Cholewka <bc...@gm...> + * + * libvidcap is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * libvidcap 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _OS_FUNCS_H +#define _OS_FUNCS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(HAVE_NANOSLEEP) || defined(HAVE_GETTIMEOFDAY) +#include <sys/time.h> +#include <time.h> +#endif + +/* os-dependent macros */ +#if defined(WIN32) || defined(_WIN32_WCE) + +#ifndef _WIN32_WINNT +// Change this to the appropriate value to target other versions of Windows. +// see: http://msdn2.microsoft.com/en-us/library/aa383745.aspx +#define _WIN32_WINNT 0x0500 +#endif + +#include <windows.h> + +#if !defined(_WIN32_WCE) +#include <process.h> +#endif + +#define STDCALL __stdcall +typedef CRITICAL_SECTION vc_mutex; +typedef uintptr_t vc_thread; + +#else + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/time.h> +#include <pthread.h> + +#define STDCALL +typedef pthread_mutex_t vc_mutex; +typedef pthread_t vc_thread; + +#endif + +#ifdef MACOSX +#include <mach/mach_init.h> +#include <mach/thread_policy.h> +#include <sched.h> +#include <sys/sysctl.h> +#endif + +#ifndef HAVE_GETTIMEOFDAY +static __inline int +gettimeofday(struct timeval * tv, struct timezone * tz) +#ifdef WIN32 +{ + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + static int tzflag; + const __int64 EPOCHFILETIME = 116444736000000000i64; + if ( tv ) + { + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + } + + return 0; + +#else /* !defined(_WINDOWS) */ + errno = ENOSYS; + return -1; +#endif +} +#endif /* !defined(HAVE_GETTIMEOFDAY) */ + + +static __inline int +vc_create_thread(vc_thread *thread, + unsigned int (STDCALL * thread_func)(void *), + void *args, unsigned int *thread_id) +{ +#ifdef WIN32 + *thread = (uintptr_t)_beginthreadex(NULL, 0, thread_func, + (void *)args, 0, thread_id); + + /* FIXME: log the error */ + if ( thread == 0 ) + return -1; +#else + int ret; + void * (*func)(void *) = (void * (*)(void *))thread_func; + + ret = pthread_create(thread, NULL, func, args); + + /* FIXME: log the error */ + if ( ret ) + return -1; +#endif + + return 0; +} + +static __inline void +vc_thread_join(vc_thread *thread) +{ +#ifdef WIN32 + HANDLE _thread = (HANDLE)thread; + + WaitForSingleObject(_thread, INFINITE); +#else + pthread_t *_thread = (pthread_t *)thread; + + pthread_join(*_thread, 0); +#endif +} + +static __inline void +vc_mutex_init(vc_mutex *m) +{ +#ifdef WIN32 + InitializeCriticalSection(m); +#else + pthread_mutex_init(m, NULL); +#endif +} + +static __inline void +vc_mutex_lock(vc_mutex *m) +{ +#ifdef WIN32 + EnterCriticalSection(m); +#else + pthread_mutex_lock(m); +#endif +} + +static __inline int +vc_mutex_trylock(vc_mutex *m) +{ +#ifdef WIN32 + return !TryEnterCriticalSection(m); +#else + return pthread_mutex_trylock(m); +#endif +} + +static __inline void +vc_mutex_unlock(vc_mutex *m) +{ +#ifdef WIN32 + LeaveCriticalSection(m); +#else + pthread_mutex_unlock(m); +#endif +} + +static __inline void +vc_mutex_destroy(vc_mutex *m) +{ +#ifdef WIN32 + DeleteCriticalSection(m); +#else + pthread_mutex_destroy(m); +#endif +} + +static __inline void +vc_millisleep(long ms) +{ +#ifdef WIN32 + + Sleep(ms); + +#else + + struct timespec req; + + req.tv_nsec = (ms % 1000) * 1000000; + req.tv_sec = ms / 1000; + + nanosleep(&req, NULL); + +#endif +} + +#endif Property changes on: trunk/src/os_funcs.h ___________________________________________________________________ Name: svn:executable + * Modified: trunk/src/sapi.c =================================================================== --- trunk/src/sapi.c 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/sapi.c 2007-11-26 17:59:33 UTC (rev 65) @@ -30,36 +30,9 @@ #include "logging.h" #include "sapi.h" -#ifndef HAVE_GETTIMEOFDAY -static __inline int gettimeofday(struct timeval * tv, struct timezone * tz) -#ifdef WIN32 -{ - FILETIME ft; - LARGE_INTEGER li; - __int64 t; - static int tzflag; - const __int64 EPOCHFILETIME = 116444736000000000i64; - if ( tv ) - { - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - } +static int +deliver_frame(struct sapi_src_context * src_ctx); - return 0; - -#else /* !defined(_WINDOWS) */ - errno = ENOSYS; - return -1; -#endif -} -#endif - static __inline int tv_greater_or_equal(struct timeval * t1, struct timeval * t0) { @@ -76,7 +49,7 @@ } static __inline void -tv_add_usecs(struct timeval *t1, struct timeval *t0, int usecs) +tv_add_usecs(struct timeval *t1, struct timeval *t0, long usecs) { int secs_carried = 0; @@ -216,6 +189,19 @@ return 0; } +static void +wait_for_error_ack(struct sapi_src_context * src_ctx) +{ + while ( !src_ctx->capture_error_ack ) + vc_millisleep(10); +} + +static void +acknowledge_error(struct sapi_src_context * src_ctx) +{ + src_ctx->capture_error_ack = 1; +} + /* NOTE: stride-ignorant sapis should pass a stride of zero */ int sapi_src_capture_notify(struct sapi_src_context * src_ctx, @@ -223,25 +209,121 @@ int stride, int error_status) { - struct vidcap_capture_info cap_info; - /* NOTE: We may be called here by the capture thread while the * main thread is clearing capture_data and capture_callback * from within vidcap_src_capture_stop(). */ + + /* Package the video information */ + struct frame_info * frame = malloc(sizeof(*frame)); + if ( !frame ) + return -1; + + frame->cap_info = malloc(sizeof(struct vidcap_capture_info)); + if ( !frame->cap_info ) + { + free(frame); + return -1; + } + + frame->cap_info->video_data_size = video_data_size; + frame->cap_info->error_status = error_status; + frame->stride = stride; + + if ( src_ctx->use_timer_thread ) + { + /* Copy this buffer. It might not exist long enough for + * read thread (capture timer thread) to copy it + */ + frame->cap_info->video_data = malloc(video_data_size); + if ( !frame->cap_info->video_data ) + { + free(frame->cap_info); + free(frame); + return -1; + } + + memcpy(frame->cap_info->video_data, video_data, video_data_size); + + /* buffer the frame - for processing by the timer thread */ + double_buffer_insert(src_ctx->double_buff, frame); + + /* If there's an error, wait here until it's acknowledged + * by the timer thread (after having delivered it to the app). + */ + if ( error_status ) + wait_for_error_ack(src_ctx); + } + else + { + frame->cap_info->video_data = video_data; + + /* process the frame now */ + src_ctx->no_timer_thread_frame = frame; + deliver_frame(src_ctx); + } + + if ( error_status ) + { + src_ctx->src_state = src_bound; + src_ctx->capture_callback = 0; + src_ctx->capture_data = VIDCAP_INVALID_USER_DATA; + } + + return 0; +} + +static int +deliver_frame(struct sapi_src_context * src_ctx) +{ vidcap_src_capture_callback cap_callback = src_ctx->capture_callback; void * cap_data = src_ctx->capture_data; void * buf = 0; int buf_data_size = 0; - int send_frame = 0; - if ( !error_status ) - send_frame = enforce_framerate(src_ctx); + struct vidcap_capture_info cap_info; - if ( send_frame < 0 ) - error_status = -1000; + struct frame_info * frame; + const char * video_data; + int video_data_size; + int stride; + int error_status; + if ( src_ctx->use_timer_thread ) + { + frame = (struct frame_info *) + double_buffer_read(src_ctx->double_buff); + + if ( !frame ) + return -1; + } + else + { + frame = src_ctx->no_timer_thread_frame; + } + + video_data = frame->cap_info->video_data; + video_data_size = frame->cap_info->video_data_size; + stride = frame->stride; + error_status = frame->cap_info->error_status; + + /* FIXME: right now enforce_framerate() and the capture timer + * thread's main loop BOTH use the frame_time_next field + */ + if ( src_ctx->use_timer_thread ) + { + send_frame = 1; + } + else + { + if ( !error_status ) + send_frame = enforce_framerate(src_ctx); + + if ( send_frame < 0 ) + error_status = -1000; + } + cap_info.error_status = error_status; if ( !cap_info.error_status && stride && @@ -290,22 +372,143 @@ if ( ( send_frame || error_status ) && cap_callback && cap_data != VIDCAP_INVALID_USER_DATA ) { - /* FIXME: Need to check return code. - * Application may want capture to stop + /* FIXME: Need to check return code (and pass it back). + * Application may want capture to stop. + * Ensure we don't perform any more callbacks. */ cap_callback(src_ctx, cap_data, &cap_info); - if ( cap_info.error_status ) + if ( src_ctx->use_timer_thread ) { - src_ctx->src_state = src_bound; - src_ctx->capture_callback = 0; - src_ctx->capture_data = VIDCAP_INVALID_USER_DATA; + /* delete frame */ + free(frame->cap_info->video_data); + free(frame->cap_info); + free(frame); + + if ( error_status ) + { + /* Let capture thread know that the app + * Has received the error status. + * Ensure we don't deliver any more frames. + */ + acknowledge_error(src_ctx); + + /* inform calling function of error */ + return 1; + } } } return 0; } +unsigned int +STDCALL sapi_src_timer_thread_func(void *args) +{ + struct sapi_src_context * src_ctx = args; + struct timeval tv_now; + + /* change to faster rate at capture time, and reduce when capture stopped */ + const long idle_state_sleep_period_ms = 100; + long sleep_ms = idle_state_sleep_period_ms; + int first_time = 1; + const int sleeps_per_capture = 1; + int got_frame = 0; + int ret; + int capture_error = 0; /* FIXME: perhaps should exit on error */ + + src_ctx->timer_thread_idle = 1; + + if ( gettimeofday(&tv_now, 0) ) + { + src_ctx->capture_timer_thread_started = -1; + log_error("gettimeofday not supported\n"); + return -1; + } + + src_ctx->frame_time_next.tv_sec = tv_now.tv_sec; + src_ctx->frame_time_next.tv_usec = tv_now.tv_usec; + + log_info("capture timer thread now running\n"); + src_ctx->capture_timer_thread_started = 1; + + while ( !src_ctx->kill_timer_thread ) + { + gettimeofday(&tv_now, 0); + + /* time to attempt to read a frame? */ + if ( capture_error || src_ctx->src_state != src_capturing || + !tv_greater_or_equal(&tv_now, &src_ctx->frame_time_next) ) + { + if ( src_ctx->src_state != src_capturing ) + { + sleep_ms = idle_state_sleep_period_ms; + first_time = 1; + } + + vc_millisleep(sleep_ms); + } + else + { + src_ctx->timer_thread_idle = 0; + /* FIXME: memory barrier needed? */ + + /* attempt to read and deliver a frame */ + ret = deliver_frame(src_ctx); + + got_frame = !ret; + capture_error = ret > 0; + + /* Is this the first frame? */ + if ( got_frame && first_time ) + { + first_time = 0; + + /* re-initialize when next to check for a frame */ + src_ctx->frame_time_next.tv_sec = tv_now.tv_sec; + src_ctx->frame_time_next.tv_usec = tv_now.tv_usec; + + sleep_ms = (1000 / sleeps_per_capture) * + src_ctx->fmt_nominal.fps_denominator / + src_ctx->fmt_nominal.fps_numerator; + } + + if ( !first_time ) + { + /* update when next to check for a frame */ + /* FIXME: reduce round-off */ + tv_add_usecs(&src_ctx->frame_time_next, &src_ctx->frame_time_next, + 1000000 * + src_ctx->fmt_nominal.fps_denominator / + src_ctx->fmt_nominal.fps_numerator); + } + else + { + /* still no first frame */ + /* update when next to check for a frame */ + tv_add_usecs(&src_ctx->frame_time_next, &tv_now, + 1000000 * + src_ctx->fmt_nominal.fps_denominator / + src_ctx->fmt_nominal.fps_numerator); + } + } + + /* FIXME: memory barrier needed? */ + src_ctx->timer_thread_idle = 1; + } + + log_info("capture timer thread now exiting...\n"); + + return 0; +} + +void +sapi_src_timer_thread_idled(struct sapi_src_context * src_ctx) +{ + while ( !src_ctx->timer_thread_idle ) + vc_millisleep(10); +} + int sapi_can_convert_native_to_nominal(const struct vidcap_fmt_info * fmt_native, const struct vidcap_fmt_info * fmt_nominal) @@ -333,3 +536,4 @@ return 0; } + Modified: trunk/src/sapi_context.h =================================================================== --- trunk/src/sapi_context.h 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/sapi_context.h 2007-11-26 17:59:33 UTC (rev 65) @@ -26,26 +26,20 @@ #ifndef _SAPI_CONTEXT_H #define _SAPI_CONTEXT_H -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 -#include <windows.h> -#endif - -#if defined(HAVE_NANOSLEEP) || defined(HAVE_GETTIMEOFDAY) -#include <sys/time.h> -#include <time.h> -#endif - #include <vidcap/vidcap.h> +#include "double_buffer.h" #include "sliding_window.h" #include "conv.h" struct sapi_context; +struct frame_info +{ + struct vidcap_capture_info *cap_info; + int stride; +}; + struct sapi_src_context { int (*release)(struct sapi_src_context *); @@ -64,6 +58,7 @@ struct vidcap_src_info src_info; struct sliding_window * frame_times; struct timeval frame_time_next; + struct double_buffer * double_buff; struct vidcap_fmt_info fmt_nominal; struct vidcap_fmt_info fmt_native; @@ -82,6 +77,15 @@ vidcap_src_capture_callback capture_callback; void * capture_data; + int use_timer_thread; + struct frame_info * no_timer_thread_frame; + vc_thread capture_timer_thread; + unsigned int capture_timer_thread_id; + int capture_timer_thread_started; + int timer_thread_idle; + int kill_timer_thread; + int capture_error_ack; + void * priv; }; @@ -124,4 +128,10 @@ void sapi_src_fps_info_clean(struct sapi_src_context *); +void +sapi_src_timer_thread_idled(struct sapi_src_context * src_ctx); + +unsigned int +STDCALL sapi_src_timer_thread_func(void *); + #endif Modified: trunk/src/sapi_dshow.cpp =================================================================== --- trunk/src/sapi_dshow.cpp 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/sapi_dshow.cpp 2007-11-26 17:59:33 UTC (rev 65) @@ -22,14 +22,12 @@ // <http://www.gnu.org/licenses/>. // -#include <windows.h> #include <stdio.h> +#include "sapi.h" #include "SourceStateMachine.h" #include "DShowSrcManager.h" - #include "logging.h" -#include "sapi.h" static const char * identifier = "DirectShow"; static const char * description = "DirectShow video capture API"; @@ -177,7 +175,7 @@ return -1; } - if ( src_ctx->priv == 0 ) + if ( src_ctx->priv == (void *)0 ) { log_warn("failed constructing source state machine for '%s'\n", src_info->identifier); Modified: trunk/src/vidcap.c =================================================================== --- trunk/src/vidcap.c 2007-11-20 17:51:57 UTC (rev 64) +++ trunk/src/vidcap.c 2007-11-26 17:59:33 UTC (rev 65) @@ -26,12 +26,6 @@ #include <stdlib.h> #include <string.h> -#include <vidcap/vidcap.h> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "logging.h" #include "sapi_context.h" #include "sapi.h" @@ -312,6 +306,41 @@ return 0; } + /* TODO: right now we always use the timer thread to enforce + * a very accurate framerate. Alternatively, we could + * allow an application to choose to forego this feature + * and the associated overhead + */ + src_ctx->use_timer_thread = 1; + + if ( src_ctx->use_timer_thread ) + { + src_ctx->kill_timer_thread = 0; + src_ctx->capture_timer_thread_started = 0; + src_ctx->capture_timer_thread = 0; + /* FIXME: memory barrier needed? */ + + if ( vc_create_thread(&src_ctx->capture_timer_thread, + sapi_src_timer_thread_func, src_ctx, + &src_ctx->capture_timer_thread_id) ) + { + src_ctx->capture_timer_thread = 0; + goto bail; + } + + /* ensure thread has started before proceeding */ + while ( !src_ctx->capture_timer_thread_started ) + vc_millisleep(10); + + if ( src_ctx->capture_timer_thread_started < 0 ) + { + log_error("source timer thread failed to start.\n"); + goto bail; + } + + log_info("using a capture timer thread for this source\n"); + } + if ( sapi_ctx->acquire_source(sapi_ctx, src_ctx, src_info) ) { log_error("failed to acquire %s\n", src_info ? @@ -330,6 +359,15 @@ return src_ctx; bail: + /* wait for it to exit (if it exists) */ + if ( src_ctx->use_timer_thread && src_ctx->capture_timer_thread ) + { + /* signal to timer thread to stop */ + src_ctx->kill_timer_thread = 1; + + vc_thread_join(&src_ctx->capture_timer_thread); + } + free(src_ctx); return 0; } @@ -352,6 +390,15 @@ if ( src_ctx->src_state == src_capturing ) return -1; + if ( src_ctx->use_timer_thread && src_ctx->capture_timer_thread ) + { + /* signal timer thread to exit */ + src_ctx->kill_timer_thread = 1; + + /* wait for it to exit */ + vc_thread_join(&src_ctx->capture_timer_thread); + } + ret = src_ctx->release(src_ctx); if ( src_ctx->fmt_list_len ) @@ -499,6 +546,53 @@ return 0; } +void +free_frame_info(void * fr) +{ + struct frame_info *frame = (struct frame_info *)fr; + + /* FIXME: unconstify video_data */ + free(frame->cap_info->video_data); + free(frame->cap_info); + free(frame); +} + +void * +copy_frame_info(void * fr) +{ + struct frame_info *frame = (struct frame_info *)fr; + + struct frame_info *dup_frame = malloc(sizeof(*dup_frame)); + + if ( !dup_frame ) + return 0; + + dup_frame->cap_info = calloc(1, sizeof(*dup_frame->cap_info)); + if ( !dup_frame->cap_info ) + { + free(dup_frame); + return 0; + } + + dup_frame->stride = frame->stride; + dup_frame->cap_info->error_status = frame->cap_info->error_status; + dup_frame->cap_info->video_data_size = frame->cap_info->video_data_size; + dup_frame->cap_info->video_data = malloc(frame->cap_info->video_data_size); + if ( !dup_frame->cap_info->video_data ) + { + free(dup_frame->cap_info); + free(dup_frame); + return 0; + } + + /* FIXME: unconstify cap_info->video_data */ + memcpy(dup_frame->cap_info->video_data, + frame->cap_info->video_data, + frame->cap_info->video_data_size); + + return dup_frame; +} + int vidcap_src_capture_start(vidcap_src * src, vidcap_src_capture_callback callback, @@ -524,6 +618,16 @@ if ( !src_ctx->frame_times ) return -2; + src_ctx->double_buff = double_buffer_create(&free_frame_info, + ©_frame_info); + + if ( !src_ctx->double_buff ) + { + sliding_window_destroy(src_ctx->frame_times); + src_ctx->frame_times = 0; + return -5; + } + src_ctx->capture_callback = callback; src_ctx->capture_data = user_data; @@ -531,6 +635,10 @@ { src_ctx->capture_callback = 0; src_ctx->capture_data = VIDCAP_INVALID_USER_DATA; + + double_buffer_destroy(src_ctx->double_buff); + src_ctx->double_buff = 0; + sliding_window_destroy(src_ctx->frame_times); src_ctx->frame_times = 0; return ret; @@ -551,12 +659,23 @@ ret = src_ctx->stop_capture(src_ctx); + /* signal to timer thread that capture has stopped */ + src_ctx->src_state = src_bound; + + if ( src_ctx->use_timer_thread ) + { + /* FIXME: memory barrier needed? */ + sapi_src_timer_thread_idled(src_ctx); + } + + double_buffer_destroy(src_ctx->double_buff); + src_ctx->double_buff = 0; + sliding_window_destroy(src_ctx->frame_times); + src_ctx->frame_times = 0; - src_ctx->frame_times = 0; src_ctx->capture_callback = 0; src_ctx->capture_data = VIDCAP_INVALID_USER_DATA; - src_ctx->src_state = src_bound; return ret; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. <lib...@li...> - 2007-11-26 18:33:10
|
Revision: 68 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=68&view=rev Author: bcholew Date: 2007-11-26 10:32:38 -0800 (Mon, 26 Nov 2007) Log Message: ----------- De-constify the vidcap buffer - removing compile-time warnings. Modified Paths: -------------- trunk/include/vidcap/vidcap.h trunk/src/directshow/SourceStateMachine.cpp trunk/src/sapi.c trunk/src/sapi.h Modified: trunk/include/vidcap/vidcap.h =================================================================== --- trunk/include/vidcap/vidcap.h 2007-11-26 18:22:32 UTC (rev 67) +++ trunk/include/vidcap/vidcap.h 2007-11-26 18:32:38 UTC (rev 68) @@ -73,7 +73,7 @@ struct vidcap_capture_info { - const char * video_data; + char * video_data; int video_data_size; int error_status; }; Modified: trunk/src/directshow/SourceStateMachine.cpp =================================================================== --- trunk/src/directshow/SourceStateMachine.cpp 2007-11-26 18:22:32 UTC (rev 67) +++ trunk/src/directshow/SourceStateMachine.cpp 2007-11-26 18:32:38 UTC (rev 68) @@ -521,7 +521,7 @@ } int ret = sapi_src_capture_notify(instance->sourceContext_, - reinterpret_cast<const char *>(pBuff), + reinterpret_cast<char *>(pBuff), static_cast<int>(buffSize), 0, 0); instance->callbackInProgress_ = false; Modified: trunk/src/sapi.c =================================================================== --- trunk/src/sapi.c 2007-11-26 18:22:32 UTC (rev 67) +++ trunk/src/sapi.c 2007-11-26 18:32:38 UTC (rev 68) @@ -205,7 +205,7 @@ /* NOTE: stride-ignorant sapis should pass a stride of zero */ int sapi_src_capture_notify(struct sapi_src_context * src_ctx, - const char * video_data, int video_data_size, + char * video_data, int video_data_size, int stride, int error_status) { Modified: trunk/src/sapi.h =================================================================== --- trunk/src/sapi.h 2007-11-26 18:22:32 UTC (rev 67) +++ trunk/src/sapi.h 2007-11-26 18:32:38 UTC (rev 68) @@ -46,7 +46,7 @@ int sapi_src_capture_notify(struct sapi_src_context * src_ctx, - const char * video_data, int video_data_size, + char * video_data, int video_data_size, int stride, int error_status); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. <lib...@li...> - 2007-11-26 19:33:09
|
Revision: 69 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=69&view=rev Author: bcholew Date: 2007-11-26 11:32:59 -0800 (Mon, 26 Nov 2007) Log Message: ----------- Keep public video data const, and the internal not. Modified Paths: -------------- trunk/include/vidcap/vidcap.h trunk/src/sapi.c trunk/src/sapi_context.h trunk/src/vidcap.c Modified: trunk/include/vidcap/vidcap.h =================================================================== --- trunk/include/vidcap/vidcap.h 2007-11-26 18:32:38 UTC (rev 68) +++ trunk/include/vidcap/vidcap.h 2007-11-26 19:32:59 UTC (rev 69) @@ -73,7 +73,7 @@ struct vidcap_capture_info { - char * video_data; + const char * video_data; int video_data_size; int error_status; }; Modified: trunk/src/sapi.c =================================================================== --- trunk/src/sapi.c 2007-11-26 18:32:38 UTC (rev 68) +++ trunk/src/sapi.c 2007-11-26 19:32:59 UTC (rev 69) @@ -219,15 +219,8 @@ if ( !frame ) return -1; - frame->cap_info = malloc(sizeof(struct vidcap_capture_info)); - if ( !frame->cap_info ) - { - free(frame); - return -1; - } - - frame->cap_info->video_data_size = video_data_size; - frame->cap_info->error_status = error_status; + frame->video_data_size = video_data_size; + frame->error_status = error_status; frame->stride = stride; if ( src_ctx->use_timer_thread ) @@ -235,15 +228,14 @@ /* Copy this buffer. It might not exist long enough for * read thread (capture timer thread) to copy it */ - frame->cap_info->video_data = malloc(video_data_size); - if ( !frame->cap_info->video_data ) + frame->video_data = malloc(video_data_size); + if ( !frame->video_data ) { - free(frame->cap_info); free(frame); return -1; } - memcpy(frame->cap_info->video_data, video_data, video_data_size); + memcpy(frame->video_data, video_data, video_data_size); /* buffer the frame - for processing by the timer thread */ double_buffer_insert(src_ctx->double_buff, frame); @@ -256,7 +248,7 @@ } else { - frame->cap_info->video_data = video_data; + frame->video_data = video_data; /* process the frame now */ src_ctx->no_timer_thread_frame = frame; @@ -303,10 +295,10 @@ frame = src_ctx->no_timer_thread_frame; } - video_data = frame->cap_info->video_data; - video_data_size = frame->cap_info->video_data_size; + video_data = frame->video_data; + video_data_size = frame->video_data_size; stride = frame->stride; - error_status = frame->cap_info->error_status; + error_status = frame->error_status; /* FIXME: right now enforce_framerate() and the capture timer * thread's main loop BOTH use the frame_time_next field @@ -381,8 +373,7 @@ if ( src_ctx->use_timer_thread ) { /* delete frame */ - free(frame->cap_info->video_data); - free(frame->cap_info); + free(frame->video_data); free(frame); if ( error_status ) Modified: trunk/src/sapi_context.h =================================================================== --- trunk/src/sapi_context.h 2007-11-26 18:32:38 UTC (rev 68) +++ trunk/src/sapi_context.h 2007-11-26 19:32:59 UTC (rev 69) @@ -36,7 +36,9 @@ struct frame_info { - struct vidcap_capture_info *cap_info; + char * video_data; + int video_data_size; + int error_status; int stride; }; Modified: trunk/src/vidcap.c =================================================================== --- trunk/src/vidcap.c 2007-11-26 18:32:38 UTC (rev 68) +++ trunk/src/vidcap.c 2007-11-26 19:32:59 UTC (rev 69) @@ -551,9 +551,7 @@ { struct frame_info *frame = (struct frame_info *)fr; - /* FIXME: unconstify video_data */ - free(frame->cap_info->video_data); - free(frame->cap_info); + free(frame->video_data); free(frame); } @@ -567,28 +565,19 @@ if ( !dup_frame ) return 0; - dup_frame->cap_info = calloc(1, sizeof(*dup_frame->cap_info)); - if ( !dup_frame->cap_info ) - { - free(dup_frame); - return 0; - } - dup_frame->stride = frame->stride; - dup_frame->cap_info->error_status = frame->cap_info->error_status; - dup_frame->cap_info->video_data_size = frame->cap_info->video_data_size; - dup_frame->cap_info->video_data = malloc(frame->cap_info->video_data_size); - if ( !dup_frame->cap_info->video_data ) + dup_frame->error_status = frame->error_status; + dup_frame->video_data_size = frame->video_data_size; + dup_frame->video_data = malloc(frame->video_data_size); + if ( !dup_frame->video_data ) { - free(dup_frame->cap_info); free(dup_frame); return 0; } - /* FIXME: unconstify cap_info->video_data */ - memcpy(dup_frame->cap_info->video_data, - frame->cap_info->video_data, - frame->cap_info->video_data_size); + memcpy(dup_frame->video_data, + frame->video_data, + frame->video_data_size); return dup_frame; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. <lib...@li...> - 2007-12-03 17:18:54
|
Revision: 75 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=75&view=rev Author: bcholew Date: 2007-12-03 09:18:46 -0800 (Mon, 03 Dec 2007) Log Message: ----------- Patch by Taybin Rutkin to compile under cygwin. Thanks. Modified Paths: -------------- trunk/configure.ac trunk/examples/simplegrab.c Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2007-12-03 14:11:12 UTC (rev 74) +++ trunk/configure.ac 2007-12-03 17:18:46 UTC (rev 75) @@ -44,7 +44,7 @@ PKG_PROG_PKG_CONFIG -AC_CHECK_FUNCS(nanosleep gettimeofday snprintf Sleep) +AC_CHECK_FUNCS(nanosleep gettimeofday snprintf) AC_CHECK_HEADER(linux/videodev.h, have_v4l=yes, have_v4l=no) Modified: trunk/examples/simplegrab.c =================================================================== --- trunk/examples/simplegrab.c 2007-12-03 14:11:12 UTC (rev 74) +++ trunk/examples/simplegrab.c 2007-12-03 17:18:46 UTC (rev 75) @@ -135,7 +135,7 @@ nanosleep(&tv, 0); -#elif defined(HAVE_SLEEP) +#elif defined(_WIN32) Sleep(milliseconds); #else #error No sleep function available. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: libvidcap c. <lib...@li...> - 2007-12-12 20:55:27
|
Revision: 84 http://libvidcap.svn.sourceforge.net/libvidcap/?rev=84&view=rev Author: bcholew Date: 2007-12-12 12:55:11 -0800 (Wed, 12 Dec 2007) Log Message: ----------- A bunch of changes - including some from Pete Grayson. Add capture time to capture callback data. Wrap gettimeofday() with new vc_now() function. Log malloc errors with log_oom(). Make some functions static. Replace double-buffer malloc()s with memcpy()s. Renamed double_buffer_insert() to double_buffer_write(). Change some info messages to debug. Some cleanup. Modified Paths: -------------- trunk/include/vidcap/vidcap.h trunk/src/double_buffer.c trunk/src/double_buffer.h trunk/src/os_funcs.h trunk/src/sapi.c trunk/src/sapi_context.h trunk/src/vidcap.c Modified: trunk/include/vidcap/vidcap.h =================================================================== --- trunk/include/vidcap/vidcap.h 2007-12-12 20:46:06 UTC (rev 83) +++ trunk/include/vidcap/vidcap.h 2007-12-12 20:55:11 UTC (rev 84) @@ -76,6 +76,8 @@ const char * video_data; int video_data_size; int error_status; + long capture_time_sec; + long capture_time_usec; }; typedef int (*vidcap_src_capture_callback) (vidcap_src *, Modified: trunk/src/double_buffer.c =================================================================== --- trunk/src/double_buffer.c 2007-12-12 20:46:06 UTC (rev 83) +++ trunk/src/double_buffer.c 2007-12-12 20:55:11 UTC (rev 84) @@ -41,16 +41,15 @@ * to make room for an incoming object */ -/* NOTE: This function is passed function pointers to call when - * necessary to free or copy an object +/* NOTE: This function is passed a function pointer to + * call when necessary to copy an object */ struct double_buffer * -double_buffer_create( void (*free_me)(void *), void * (*copy_me)(void *) ) +double_buffer_create( void (*copy_func)(void *, const void *), void *object1, void *object2 ) { - struct double_buffer * db_buff; - if ( !free_me || !copy_me ) + if ( !copy_func ) return 0; db_buff = calloc(1, sizeof(*db_buff)); @@ -65,11 +64,10 @@ db_buff->write_count = 0; db_buff->count[0] = -1; db_buff->count[1] = -1; - db_buff->objects[0] = 0; - db_buff->objects[1] = 0; + db_buff->objects[0] = object1; + db_buff->objects[1] = object2; - db_buff->free_object = free_me; - db_buff->copy_object = copy_me; + db_buff->copy_object = copy_func; vc_mutex_init(&db_buff->locks[0]); vc_mutex_init(&db_buff->locks[1]); @@ -86,33 +84,18 @@ vc_mutex_destroy(&db_buff->locks[1]); vc_mutex_destroy(&db_buff->locks[0]); - if ( db_buff->write_count > 0 ) - db_buff->free_object(db_buff->objects[0]); + log_debug("Double buffer had counter reading of %d\n", + db_buff->num_insert_too_far_failures); - if ( db_buff->write_count > 1 ) - db_buff->free_object(db_buff->objects[1]); - free(db_buff); } void -double_buffer_insert(struct double_buffer * db_buff, void * new_object) +double_buffer_write(struct double_buffer * db_buff, const void * new_object) { const int insertion_index = db_buff->write_count % 2; - /* TODO: we could eliminate a copy by having the reader free - * all buffered objects. This would require that a failed - * check below result in the object being freed. This - * would ensure that the reader sees all BUFFERED objects. - * - * The reader would then need to take care to free objects - * as they become outdated. - * - * The tradeoff is the occasional dropped object when - * the writer gets ahead a little. The counter can help - * to evaluate the cost of this tradeoff - */ - /* don't get far ahead of the reader*/ + /* don't get far ahead of the reader */ if ( db_buff->write_count > ( db_buff->read_count + 2 ) ) { db_buff->num_insert_too_far_failures++; @@ -124,18 +107,13 @@ { /* failed to obtain lock */ /* drop incoming object */ - log_info("vidcap callback failed to write a frame\n"); - db_buff->free_object(new_object); + log_info("callback is skipping a frame\n"); return; } - /* free the slot object if something is already there */ - if ( db_buff->write_count > 1 ) - db_buff->free_object(db_buff->objects[insertion_index]); + /* copy object */ + db_buff->copy_object(db_buff->objects[insertion_index], new_object); - /* insert object */ - db_buff->objects[insertion_index] = new_object; - /* stamp the buffer with the write count */ db_buff->count[insertion_index] = db_buff->write_count; @@ -146,14 +124,13 @@ vc_mutex_unlock(&db_buff->locks[insertion_index]); } -void * -double_buffer_read(struct double_buffer * db_buff) +int +double_buffer_read(struct double_buffer * db_buff, void *dest_buffer) { int copy_index = db_buff->read_count % 2; - void * buff; if ( db_buff->write_count < 1 ) - return 0; + return -1; /* try the next buffer */ if ( db_buff->count[copy_index] < db_buff->read_count ) @@ -162,14 +139,13 @@ copy_index = 1 - copy_index; } - if ( vc_mutex_trylock(&db_buff->locks[copy_index] ) ) { - /* Failed to obtain lock. - * Try the other slot? + /* Failed to obtain buffer's lock. + * Try the other buffer? */ if ( db_buff->write_count < 2 ) - return 0; + return -1; copy_index = 1 - copy_index; @@ -177,14 +153,15 @@ { /* Too old. Don't read this buffer */ vc_mutex_unlock(&db_buff->locks[copy_index]); - return 0; + log_info("Capture timer thread failed to obtain lock\n"); + return -1; } /* Try other lock. Failure should be rare */ if ( vc_mutex_trylock(&db_buff->locks[copy_index] ) ) { log_info("Capture timer thread failed to obtain 2nd lock\n"); - return 0; + return -1; } } @@ -195,16 +172,17 @@ * This needs to be rare. */ vc_mutex_unlock(&db_buff->locks[copy_index]); - return 0; + log_info("Capture timer thread won't read stale buffer\n"); + return -1; } - buff = db_buff->copy_object(db_buff->objects[copy_index]); + db_buff->copy_object(dest_buffer, db_buff->objects[copy_index]); db_buff->read_count = db_buff->count[copy_index] + 1; vc_mutex_unlock(&db_buff->locks[copy_index]); - return buff; + return 0; } int Modified: trunk/src/double_buffer.h =================================================================== --- trunk/src/double_buffer.h 2007-12-12 20:46:06 UTC (rev 83) +++ trunk/src/double_buffer.h 2007-12-12 20:55:11 UTC (rev 84) @@ -39,25 +39,23 @@ int count[_DOUBLE_MEANS_TWO_]; - void * (*copy_object)(void *); - void (*free_object)(void *); + void (*copy_object)(void *, const void *); /* TODO: remove */ int num_insert_too_far_failures; }; struct double_buffer * -double_buffer_create( void (*free_obj_func)(void *), - void * (*copy_object)(void *)); +double_buffer_create(void (*copy_object)(void *, const void *), void *, void *); void double_buffer_destroy(struct double_buffer * db_buff); void -double_buffer_insert(struct double_buffer * db_buff, void * object); +double_buffer_write(struct double_buffer * db_buff, const void * object); -void * -double_buffer_read(struct double_buffer * db_buff); +int +double_buffer_read(struct double_buffer * db_buff, void * object); int double_buffer_count(struct double_buffer * db_buff); Modified: trunk/src/os_funcs.h =================================================================== --- trunk/src/os_funcs.h 2007-12-12 20:46:06 UTC (rev 83) +++ trunk/src/os_funcs.h 2007-12-12 20:55:11 UTC (rev 84) @@ -79,38 +79,33 @@ #include <sys/sysctl.h> #endif -#ifndef HAVE_GETTIMEOFDAY -static __inline int -gettimeofday(struct timeval * tv, struct timezone * tz) -#ifdef WIN32 +static __inline struct timeval +vc_now(void) { + struct timeval tv; +#ifdef HAVE_GETTIMEOFDAY + gettimeofday(&tv, 0); +#elif defined(WIN32) FILETIME ft; LARGE_INTEGER li; __int64 t; static int tzflag; const __int64 EPOCHFILETIME = 116444736000000000i64; - if ( tv ) - { - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - } - return 0; - -#else /* !defined(_WINDOWS) */ - errno = ENOSYS; - return -1; + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv.tv_sec = (long)(t / 1000000); + tv.tv_usec = (long)(t % 1000000); +#else +#error no gettimeofday or equivalent available #endif + return tv; } -#endif /* !defined(HAVE_GETTIMEOFDAY) */ - static __inline int vc_create_thread(vc_thread *thread, unsigned int (STDCALL * thread_func)(void *), Modified: trunk/src/sapi.c =================================================================== --- trunk/src/sapi.c 2007-12-12 20:46:06 UTC (rev 83) +++ trunk/src/sapi.c 2007-12-12 20:55:11 UTC (rev 84) @@ -30,9 +30,6 @@ #include "logging.h" #include "sapi.h" -static int -deliver_frame(struct sapi_src_context * src_ctx); - static __inline int tv_greater_or_equal(struct timeval * t1, struct timeval * t0) { @@ -73,8 +70,7 @@ first_time = !sliding_window_count(src_ctx->frame_times); - if ( gettimeofday(&tv_now, 0) ) - return -1; + tv_now = vc_now(); if ( !first_time && !tv_greater_or_equal( &tv_now, &src_ctx->frame_time_next) ) @@ -202,76 +198,6 @@ src_ctx->capture_error_ack = 1; } -/* NOTE: stride-ignorant sapis should pass a stride of zero */ -int -sapi_src_capture_notify(struct sapi_src_context * src_ctx, - char * video_data, int video_data_size, - int stride, - int error_status) -{ - /* NOTE: We may be called here by the capture thread while the - * main thread is clearing capture_data and capture_callback - * from within vidcap_src_capture_stop(). - */ - - /* Package the video information */ - struct frame_info * frame = malloc(sizeof(*frame)); - if ( !frame ) - return -1; - - /* Screen-out useless callbacks */ - if ( video_data_size < 1 && !error_status ) - { - log_info("callback with no data?\n"); - return 0; - } - - frame->video_data_size = video_data_size; - frame->error_status = error_status; - frame->stride = stride; - - if ( src_ctx->use_timer_thread ) - { - /* Copy this buffer. It might not exist long enough for - * read thread (capture timer thread) to copy it - */ - frame->video_data = malloc(video_data_size); - if ( !frame->video_data ) - { - free(frame); - return -1; - } - - memcpy(frame->video_data, video_data, video_data_size); - - /* buffer the frame - for processing by the timer thread */ - double_buffer_insert(src_ctx->double_buff, frame); - - /* If there's an error, wait here until it's acknowledged - * by the timer thread (after having delivered it to the app). - */ - if ( error_status ) - wait_for_error_ack(src_ctx); - } - else - { - frame->video_data = video_data; - - /* process the frame now */ - src_ctx->no_timer_thread_frame = frame; - deliver_frame(src_ctx); - } - - if ( error_status ) - { - src_ctx->src_state = src_bound; - src_ctx->capture_callback = 0; - src_ctx->capture_data = VIDCAP_INVALID_USER_DATA; - } - - return 0; -} - static int deliver_frame(struct sapi_src_context * src_ctx) { @@ -283,7 +209,7 @@ struct vidcap_capture_info cap_info; - struct frame_info * frame; + const struct frame_info * frame; const char * video_data; int video_data_size; int stride; @@ -291,21 +217,23 @@ if ( src_ctx->use_timer_thread ) { - frame = (struct frame_info *) - double_buffer_read(src_ctx->double_buff); - - if ( !frame ) + if ( double_buffer_read(src_ctx->double_buff, + &src_ctx->timer_thread_frame) ) return -1; + + frame = &src_ctx->timer_thread_frame; } else { - frame = src_ctx->no_timer_thread_frame; + frame = &src_ctx->callback_frame; } video_data = frame->video_data; video_data_size = frame->video_data_size; stride = frame->stride; error_status = frame->error_status; + cap_info.capture_time_sec = frame->capture_time.tv_sec; + cap_info.capture_time_usec = frame->capture_time.tv_usec; /* FIXME: right now enforce_framerate() and the capture timer * thread's main loop BOTH use the frame_time_next field @@ -379,10 +307,6 @@ if ( src_ctx->use_timer_thread ) { - /* delete frame */ - free(frame->video_data); - free(frame); - if ( error_status ) { /* Let capture thread know that the app @@ -400,11 +324,66 @@ return 0; } +/* NOTE: stride-ignorant sapis should pass a stride of zero */ +int +sapi_src_capture_notify(struct sapi_src_context * src_ctx, + char * video_data, int video_data_size, + int stride, + int error_status) +{ + /* NOTE: We may be called here by the capture thread while the + * main thread is clearing capture_data and capture_callback + * from within vidcap_src_capture_stop(). + */ + + struct frame_info *frame = &src_ctx->callback_frame; + + /* Screen-out useless callbacks */ + if ( video_data_size < 1 && !error_status ) + { + log_info("callback with no data?\n"); + return 0; + } + + /* Package the video information */ + frame->video_data_size = video_data_size; + frame->error_status = error_status; + frame->stride = stride; + frame->capture_time = vc_now(); + frame->video_data = video_data; + + if ( src_ctx->use_timer_thread ) + { + /* buffer the frame - for processing by the timer thread */ + double_buffer_write(src_ctx->double_buff, frame); + + /* If there's an error, wait here until it's acknowledged + * by the timer thread (after having delivered it to the app). + */ + if ( error_status ) + wait_for_error_ack(src_ctx); + } + else + { + /* process the frame now */ + deliver_frame(src_ctx); + } + + if ( error_status ) + { + src_ctx->src_state = src_bound; + src_ctx->capture_callback = 0; + src_ctx->capture_data = VIDCAP_INVALID_USER_DATA; + } + + return 0; +} + unsigned int STDCALL sapi_src_timer_thread_func(void *args) { struct sapi_src_context * src_ctx = args; - struct timeval tv_now; + struct timeval tv_now; const long idle_state_sleep_period_ms = 100; long sleep_ms = idle_state_sleep_period_ms; int first_time = 1; @@ -414,12 +393,7 @@ src_ctx->timer_thread_idle = 1; - if ( gettimeofday(&tv_now, 0) ) - { - src_ctx->capture_timer_thread_started = -1; - log_error("gettimeofday not supported\n"); - return -1; - } + tv_now = vc_now(); src_ctx->frame_time_next.tv_sec = tv_now.tv_sec; src_ctx->frame_time_next.tv_usec = tv_now.tv_usec; @@ -428,7 +402,7 @@ while ( !src_ctx->kill_timer_thread ) { - gettimeofday(&tv_now, 0); + tv_now = vc_now(); /* sleep or read? */ if ( capture_error || src_ctx->src_state != src_capturing || Modified: trunk/src/sapi_context.h =================================================================== --- trunk/src/sapi_context.h 2007-12-12 20:46:06 UTC (rev 83) +++ trunk/src/sapi_context.h 2007-12-12 20:55:11 UTC (rev 84) @@ -40,6 +40,7 @@ int video_data_size; int error_status; int stride; + struct timeval capture_time; }; struct sapi_src_context @@ -79,8 +80,11 @@ vidcap_src_capture_callback capture_callback; void * capture_data; + struct frame_info buffered_frames[2]; + struct frame_info timer_thread_frame; + int use_timer_thread; - struct frame_info * no_timer_thread_frame; + struct frame_info callback_frame; vc_thread capture_timer_thread; unsigned int capture_timer_thread_id; int capture_timer_thread_started; Modified: trunk/src/vidcap.c =================================================================== --- trunk/src/vidcap.c 2007-12-12 20:46:06 UTC (rev 83) +++ trunk/src/vidcap.c 2007-12-12 20:55:11 UTC (rev 84) @@ -338,7 +338,7 @@ goto bail; } - log_info("using a capture timer thread for this source\n"); + log_debug("using a capture timer thread for this source\n"); } if ( sapi_ctx->acquire_source(sapi_ctx, src_ctx, src_info) ) @@ -528,7 +528,7 @@ return -1; } - log_info("format bind requires conversion: %s\n", + log_debug("format bind requires conversion: %s\n", conv_conversion_name_get(src_ctx->fmt_conv_func)); } @@ -546,40 +546,20 @@ return 0; } -void -free_frame_info(void * fr) +static __inline void +copy_frame_info(void * fr2, const void *fr1) { - struct frame_info *frame = (struct frame_info *)fr; + const struct frame_info *frame_orig = (struct frame_info *)fr1; + struct frame_info *frame_dup = (struct frame_info *)fr2; - free(frame->video_data); - free(frame); -} + frame_dup->capture_time = frame_orig->capture_time; + frame_dup->error_status = frame_orig->error_status; + frame_dup->stride = frame_orig->stride; + frame_dup->video_data_size = frame_orig->video_data_size; -void * -copy_frame_info(void * fr) -{ - struct frame_info *frame = (struct frame_info *)fr; - - struct frame_info *dup_frame = malloc(sizeof(*dup_frame)); - - if ( !dup_frame ) - return 0; - - dup_frame->stride = frame->stride; - dup_frame->error_status = frame->error_status; - dup_frame->video_data_size = frame->video_data_size; - dup_frame->video_data = malloc(frame->video_data_size); - if ( !dup_frame->video_data ) - { - free(dup_frame); - return 0; - } - - memcpy(dup_frame->video_data, - frame->video_data, - frame->video_data_size); - - return dup_frame; + memcpy(frame_dup->video_data, + frame_orig->video_data, + frame_orig->video_data_size); } int @@ -587,54 +567,108 @@ vidcap_src_capture_callback callback, void * user_data) { - int ret; + int ret = 0; struct sapi_src_context * src_ctx = (struct sapi_src_context *)src; const int sliding_window_seconds = 4; + /* Assume worst-case video data with stride is 50% + * bigger than without a stride. + */ + /* FIXME: Defer measurement of stride-full + * buffer until first capture callback + */ + const int stride_full_buf_size = src_ctx->stride_free_buf_size * 3 / 2; + if ( user_data == VIDCAP_INVALID_USER_DATA ) return -3; if ( src_ctx->src_state != src_bound ) return -4; - src_ctx->frame_time_next.tv_sec = 0; - src_ctx->frame_time_next.tv_usec = 0; - src_ctx->frame_times = sliding_window_create(sliding_window_seconds * - src_ctx->fmt_nominal.fps_numerator / - src_ctx->fmt_nominal.fps_denominator, - sizeof(struct timeval)); + memset(src_ctx->buffered_frames, 0, sizeof(src_ctx->buffered_frames)); + src_ctx->timer_thread_frame.video_data = 0; + src_ctx->frame_times = 0; + src_ctx->double_buff = 0; - if ( !src_ctx->frame_times ) - return -2; + if ( src_ctx->use_timer_thread ) + { + /* allocate space for double-buffering video buffers */ + src_ctx->buffered_frames[0].video_data = + malloc(2 * stride_full_buf_size); + if ( !src_ctx->buffered_frames[0].video_data ) + { + log_oom(__FILE__, __LINE__); + ret = -6; + goto capture_start_bail; + } - src_ctx->double_buff = double_buffer_create(&free_frame_info, - ©_frame_info); + src_ctx->buffered_frames[1].video_data = + src_ctx->buffered_frames[0].video_data + + stride_full_buf_size; - if ( !src_ctx->double_buff ) + src_ctx->timer_thread_frame.video_data = + malloc(stride_full_buf_size); + if ( !src_ctx->timer_thread_frame.video_data ) + { + log_oom(__FILE__, __LINE__); + ret = -6; + goto capture_start_bail; + } + + src_ctx->double_buff = double_buffer_create(©_frame_info, + &src_ctx->buffered_frames[0], &src_ctx->buffered_frames[1]); + if ( !src_ctx->double_buff ) + { + ret = -5; + goto capture_start_bail; + } + } + else { - sliding_window_destroy(src_ctx->frame_times); - src_ctx->frame_times = 0; - return -5; + src_ctx->frame_time_next.tv_sec = 0; + src_ctx->frame_time_next.tv_usec = 0; + src_ctx->frame_times = sliding_window_create(sliding_window_seconds * + src_ctx->fmt_nominal.fps_numerator / + src_ctx->fmt_nominal.fps_denominator, + sizeof(struct timeval)); + + if ( !src_ctx->frame_times ) + return -2; } src_ctx->capture_callback = callback; src_ctx->capture_data = user_data; if ( (ret = src_ctx->start_capture(src_ctx)) ) - { - src_ctx->capture_callback = 0; - src_ctx->capture_data = VIDCAP_INVALID_USER_DATA; + goto capture_start_bail; + src_ctx->src_state = src_capturing; + return 0; + +capture_start_bail: + + src_ctx->capture_callback = 0; + src_ctx->capture_data = VIDCAP_INVALID_USER_DATA; + + if ( src_ctx->double_buff ) double_buffer_destroy(src_ctx->double_buff); - src_ctx->double_buff = 0; + if ( src_ctx->buffered_frames[0].video_data ) + free(src_ctx->buffered_frames[0].video_data); + + if ( src_ctx->buffered_frames[1].video_data ) + free(src_ctx->buffered_frames[1].video_data); + + if ( src_ctx->timer_thread_frame.video_data ) + free(src_ctx->timer_thread_frame.video_data); + + if ( src_ctx->frame_times ) sliding_window_destroy(src_ctx->frame_times); - src_ctx->frame_times = 0; - return ret; - } - src_ctx->src_state = src_capturing; - return 0; + src_ctx->double_buff = 0; + src_ctx->frame_times = 0; + + return ret; } int @@ -657,10 +691,21 @@ sapi_src_timer_thread_idled(src_ctx); } - double_buffer_destroy(src_ctx->double_buff); + if ( src_ctx->double_buff ) + double_buffer_destroy(src_ctx->double_buff); src_ctx->double_buff = 0; - sliding_window_destroy(src_ctx->frame_times); + if ( src_ctx->buffered_frames[0].video_data ) + free(src_ctx->buffered_frames[0].video_data); + + if ( src_ctx->buffered_frames[1].video_data ) + free(src_ctx->buffered_frames[1].video_data); + + if ( src_ctx->timer_thread_frame.video_data ) + free(src_ctx->timer_thread_frame.video_data); + + if ( src_ctx->frame_times ) + sliding_window_destroy(src_ctx->frame_times); src_ctx->frame_times = 0; src_ctx->capture_callback = 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |