├── .gitignore ├── .gitmodules ├── BUILD ├── CMakeLists.txt ├── COPYING ├── Doxyfile ├── NEWS ├── README.md ├── TODO ├── build.sh ├── cmake_modules ├── FindELFHACKS.cmake └── FindPACKETSTREAM.cmake ├── package.sh ├── scripts ├── CMakeLists.txt ├── capture.sh ├── encode.sh ├── glc-build.sh ├── pipe_ffmpeg.sh ├── play.sh └── webcam_overlay_mix_audio.sh └── src ├── CMakeLists.txt ├── capture.c ├── glc ├── CMakeLists.txt ├── capture │ ├── alsa_capture.c │ ├── alsa_capture.h │ ├── alsa_hook.c │ ├── alsa_hook.h │ ├── audio_capture.c │ ├── audio_capture.h │ ├── gl_capture.c │ └── gl_capture.h ├── common │ ├── core.c │ ├── core.h │ ├── glc.h │ ├── log.c │ ├── log.h │ ├── optimization.h │ ├── rational.c │ ├── rational.h │ ├── signal.c │ ├── signal.h │ ├── state.c │ ├── state.h │ ├── thread.c │ ├── thread.h │ ├── util.c │ ├── util.h │ └── version.h.in ├── core │ ├── color.c │ ├── color.h │ ├── copy.c │ ├── copy.h │ ├── file.c │ ├── file.h │ ├── frame_writers.c │ ├── frame_writers.h │ ├── info.c │ ├── info.h │ ├── pack.c │ ├── pack.h │ ├── pipe.c │ ├── pipe.h │ ├── rgb.c │ ├── rgb.h │ ├── scale.c │ ├── scale.h │ ├── sink.h │ ├── source.h │ ├── tracker.c │ ├── tracker.h │ ├── ycbcr.c │ └── ycbcr.h ├── export │ ├── img.c │ ├── img.h │ ├── wav.c │ ├── wav.h │ ├── yuv4mpeg.c │ └── yuv4mpeg.h └── play │ ├── alsa_play.c │ ├── alsa_play.h │ ├── demux.c │ ├── demux.h │ ├── gl_play.c │ └── gl_play.h ├── hook ├── CMakeLists.txt ├── alsa.c ├── lib.h ├── main.c ├── opengl.c └── x11.c └── play.c /.gitignore: -------------------------------------------------------------------------------- 1 | src/glc/common/version.h 2 | build/ 3 | 4 | # CMake stuff 5 | CMakeFiles/ 6 | CMakeCache.txt 7 | Makefile 8 | cmake_install.cmake 9 | 10 | # Binaries 11 | glc-capture 12 | glc-play 13 | libglc-*.so* 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "support"] 2 | path = support 3 | url = https://github.com/lano1106/glcs-support.git 4 | branch = master 5 | [submodule "packetstream"] 6 | path = packetstream 7 | url = https://github.com/lano1106/glcs-packetstream.git 8 | branch = master 9 | [submodule "elfhacks"] 10 | path = elfhacks 11 | url = https://github.com/nullkey/elfhacks.git 12 | branch = stable 13 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | This project is using git submodules. They are not included in zipball or tarball. Hence 2 | it is recommended that you fetch the source code with git clone by doing: 3 | 4 | 1. 5 | 6 | git clone --recursive https://github.com/lano1106/glcs.git 7 | 8 | 2. 9 | 10 | git clone https://github.com/lano1106/glcs.git 11 | git submodule init 12 | git submodule update 13 | 14 | For building and installing, you can use the 2 provided bash scripts or get packages for ArchLinux 15 | 16 | at https://aur.archlinux.org/packages/glcs/ 17 | 18 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 2 | 3 | PROJECT("glcs" "C") 4 | 5 | SET(GLCS_SOVER 0) 6 | SET(GLCS_VER 0.6.3) 7 | FIND_PACKAGE(Threads REQUIRED) 8 | 9 | IF (NOT CMAKE_BUILD_TYPE) 10 | SET(CMAKE_BUILD_TYPE "Release") 11 | ENDIF (NOT CMAKE_BUILD_TYPE) 12 | 13 | 14 | # Define options. 15 | OPTION(QUICKLZ "QuickLZ support" ON) 16 | OPTION(LZO "LZO support" ON) 17 | OPTION(LZJB "LZJB support" ON) 18 | OPTION(BINARIES "Build and install glc-capture and glc-play" ON) 19 | OPTION(HOOK "Build and install glc-hook" ON) 20 | OPTION(SCRIPTS "Install sample scripts." OFF) 21 | 22 | 23 | # Define search and install paths. 24 | IF (NOT LIBRARY_INSTALL_DIR) 25 | SET(LIBRARY_INSTALL_DIR "lib") 26 | # Support the old "mlibdir" option too. 27 | IF (MLIBDIR) 28 | SET(LIBRARY_INSTALL_DIR ${MLIBDIR}) 29 | ENDIF (MLIBDIR) 30 | ENDIF (NOT LIBRARY_INSTALL_DIR) 31 | 32 | IF (NOT BINARY_INSTALL_DIR) 33 | SET(BINARY_INSTALL_DIR "bin") 34 | ENDIF (NOT BINARY_INSTALL_DIR) 35 | 36 | IF (NOT SCRIPTS_INSTALL_DIR) 37 | SET(SCRIPTS_INSTALL_DIR "share/glc") 38 | ENDIF (NOT SCRIPTS_INSTALL_DIR) 39 | 40 | 41 | # Add stuff to build. 42 | ADD_SUBDIRECTORY("src") 43 | 44 | IF (SCRIPTS) 45 | ADD_SUBDIRECTORY("scripts") 46 | ENDIF (SCRIPTS) 47 | -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.5.3 2 | 3 | #--------------------------------------------------------------------------- 4 | # Project related configuration options 5 | #--------------------------------------------------------------------------- 6 | DOXYFILE_ENCODING = UTF-8 7 | PROJECT_NAME = glc 8 | PROJECT_NUMBER = 0.5.8 9 | OUTPUT_DIRECTORY = doc/ 10 | CREATE_SUBDIRS = NO 11 | OUTPUT_LANGUAGE = English 12 | BRIEF_MEMBER_DESC = YES 13 | REPEAT_BRIEF = YES 14 | ABBREVIATE_BRIEF = "The $name class" \ 15 | "The $name widget" \ 16 | "The $name file" \ 17 | is \ 18 | provides \ 19 | specifies \ 20 | contains \ 21 | represents \ 22 | a \ 23 | an \ 24 | the 25 | ALWAYS_DETAILED_SEC = NO 26 | INLINE_INHERITED_MEMB = NO 27 | FULL_PATH_NAMES = YES 28 | STRIP_FROM_PATH = 29 | STRIP_FROM_INC_PATH = 30 | SHORT_NAMES = NO 31 | JAVADOC_AUTOBRIEF = NO 32 | QT_AUTOBRIEF = NO 33 | MULTILINE_CPP_IS_BRIEF = NO 34 | DETAILS_AT_TOP = NO 35 | INHERIT_DOCS = YES 36 | SEPARATE_MEMBER_PAGES = NO 37 | TAB_SIZE = 8 38 | ALIASES = 39 | OPTIMIZE_OUTPUT_FOR_C = YES 40 | OPTIMIZE_OUTPUT_JAVA = NO 41 | BUILTIN_STL_SUPPORT = NO 42 | CPP_CLI_SUPPORT = NO 43 | DISTRIBUTE_GROUP_DOC = NO 44 | SUBGROUPING = YES 45 | #--------------------------------------------------------------------------- 46 | # Build related configuration options 47 | #--------------------------------------------------------------------------- 48 | EXTRACT_ALL = NO 49 | EXTRACT_PRIVATE = NO 50 | EXTRACT_STATIC = NO 51 | EXTRACT_LOCAL_CLASSES = YES 52 | EXTRACT_LOCAL_METHODS = NO 53 | EXTRACT_ANON_NSPACES = NO 54 | HIDE_UNDOC_MEMBERS = YES 55 | HIDE_UNDOC_CLASSES = YES 56 | HIDE_FRIEND_COMPOUNDS = NO 57 | HIDE_IN_BODY_DOCS = NO 58 | INTERNAL_DOCS = NO 59 | CASE_SENSE_NAMES = YES 60 | HIDE_SCOPE_NAMES = NO 61 | SHOW_INCLUDE_FILES = YES 62 | INLINE_INFO = YES 63 | SORT_MEMBER_DOCS = YES 64 | SORT_BRIEF_DOCS = NO 65 | SORT_BY_SCOPE_NAME = NO 66 | GENERATE_TODOLIST = YES 67 | GENERATE_TESTLIST = YES 68 | GENERATE_BUGLIST = YES 69 | GENERATE_DEPRECATEDLIST= YES 70 | ENABLED_SECTIONS = 71 | MAX_INITIALIZER_LINES = 30 72 | SHOW_USED_FILES = YES 73 | SHOW_DIRECTORIES = NO 74 | FILE_VERSION_FILTER = 75 | #--------------------------------------------------------------------------- 76 | # configuration options related to warning and progress messages 77 | #--------------------------------------------------------------------------- 78 | QUIET = NO 79 | WARNINGS = YES 80 | WARN_IF_UNDOCUMENTED = YES 81 | WARN_IF_DOC_ERROR = YES 82 | WARN_NO_PARAMDOC = NO 83 | WARN_FORMAT = "$file:$line: $text " 84 | WARN_LOGFILE = 85 | #--------------------------------------------------------------------------- 86 | # configuration options related to the input files 87 | #--------------------------------------------------------------------------- 88 | INPUT = src/glc/ 89 | INPUT_ENCODING = UTF-8 90 | FILE_PATTERNS = *.c \ 91 | *.h 92 | RECURSIVE = YES 93 | EXCLUDE = 94 | EXCLUDE_SYMLINKS = NO 95 | EXCLUDE_PATTERNS = 96 | EXCLUDE_SYMBOLS = 97 | EXAMPLE_PATH = 98 | EXAMPLE_PATTERNS = * 99 | EXAMPLE_RECURSIVE = NO 100 | IMAGE_PATH = 101 | INPUT_FILTER = 102 | FILTER_PATTERNS = 103 | FILTER_SOURCE_FILES = NO 104 | #--------------------------------------------------------------------------- 105 | # configuration options related to source browsing 106 | #--------------------------------------------------------------------------- 107 | SOURCE_BROWSER = YES 108 | INLINE_SOURCES = NO 109 | STRIP_CODE_COMMENTS = YES 110 | REFERENCED_BY_RELATION = NO 111 | REFERENCES_RELATION = NO 112 | REFERENCES_LINK_SOURCE = YES 113 | USE_HTAGS = NO 114 | VERBATIM_HEADERS = NO 115 | #--------------------------------------------------------------------------- 116 | # configuration options related to the alphabetical class index 117 | #--------------------------------------------------------------------------- 118 | ALPHABETICAL_INDEX = NO 119 | COLS_IN_ALPHA_INDEX = 5 120 | IGNORE_PREFIX = 121 | #--------------------------------------------------------------------------- 122 | # configuration options related to the HTML output 123 | #--------------------------------------------------------------------------- 124 | GENERATE_HTML = YES 125 | HTML_OUTPUT = html 126 | HTML_FILE_EXTENSION = .html 127 | HTML_HEADER = 128 | HTML_FOOTER = 129 | HTML_STYLESHEET = 130 | HTML_ALIGN_MEMBERS = YES 131 | GENERATE_HTMLHELP = NO 132 | HTML_DYNAMIC_SECTIONS = NO 133 | CHM_FILE = 134 | HHC_LOCATION = 135 | GENERATE_CHI = NO 136 | BINARY_TOC = NO 137 | TOC_EXPAND = NO 138 | DISABLE_INDEX = NO 139 | ENUM_VALUES_PER_LINE = 4 140 | GENERATE_TREEVIEW = NO 141 | TREEVIEW_WIDTH = 250 142 | #--------------------------------------------------------------------------- 143 | # configuration options related to the LaTeX output 144 | #--------------------------------------------------------------------------- 145 | GENERATE_LATEX = YES 146 | LATEX_OUTPUT = latex 147 | LATEX_CMD_NAME = latex 148 | MAKEINDEX_CMD_NAME = makeindex 149 | COMPACT_LATEX = NO 150 | PAPER_TYPE = a4 151 | EXTRA_PACKAGES = 152 | LATEX_HEADER = 153 | PDF_HYPERLINKS = YES 154 | USE_PDFLATEX = YES 155 | LATEX_BATCHMODE = NO 156 | LATEX_HIDE_INDICES = NO 157 | #--------------------------------------------------------------------------- 158 | # configuration options related to the RTF output 159 | #--------------------------------------------------------------------------- 160 | GENERATE_RTF = NO 161 | RTF_OUTPUT = rtf 162 | COMPACT_RTF = NO 163 | RTF_HYPERLINKS = NO 164 | RTF_STYLESHEET_FILE = 165 | RTF_EXTENSIONS_FILE = 166 | #--------------------------------------------------------------------------- 167 | # configuration options related to the man page output 168 | #--------------------------------------------------------------------------- 169 | GENERATE_MAN = NO 170 | MAN_OUTPUT = man 171 | MAN_EXTENSION = .3 172 | MAN_LINKS = NO 173 | #--------------------------------------------------------------------------- 174 | # configuration options related to the XML output 175 | #--------------------------------------------------------------------------- 176 | GENERATE_XML = NO 177 | XML_OUTPUT = xml 178 | XML_SCHEMA = 179 | XML_DTD = 180 | XML_PROGRAMLISTING = YES 181 | #--------------------------------------------------------------------------- 182 | # configuration options for the AutoGen Definitions output 183 | #--------------------------------------------------------------------------- 184 | GENERATE_AUTOGEN_DEF = NO 185 | #--------------------------------------------------------------------------- 186 | # configuration options related to the Perl module output 187 | #--------------------------------------------------------------------------- 188 | GENERATE_PERLMOD = NO 189 | PERLMOD_LATEX = NO 190 | PERLMOD_PRETTY = YES 191 | PERLMOD_MAKEVAR_PREFIX = 192 | #--------------------------------------------------------------------------- 193 | # Configuration options related to the preprocessor 194 | #--------------------------------------------------------------------------- 195 | ENABLE_PREPROCESSING = YES 196 | MACRO_EXPANSION = YES 197 | EXPAND_ONLY_PREDEF = YES 198 | SEARCH_INCLUDES = YES 199 | INCLUDE_PATH = 200 | INCLUDE_FILE_PATTERNS = 201 | PREDEFINED = __PUBLIC \ 202 | __PRIVATE 203 | EXPAND_AS_DEFINED = 204 | SKIP_FUNCTION_MACROS = YES 205 | #--------------------------------------------------------------------------- 206 | # Configuration::additions related to external references 207 | #--------------------------------------------------------------------------- 208 | TAGFILES = 209 | GENERATE_TAGFILE = 210 | ALLEXTERNALS = NO 211 | EXTERNAL_GROUPS = YES 212 | PERL_PATH = /usr/bin/perl 213 | #--------------------------------------------------------------------------- 214 | # Configuration options related to the dot tool 215 | #--------------------------------------------------------------------------- 216 | CLASS_DIAGRAMS = NO 217 | MSCGEN_PATH = 218 | HIDE_UNDOC_RELATIONS = YES 219 | HAVE_DOT = YES 220 | CLASS_GRAPH = YES 221 | COLLABORATION_GRAPH = YES 222 | GROUP_GRAPHS = YES 223 | UML_LOOK = NO 224 | TEMPLATE_RELATIONS = NO 225 | INCLUDE_GRAPH = YES 226 | INCLUDED_BY_GRAPH = YES 227 | CALL_GRAPH = NO 228 | CALLER_GRAPH = NO 229 | GRAPHICAL_HIERARCHY = YES 230 | DIRECTORY_GRAPH = YES 231 | DOT_IMAGE_FORMAT = png 232 | DOT_PATH = 233 | DOTFILE_DIRS = 234 | DOT_GRAPH_MAX_NODES = 50 235 | MAX_DOT_GRAPH_DEPTH = 1000 236 | DOT_TRANSPARENT = NO 237 | DOT_MULTI_TARGETS = NO 238 | GENERATE_LEGEND = YES 239 | DOT_CLEANUP = YES 240 | #--------------------------------------------------------------------------- 241 | # Configuration::additions related to the search engine 242 | #--------------------------------------------------------------------------- 243 | SEARCHENGINE = NO 244 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Version 0.6.3 - June 19, 2014 2 | - Initialized to NULL a pointer (https://github.com/lano1106/glcs/issues/12) 3 | - Fix regression where some application fork a child where the actual opengl rendering happens 4 | (https://github.com/lano1106/glcs/issues/11) 5 | - Fix a linkage issue with pthreads on some platforms. 6 | 7 | Version 0.6.2 - May 08, 2014 8 | 9 | - Fix invert_framewriter when restart capture after an interrupted one. 10 | - Add the option to delay the writting of the frames in the pipe after having 11 | created the pipe reader process. 12 | - Improve cmake files. 13 | - Fix compiler warnings 14 | - Replace sched_yield which is not implemented in Linux 15 | - Robustify gl_capture multithread sync design 16 | - Improve gl_capture logs 17 | - Remove unneeded PTHREAD_CANCEL_ASYNCHRONOUS type use. 18 | 19 | Version 0.6.1 - March 19, 2014 20 | 21 | - Webcam overlay + audio streams mix 22 | - Give more time to pipe process to terminate after having sent a SIGINT. 23 | - Remove custom sighandler code. 24 | - Allow the pipe sink thread to recuperate from a failure from child program 25 | and make possible a capture restart without having to restart the host app. 26 | 27 | Version 0.6.0 - March 6, 2014 28 | 29 | - Add the option to send raw video stream to a pipe making it possible process the stream with external tools such as FFMPEG. 30 | - Fix buffer overflow causing heap corruption in src/hook/alsa.c 31 | - Change the delimiter from comma (,) to pound (#) for the alsa capture devices param. 32 | - branch prediction optimization 33 | - Replace several malloc+memset with calloc 34 | - Replace bitwise and/or operators with short-circuit logical operators. 35 | - Replace direct io syscalls with stdio 36 | - Use reentrant version of ctime() and localtime() 37 | - Replace a while loop with strstr() with a single strrchr() call. 38 | - Upgrade minilzo 2.02 to 2.06 39 | - Upgrade quicklz to 1.5.0 40 | - Replace custom init sync with standard pthread_once 41 | - Add performance logs 42 | - Increase timestamp precision to nanosecond. 43 | - Remove zombie alsa hook capture thread leak 44 | - make the alsa hook thread code async signal safe by blocking signals from the thread. 45 | - replace malloc with alloca for small temp ALSA params structs 46 | - replace signals to io poll for alsa_capture. 47 | - alsa_capture exclusively calls real alsa 48 | - fix alsa playback underrun and premature shutdown 49 | - Add rtpriority option for ALSA threads 50 | - remove several getenv() calls 51 | - forbids current frame ts to be in the futur 52 | - introduce sink and source abstract interface 53 | - shorten log level defines name 54 | - Improve how capture reload is performed 55 | - Creation of 2 frame writer classes 56 | 57 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Here are a couple of suggestions of aspect of glcs that I think could be improved: 2 | 3 | - Increase the number of piping scripts to server various purposes. 4 | - Add ffmpeg preset files to fullfill the various Internet Streaming service encoding requirements. 5 | - Usual stuff: bug fixes code and doc improvements 6 | 7 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Takes one optional param. 4 | # 5 | # PREFIX: Specify where the project is installed. default is / 6 | # 7 | 8 | usage() 9 | { 10 | echo "usage: $0 destdir [libdir]" 11 | exit 1 12 | } 13 | 14 | mods=("elfhacks" "packetstream" "../glcs") 15 | 16 | if ! (( ($# == 1) || ($# == 2) )); then 17 | usage 18 | fi 19 | 20 | DESTDIR=$1 21 | MLIBDIR=${2:-"lib"} 22 | GLCSDIR=$PWD 23 | 24 | export CMAKE_INCLUDE_PATH="$GLCSDIR/elfhacks/src:$GLCSDIR/packetstream/src" 25 | export CMAKE_LIBRARY_PATH="$GLCSDIR/elfhacks/build/src:$GLCSDIR/packetstream/build/src" 26 | 27 | for mod in ${mods[@]}; do 28 | echo "Building $mod..." 29 | [ -d $mod/build ] || mkdir $mod/build 30 | cd $mod/build 31 | 32 | cmake .. \ 33 | -DCMAKE_INSTALL_PREFIX:PATH="${DESTDIR}" \ 34 | -DCMAKE_BUILD_TYPE:STRING="Release" \ 35 | -DCMAKE_C_FLAGS_RELEASE:STRING="${CFLAGS}" \ 36 | -DMLIBDIR:PATH=${MLIBDIR} \ 37 | || exit 1 38 | make || exit 1 39 | cd ../.. 40 | done 41 | 42 | -------------------------------------------------------------------------------- /cmake_modules/FindELFHACKS.cmake: -------------------------------------------------------------------------------- 1 | FIND_PATH(ELFHACKS_INCLUDE_DIR "elfhacks.h") 2 | FIND_LIBRARY(ELFHACKS_LIBRARY NAMES "elfhacks") 3 | 4 | IF (ELFHACKS_INCLUDE_DIR AND ELFHACKS_LIBRARY) 5 | SET(ELFHACKS_FOUND TRUE) 6 | ENDIF (ELFHACKS_INCLUDE_DIR AND ELFHACKS_LIBRARY) 7 | 8 | IF (ELFHACKS_FOUND) 9 | IF (NOT ELFHACKS_FIND_QUIETLY) 10 | MESSAGE(STATUS "Found elfhacks: ${ELFHACKS_LIBRARY}") 11 | ENDIF (NOT ELFHACKS_FIND_QUIETLY) 12 | ELSE (ELFHACKS_FOUND) 13 | IF (ELFHACKS_FIND_REQUIRED) 14 | MESSAGE(FATAL_ERROR "Could not find elfhacks") 15 | ENDIF (ELFHACKS_FIND_REQUIRED) 16 | ENDIF (ELFHACKS_FOUND) 17 | -------------------------------------------------------------------------------- /cmake_modules/FindPACKETSTREAM.cmake: -------------------------------------------------------------------------------- 1 | FIND_PATH(PACKETSTREAM_INCLUDE_DIR "packetstream.h") 2 | FIND_LIBRARY(PACKETSTREAM_LIBRARY NAMES "packetstream") 3 | 4 | IF (PACKETSTREAM_INCLUDE_DIR AND PACKETSTREAM_LIBRARY) 5 | SET(PACKETSTREAM_FOUND TRUE) 6 | ENDIF (PACKETSTREAM_INCLUDE_DIR AND PACKETSTREAM_LIBRARY) 7 | 8 | IF (PACKETSTREAM_FOUND) 9 | IF (NOT PACKETSTREAM_FIND_QUIETLY) 10 | MESSAGE(STATUS "Found packetstream: ${PACKETSTREAM_LIBRARY}") 11 | ENDIF (NOT PACKETSTREAM_FIND_QUIETLY) 12 | ELSE (PACKETSTREAM_FOUND) 13 | IF (PACKETSTREAM_FIND_REQUIRED) 14 | MESSAGE(FATAL_ERROR "Could not find packetstream") 15 | ENDIF (PACKETSTREAM_FIND_REQUIRED) 16 | ENDIF (PACKETSTREAM_FOUND) 17 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Takes one optional param. 4 | # 5 | # PREFIX: Specify where the project is installed. default is / 6 | # 7 | 8 | usage() 9 | { 10 | echo "usage: $0 destdir" 11 | exit 1 12 | } 13 | 14 | mods=("elfhacks" "packetstream" "../glcs") 15 | 16 | if ! (( $# == 1 )); then 17 | usage 18 | fi 19 | 20 | DESTDIR=$1 21 | 22 | GLCSDIR=$PWD 23 | 24 | for mod in ${mods[@]}; do 25 | echo "Installing $mod to $DESTDIR ..." 26 | cd $GLCSDIR/$mod/build 27 | make install || exit 1 28 | done 29 | 30 | install -d -m755 $DESTDIR/share/glcs/scripts 31 | install -m755 $GLCSDIR/scripts/capture.sh $DESTDIR/share/glcs/scripts/capture.sh 32 | install -m755 $GLCSDIR/scripts/pipe_ffmpeg.sh $DESTDIR/share/glcs/scripts/pipe_ffmpeg.sh 33 | install -m755 $GLCSDIR/scripts/webcam_overlay_mix_audio.sh $DESTDIR/share/glcs/scripts/webcam_overlay_mix_audio.sh 34 | install -d -m755 $DESTDIR/share/licenses/glcs 35 | install -m644 $GLCSDIR/COPYING $DESTDIR/share/licenses/glcs/COPYING 36 | 37 | -------------------------------------------------------------------------------- /scripts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | IF (UNIX) 2 | INSTALL(FILES "capture.sh" "encode.sh" "play.sh" 3 | DESTINATION ${SCRIPTS_INSTALL_DIR}) 4 | ENDIF (UNIX) 5 | -------------------------------------------------------------------------------- /scripts/capture.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # capture.sh -- example: glc environment variables and usage 4 | # Copyright (C) 2007 Pyry Haulos 5 | # For conditions of distribution and use, see copyright notice in glc.h 6 | 7 | # picture stream fps 8 | export GLC_FPS=30 9 | 10 | # scale pictures 11 | export GLC_SCALE=1.0 12 | 13 | # capture audio 14 | export GLC_AUDIO=0 15 | 16 | # captured pictures and audio buffer size, in MiB 17 | export GLC_UNCOMPRESSED_BUFFER_SIZE=25 18 | 19 | # unscaled pictures buffer size, in MiB 20 | export GLC_UNSCALED_BUFFER_SIZE=25 21 | 22 | # compressed data buffer size, in MiB 23 | export GLC_COMPRESSED_BUFFER_SIZE=50 24 | 25 | # take picture at glFinish(), compiz needs this 26 | export GLC_CAPTURE_GLFINISH=0 27 | 28 | # take picture from front or back buffer 29 | export GLC_CAPTURE=back 30 | 31 | # compress stream using 'lzo', 'quicklz', 'lzjb' or 'none' 32 | export GLC_COMPRESS=quicklz 33 | 34 | # try GL_ARB_pixel_buffer_object to speed up readback 35 | export GLC_TRY_PBO=1 36 | 37 | # Skip audio packets. Not skipping requires some busy 38 | # waiting and can slow program down a quite bit. 39 | export GLC_AUDIO_SKIP=0 40 | 41 | # show indicator when capturing 42 | # NOTE this doesn't work properly when capturing front buffer 43 | export GLC_INDICATOR=0 44 | 45 | # start capturing immediately 46 | export GLC_START=0 47 | 48 | # capture hotkey, and mods are supported 49 | #export GLC_HOTKEY="F8" 50 | 51 | # lock fps when capturing 52 | export GLC_LOCK_FPS=0 53 | 54 | # saved stream colorspace, bgr or 420jpeg 55 | # set 420jpeg to convert to Y'CbCr (420JPEG) at capture 56 | # NOTE this is a lossy operation 57 | export GLC_COLORSPACE=bgra 58 | 59 | # crop capture area to WxH+X+Y 60 | # export GLC_CROP=WxH+X+Y 61 | 62 | # record alsa devices 63 | # format is device#rate#channels;device2... 64 | #export GLC_AUDIO_RECORD=hw:0,0#44100#2 65 | 66 | # Use SCHED_RR rt priority for ALSA threads 67 | export GLC_RTPRIO=1 68 | 69 | # pipe raw video stream to an external tool 70 | # 4 command line arguments are going to passed to the program: 71 | # 1. video_size (wxh) 72 | # 2. pixel_format (bgr24, bgra or rgb24) 73 | # 3. fps 74 | # 4. output filename 75 | export GLC_PIPE="/usr/share/glcs/scripts/pipe_ffmpeg.sh" 76 | 77 | # 78 | # Flip vertically the images sent through the pipe 79 | # 80 | export GLC_PIPE_INVERT=1 81 | 82 | # delay in ms between the creation of the pipe reader process 83 | # and the time we start writting frames to the pipe. 84 | # This can help keep audio/video in sync in a ffmpeg setup 85 | # with several inputs and 1 of them is slow to initialize 86 | # http://ffmpeg.org/pipermail/ffmpeg-devel/2014-March/155704.html 87 | export GLC_PIPE_DELAY=0 88 | 89 | # use GL_PACK_ALIGNMENT 8 90 | #export GLC_CAPTURE_DWORD_ALIGNED=1 91 | 92 | # set SDL audiodriver to alsa 93 | export SDL_AUDIODRIVER=alsa 94 | 95 | # log verbosity 96 | export GLC_LOG=4 97 | 98 | export GLC_FILE="%app%-%pid%-%capture%.glc" 99 | 100 | # log file 101 | export GLC_LOG_FILE="/tmp/glcs.log" 102 | 103 | LD_PRELOAD=libglc-hook.so "${@}" 104 | 105 | -------------------------------------------------------------------------------- /scripts/encode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # encode.sh -- encoding glc stream to x264-encoded video 4 | # Copyright (C) 2007-2008 Pyry Haulos 5 | # For conditions of distribution and use, see copyright notice in glc.h 6 | 7 | FILE="" 8 | QUALITY="" 9 | 10 | AUDIO="1" 11 | VIDEO="1" 12 | 13 | BITRATE="2000" 14 | QP="20" 15 | CRF="18" 16 | 17 | METHOD="qp" 18 | 19 | OUTFMT="mp4" 20 | OUT="video.${OUTFMT}" 21 | 22 | PASSLOG="pass.log" 23 | AUDIOTMP="audio.mp3.tmp" 24 | 25 | MULTIPASS="no" 26 | ADDOPTS="" 27 | 28 | showhelp () { 29 | echo "$0 [option]... [glc stream file]" 30 | echo " -o, --out=FILE write video to FILE" 31 | echo " default is ${OUT}" 32 | echo " -v, --video=NUM video stream number" 33 | echo " default is ${VIDEO}" 34 | echo " -a, --audio=NUM audio stream number" 35 | echo " default is ${AUDIO}" 36 | echo " -m, --method=METHOD bitrate calculation method" 37 | echo " supported methods are bitrate, qp, crf" 38 | echo " default method is ${METHOD}" 39 | echo " -q, --quality=VAL quality parameter" 40 | echo " -f, --outfmt=FORMAT output container format" 41 | echo " default is ${OUTFMT}" 42 | echo " -x, --addopts=OPTS additional options to mencoder" 43 | echo " -h, --help show this help" 44 | } 45 | 46 | OPT_TMP=`getopt -o o:v:a:m:q:f:x:h -l out:,video:,audio:,method:,quality:,outfmt:,addopts: \ 47 | -n "$0" -- "$@"` 48 | if [ $? != 0 ]; then showhelp; exit 1; fi 49 | 50 | eval set -- "$OPT_TMP" 51 | 52 | while true; do 53 | case "$1" in 54 | -o|--out) 55 | OUT="$2" 56 | shift 2 57 | ;; 58 | -v|--video) 59 | VIDEO="$2" 60 | shift 2 61 | ;; 62 | -a|--audio) 63 | AUDIO="$2" 64 | shift 2 65 | ;; 66 | -m|--method) 67 | METHOD="$2" 68 | shift 2 69 | ;; 70 | -q|--quality) 71 | QUALITY="$2" 72 | shift 2 73 | ;; 74 | -f|--outfmt) 75 | OUTFMT="$2" 76 | shift 2 77 | ;; 78 | -x|--addopts) 79 | ADDOPTS="$2" 80 | shift 2 81 | ;; 82 | -h|--help) 83 | showhelp 84 | exit 0 85 | shift 2 86 | ;; 87 | --) 88 | shift 89 | break 90 | ;; 91 | *) 92 | echo "Unrecognized option: $1" 93 | showhelp 94 | exit 1 95 | ;; 96 | esac 97 | done 98 | 99 | for arg do FILE=$arg; done 100 | if [ "$FILE" == "" ]; then 101 | showhelp 102 | exit 1 103 | fi 104 | 105 | KEYINT=300 106 | 107 | X264_OPTS="ref=4:mixed_refs:bframes=3:b_pyramid:bime:weightb:direct_pred=auto:filter=-1,0:partitions=all:turbo=1:threads=auto:keyint=${KEYINT}" 108 | LAME_OPTS="q=4" # TODO configure q, cbr or abr 109 | 110 | case ${METHOD} in 111 | crf) 112 | [ "$QUALITY" != "" ] && CRF=$QUALITY 113 | X264_OPTS="crf=${CRF}:${X264_OPTS}" 114 | MULTIPASS="no" 115 | ;; 116 | bitrate) 117 | [ "$QUALITY" != "" ] && BITRATE=$QUALITY 118 | X264_OPTS="bitrate=${BITRATE}:${X264_OPTS}" 119 | MULTIPASS="yes" 120 | ;; 121 | qp) 122 | [ "$QUALITY" != "" ] && QP=$QUALITY 123 | X264_OPTS="qp=${QP}:${X264_OPTS}" 124 | MULTIPASS="yes" 125 | ;; 126 | *) 127 | showhelp 128 | exit 1 129 | ;; 130 | esac 131 | 132 | [ "$OUTFMT" != "avi" ] && OUTFMT="lavf -lavfopts format=${OUTFMT}" 133 | 134 | glc-play "${FILE}" -o - -a "${AUDIO}" | lame -hV2 - "${AUDIOTMP}" 135 | 136 | if [ "${MULTIPASS}" == "no" ]; then 137 | glc-play "${FILE}" -o - -y "${VIDEO}" | \ 138 | mencoder - \ 139 | -audiofile "${AUDIOTMP}"\ 140 | -demuxer y4m \ 141 | -ovc x264 \ 142 | -x264encopts "${X264_OPTS}" \ 143 | -of ${OUTFMT} \ 144 | ${ADDOPTS} \ 145 | -o "${OUT}" 146 | else 147 | glc-play "${FILE}" -o - -y "${VIDEO}" | \ 148 | mencoder - \ 149 | -nosound \ 150 | -demuxer y4m \ 151 | -ovc x264 \ 152 | -x264encopts "${X264_OPTS}:pass=1" \ 153 | -passlogfile "${PASSLOG}" \ 154 | -of ${OUTFMT} \ 155 | ${ADDOPTS} \ 156 | -o "${OUT}" 157 | glc-play "${FILE}" -o - -y "${VIDEO}" | \ 158 | mencoder - \ 159 | -audiofile "${AUDIOTMP}" \ 160 | -demuxer y4m \ 161 | -ovc x264 \ 162 | -x264encopts "${X264_OPTS}:pass=2" \ 163 | -passlogfile "${PASSLOG}" \ 164 | -oac copy \ 165 | -of ${OUTFMT} \ 166 | ${ADDOPTS} \ 167 | -o "${OUT}" 168 | fi 169 | 170 | rm -f "${PASSLOG}" "${AUDIOTMP}" 171 | -------------------------------------------------------------------------------- /scripts/pipe_ffmpeg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | printf "Usage: %s video_size pixel_format framerate base_output_filename\n" "$0" 5 | } 6 | 7 | # validate num params 8 | if ! (( $# == 4 )); then 9 | usage 10 | exit -1 11 | fi 12 | 13 | exec >/tmp/pipe_ffmpeg.out 2>&1 14 | 15 | echo "cmdline: $@" 16 | 17 | # 18 | # tweaking suggesting: 19 | # Depending on your hardware, you might be able to use an higher quality 20 | # preset. Possible value for preset are: 21 | # 22 | # - superfast 23 | # - veryfast 24 | # - faster 25 | # - fast 26 | # 27 | # If using linux-ck, using schedtool -I -e for ffmpeg is a good idea! 28 | # 29 | # For aac encoding, I prefer libfdk_aac as described at: 30 | # http://trac.ffmpeg.org/wiki/AACEncodingGuide 31 | # but since not all distributions compiles ffmpeg with libfdk_aac, 32 | # I choose to not make it the default encoder to make first users experience 33 | # easier. 34 | # 35 | exec ffmpeg -nostats -f rawvideo -video_size $1 -pixel_format $2 -framerate $3 -i /dev/stdin \ 36 | -f alsa -acodec pcm_s16le -ar 48000 -ac 2 -i loop_capture \ 37 | -strict experimental -c:a aac -profile:a aac_low -b:a 128k -ar 44100 \ 38 | -c:v libx264 -preset superfast -profile:v main -level 4.1 -pix_fmt yuv420p \ 39 | -x264opts keyint=60:bframes=2:ref=1 -maxrate 4500k -bufsize 9000k -shortest $4.mkv 40 | 41 | -------------------------------------------------------------------------------- /scripts/play.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # play.sh -- playing glc stream with mplayer 4 | # Copyright (C) 2007 Pyry Haulos 5 | # For conditions of distribution and use, see copyright notice in glc.h 6 | 7 | CTX="1" 8 | AUDIO="1" 9 | 10 | AUDIOFIFO="/tmp/glc-audio.fifo" 11 | VIDEOFIFO="/tmp/glc-video.fifo" 12 | 13 | if [ "$1" == "" ]; then 14 | echo "$0 FILE [ctx] [audio]" 15 | exit 1 16 | fi 17 | 18 | [ "$2" != "" ] && CTX=$2 19 | [ "$3" != "" ] && AUDIO=$3 20 | 21 | mkfifo "${AUDIOFIFO}" 22 | mkfifo "${VIDEOFIFO}" 23 | 24 | glc-play "$1" -o "${AUDIOFIFO}" -a "${AUDIO}" & 25 | glc-play "$1" -o "${VIDEOFIFO}" -y "${CTX}" & 26 | 27 | mplayer -audio-demuxer lavf -demuxer y4m -audiofile "${AUDIOFIFO}" "${VIDEOFIFO}" 28 | 29 | rm -f "${AUDIOFIFO}" "${VIDEOFIFO}" 30 | -------------------------------------------------------------------------------- /scripts/webcam_overlay_mix_audio.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | printf "Usage: %s video_size pixel_format framerate base_output_filename\n" "$0" 5 | } 6 | 7 | # validate num params 8 | if ! (( $# == 4 )); then 9 | usage 10 | exit -1 11 | fi 12 | 13 | exec >/tmp/pipe_ffmpeg.out 2>&1 14 | 15 | echo "cmdline: $@" 16 | 17 | # 18 | # tweaking suggesting: 19 | # Depending on your hardware, you might be able to use an higher quality 20 | # preset. Possible value for preset are: 21 | # 22 | # - superfast 23 | # - veryfast 24 | # - faster 25 | # - fast 26 | # 27 | exec schedtool -I -e ffmpeg -nostats -y \ 28 | -f rawvideo -video_size $1 -pixel_format $2 -framerate $3 -i /dev/stdin \ 29 | -f alsa -acodec pcm_s16le -ar 44100 -ac 2 -i loop_capture \ 30 | -f alsa -acodec pcm_s16le -ar 32000 -ac 2 -i hw:3,0 \ 31 | -f v4l2 -input_format yuyv422 -video_size 320x240 -framerate 30 -i /dev/video0 \ 32 | -filter_complex "overlay;amix" \ 33 | -c:a libfdk_aac -profile:a aac_low -b:a 128k -ar 44100 \ 34 | -c:v libx264 -preset veryfast -profile:v main -level 4.1 -pix_fmt yuv420p \ 35 | -x264opts keyint=60:bframes=2 -maxrate 6000k -bufsize 12000k -shortest $4.mkv 36 | 37 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules") 2 | 3 | 4 | FIND_PACKAGE(PACKETSTREAM) 5 | IF (PACKETSTREAM_FOUND) 6 | # TODO: Try to build local copy of library if no system version is found. 7 | INCLUDE_DIRECTORIES(${PACKETSTREAM_INCLUDE_DIR}) 8 | ENDIF (PACKETSTREAM_FOUND) 9 | 10 | 11 | IF (UNIX) 12 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -Wall") 13 | ADD_DEFINITIONS("-D_GNU_SOURCE") 14 | ADD_DEFINITIONS("-D_FILE_OFFSET_BITS=64") 15 | ENDIF (UNIX) 16 | 17 | 18 | IF (BINARIES) 19 | ADD_EXECUTABLE("capture" "capture.c") 20 | TARGET_LINK_LIBRARIES("capture" "dl" ${CMAKE_THREAD_LIBS_INIT}) 21 | SET_TARGET_PROPERTIES("capture" PROPERTIES OUTPUT_NAME "glc-capture") 22 | 23 | ADD_EXECUTABLE("play" "play.c") 24 | TARGET_LINK_LIBRARIES("play" "glc-core" "glc-play" "glc-export" 25 | ${PACKETSTREAM_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) 26 | SET_TARGET_PROPERTIES("play" PROPERTIES OUTPUT_NAME "glc-play") 27 | 28 | IF (UNIX) 29 | INSTALL(TARGETS "capture" "play" RUNTIME 30 | DESTINATION ${BINARY_INSTALL_DIR}) 31 | ENDIF (UNIX) 32 | ENDIF (BINARIES) 33 | 34 | 35 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) 36 | ADD_SUBDIRECTORY("glc") 37 | 38 | IF (HOOK) 39 | ADD_SUBDIRECTORY("hook") 40 | ENDIF (HOOK) 41 | -------------------------------------------------------------------------------- /src/glc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Look for a .git directory at the project root. 2 | IF (NOT GIT_DIR AND EXISTS "${PROJECT_SOURCE_DIR}/.git") 3 | SET(GIT_DIR ${PROJECT_SOURCE_DIR}) 4 | ENDIF (NOT GIT_DIR AND EXISTS "${PROJECT_SOURCE_DIR}/.git") 5 | 6 | # Use `git describe` to set a version number. Fall-back to GLCS_VER. 7 | IF (GIT_DIR) 8 | EXEC_PROGRAM("git" ${GIT_DIR} ARGS "describe --always --dirty" 9 | OUTPUT_VARIABLE GLCS_VERSION RETURN_VALUE GIT_RETURN) 10 | IF (NOT GIT_RETURN EQUAL 0) 11 | SET(GLCS_VERSION ${GLCS_VER}) 12 | ENDIF (NOT GIT_RETURN EQUAL 0) 13 | ELSE (GIT_DIR) 14 | SET(GLCS_VERSION ${GLCS_VER}) 15 | ENDIF (GIT_DIR) 16 | 17 | CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/common/version.h.in" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/common/version.h") 19 | 20 | 21 | # Set up the compression libraries. 22 | SET(QUICKLZ_SRC) 23 | IF (QUICKLZ) 24 | SET(QUICKLZ_DIR "${PROJECT_SOURCE_DIR}/support/quicklz") 25 | SET(QUICKLZ_SRC "${QUICKLZ_DIR}/quicklz.h" "${QUICKLZ_DIR}/quicklz.c") 26 | INCLUDE_DIRECTORIES(${QUICKLZ_DIR}) 27 | ADD_DEFINITIONS("-D__QUICKLZ") 28 | ENDIF (QUICKLZ) 29 | 30 | SET(LZO_SRC) 31 | IF (LZO) 32 | SET(LZO_DIR "${PROJECT_SOURCE_DIR}/support/minilzo") 33 | SET(LZO_SRC "${LZO_DIR}/lzoconf.h" "${LZO_DIR}/lzodefs.h" 34 | "${LZO_DIR}/minilzo.h" "${LZO_DIR}/minilzo.c") 35 | INCLUDE_DIRECTORIES(${LZO_DIR}) 36 | ADD_DEFINITIONS("-D__MINILZO") 37 | ENDIF (LZO) 38 | 39 | SET(LZJB_SRC) 40 | IF (LZJB) 41 | SET(LZJB_DIR "${PROJECT_SOURCE_DIR}/support/lzjb") 42 | SET(LZJB_SRC "${LZJB_DIR}/lzjb.h" "${LZJB_DIR}/lzjb.c") 43 | INCLUDE_DIRECTORIES(${LZJB_DIR}) 44 | ADD_DEFINITIONS("-D__LZJB") 45 | ENDIF (LZJB) 46 | 47 | 48 | # This is where the library targets are defined. 49 | SET(COMMON_SRC "common/core.h" "common/glc.h" "common/log.h" 50 | "common/optimization.h" "common/signal.h" "common/state.h" 51 | "common/thread.h" "common/util.h" "common/version.h" "common/rational.h" 52 | "common/core.c" "common/log.c" "common/signal.c" "common/state.c" 53 | "common/thread.c" "common/util.c" "common/rational.c") 54 | 55 | # GLCS Core library. 56 | ADD_LIBRARY("glc-core" SHARED ${COMMON_SRC} 57 | "core/color.h" "core/copy.h" "core/file.h" "core/frame_writers.h" 58 | "core/info.h" "core/pack.h" "core/pipe.h" "core/rgb.h" "core/scale.h" 59 | "core/sink.h" "core/source.h" "core/tracker.h" "core/ycbcr.h" 60 | "core/color.c" "core/copy.c" "core/file.c" "core/frame_writers.c" 61 | "core/info.c" "core/pack.c" "core/pipe.c" "core/rgb.c" "core/scale.c" 62 | "core/tracker.c" "core/ycbcr.c" ${QUICKLZ_SRC} ${LZO_SRC} ${LZJB_SRC}) 63 | TARGET_LINK_LIBRARIES("glc-core" "m" ${ACKETSTREAM_LIBRARY}) 64 | SET_TARGET_PROPERTIES("glc-core" PROPERTIES OUTPUT_NAME "glc-core" 65 | VERSION ${GLCS_VER} SOVERSION ${GLCS_SOVER}) 66 | 67 | # Capture library. 68 | ADD_LIBRARY("glc-capture" SHARED ${COMMON_SRC} 69 | "capture/alsa_capture.h" "capture/alsa_hook.h" "capture/audio_capture.h" 70 | "capture/gl_capture.h" "capture/alsa_capture.c" "capture/alsa_hook.c" 71 | "capture/audio_capture.c" "capture/gl_capture.c") 72 | TARGET_LINK_LIBRARIES("glc-capture" "GL" "dl" "asound" "X11" "Xxf86vm" "glc-core") 73 | SET_TARGET_PROPERTIES("glc-capture" PROPERTIES OUTPUT_NAME "glc-capture" 74 | VERSION ${GLCS_VER} SOVERSION ${GLCS_SOVER}) 75 | 76 | # Player library. 77 | ADD_LIBRARY("glc-play" SHARED ${COMMON_SRC} 78 | "play/alsa_play.h" "play/demux.h" "play/gl_play.h" 79 | "play/alsa_play.c" "play/demux.c" "play/gl_play.c") 80 | TARGET_LINK_LIBRARIES("glc-play" "GL" "asound" "X11" "glc-core") 81 | SET_TARGET_PROPERTIES("glc-play" PROPERTIES OUTPUT_NAME "glc-play" 82 | VERSION ${GLCS_VER} SOVERSION ${GLCS_SOVER}) 83 | 84 | ADD_LIBRARY("glc-export" SHARED ${COMMON_SRC} 85 | "export/img.h" "export/wav.h" "export/yuv4mpeg.h" 86 | "export/img.c" "export/wav.c" "export/yuv4mpeg.c") 87 | TARGET_LINK_LIBRARIES("glc-export" "png" "glc-core") 88 | SET_TARGET_PROPERTIES("glc-export" PROPERTIES OUTPUT_NAME "glc-export" 89 | VERSION ${GLCS_VER} SOVERSION ${GLCS_SOVER}) 90 | 91 | 92 | # Install this stuff! 93 | IF (UNIX) 94 | INSTALL(TARGETS "glc-core" "glc-capture" "glc-play" "glc-export" 95 | LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}) 96 | ENDIF (UNIX) 97 | -------------------------------------------------------------------------------- /src/glc/capture/alsa_capture.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/capture/alsa_capture.h 3 | * \brief audio capture 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup capture 11 | * \{ 12 | * \defgroup alsa_capture audio capture 13 | * \{ 14 | */ 15 | 16 | #ifndef _ALSA_CAPTURE_H 17 | #define _ALSA_CAPTURE_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | typedef struct { 27 | int (*snd_pcm_open)(snd_pcm_t **, const char *, snd_pcm_stream_t, int); 28 | int (*snd_pcm_open_lconf)(snd_pcm_t **, const char *, snd_pcm_stream_t, 29 | int, snd_config_t *); 30 | int (*snd_pcm_close)(snd_pcm_t *); 31 | int (*snd_pcm_hw_params)(snd_pcm_t *, snd_pcm_hw_params_t *); 32 | snd_pcm_sframes_t (*snd_pcm_writei)(snd_pcm_t *, const void *, 33 | snd_pcm_uframes_t); 34 | snd_pcm_sframes_t (*snd_pcm_writen)(snd_pcm_t *, void **, snd_pcm_uframes_t); 35 | snd_pcm_sframes_t (*snd_pcm_mmap_writei)(snd_pcm_t *, const void *, 36 | snd_pcm_uframes_t); 37 | snd_pcm_sframes_t (*snd_pcm_mmap_writen)(snd_pcm_t *, void **, 38 | snd_pcm_uframes_t); 39 | int (*snd_pcm_mmap_begin)(snd_pcm_t *, const snd_pcm_channel_area_t **, 40 | snd_pcm_uframes_t *, snd_pcm_uframes_t *); 41 | snd_pcm_sframes_t (*snd_pcm_mmap_commit)(snd_pcm_t *, snd_pcm_uframes_t, 42 | snd_pcm_uframes_t); 43 | } alsa_real_api_t; 44 | 45 | /** 46 | * \brief alsa_capture object 47 | */ 48 | typedef struct alsa_capture_s* alsa_capture_t; 49 | 50 | /** 51 | * \brief initialize alsa_capture object 52 | * \param alsa_capture alsa_capture object 53 | * \param glc glc 54 | * \param api real alsa functions addresses 55 | * \return 0 on success otherwise an error code 56 | */ 57 | __PUBLIC int alsa_capture_init(alsa_capture_t *alsa_capture, glc_t *glc, 58 | alsa_real_api_t *api); 59 | 60 | /** 61 | * \brief set target buffer 62 | * \param alsa_capture alsa_capture object 63 | * \param buffer target buffer 64 | * \return 0 on success otherwise an error code 65 | */ 66 | __PUBLIC int alsa_capture_set_buffer(alsa_capture_t alsa_capture, ps_buffer_t *buffer); 67 | 68 | /** 69 | * \brief set capture device 70 | * 71 | * Default ALSA capture device is 'default'. 72 | * \param alsa_capture alsa_capture object 73 | * \param device ALSA device 74 | * \return 0 on success otherwise an error code 75 | */ 76 | __PUBLIC int alsa_capture_set_device(alsa_capture_t alsa_capture, const char *device); 77 | 78 | /** 79 | * \brief set capture rate 80 | * 81 | * Default capture rate is 44100Hz 82 | * \param alsa_capture alsa_capture object 83 | * \param rate rate in Hz 84 | * \return 0 on success otherwise an error code 85 | */ 86 | __PUBLIC int alsa_capture_set_rate(alsa_capture_t alsa_capture, unsigned int rate); 87 | 88 | /** 89 | * \brief set number of channels 90 | * 91 | * Default number of channels is 2 92 | * \param alsa_capture alsa_capture object 93 | * \param channels number of channels 94 | * \return 0 on success otherwise an error code 95 | */ 96 | __PUBLIC int alsa_capture_set_channels(alsa_capture_t alsa_capture, unsigned int channels); 97 | 98 | /** 99 | * \brief start capturing 100 | * \param alsa_capture alsa_capture object 101 | * \return 0 on success otherwise an error code 102 | */ 103 | __PUBLIC int alsa_capture_start(alsa_capture_t alsa_capture); 104 | 105 | /** 106 | * \brief stop capturing 107 | * \param alsa_capture alsa_capture object 108 | * \return 0 on success otherwise an error code 109 | */ 110 | __PUBLIC int alsa_capture_stop(alsa_capture_t alsa_capture); 111 | 112 | /** 113 | * \brief destroy alsa_capture object 114 | * \param alsa_capture alsa_capture object 115 | * \return 0 on success otherwise an error code 116 | */ 117 | __PUBLIC int alsa_capture_destroy(alsa_capture_t alsa_capture); 118 | 119 | #ifdef __cplusplus 120 | } 121 | #endif 122 | 123 | #endif 124 | 125 | /** \} */ 126 | /** \} */ 127 | -------------------------------------------------------------------------------- /src/glc/capture/alsa_hook.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/capture/alsa_hook.h 3 | * \brief audio capture hooks 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup capture 11 | * \{ 12 | * \defgroup alsa_hook audio capture hooks 13 | * \{ 14 | */ 15 | 16 | #ifndef _ALSA_HOOK_H 17 | #define _ALSA_HOOK_H 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /** 28 | * \brief alsa_hook object 29 | */ 30 | typedef struct alsa_hook_s* alsa_hook_t; 31 | 32 | /** 33 | * \brief initialize alsa_hook 34 | * 35 | * Initializes alsa_hook and binds it into given glc. 36 | * \param alsa_hook alsa_hook object 37 | * \param glc glc 38 | * \return 0 on success otherwise an error code 39 | */ 40 | __PUBLIC int alsa_hook_init(alsa_hook_t *alsa_hook, glc_t *glc); 41 | 42 | /** 43 | * \brief allow audio skipping in some cases 44 | * 45 | * If audio_skip is enabled, alsa_hook may skip some audio data 46 | * if buffer is not ready and pcm is opened in asynchronous mode. 47 | * \param alsa_hook alsa_hook object 48 | * \param allow_skip 1 allows skipping, 0 disallows 49 | * \return 0 on success otherwise an error code 50 | */ 51 | __PUBLIC int alsa_hook_allow_skip(alsa_hook_t alsa_hook, int allow_skip); 52 | 53 | /** 54 | * \brief set target buffer 55 | * \param alsa_hook alsa_hook object 56 | * \param buffer target buffer 57 | * \return 0 on success otherwise an error code 58 | */ 59 | __PUBLIC int alsa_hook_set_buffer(alsa_hook_t alsa_hook, ps_buffer_t *buffer); 60 | 61 | /** 62 | * \brief start capturing hooked audio 63 | * \param alsa_hook alsa_hook object 64 | * \return 0 on success otherwise an error code 65 | */ 66 | __PUBLIC int alsa_hook_start(alsa_hook_t alsa_hook); 67 | 68 | /** 69 | * \brief stop capturing 70 | * \param alsa_hook alsa_hook object 71 | * \return 0 on success otherwise an error code 72 | */ 73 | __PUBLIC int alsa_hook_stop(alsa_hook_t alsa_hook); 74 | 75 | /** 76 | * \brief destroy alsa_hook object 77 | * \param alsa_hook alsa_hook object 78 | * \return 0 on success otherwise an error code 79 | */ 80 | __PUBLIC int alsa_hook_destroy(alsa_hook_t alsa_hook); 81 | 82 | /** 83 | * \brief hook function for snd_pcm_open() 84 | * 85 | * Call after calling real snd_pcm_open(). 86 | * \code 87 | * if (snd_pcm_open(pcmp, name, stream, mode) == 0) 88 | * alsa_hook_open(alsa_hook, *pcmp, nome, stream, mode); 89 | * \endcode 90 | * \param alsa_hook alsa_hook object 91 | * \param pcm pcm pointer given by snd_pcm_open() 92 | * \param name pcm name 93 | * \param pcm_stream pcm stream 94 | * \param mode open mode 95 | * \return 0 on success otherwise an error code 96 | */ 97 | __PUBLIC int alsa_hook_open(alsa_hook_t alsa_hook, snd_pcm_t *pcm, const char *name, 98 | snd_pcm_stream_t pcm_stream, int mode); 99 | 100 | /** 101 | * \brief hook function for snd_pcm_close() 102 | * \code 103 | * snd_pcm_close(pcm); 104 | * alsa_hook_close(alsa_hook, pcm); 105 | * \endcode 106 | * \param alsa_hook alsa_hook object 107 | * \param pcm closed pcm 108 | * \return 0 on success otherwise an error code 109 | */ 110 | __PUBLIC int alsa_hook_close(alsa_hook_t alsa_hook, snd_pcm_t *pcm); 111 | 112 | /** 113 | * \brief hook function for snd_pcm_hw_params() 114 | * \code 115 | * if (snd_pcm_hw_params(pcm, params)) 116 | * alsa_hook_hw_params(alsa_hook, pcm, params); 117 | * \endcode 118 | * \param alsa_hook alsa_hook object 119 | * \param pcm pcm 120 | * \param params active hardware parameters 121 | * \return 0 on success otherwise an error code 122 | */ 123 | __PUBLIC int alsa_hook_hw_params(alsa_hook_t alsa_hook, snd_pcm_t *pcm, 124 | snd_pcm_hw_params_t *params); 125 | 126 | /** 127 | * \brief hook function for snd_pcm_writei() 128 | * \code 129 | * snd_pcm_sframes_t ret = snd_pcm_writei(pcm, buffer, size); 130 | * if (ret > 0) 131 | * alsa_hook_writei(alsa_hook, pcm, buffer, ret); 132 | * \endcode 133 | * \param alsa_hook alsa_hook object 134 | * \param pcm pcm 135 | * \param buffer audio data 136 | * \param size actually written frames 137 | * \return 0 on success otherwise an error code 138 | */ 139 | __PUBLIC int alsa_hook_writei(alsa_hook_t alsa_hook, snd_pcm_t *pcm, 140 | const void *buffer, snd_pcm_uframes_t size); 141 | 142 | /** 143 | * \brief hook function for snd_pcm_writen() 144 | * \code 145 | * snd_pcm_sframes_t ret = snd_pcm_writen(pcm, bufs, size); 146 | * if (ret > 0) 147 | * alsa_hook_writen(alsa_hook, pcm, bufs, size); 148 | * \endcode 149 | * \param alsa_hook alsa_hook object 150 | * \param pcm pcm 151 | * \param bufs channel data areas 152 | * \param size actually written frames 153 | * \return 0 on success otherwise an error code 154 | */ 155 | __PUBLIC int alsa_hook_writen(alsa_hook_t alsa_hook, snd_pcm_t *pcm, 156 | void **bufs, snd_pcm_uframes_t size); 157 | 158 | /** 159 | * \brief hook function for snd_pcm_mmap_begin() 160 | * \code 161 | * if (snd_pcm_mmap_begin(pcm, areas, offset, frames) >= 0) 162 | * alsa_hook_mmap_begin(alsa_hook, pcm, *areas, *offset, *frames); 163 | * \endcode 164 | * \param alsa_hook alsa_hook object 165 | * \param pcm pcm 166 | * \param areas channel data areas given by snd_pcm_mmap_begin() 167 | * \param offset offset given by snd_pcm_mmap_begin() 168 | * \param frames frames given by snd_pcm_mmap_begin() 169 | * \return 0 on success otherwise an error code 170 | */ 171 | __PUBLIC int alsa_hook_mmap_begin(alsa_hook_t alsa_hook, snd_pcm_t *pcm, 172 | const snd_pcm_channel_area_t *areas, 173 | snd_pcm_uframes_t offset, snd_pcm_uframes_t frames); 174 | 175 | /** 176 | * \brief hook function for snd_pcm_mmap_commit() 177 | * 178 | * Must be called before calling real snd_pcm_mmap_commit(). 179 | * \code 180 | * alsa_hook_mmap_commit(alsa_hook, pcm, offset, frames); 181 | * snd_pcm_mmap_commit(pcm, offset, frames); 182 | * \endcode 183 | * \param alsa_hook alsa_hook object 184 | * \param pcm pcm 185 | * \param offset offset 186 | * \param frames number of frames written 187 | * \return 0 on success otherwise an error code 188 | */ 189 | __PUBLIC int alsa_hook_mmap_commit(alsa_hook_t alsa_hook, snd_pcm_t *pcm, 190 | snd_pcm_uframes_t offset, snd_pcm_uframes_t frames); 191 | 192 | #ifdef __cplusplus 193 | } 194 | #endif 195 | 196 | #endif 197 | 198 | /** \} */ 199 | /** \} */ 200 | -------------------------------------------------------------------------------- /src/glc/capture/audio_capture.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/capture/audio_capture.c 3 | * \brief generic audio capture adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup audio_capture 28 | * \{ 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "audio_capture.h" 45 | 46 | #define AUDIO_CAPTURE_CAPTURING 0x1 47 | #define AUDIO_CAPTURE_CFG_CHANGED 0x2 48 | #define AUDIO_CAPTURE_IGNORE_TIME 0x4 49 | 50 | struct audio_capture_s { 51 | glc_t *glc; 52 | glc_flags_t flags; 53 | ps_buffer_t *target; 54 | ps_packet_t packet; 55 | 56 | glc_flags_t format_flags; 57 | glc_audio_format_t format; 58 | u_int32_t rate, channels; 59 | 60 | glc_stream_id_t id; 61 | glc_state_audio_t state_audio; 62 | 63 | glc_utime_t time; 64 | }; 65 | 66 | static int audio_capture_write_cfg(audio_capture_t audio_capture); 67 | 68 | int audio_capture_init(audio_capture_t *audio_capture, glc_t *glc) 69 | { 70 | *audio_capture = (audio_capture_t) calloc(1, sizeof(struct audio_capture_s)); 71 | (*audio_capture)->glc = glc; 72 | return 0; 73 | } 74 | 75 | int audio_capture_destroy(audio_capture_t audio_capture) 76 | { 77 | if (audio_capture->target) 78 | ps_packet_destroy(&audio_capture->packet); 79 | 80 | free(audio_capture); 81 | return 0; 82 | } 83 | 84 | int audio_capture_set_buffer(audio_capture_t audio_capture, ps_buffer_t *buffer) 85 | { 86 | if (unlikely(audio_capture->target)) 87 | return EAGAIN; 88 | 89 | audio_capture->target = buffer; 90 | ps_packet_init(&audio_capture->packet, audio_capture->target); 91 | 92 | return 0; 93 | } 94 | 95 | int audio_capture_set_flags(audio_capture_t audio_capture, 96 | glc_flags_t format_flags) 97 | { 98 | /* check for unsupported flags */ 99 | if (unlikely(format_flags & (~(GLC_AUDIO_INTERLEAVED)))) 100 | return EINVAL; 101 | 102 | if (audio_capture->format_flags != format_flags) { 103 | audio_capture->format_flags = format_flags; 104 | audio_capture->flags |= AUDIO_CAPTURE_CFG_CHANGED; 105 | } 106 | return 0; 107 | } 108 | 109 | int audio_capture_set_format(audio_capture_t audio_capture, 110 | glc_audio_format_t format) 111 | { 112 | if (unlikely((format != GLC_AUDIO_S16_LE) || 113 | (format != GLC_AUDIO_S24_LE) || 114 | (format != GLC_AUDIO_S32_LE))) 115 | return EINVAL; 116 | 117 | if (audio_capture->format != format) { 118 | audio_capture->format = format; 119 | audio_capture->flags |= AUDIO_CAPTURE_CFG_CHANGED; 120 | } 121 | return 0; 122 | } 123 | 124 | int audio_capture_set_rate(audio_capture_t audio_capture, 125 | u_int32_t rate) 126 | { 127 | if (unlikely(!rate)) 128 | return EINVAL; 129 | 130 | if (audio_capture->rate != rate) { 131 | audio_capture->rate = rate; 132 | audio_capture->flags |= AUDIO_CAPTURE_CFG_CHANGED; 133 | } 134 | return 0; 135 | } 136 | 137 | int audio_capture_set_channels(audio_capture_t audio_capture, 138 | u_int32_t channels) 139 | { 140 | if (unlikely(!channels)) 141 | return EINVAL; 142 | 143 | if (audio_capture->channels != channels) { 144 | audio_capture->channels = channels; 145 | audio_capture->flags |= AUDIO_CAPTURE_CFG_CHANGED; 146 | } 147 | return 0; 148 | } 149 | 150 | int audio_capture_ignore_time(audio_capture_t audio_capture, int ignore_time) 151 | { 152 | if (ignore_time) 153 | audio_capture->flags |= AUDIO_CAPTURE_IGNORE_TIME; 154 | else 155 | audio_capture->flags &= ~AUDIO_CAPTURE_IGNORE_TIME; 156 | 157 | return 0; 158 | } 159 | 160 | size_t audio_capture_samples_to_bytes(audio_capture_t audio_capture, 161 | unsigned int samples) 162 | { 163 | switch (audio_capture->format) { 164 | case GLC_AUDIO_S16_LE: 165 | return 2 * samples; 166 | case GLC_AUDIO_S24_LE: 167 | return 3 * samples; 168 | case GLC_AUDIO_S32_LE: 169 | return 4 * samples; 170 | } 171 | 172 | return 0; /* unknown */ 173 | } 174 | 175 | size_t audio_capture_frames_to_bytes(audio_capture_t audio_capture, 176 | unsigned int frames) 177 | { 178 | return audio_capture_samples_to_bytes(audio_capture, 179 | audio_capture->channels * frames); 180 | } 181 | 182 | int audio_capture_start(audio_capture_t audio_capture) 183 | { 184 | if (unlikely(audio_capture->flags & AUDIO_CAPTURE_CAPTURING)) 185 | return EALREADY; 186 | 187 | /* target buffer must be set */ 188 | if (unlikely(!audio_capture->target)) 189 | return EINVAL; 190 | 191 | /* and we need valid configuration */ 192 | if (unlikely((!audio_capture->format_flags) || 193 | (!audio_capture->rate) || 194 | (!audio_capture->channels))) 195 | return EINVAL; 196 | 197 | audio_capture->flags |= AUDIO_CAPTURE_CAPTURING; 198 | return 0; 199 | } 200 | 201 | int audio_capture_stop(audio_capture_t audio_capture) 202 | { 203 | if (unlikely(!(audio_capture->flags & AUDIO_CAPTURE_CAPTURING))) 204 | return EAGAIN; 205 | 206 | audio_capture->flags &= ~AUDIO_CAPTURE_CAPTURING; 207 | return 0; 208 | } 209 | 210 | int audio_capture_write_cfg(audio_capture_t audio_capture) 211 | { 212 | glc_message_header_t hdr; 213 | glc_audio_format_message_t fmt_msg; 214 | int ret = 0; 215 | 216 | if (!audio_capture->id) 217 | glc_state_audio_new(audio_capture->glc, &audio_capture->id, 218 | &audio_capture->state_audio); 219 | 220 | hdr.type = GLC_MESSAGE_AUDIO_FORMAT; 221 | fmt_msg.id = audio_capture->id; 222 | fmt_msg.flags = audio_capture->format_flags; 223 | fmt_msg.rate = audio_capture->rate; 224 | fmt_msg.channels = audio_capture->channels; 225 | fmt_msg.format = audio_capture->format; 226 | 227 | if (unlikely((ret = ps_packet_open(&audio_capture->packet, PS_PACKET_WRITE)))) 228 | goto err; 229 | if (unlikely((ret = ps_packet_write(&audio_capture->packet, 230 | &hdr, sizeof(glc_message_header_t))))) 231 | goto err; 232 | if (unlikely((ret = ps_packet_write(&audio_capture->packet, 233 | &fmt_msg, sizeof(glc_audio_format_message_t))))) 234 | goto err; 235 | if (unlikely((ret = ps_packet_close(&audio_capture->packet)))) 236 | goto err; 237 | 238 | return 0; 239 | err: 240 | glc_state_set(audio_capture->glc, GLC_STATE_CANCEL); 241 | ps_buffer_cancel(audio_capture->target); 242 | glc_log(audio_capture->glc, GLC_ERROR, "audio_capture", 243 | "can't write audio stream configuration to buffer"); 244 | glc_log(audio_capture->glc, GLC_ERROR, "audio_capture", 245 | "%s (%d)", strerror(ret), ret); 246 | return ret; 247 | } 248 | 249 | int audio_capture_data(audio_capture_t audio_capture, 250 | void *data, size_t size) 251 | { 252 | glc_message_header_t msg_hdr; 253 | glc_audio_data_header_t audio_hdr; 254 | 255 | int ret; 256 | if (!(audio_capture->flags & AUDIO_CAPTURE_CAPTURING)) 257 | return 0; 258 | 259 | if (audio_capture->flags & AUDIO_CAPTURE_CFG_CHANGED) { 260 | if (unlikely((ret = audio_capture_write_cfg(audio_capture)))) 261 | return ret; 262 | audio_capture->flags &= ~AUDIO_CAPTURE_CFG_CHANGED; 263 | } 264 | 265 | if (likely(!(audio_capture->flags & AUDIO_CAPTURE_IGNORE_TIME))) 266 | audio_capture->time = glc_state_time(audio_capture->glc); 267 | 268 | msg_hdr.type = GLC_MESSAGE_AUDIO_DATA; 269 | audio_hdr.id = audio_capture->id; /* should be set to valid one */ 270 | audio_hdr.size = size; 271 | audio_hdr.time = audio_capture->time; 272 | 273 | if (unlikely(audio_capture->flags & AUDIO_CAPTURE_IGNORE_TIME)) 274 | audio_capture->time += ((glc_utime_t) size * (glc_utime_t) 1000000000) / 275 | (glc_utime_t) (audio_capture_frames_to_bytes(audio_capture, 1) * 276 | audio_capture->rate); 277 | 278 | if (unlikely((ret = ps_packet_open(&audio_capture->packet, PS_PACKET_WRITE)))) 279 | goto err; 280 | if (unlikely((ret = ps_packet_write(&audio_capture->packet, 281 | &msg_hdr, sizeof(glc_message_header_t))))) 282 | goto err; 283 | if (unlikely((ret = ps_packet_write(&audio_capture->packet, 284 | &audio_hdr, sizeof(glc_audio_data_header_t))))) 285 | goto err; 286 | if (unlikely((ret = ps_packet_write(&audio_capture->packet, 287 | data, size)))) 288 | goto err; 289 | if (unlikely((ret = ps_packet_close(&audio_capture->packet)))) 290 | goto err; 291 | 292 | return 0; 293 | err: 294 | ps_buffer_cancel(audio_capture->target); 295 | glc_state_set(audio_capture->glc, GLC_STATE_CANCEL); 296 | glc_log(audio_capture->glc, GLC_ERROR, "audio_capture", 297 | "can't write audio data to buffer"); 298 | glc_log(audio_capture->glc, GLC_ERROR, "audio_capture", 299 | "%s (%d)", strerror(ret), ret); 300 | return ret; 301 | } 302 | 303 | /** \} */ 304 | -------------------------------------------------------------------------------- /src/glc/capture/audio_capture.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/capture/audio_capture.h 3 | * \brief generic audio capture interface 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup capture 11 | * \{ 12 | * \defgroup audio_capture generic audio capture 13 | * \{ 14 | */ 15 | 16 | #ifndef _AUDIO_CAPTURE_H 17 | #define _AUDIO_CAPTURE_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief audio_capture object 28 | */ 29 | typedef struct audio_capture_s* audio_capture_t; 30 | 31 | /** 32 | * \brief initialize audio_capture 33 | * 34 | * Initializes audio_capture and binds it into given glc. 35 | * \param audio_capture audio_capture object 36 | * \param glc glc 37 | * \return 0 on success otherwise an error code 38 | */ 39 | __PUBLIC int audio_capture_init(audio_capture_t *audio_capture, glc_t *glc); 40 | 41 | /** 42 | * \brief set target buffer 43 | * \param audio_capture audio_capture object 44 | * \param buffer target buffer 45 | * \return 0 on success otherwise an error code 46 | */ 47 | __PUBLIC int audio_capture_set_buffer(audio_capture_t audio_capture, ps_buffer_t *buffer); 48 | 49 | /** 50 | * \brief set data format 51 | * 52 | * Currently supported formats are 53 | * * GLC_AUDIO_S16_LE 54 | * * GLC_AUDIO_S24_LE 55 | * * GLC_AUDIO_S32_LE 56 | * \param audio_capture audio_capture object 57 | * \param format format 58 | * \return 0 on success otherwise an error code 59 | */ 60 | __PUBLIC int audio_capture_set_format(audio_capture_t audio_capture, 61 | glc_audio_format_t format); 62 | 63 | /** 64 | * \brief set data format flags 65 | * 66 | * Currently supported flags are 67 | * * GLC_AUDIO_INTERLEAVED audio data is interleaved 68 | * \param audio_capture audio_capture object 69 | * \param format_flags format flags 70 | * \return 0 on success otherwise an error code 71 | */ 72 | __PUBLIC int audio_capture_set_flags(audio_capture_t audio_capture, 73 | glc_flags_t format_flags); 74 | 75 | /** 76 | * \brief set rate 77 | * \param audio_capture audio_capture object 78 | * \param rate rate in Hz 79 | * \return 0 on success otherwise an error code 80 | */ 81 | __PUBLIC int audio_capture_set_rate(audio_capture_t audio_capture, 82 | u_int32_t rate); 83 | 84 | /** 85 | * \brief set channels 86 | * \param audio_capture audio_capture object 87 | * \param channels number of channels 88 | * \return 0 on success otherwise an error code 89 | */ 90 | __PUBLIC int audio_capture_set_channels(audio_capture_t audio_capture, 91 | u_int32_t channels); 92 | 93 | /** 94 | * \brief ignore time 95 | * 96 | * If glc state time is ignored, audio_capture uses internal time which 97 | * is incremented by (written frames)/rate seconds each time data is captured. 98 | * \param audio_capture audio_capture object 99 | * \param ignore_time 1 means state time is ignored, 100 | * 0 enables regular time calculations 101 | * \return 0 on success otherwise an error code 102 | */ 103 | __PUBLIC int audio_capture_ignore_time(audio_capture_t audio_capture, int ignore_time); 104 | 105 | /** 106 | * \brief start capturing 107 | * 108 | * If capturing is not active, all submitted data is discarded. 109 | * \param audio_capture audio_capture object 110 | * \return 0 on success otherwise an error code 111 | */ 112 | __PUBLIC int audio_capture_start(audio_capture_t audio_capture); 113 | 114 | /** 115 | * \brief stop capturing 116 | * \param audio_capture audio_capture object 117 | * \return 0 on success otherwise an error code 118 | */ 119 | __PUBLIC int audio_capture_stop(audio_capture_t audio_capture); 120 | 121 | /** 122 | * \brief destroy audio_capture object 123 | * \param audio_capture audio_capture object 124 | * \return 0 on success otherwise an error code 125 | */ 126 | __PUBLIC int audio_capture_destroy(audio_capture_t audio_capture); 127 | 128 | /** 129 | * \brief submit audio data 130 | * \param audio_capture audio_capture object 131 | * \param data audio data 132 | * \param size data size in bytes (not samples or frames) 133 | * \return 0 on success otherwise an error code 134 | */ 135 | __PUBLIC int audio_capture_data(audio_capture_t audio_capture, 136 | void *data, size_t size); 137 | 138 | /** 139 | * \brief samples to bytes 140 | * \param audio_capture audio_capture object 141 | * \param samples samples 142 | * \return size in bytes 143 | */ 144 | __PUBLIC size_t audio_capture_samples_to_bytes(audio_capture_t audio_capture, 145 | unsigned int samples); 146 | 147 | /** 148 | * \brief frames to bytes 149 | * \param audio_capture audio_capture object 150 | * \param frames frames 151 | * \return size in bytes 152 | */ 153 | __PUBLIC size_t audio_capture_frames_to_bytes(audio_capture_t audio_capture, 154 | unsigned int frames); 155 | 156 | #ifdef __cplusplus 157 | } 158 | #endif 159 | 160 | #endif 161 | 162 | /** \} */ 163 | /** \} */ 164 | -------------------------------------------------------------------------------- /src/glc/capture/gl_capture.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/capture/gl_capture.h 3 | * \brief OpenGL capture 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup capture 11 | * \{ 12 | * \defgroup gl_capture OpenGL capture 13 | * \{ 14 | */ 15 | 16 | #ifndef _GL_CAPTURE_H 17 | #define _GL_CAPTURE_H 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /** 29 | * \brief gl_capture object 30 | */ 31 | typedef struct gl_capture_s* gl_capture_t; 32 | 33 | /** 34 | * \brief initialize gl_capture object 35 | * 36 | * Function initializes gl_capture object and binds it into given glc. 37 | * \param gl_capture gl_capture object 38 | * \param glc glc 39 | * \return 0 on success otherwise an error code 40 | */ 41 | __PUBLIC int gl_capture_init(gl_capture_t *gl_capture, glc_t *glc); 42 | 43 | /** 44 | * \brief set target buffer 45 | * \param gl_capture gl_capture object 46 | * \param buffer target buffer 47 | * \return 0 on success otherwise an error code 48 | */ 49 | __PUBLIC int gl_capture_set_buffer(gl_capture_t gl_capture, ps_buffer_t *buffer); 50 | 51 | /** 52 | * \brief set OpenGL read buffer for capturing 53 | * 54 | * Default read buffer is GL_FRONT. 55 | * \param gl_capture gl_capture object 56 | * \param buffer GL_BACK or GL_FRONT 57 | * \return 0 on success otherwise an error code 58 | */ 59 | __PUBLIC int gl_capture_set_read_buffer(gl_capture_t gl_capture, GLenum buffer); 60 | 61 | /** 62 | * \brief set fps 63 | * \param gl_capture gl_capture object 64 | * \param fps fps 65 | * \return 0 on success otherwise an error code 66 | */ 67 | __PUBLIC int gl_capture_set_fps(gl_capture_t gl_capture, double fps); 68 | 69 | /** 70 | * \brief set GL_PACK_ALIGNMENT for OpenGL read calls 71 | * \param gl_capture gl_capture object 72 | * \param pack_alignment GL_PACK_ALIGNMENT 73 | * \return 0 on success otherwise an error code 74 | */ 75 | __PUBLIC int gl_capture_set_pack_alignment(gl_capture_t gl_capture, 76 | GLint pack_alignment); 77 | 78 | /** 79 | * \brief set PBO hint 80 | * \param gl_capture gl_capture object 81 | * \param try_pbo 1 means gl_capture tries to use PBO, 82 | * 0 disables PBO even if it is supported 83 | * \return 0 on success otherwise an error code 84 | */ 85 | __PUBLIC int gl_capture_try_pbo(gl_capture_t gl_capture, int try_pbo); 86 | 87 | /** 88 | * \brief set pixel format 89 | * 90 | * Default pixel format is GL_BGRA. 91 | * \param gl_capture gl_capture object 92 | * \param format pixel format (currently GL_BGR and GL_BGRA are supported) 93 | * \return 0 on succcess otherwise an error code 94 | */ 95 | __PUBLIC int gl_capture_set_pixel_format(gl_capture_t gl_capture, GLenum format); 96 | 97 | /** 98 | * \brief draw indicator when capturing 99 | * 100 | * Drawing indicator does not currently work well when capturing from 101 | * front buffer. 102 | * \param gl_capture gl_capture object 103 | * \param draw_indicator 1 means indicator is drawn when capturing, 104 | * 0 disables indicator 105 | * \return 0 on success otherwise an error code 106 | */ 107 | __PUBLIC int gl_capture_draw_indicator(gl_capture_t gl_capture, int draw_indicator); 108 | 109 | /** 110 | * \brief ignore time 111 | * 112 | * If glc state time is ignored, gl_capture uses internal time which 113 | * is incremented by 1/fps seconds each time a frame is captured. 114 | * 115 | * Setting this disables fps cap. No frames are dropped when this option 116 | * is enabled. 117 | * \param gl_capture gl_capture object 118 | * \param ignore_time 1 means state time is ignored, 119 | * 0 enables regular time calculations 120 | * \return 0 on success otherwise an error code 121 | */ 122 | __PUBLIC int gl_capture_ignore_time(gl_capture_t gl_capture, int ignore_time); 123 | 124 | /** 125 | * \brief capture only selected area 126 | * 127 | * Calculated from top left corner. Use 0, 0, 0, 0 to disable cropping. 128 | * \param gl_capture gl_capture object 129 | * \param x x-coordinate 130 | * \param y y-coordinate 131 | * \param width width 132 | * \param height height 133 | * \return 0 on success otherwise an error code 134 | */ 135 | __PUBLIC int gl_capture_crop(gl_capture_t gl_capture, unsigned int x, unsigned int y, 136 | unsigned int width, unsigned int height); 137 | 138 | /** 139 | * \brief lock fps when capturing 140 | * \param gl_capture gl_capture object 141 | * \param lock_fps 1 means fps is locked, 0 disables fps cap 142 | * \return 0 on success otherwise an error code 143 | */ 144 | __PUBLIC int gl_capture_lock_fps(gl_capture_t gl_capture, int lock_fps); 145 | 146 | /** 147 | * \brief start capturing 148 | * \param gl_capture gl_capture object 149 | * \return 0 on success otherwise an error code 150 | */ 151 | __PUBLIC int gl_capture_start(gl_capture_t gl_capture); 152 | 153 | /** 154 | * \brief stop capturing 155 | * \param gl_capture gl_capture object 156 | * \return 0 on success otherwise an error code 157 | */ 158 | __PUBLIC int gl_capture_stop(gl_capture_t gl_capture); 159 | 160 | /** 161 | * \brief destroy gl_capture object 162 | * \param gl_capture gl_capture object to destroy 163 | * \return 0 on success otherwise an error code 164 | */ 165 | __PUBLIC int gl_capture_destroy(gl_capture_t gl_capture); 166 | 167 | /** 168 | * \brief process full frame 169 | * 170 | * Call this function when selected read buffer contains ready 171 | * frame for capturing. If gl_capture is not in capturing state, 172 | * this function does nothing. 173 | * \code 174 | * // init 175 | * ... 176 | * gl_capture_set_read_buffer(gl_capture, GL_FRONT); 177 | * gl_capture_start(gl_capture); 178 | * ... 179 | * // main loop 180 | * glXSwapBuffers(dpy, drawable); 181 | * gl_capture_frame(gl_capture, dpy, drawable); 182 | * \endcode 183 | * \param gl_capture gl_capture object 184 | * \param dpy X Display 185 | * \param drawable GLX Drawable 186 | * \return 0 on success otherwise an error code 187 | */ 188 | __PUBLIC int gl_capture_frame(gl_capture_t gl_capture, Display *dpy, GLXDrawable drawable); 189 | 190 | /** 191 | * \brief refresh color correction information 192 | * \param gl_capture gl_capture object 193 | * \return 0 on success otherwise an error code 194 | */ 195 | __PUBLIC int gl_capture_refresh_color_correction(gl_capture_t gl_capture); 196 | 197 | /** 198 | * \brief set attribute window for drawable 199 | * 200 | * Sets window where window attributes (eg. size) are read from. 201 | * Use this if drawable doesn't have normal window attributes. 202 | * 203 | * For example windows created with glXCreateWindow() need this. 204 | * \code 205 | * GLXWindow glxWin = glXCreateWindow(dpy, config, win, attrib_list); 206 | * gl_capture_set_attribute_window(dpy, glxWin, win); 207 | * ... 208 | * glXSwapBuffers(dpy, glxWin); 209 | * gl_capture_frame(gl_capture, dpy, glxWin); 210 | * \endcode 211 | * \param gl_capture gl_capture object 212 | * \param dpy X Display 213 | * \param drawable GLX Drawable 214 | * \param window attribute window 215 | * \return 0 on success otherwise an error code 216 | */ 217 | __PUBLIC int gl_capture_set_attribute_window(gl_capture_t gl_capture, Display *dpy, 218 | GLXDrawable drawable, Window window); 219 | 220 | #ifdef __cplusplus 221 | } 222 | #endif 223 | 224 | #endif 225 | 226 | /** \} */ 227 | /** \} */ 228 | -------------------------------------------------------------------------------- /src/glc/common/core.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/core.c 3 | * \brief glc core adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup common_core 28 | * \{ 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "glc.h" 38 | #include "core.h" 39 | #include "log.h" 40 | #include "util.h" 41 | #include "optimization.h" 42 | 43 | struct glc_core_s { 44 | struct timespec init_time; 45 | long int single_process_num; 46 | long int multi_process_num; 47 | long int threads_hint; 48 | int allow_rt; 49 | }; 50 | 51 | const char *glc_version() 52 | { 53 | return GLC_VERSION; 54 | } 55 | 56 | int glc_init(glc_t *glc) 57 | { 58 | int ret = 0; 59 | 60 | /* clear 'em */ 61 | glc->core = NULL; 62 | glc->state = NULL; 63 | glc->util = NULL; 64 | glc->log = NULL; 65 | 66 | glc->core = (glc_core_t) calloc(1, sizeof(struct glc_core_s)); 67 | 68 | clock_gettime(CLOCK_MONOTONIC, &glc->core->init_time); 69 | 70 | glc->core->threads_hint = 1; /* safe conservative default value */ 71 | 72 | if (unlikely((ret = glc_log_init(glc)))) 73 | return ret; 74 | ret = glc_util_init(glc); 75 | return ret; 76 | } 77 | 78 | int glc_destroy(glc_t *glc) 79 | { 80 | glc_util_destroy(glc); 81 | glc_log_destroy(glc); 82 | 83 | free(glc->core); 84 | 85 | /* and clear */ 86 | glc->core = NULL; 87 | glc->state = NULL; 88 | glc->util = NULL; 89 | glc->log = NULL; 90 | 91 | return 0; 92 | } 93 | 94 | glc_utime_t glc_time(glc_t *glc) 95 | { 96 | struct timespec ts; 97 | 98 | clock_gettime(CLOCK_MONOTONIC, &ts); 99 | 100 | ts.tv_sec -= glc->core->init_time.tv_sec; 101 | ts.tv_nsec -= glc->core->init_time.tv_nsec; 102 | 103 | if (ts.tv_nsec < 0) { 104 | ts.tv_sec--; 105 | ts.tv_nsec += 1000000000; 106 | } 107 | 108 | return (glc_utime_t) ts.tv_sec * (glc_utime_t) 1000000000 + (glc_utime_t) ts.tv_nsec; 109 | } 110 | 111 | long int glc_threads_hint(glc_t *glc) 112 | { 113 | return glc->core->threads_hint; 114 | } 115 | 116 | int glc_set_threads_hint(glc_t *glc, long int count) 117 | { 118 | if (unlikely(count <= 0)) 119 | return EINVAL; 120 | glc->core->threads_hint = count; 121 | return 0; 122 | } 123 | 124 | void glc_account_threads(glc_t *glc, long int single, long int multi) 125 | { 126 | glc->core->single_process_num += single; 127 | glc->core->multi_process_num += multi; 128 | } 129 | 130 | void glc_compute_threads_hint(glc_t *glc) 131 | { 132 | long int divisor; 133 | if (glc->core->multi_process_num) 134 | divisor = glc->core->multi_process_num; /* Avoid division by 0 */ 135 | else 136 | divisor = 1; 137 | glc->core->threads_hint = sysconf(_SC_NPROCESSORS_ONLN) - glc->core->single_process_num; 138 | glc->core->threads_hint /= divisor; 139 | if (unlikely(glc->core->threads_hint < 1)) 140 | glc->core->threads_hint = 1; 141 | glc_log(glc, GLC_INFO, "core", 142 | "single proc num %ld multi proc num %ld, threads num per multi proc %ld", 143 | glc->core->single_process_num, glc->core->multi_process_num, 144 | glc->core->threads_hint); 145 | } 146 | 147 | void glc_set_allow_rt(glc_t *glc, int allow) 148 | { 149 | glc->core->allow_rt = allow; 150 | } 151 | 152 | int glc_allow_rt(glc_t *glc) 153 | { 154 | return glc->core->allow_rt; 155 | } 156 | 157 | /** \} */ 158 | -------------------------------------------------------------------------------- /src/glc/common/core.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/core.h 3 | * \brief glc core interface adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup common 28 | * \{ 29 | * \defgroup common_core core 30 | * \{ 31 | */ 32 | 33 | #ifndef _CORE_H 34 | #define _CORE_H 35 | 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /** 43 | * \brief get glc version 44 | * \return glc version string 45 | */ 46 | __PUBLIC const char *glc_version(); 47 | 48 | /** 49 | * \brief initialize glc 50 | * 51 | * This function initializes core, log and util components. 52 | * State is not initialized. 53 | * \param glc glc 54 | * \return 0 on success otherwise an error code 55 | */ 56 | __PUBLIC int glc_init(glc_t *glc); 57 | 58 | /** 59 | * \brief destroy glc 60 | * 61 | * This cleans up core, log and util. State must be destroyed 62 | * before calling this function. 63 | * \param glc glc 64 | * \return 0 on success otherwise an error code 65 | */ 66 | __PUBLIC int glc_destroy(glc_t *glc); 67 | 68 | /** 69 | * \brief current time in nanoseconds since initialization 70 | * 71 | * the 64 bits glc_utime_t is big enough to store over 500 years in 72 | * nanoseconds so overflow is not an issue. 73 | * \param glc glc 74 | * \return time elapsed since initialization 75 | */ 76 | __PUBLIC glc_utime_t glc_time(glc_t *glc); 77 | 78 | /** 79 | * \brief thread count hint 80 | * 81 | * All processing filters that can employ multiple threads use 82 | * this function to determine how many threads to create. By default 83 | * this returns number of processors online, but custom value can 84 | * be set via glc_set_threads_hint(). 85 | * \param glc glc 86 | * \return thread count hint 87 | */ 88 | __PUBLIC long int glc_threads_hint(glc_t *glc); 89 | 90 | /** 91 | * \brief set thread count hint 92 | * 93 | * Default value is number of processors. 94 | * \param glc glc 95 | * \param count thread count hint 96 | * \return 0 on success otherwise an error code 97 | */ 98 | __PUBLIC int glc_set_threads_hint(glc_t *glc, long int count); 99 | 100 | __PUBLIC void glc_account_threads(glc_t *glc, long int single, long int multi); 101 | 102 | __PUBLIC void glc_compute_threads_hint(glc_t *glc); 103 | 104 | __PUBLIC void glc_set_allow_rt(glc_t *glc, int allow); 105 | __PUBLIC int glc_allow_rt(glc_t *glc); 106 | 107 | #ifdef __cplusplus 108 | } 109 | #endif 110 | 111 | #endif 112 | 113 | /** \} */ 114 | /** \} */ 115 | -------------------------------------------------------------------------------- /src/glc/common/log.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/log.c 3 | * \brief logging adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup log 28 | * \{ 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "core.h" 37 | #include "log.h" 38 | #include "optimization.h" 39 | 40 | struct glc_log_s { 41 | int level; 42 | FILE *stream; 43 | FILE *default_stream; 44 | pthread_mutex_t log_mutex; 45 | }; 46 | 47 | static void glc_log_write_prefix(glc_t *glc, FILE *stream, int level, const char *module); 48 | 49 | int glc_log_init(glc_t *glc) 50 | { 51 | glc->log = (glc_log_t) calloc(1, sizeof(struct glc_log_s)); 52 | 53 | pthread_mutex_init(&glc->log->log_mutex, NULL); 54 | glc->log->default_stream = stderr; 55 | glc->log->stream = glc->log->default_stream; 56 | 57 | return 0; 58 | } 59 | 60 | int glc_log_destroy(glc_t *glc) 61 | { 62 | pthread_mutex_destroy(&glc->log->log_mutex); 63 | free(glc->log); 64 | return 0; 65 | } 66 | 67 | int glc_log_open_file(glc_t *glc, const char *filename) 68 | { 69 | int ret; 70 | FILE *stream = fopen(filename, "w"); 71 | if (unlikely(!stream)) 72 | return errno; 73 | 74 | /* line buffered like stderr */ 75 | setvbuf( stream, NULL, _IOLBF, 0 ); 76 | 77 | if (unlikely((ret = glc_log_set_stream(glc, stream)))) { 78 | fclose(stream); 79 | return ret; 80 | } 81 | 82 | glc_log(glc, GLC_INFO, "log", "opened %s for log", filename); 83 | return 0; 84 | } 85 | 86 | int glc_log_set_stream(glc_t *glc, FILE *stream) 87 | { 88 | /** \todo check that stream is good */ 89 | if (unlikely(!stream)) 90 | return EINVAL; 91 | glc->log->stream = stream; 92 | return 0; 93 | } 94 | 95 | int glc_log_set_level(glc_t *glc, int level) 96 | { 97 | if (unlikely(level < 0)) 98 | return EINVAL; 99 | glc->log->level = level; 100 | return 0; 101 | } 102 | 103 | int glc_log_get_level(glc_t *glc) 104 | { 105 | return glc->log->level; 106 | } 107 | 108 | FILE *glc_log_get_stream(glc_t *glc) 109 | { 110 | return glc->log->stream; 111 | } 112 | 113 | int glc_log_close(glc_t *glc) 114 | { 115 | glc_log(glc, GLC_INFO, "log", "log closed"); 116 | if (unlikely(fclose(glc->log->stream))) 117 | return errno; 118 | glc->log->stream = glc->log->default_stream; 119 | 120 | return 0; 121 | } 122 | 123 | void glc_log(glc_t *glc, int level, const char *module, const char *format, ...) 124 | { 125 | va_list ap; 126 | 127 | if (level > glc->log->level) 128 | return; 129 | 130 | va_start(ap, format); 131 | 132 | /* this is highly threaded application and we want 133 | non-corrupted logs */ 134 | pthread_mutex_lock(&glc->log->log_mutex); 135 | glc_log_write_prefix(glc, glc->log->stream, level, module); 136 | vfprintf(glc->log->stream, format, ap); 137 | fputc('\n', glc->log->stream); 138 | 139 | pthread_mutex_unlock(&glc->log->log_mutex); 140 | 141 | va_end(ap); 142 | } 143 | 144 | void glc_log_write_prefix(glc_t *glc, FILE *stream, int level, const char *module) 145 | { 146 | const char *level_str = NULL; 147 | 148 | /* human-readable msg level */ 149 | switch (level) { 150 | case GLC_ERROR: 151 | level_str = "error"; 152 | break; 153 | case GLC_WARN: 154 | level_str = "warn"; 155 | break; 156 | case GLC_PERF: 157 | level_str = "perf"; 158 | break; 159 | case GLC_INFO: 160 | level_str = "info"; 161 | break; 162 | case GLC_DEBUG: 163 | level_str = "dbg"; 164 | break; 165 | default: 166 | level_str = "unknown"; 167 | break; 168 | } 169 | 170 | fprintf(stream, "[%7.2fs %10s %5s ] ", 171 | (double) glc_time(glc) / 1000000000.0, module, level_str); 172 | } 173 | 174 | /** \} */ 175 | -------------------------------------------------------------------------------- /src/glc/common/log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/log.h 3 | * \brief glc log interface adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup common 28 | * \{ 29 | * \defgroup log logging 30 | * \{ 31 | */ 32 | 33 | #ifndef _LOG_H 34 | #define _LOG_H 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | /** 45 | * \brief initialize log 46 | * \param glc glc 47 | * \return 0 on success otherwise an error code 48 | */ 49 | __PRIVATE int glc_log_init(glc_t *glc); 50 | 51 | /** 52 | * \brief destroy log 53 | * \param glc glc 54 | * \return 0 on success otherwise an error code 55 | */ 56 | __PRIVATE int glc_log_destroy(glc_t *glc); 57 | 58 | /** 59 | * \brief set log level 60 | * 61 | * Messages with level <= current log level will be written 62 | * into log. 63 | * \param glc glc 64 | * \param level log level 65 | * \return 0 on success otherwise an error code 66 | */ 67 | __PUBLIC int glc_log_set_level(glc_t *glc, int level); 68 | __PUBLIC int glc_log_get_level(glc_t *glc); 69 | 70 | __PUBLIC FILE *glc_log_get_stream(glc_t *glc); 71 | 72 | /** 73 | * \brief open file for log 74 | * \note this calls glc_log_set_stream() 75 | * \param glc glc 76 | * \param filename log file name 77 | * \return 0 on success otherwise an error code 78 | */ 79 | __PUBLIC int glc_log_open_file(glc_t *glc, const char *filename); 80 | 81 | /** 82 | * \brief set log stream 83 | * 84 | * Default log target is stderr. 85 | * \param glc glc 86 | * \param stream log stream 87 | * \return 0 on success otherwise an error code 88 | */ 89 | __PUBLIC int glc_log_set_stream(glc_t *glc, FILE *stream); 90 | 91 | /** 92 | * \brief close current log stream 93 | * 94 | * Log file is set to stderr. 95 | * \param glc glc 96 | * \return 0 on success otherwise an error code 97 | */ 98 | __PUBLIC int glc_log_close(glc_t *glc); 99 | 100 | /** 101 | * \brief write message to log 102 | * 103 | * Message is actually written to log if level is 104 | * lesser than, or equal to current log verbosity level and 105 | * logging is enabled. 106 | * \param glc glc 107 | * \param level message level 108 | * \param module module 109 | * \param format passed to fprintf() 110 | * \param ... passed to fprintf() 111 | */ 112 | __PUBLIC void glc_log(glc_t *glc, int level, const char *module, const char *format, ...) 113 | __attribute__((format(printf, 4, 5))); 114 | 115 | #ifdef __cplusplus 116 | } 117 | #endif 118 | 119 | #endif 120 | 121 | /** \} */ 122 | /** \} */ 123 | -------------------------------------------------------------------------------- /src/glc/common/optimization.h: -------------------------------------------------------------------------------- 1 | /* 2 | * optimization.h 3 | * 4 | * Olivier Langlois - Sept 27, 2013 5 | */ 6 | 7 | #ifndef __OPTIMIZATION_H__ 8 | #define __OPTIMIZATION_H__ 9 | 10 | #ifndef likely 11 | #define likely(x) __builtin_expect (!!(x), 1) 12 | #endif 13 | 14 | #ifndef unlikely 15 | #define unlikely(x) __builtin_expect (!!(x), 0) 16 | #endif 17 | 18 | #endif 19 | 20 | -------------------------------------------------------------------------------- /src/glc/common/rational.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glcs_rational.c 3 | * \brief Straight from ffmpeg libavutil/rational written by Michael Niedermayer 4 | * I did just prefer to cut & paste this very small subset than requiring to depend on ffmpeg. 5 | * \author Olivier Langlois 6 | * \date 2014 7 | 8 | Copyright 2014 Olivier Langlois 9 | 10 | This file is part of glcs. 11 | 12 | glcs is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | glcs is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with glcs. If not, see . 24 | 25 | */ 26 | 27 | #include "rational.h" 28 | #include 29 | #include 30 | #include 31 | 32 | #define GLCSABS(a) ((a) >= 0 ? (a) : (-(a))) 33 | #define GLCSMAX(a,b) ((a) > (b) ? (a) : (b)) 34 | #define GLCSMIN(a,b) ((a) < (b) ? (a) : (b)) 35 | 36 | /* 37 | * As an interesting side note, the original code was recursive: 38 | * 39 | * int64_t av_gcd(int64_t a, int64_t b){ 40 | * if(b) return av_gcd(b, a%b); 41 | * else return a; 42 | * } 43 | * 44 | * I just checked the emitted code by gcc with 45 | * gcc -O2 -S -c 46 | * 47 | * and the compiler optimize out the recursivity and emits identical 48 | * iterative code either with the original code or the new version. 49 | */ 50 | static int64_t glcs_gcd(int64_t u, int64_t v) 51 | { 52 | while (v) { 53 | int64_t tmp = v; 54 | v = u%v; 55 | u = tmp; 56 | } 57 | return u; 58 | } 59 | 60 | int glcs_reduce(int *dst_num, int *dst_den, 61 | int64_t num, int64_t den, int64_t max) 62 | { 63 | glcs_Rational_t a0 = { 0, 1 }, a1 = { 1, 0 }; 64 | int sign = (num < 0) ^ (den < 0); 65 | int64_t gcd = glcs_gcd(GLCSABS(num), GLCSABS(den)); 66 | 67 | if (gcd) { 68 | num = GLCSABS(num) / gcd; 69 | den = GLCSABS(den) / gcd; 70 | } 71 | if (num <= max && den <= max) { 72 | a1 = (glcs_Rational_t) { num, den }; 73 | den = 0; 74 | } 75 | 76 | while (den) { 77 | uint64_t x = num / den; 78 | int64_t next_den = num - den * x; 79 | int64_t a2n = x * a1.num + a0.num; 80 | int64_t a2d = x * a1.den + a0.den; 81 | 82 | if (a2n > max || a2d > max) { 83 | if (a1.num) x = (max - a0.num) / a1.num; 84 | if (a1.den) x = GLCSMIN(x, (max - a0.den) / a1.den); 85 | 86 | if (den * (2 * x * a1.den + a0.den) > num * a1.den) 87 | a1 = (glcs_Rational_t) { x * a1.num + a0.num, x * a1.den + a0.den }; 88 | break; 89 | } 90 | 91 | a0 = a1; 92 | a1 = (glcs_Rational_t) { a2n, a2d }; 93 | num = den; 94 | den = next_den; 95 | } 96 | assert(glcs_gcd(a1.num, a1.den) <= 1U); 97 | 98 | *dst_num = sign ? -a1.num : a1.num; 99 | *dst_den = a1.den; 100 | 101 | return den == 0; 102 | } 103 | 104 | glcs_Rational_t glcs_mul_q(glcs_Rational_t b, glcs_Rational_t c) 105 | { 106 | glcs_reduce(&b.num, &b.den, 107 | b.num * (int64_t) c.num, 108 | b.den * (int64_t) c.den, INT_MAX); 109 | return b; 110 | } 111 | 112 | glcs_Rational_t glcs_div_q(glcs_Rational_t b, glcs_Rational_t c) 113 | { 114 | return glcs_mul_q(b, (glcs_Rational_t) { c.den, c.num }); 115 | } 116 | 117 | glcs_Rational_t glcs_d2q(double d, int max) 118 | { 119 | glcs_Rational_t a; 120 | #define LOG2 0.69314718055994530941723212145817656807550013436025 121 | int exponent; 122 | int64_t den; 123 | if (isnan(d)) 124 | return (glcs_Rational_t) { 0,0 }; 125 | if (fabs(d) > INT_MAX + 3LL) 126 | return (glcs_Rational_t) { d < 0 ? -1 : 1, 0 }; 127 | exponent = GLCSMAX( (int)(log(fabs(d) + 1e-20)/LOG2), 0); 128 | den = 1LL << (61 - exponent); 129 | // (int64_t)rint() and llrint() do not work with gcc on ia64 and sparc64 130 | glcs_reduce(&a.num, &a.den, floor(d * den + 0.5), den, max); 131 | if ((!a.num || !a.den) && d && max>0 && max 4 | * I did just prefer to cut & paste this very small subset than requiring to depend on ffmpeg. 5 | * \author Olivier Langlois 6 | * \date 2014 7 | 8 | Copyright 2014 Olivier Langlois 9 | 10 | This file is part of glcs. 11 | 12 | glcs is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | glcs is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with glcs. If not, see . 24 | 25 | */ 26 | 27 | #ifndef __GLCS_RATIONAL_H__ 28 | #define __GLCS_RATIONAL_H__ 29 | 30 | #include 31 | 32 | /** 33 | * rational number numerator/denominator 34 | */ 35 | typedef struct glcs_Rational{ 36 | int num; ///< numerator 37 | int den; ///< denominator 38 | } glcs_Rational_t; 39 | 40 | /** 41 | * Reduce a fraction. 42 | * This is useful for framerate calculations. 43 | * @param dst_num destination numerator 44 | * @param dst_den destination denominator 45 | * @param num source numerator 46 | * @param den source denominator 47 | * @param max the maximum allowed for dst_num & dst_den 48 | * @return 1 if exact, 0 otherwise 49 | */ 50 | int glcs_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max); 51 | 52 | /** 53 | * Multiply two rationals. 54 | * @param b first rational 55 | * @param c second rational 56 | * @return b*c 57 | */ 58 | glcs_Rational_t glcs_mul_q(glcs_Rational_t b, glcs_Rational_t c); 59 | 60 | /** 61 | * Divide one rational by another. 62 | * @param b first rational 63 | * @param c second rational 64 | * @return b/c 65 | */ 66 | glcs_Rational_t glcs_div_q(glcs_Rational_t b, glcs_Rational_t c); 67 | 68 | /** 69 | * Convert a double precision floating point number to a rational. 70 | * inf is expressed as {1,0} or {-1,0} depending on the sign. 71 | * 72 | * @param d double to convert 73 | * @param max the maximum allowed numerator and denominator 74 | * @return (AVRational) d 75 | */ 76 | glcs_Rational_t glcs_d2q(double d, int max); 77 | 78 | #endif 79 | 80 | -------------------------------------------------------------------------------- /src/glc/common/signal.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/signal.c 3 | * \brief glcs signal related functions. 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | #include 27 | #include // for strerror() 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "optimization.h" 35 | 36 | /* Prototype __libc_allocate_rtsig() to avoid an implicit declaration. */ 37 | extern int __libc_allocate_rtsig(int); 38 | 39 | /** async signal number */ 40 | static int glcs_signal_signo; 41 | 42 | /* 43 | * Will be called automatically at lib load. 44 | * __libc_allocate_rtsig() is not thread safe so calling it prior 45 | * creating threads is a good idea. 46 | */ 47 | void glcs_signal_init(void) __attribute__ ((constructor)); 48 | 49 | void glcs_signal_init(void) 50 | { 51 | /* 52 | * The param indicates that we are not looking to have a high prio rtsig 53 | */ 54 | glcs_signal_signo = __libc_allocate_rtsig(0); 55 | } 56 | 57 | static void glcs_signal_handler(int signo) 58 | { 59 | // empty for now 60 | } 61 | 62 | int glcs_signal_init_thread_disposition(glc_t *glc) 63 | { 64 | int ret; 65 | struct sigaction act; 66 | sigset_t mask; 67 | 68 | glc_log(glc, GLC_DEBUG, "signal", "installing rtsig %d", glcs_signal_signo); 69 | act.sa_handler = glcs_signal_handler; 70 | act.sa_flags = SA_INTERRUPT; 71 | sigemptyset(&act.sa_mask); 72 | if (unlikely((ret = sigaction(glcs_signal_signo, &act, NULL)) < 0)) 73 | { 74 | glc_log(glc, GLC_ERROR, "signal", 75 | "failed to install glcs_signal handler: %s (%d)", 76 | strerror(errno), errno); 77 | return ret; 78 | } 79 | sigemptyset(&mask); 80 | sigaddset(&mask, glcs_signal_signo); 81 | if (unlikely((ret = pthread_sigmask(SIG_UNBLOCK, &mask, NULL)) < 0)) 82 | glc_log(glc, GLC_ERROR, "signal", 83 | "failed to unblock glcs_signal: %s (%d)", 84 | strerror(errno), errno); 85 | return ret; 86 | } 87 | 88 | struct timed_waitpid_param 89 | { 90 | pthread_t parent; 91 | const struct timespec *ts; 92 | }; 93 | 94 | static void *timed_waitpid_threadfunc(void *arg) 95 | { 96 | struct timed_waitpid_param *param = (struct timed_waitpid_param *)arg; 97 | clock_nanosleep(CLOCK_MONOTONIC, 0, param->ts, NULL); 98 | /* 99 | * If everything goes well, the thread should be cancelled inside 100 | * clock_nanosleep(). 101 | */ 102 | pthread_kill(param->parent, glcs_signal_signo); 103 | return NULL; 104 | } 105 | 106 | int glcs_signal_timed_waitpid(glc_t *glc, pid_t pid, int *stat_loc, 107 | const struct timespec *ts) 108 | { 109 | int ret; 110 | pthread_t thread; 111 | struct timed_waitpid_param param = 112 | { 113 | .parent = pthread_self(), 114 | .ts = ts, 115 | }; 116 | if (unlikely((ret = pthread_create(&thread, NULL, 117 | timed_waitpid_threadfunc, ¶m)))) 118 | { 119 | errno = ret; 120 | return -1; 121 | } 122 | glc_log(glc, GLC_DEBUG, "signal", "wait for pid %d", pid); 123 | ret = waitpid(pid, stat_loc, 0); 124 | if (!ret || errno != EINTR) 125 | pthread_cancel(thread); 126 | else 127 | glc_log(glc, GLC_DEBUG, "signal", "waitpid() has timed out"); 128 | pthread_join(thread,NULL); 129 | return ret; 130 | } 131 | 132 | /* 133 | * Code adapted from APUE from Stevens. 134 | */ 135 | void glcs_signal_pr_exit(glc_t *glc, pid_t pid, int status) 136 | { 137 | if (WIFEXITED(status)) 138 | glc_log(glc, GLC_INFO, "signal", 139 | "(%d) normal termination, exit status = %d", 140 | pid, WEXITSTATUS(status)); 141 | else if (WIFSIGNALED(status)) 142 | glc_log(glc, GLC_INFO, "signal", 143 | "(%d) abnormal termination, signal number = %d%s", 144 | pid, WTERMSIG(status), 145 | WCOREDUMP(status) ? " (core file generated)" : ""); 146 | else if (WIFSTOPPED(status)) 147 | glc_log(glc, GLC_INFO, "signal", 148 | "(%d) child stopped, signal number = %d", 149 | WSTOPSIG(status)); 150 | } 151 | 152 | void glcs_signal_reset() 153 | { 154 | unsigned i; 155 | struct sigaction act; 156 | act.sa_handler = SIG_DFL; 157 | act.sa_flags = 0; 158 | sigemptyset(&act.sa_mask); 159 | 160 | for (i = 1; /* skip null sig */ 161 | i < NSIG; ++i) 162 | sigaction(i, &act, NULL); 163 | } 164 | 165 | -------------------------------------------------------------------------------- /src/glc/common/signal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/signal.h 3 | * \brief glcs signal related functions. 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | #ifndef _GLCS_SIGNAL_H 27 | #define _GLCS_SIGNAL_H 28 | 29 | #include // for pid_t 30 | #include // for struct timespec 31 | #include 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | /** 38 | * \brief Configure the calling thread signal dispositions 39 | * in order to make the others functions of this module 40 | * work properly. 41 | */ 42 | __PUBLIC int glcs_signal_init_thread_disposition(glc_t *glc); 43 | 44 | __PUBLIC void glcs_signal_reset(); 45 | 46 | /* 47 | * Must have called glcs_signal_init_thread_disposition() first from the thread calling 48 | * this function. 49 | */ 50 | __PUBLIC int glcs_signal_timed_waitpid(glc_t *glc, pid_t pid, int *stat_loc, 51 | const struct timespec *ts); 52 | 53 | __PUBLIC void glcs_signal_pr_exit(glc_t *glc, pid_t pid, int status); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif 60 | 61 | -------------------------------------------------------------------------------- /src/glc/common/state.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/state.c 3 | * \brief glc state adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup state 28 | * \{ 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include // for PRI64d 35 | 36 | #include "glc.h" 37 | #include "core.h" 38 | #include "log.h" 39 | #include "state.h" 40 | 41 | struct glc_state_video_s { 42 | glc_stream_id_t id; 43 | struct glc_state_video_s *next; 44 | }; 45 | 46 | struct glc_state_audio_s { 47 | glc_stream_id_t id; 48 | struct glc_state_audio_s *next; 49 | }; 50 | 51 | struct glc_state_s { 52 | pthread_rwlock_t state_rwlock; 53 | 54 | /* lock maybe not needed */ 55 | pthread_rwlock_t time_rwlock; 56 | glc_stime_t time_difference; 57 | 58 | pthread_rwlock_t video_rwlock; 59 | struct glc_state_video_s *video; 60 | glc_stream_id_t video_count; 61 | 62 | pthread_rwlock_t audio_rwlock; 63 | struct glc_state_audio_s *audio; 64 | glc_stream_id_t audio_count; 65 | }; 66 | 67 | int glc_state_init(glc_t *glc) 68 | { 69 | glc->state_flags = 0; 70 | glc->state = (glc_state_t) calloc(1, sizeof(struct glc_state_s)); 71 | 72 | pthread_rwlock_init(&glc->state->state_rwlock, NULL); 73 | pthread_rwlock_init(&glc->state->time_rwlock, NULL); 74 | 75 | pthread_rwlock_init(&glc->state->video_rwlock, NULL); 76 | pthread_rwlock_init(&glc->state->audio_rwlock, NULL); 77 | 78 | return 0; 79 | } 80 | 81 | int glc_state_destroy(glc_t *glc) 82 | { 83 | struct glc_state_video_s *video_del; 84 | struct glc_state_audio_s *audio_del; 85 | 86 | while (glc->state->video != NULL) { 87 | video_del = glc->state->video; 88 | glc->state->video = glc->state->video->next; 89 | 90 | free(video_del); 91 | } 92 | 93 | while (glc->state->audio != NULL) { 94 | audio_del = glc->state->audio; 95 | glc->state->audio = glc->state->audio->next; 96 | 97 | free(audio_del); 98 | } 99 | 100 | pthread_rwlock_destroy(&glc->state->state_rwlock); 101 | pthread_rwlock_destroy(&glc->state->time_rwlock); 102 | 103 | pthread_rwlock_destroy(&glc->state->video_rwlock); 104 | pthread_rwlock_destroy(&glc->state->audio_rwlock); 105 | 106 | free(glc->state); 107 | glc->state_flags = 0; 108 | 109 | return 0; 110 | } 111 | 112 | int glc_state_video_new(glc_t *glc, glc_stream_id_t *id, 113 | glc_state_video_t *video) 114 | { 115 | *video = (glc_state_video_t) calloc(1, sizeof(struct glc_state_video_s)); 116 | 117 | pthread_rwlock_wrlock(&glc->state->video_rwlock); 118 | (*video)->id = ++glc->state->video_count; 119 | (*video)->next = glc->state->video; 120 | glc->state->video = *video; 121 | pthread_rwlock_unlock(&glc->state->video_rwlock); 122 | 123 | *id = (*video)->id; 124 | return 0; 125 | } 126 | 127 | int glc_state_audio_new(glc_t *glc, glc_stream_id_t *id, 128 | glc_state_audio_t *audio) 129 | { 130 | *audio = (glc_state_audio_t) calloc(1, sizeof(struct glc_state_audio_s)); 131 | 132 | pthread_rwlock_wrlock(&glc->state->audio_rwlock); 133 | (*audio)->id = ++glc->state->audio_count; 134 | (*audio)->next = glc->state->audio; 135 | glc->state->audio = *audio; 136 | pthread_rwlock_unlock(&glc->state->audio_rwlock); 137 | 138 | *id = (*audio)->id; 139 | return 0; 140 | } 141 | 142 | int glc_state_set(glc_t *glc, int flag) 143 | { 144 | pthread_rwlock_wrlock(&glc->state->state_rwlock); 145 | glc->state_flags |= flag; 146 | pthread_rwlock_unlock(&glc->state->state_rwlock); 147 | return 0; 148 | } 149 | 150 | int glc_state_clear(glc_t *glc, int flag) 151 | { 152 | pthread_rwlock_wrlock(&glc->state->state_rwlock); 153 | glc->state_flags &= ~flag; 154 | pthread_rwlock_unlock(&glc->state->state_rwlock); 155 | return 0; 156 | } 157 | 158 | int glc_state_test(glc_t *glc, int flag) 159 | { 160 | return (glc->state_flags & flag); 161 | } 162 | 163 | glc_utime_t glc_state_time(glc_t *glc) 164 | { 165 | return glc_time(glc) - glc->state->time_difference; 166 | } 167 | 168 | void glc_state_time_reset(glc_t *glc) 169 | { 170 | pthread_rwlock_wrlock(&glc->state->time_rwlock); 171 | glc->state->time_difference = glc_time(glc); 172 | pthread_rwlock_unlock(&glc->state->time_rwlock); 173 | } 174 | 175 | int glc_state_time_add_diff(glc_t *glc, glc_stime_t diff) 176 | { 177 | glc_log(glc, GLC_DEBUG, "state", "applying %" PRId64 " nsec time difference", diff); 178 | pthread_rwlock_wrlock(&glc->state->time_rwlock); 179 | glc->state->time_difference += diff; 180 | pthread_rwlock_unlock(&glc->state->time_rwlock); 181 | return 0; 182 | } 183 | 184 | /** \} */ 185 | -------------------------------------------------------------------------------- /src/glc/common/state.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/state.h 3 | * \brief glc state interface adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup common 28 | * \{ 29 | * \defgroup state glc state 30 | * \{ 31 | */ 32 | 33 | #ifndef _STATE_H 34 | #define _STATE_H 35 | 36 | #include 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /** all stream operations should cancel */ 43 | #define GLC_STATE_CANCEL 0x1 44 | 45 | /** 46 | * \brief video stream object 47 | */ 48 | typedef struct glc_state_video_s* glc_state_video_t; 49 | 50 | /** 51 | * \brief audio stream object 52 | */ 53 | typedef struct glc_state_audio_s* glc_state_audio_t; 54 | 55 | /** 56 | * \brief initialize state 57 | * \param glc glc 58 | * \return 0 on success otherwise an error code 59 | */ 60 | __PUBLIC int glc_state_init(glc_t *glc); 61 | 62 | /** 63 | * \brief destroy state 64 | * \param glc glc 65 | * \return 0 on success otherwise an error code 66 | */ 67 | __PUBLIC int glc_state_destroy(glc_t *glc); 68 | 69 | /** 70 | * \brief acquire a new video stream 71 | * \param glc glc 72 | * \param id returned video stream identifier 73 | * \param video returned video stream object 74 | * \return 0 on success otherwise an error code 75 | */ 76 | __PUBLIC int glc_state_video_new(glc_t *glc, glc_stream_id_t *id, 77 | glc_state_video_t *video); 78 | 79 | /** 80 | * \brief acquire a new audio stream 81 | * \param glc glc 82 | * \param id returned audio stream identifier 83 | * \param audio returned audio stream object 84 | * \return 0 on success otherwise an error code 85 | */ 86 | __PUBLIC int glc_state_audio_new(glc_t *glc, glc_stream_id_t *id, 87 | glc_state_audio_t *audio); 88 | 89 | /** 90 | * \brief set state flag 91 | * \param glc glc 92 | * \param flag flag to set 93 | * \return 0 on success otherwise an error code 94 | */ 95 | __PUBLIC int glc_state_set(glc_t *glc, int flag); 96 | 97 | /** 98 | * \brief clear state flag 99 | * \param glc glc 100 | * \param flag flag to clear 101 | * \return 0 on success otherwise an error code 102 | */ 103 | __PUBLIC int glc_state_clear(glc_t *glc, int flag); 104 | 105 | /** 106 | * \brief test state flag 107 | * \note for performance reasons this function doesn't acquire 108 | * a global state mutex lock. 109 | * \param glc glc 110 | * \param flag flag to test 111 | * \return 1 if flag is set, otherwise 0 112 | */ 113 | __PUBLIC __inline__ int glc_state_test(glc_t *glc, int flag); 114 | 115 | /** 116 | * \brief get state time 117 | * 118 | * State time is glc_time() minus current state time difference. 119 | * \note doesn't acquire a global time difference lock 120 | * \param glc glc 121 | * \return current state time 122 | */ 123 | __PUBLIC glc_utime_t glc_state_time(glc_t *glc); 124 | 125 | /** 126 | * \brief add value to state time difference 127 | * \param glc glc 128 | * \param diff new time difference 129 | * \return 0 on success otherwise an error code 130 | */ 131 | __PUBLIC int glc_state_time_add_diff(glc_t *glc, glc_stime_t diff); 132 | 133 | __PUBLIC void glc_state_time_reset(glc_t *glc); 134 | 135 | #ifdef __cplusplus 136 | } 137 | #endif 138 | 139 | #endif 140 | 141 | /** \} */ 142 | /** \} */ 143 | -------------------------------------------------------------------------------- /src/glc/common/thread.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/thread.c 3 | * \brief generic stream processor thread adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup common 28 | * \{ 29 | * \defgroup thread generic thread 30 | * \{ 31 | */ 32 | 33 | #ifndef _THREAD_H 34 | #define _THREAD_H 35 | 36 | #include 37 | #include 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | /** currently unused legacy */ 44 | #define GLC_THREAD_UNUSED1 1 45 | /** currently unused legacy */ 46 | #define GLC_THREAD_UNUSED2 2 47 | /** thread does not yet know final packet size, so write dma 48 | is not acquired */ 49 | #define GLC_THREAD_STATE_UNKNOWN_FINAL_SIZE 4 50 | /** thread wants to skip reading a packet */ 51 | #define GLC_THREAD_STATE_SKIP_READ 8 52 | /** thread wants to skip writing a packet */ 53 | #define GLC_THREAD_STATE_SKIP_WRITE 16 54 | /** just copy data to write packet, skip write callback */ 55 | #define GLC_THREAD_COPY 32 56 | /** thread wants to stop */ 57 | #define GLC_THREAD_STOP 64 58 | 59 | /** 60 | * \brief thread state 61 | * 62 | * Thread state structure holds information about 63 | * current read and write packet and thread state. 64 | * Callback functions modify data and thread state 65 | * using this structure. 66 | */ 67 | typedef struct { 68 | /** flags */ 69 | glc_flags_t flags; 70 | /** current message header */ 71 | glc_message_header_t header; 72 | /** read data excluding header */ 73 | char *read_data; 74 | /** data to be written excluding header */ 75 | char *write_data; 76 | /** read data size */ 77 | size_t read_size; 78 | /** write data size, read callback should set this 79 | so thread knows how big dma to request */ 80 | size_t write_size; 81 | /** global argument pointer */ 82 | void *ptr; 83 | /** per-thread argument pointer */ 84 | void *threadptr; 85 | 86 | /** 87 | * This variable is to make possible buffer drain from callback. 88 | * This is leaking some implementation data but the right alternative 89 | * would be to pass an opaque void pointer + a new function 90 | * glc_thread_drain_buffer( glc_thread_state_t *state ); 91 | * and I find this a bit heavy for the risk the shortcut represents. 92 | */ 93 | ps_buffer_t *from; 94 | } glc_thread_state_t; 95 | 96 | /** thread does read operations */ 97 | #define GLC_THREAD_READ 1 98 | /** thread does write operations */ 99 | #define GLC_THREAD_WRITE 2 100 | /** 101 | * \brief thread vtable 102 | * 103 | * glc_thread_t holds information about thread callbacks 104 | * and features. Mandatory values are flags, and threads. 105 | * If callback is NULL, it is ignored. 106 | */ 107 | typedef struct { 108 | /** flags, GLC_THREAD_READ or GLC_THREAD_WRITE or both */ 109 | glc_flags_t flags; 110 | /** global argument pointer */ 111 | void *ptr; 112 | /** number of threads to create */ 113 | size_t threads; 114 | /** flag to indicate that rt prio is desired. */ 115 | int ask_rt; 116 | /** implementation specific */ 117 | void *priv; 118 | 119 | /** thread create callback is called when a thread starts */ 120 | int (*thread_create_callback)(void *, void **); 121 | /** thread finish callback is called when a thread is finished */ 122 | void (*thread_finish_callback)(void *, void *, int); 123 | /** open callback is called before thread tries to 124 | open read (or write if GLC_THREAD_READ is not specified) 125 | packet */ 126 | int (*open_callback)(glc_thread_state_t *); 127 | /** header callback is called when thread has read 128 | header from packet */ 129 | int (*header_callback)(glc_thread_state_t *); 130 | /** read callback is called when thread has read the 131 | whole packet */ 132 | int (*read_callback)(glc_thread_state_t *); 133 | /** write callback is called when thread has opened 134 | dma to write packet */ 135 | int (*write_callback)(glc_thread_state_t *); 136 | /** close callback is called when both packets are closed */ 137 | int (*close_callback)(glc_thread_state_t *); 138 | /** finish callback is called only once, when all threads have 139 | finished */ 140 | void (*finish_callback)(void *, int); 141 | } glc_thread_t; 142 | 143 | /** 144 | * \brief create thread 145 | * 146 | * Creates thread.threads threads (glc_thread()). 147 | * \param glc glc 148 | * \param thread thread information structure 149 | * \param from buffer where data is read from 150 | * \param to buffer where data is written to 151 | * \return 0 on success otherwise an error code 152 | */ 153 | __PUBLIC int glc_thread_create(glc_t *glc, glc_thread_t *thread, 154 | ps_buffer_t *from, ps_buffer_t *to); 155 | 156 | /** 157 | * \brief block until threads have finished and clean up 158 | * \param thread thread 159 | * \return 0 on success otherwise an error code 160 | */ 161 | __PUBLIC int glc_thread_wait(glc_thread_t *thread); 162 | 163 | typedef struct { 164 | pthread_t thread; 165 | /** flag to indicate that rt prio is desired. */ 166 | int ask_rt; 167 | int running; 168 | } glc_simple_thread_t; 169 | 170 | __PUBLIC int glc_simple_thread_create(glc_t *glc, glc_simple_thread_t *thread, 171 | void *(*start_routine) (void *), void *arg); 172 | 173 | __PUBLIC int glc_simple_thread_wait(glc_t *glc, glc_simple_thread_t *thread); 174 | 175 | #ifdef __cplusplus 176 | } 177 | #endif 178 | 179 | #endif 180 | 181 | /** \} */ 182 | /** \} */ 183 | -------------------------------------------------------------------------------- /src/glc/common/util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/common/util.h 3 | * \brief utility functions interface adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup common 28 | * \{ 29 | * \defgroup util utility functions 30 | * \{ 31 | */ 32 | 33 | #ifndef _UTIL_H 34 | #define _UTIL_H 35 | 36 | #include 37 | #include 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | /** 44 | * \brief initialize utilities 45 | * \param glc glc 46 | * \return 0 on success otherwise an error code 47 | */ 48 | __PRIVATE int glc_util_init(glc_t *glc); 49 | 50 | /** 51 | * \brief destroy utilities 52 | * \param glc glc 53 | * \return 0 on success otherwise an error code 54 | */ 55 | __PRIVATE int glc_util_destroy(glc_t *glc); 56 | 57 | /** 58 | * \brief set fps hint for stream information 59 | * \param glc glc 60 | * \param fps fps 61 | * \return 0 on success otherwise an error code 62 | */ 63 | __PUBLIC int glc_util_info_fps(glc_t *glc, double fps); 64 | 65 | /** 66 | * \brief create stream information 67 | * \param glc glc 68 | * \param stream_info returned stream information structure 69 | * \param info_name returned application name 70 | * \param info_date returned date 71 | * \return 0 on success otherwise an error code 72 | */ 73 | __PUBLIC int glc_util_info_create(glc_t *glc, glc_stream_info_t **stream_info, 74 | char **info_name, char *info_date); 75 | 76 | /** 77 | * \brief write version message into log 78 | * \param glc glc 79 | * \return 0 on success otherwise an error code 80 | */ 81 | __PUBLIC int glc_util_log_version(glc_t *glc); 82 | 83 | /** 84 | * \brief write system information into log 85 | * \param glc glc 86 | * \return 0 on success otherwise an error code 87 | */ 88 | __PUBLIC int glc_util_log_info(glc_t *glc); 89 | 90 | /** 91 | * \brief write 'end of stream'-packet into buffer 92 | * \param glc glc 93 | * \param to target buffer 94 | * \return 0 on success otherwise an error code 95 | */ 96 | __PUBLIC int glc_util_write_end_of_stream(glc_t *glc, ps_buffer_t *to); 97 | 98 | /** 99 | * \brief replace all occurences of string with another string 100 | * \param str string to manipulate 101 | * \param find string to find 102 | * \param replace string to replace occurences with 103 | * \return new string 104 | */ 105 | __PUBLIC char *glc_util_str_replace(const char *str, const char *find, const char *replace); 106 | 107 | /** 108 | * \brief create filename based on current date, time, app name, pid etc. 109 | * 110 | * Available tags in format are: 111 | * %app% binary name without path 112 | * %pid% process id 113 | * %capture% N'th capture (given as argument) 114 | * %year% 4-digit year 115 | * %month% 2-digit month 116 | * %day% 2-digit day 117 | * %hour% 2-digit hour 118 | * %min% 2-digit minute 119 | * %sec% 2-digit second 120 | * \param format format string 121 | * \param capture N'th capture 122 | * \return new filename string 123 | */ 124 | __PUBLIC char *glc_util_format_filename(const char *fmt, unsigned int capture); 125 | 126 | __PUBLIC int glc_util_setflag( int fd, int flag ); 127 | __PUBLIC int glc_util_clearflag( int fd, int flag ); 128 | __PUBLIC int glc_util_set_nonblocking(int fd); 129 | __PUBLIC void glc_util_empty_pipe(int fd); 130 | __PUBLIC int glc_util_set_pipe_size(glc_t *glc, int fd, int size); 131 | __PUBLIC const char *glc_util_msgtype_to_str(glc_message_type_t type); 132 | __PUBLIC const char *glc_util_videofmt_to_str(glc_video_format_t fmt); 133 | __PUBLIC int glc_util_get_videofmt_bpp(glc_video_format_t fmt); 134 | __PUBLIC void glc_util_close_fds(int start_fd); 135 | 136 | #ifdef __cplusplus 137 | } 138 | #endif 139 | 140 | #endif 141 | 142 | /** \} */ 143 | /** \} */ 144 | -------------------------------------------------------------------------------- /src/glc/common/version.h.in: -------------------------------------------------------------------------------- 1 | #ifndef _VERSION_H 2 | #define _VERSION_H 3 | 4 | #define GLC_VERSION "@GLCS_VERSION@" 5 | 6 | #endif /* _VERSION_H */ 7 | -------------------------------------------------------------------------------- /src/glc/core/color.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/color.h 3 | * \brief color correction 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup core 11 | * \{ 12 | * \defgroup color color correction 13 | * \{ 14 | */ 15 | 16 | #ifndef _COLOR_H 17 | #define _COLOR_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief color object 28 | */ 29 | typedef struct color_s* color_t; 30 | 31 | /** 32 | * \brief initialize color object 33 | * \param color color object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int color_init(color_t *color, glc_t *glc); 38 | 39 | /** 40 | * \brief destroy color object 41 | * \param color color object 42 | * \return 0 on success otherwise an error code 43 | */ 44 | __PUBLIC int color_destroy(color_t color); 45 | 46 | /** 47 | * \brief override color correction 48 | * \param color color object 49 | * \param brightness brightness value 50 | * \param contrast contrast value 51 | * \param red red gamma 52 | * \param green green gamma 53 | * \param blue blue gamma 54 | * \return 0 on success otherwise an error code 55 | */ 56 | __PUBLIC int color_override(color_t color, float brightness, float contrast, 57 | float red, float green, float blue); 58 | 59 | /** 60 | * \brief clear override 61 | * \param color color object 62 | * \return 0 on success otherwise an error code 63 | */ 64 | __PUBLIC int color_override_clear(color_t color); 65 | 66 | /** 67 | * \brief start color process 68 | * 69 | * color applies color corretion to all Y'CbCr and RGB 70 | * frames in stream. 71 | * \param color color object 72 | * \param from source buffer 73 | * \param to target buffer 74 | * \return 0 on success otherwise an error code 75 | */ 76 | __PUBLIC int color_process_start(color_t color, ps_buffer_t *from, ps_buffer_t *to); 77 | 78 | /** 79 | * \brief block until process has finished 80 | * \param color color object 81 | * \return 0 on success otherwise an error code 82 | */ 83 | __PUBLIC int color_process_wait(color_t color); 84 | 85 | #ifdef __cplusplus 86 | } 87 | #endif 88 | 89 | #endif 90 | 91 | /** \} */ 92 | /** \} */ 93 | -------------------------------------------------------------------------------- /src/glc/core/copy.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/copy.c 3 | * \brief generic stream demuxer adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup copy 28 | * \{ 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "copy.h" 47 | 48 | struct copy_target_s { 49 | ps_buffer_t *buffer; 50 | ps_packet_t packet; 51 | glc_message_type_t type; 52 | 53 | struct copy_target_s *next; 54 | }; 55 | 56 | struct copy_s { 57 | glc_t *glc; 58 | ps_buffer_t *from; 59 | 60 | glc_simple_thread_t thread; 61 | 62 | struct copy_target_s *copy_target; 63 | }; 64 | 65 | void *copy_thread(void *argptr); 66 | 67 | int copy_init(copy_t *copy, glc_t *glc) 68 | { 69 | *copy = (copy_t) calloc(1, sizeof(struct copy_s)); 70 | (*copy)->glc = glc; 71 | return 0; 72 | } 73 | 74 | int copy_destroy(copy_t copy) 75 | { 76 | struct copy_target_s *del; 77 | 78 | while (copy->copy_target != NULL) { 79 | del = copy->copy_target; 80 | copy->copy_target = copy->copy_target->next; 81 | 82 | ps_packet_destroy(&del->packet); 83 | free(del); 84 | } 85 | 86 | free(copy); 87 | return 0; 88 | } 89 | 90 | int copy_add(copy_t copy, ps_buffer_t *target, glc_message_type_t type) 91 | { 92 | struct copy_target_s *newtarget = (struct copy_target_s *) 93 | calloc(1, sizeof(struct copy_target_s)); 94 | 95 | newtarget->buffer = target; 96 | newtarget->type = type; 97 | 98 | /** \todo one packet per buffer */ 99 | ps_packet_init(&newtarget->packet, newtarget->buffer); 100 | 101 | newtarget->next = copy->copy_target; 102 | copy->copy_target = newtarget; 103 | 104 | return 0; 105 | } 106 | 107 | int copy_process_start(copy_t copy, ps_buffer_t *from) 108 | { 109 | if (unlikely(copy->thread.running)) 110 | return EALREADY; 111 | 112 | copy->from = from; 113 | 114 | return glc_simple_thread_create(copy->glc, ©->thread, 115 | copy_thread, copy); 116 | } 117 | 118 | int copy_process_wait(copy_t copy) 119 | { 120 | return glc_simple_thread_wait(copy->glc, ©->thread); 121 | } 122 | 123 | void *copy_thread(void *argptr) 124 | { 125 | copy_t copy = (copy_t) argptr; 126 | struct copy_target_s *target; 127 | glc_message_header_t msg_hdr; 128 | size_t data_size; 129 | void *data; 130 | int ret = 0; 131 | 132 | ps_packet_t read; 133 | 134 | if (unlikely((ret = ps_packet_init(&read, copy->from)))) 135 | goto err; 136 | 137 | do { 138 | if (unlikely((ret = ps_packet_open(&read, PS_PACKET_READ)))) 139 | goto err; 140 | 141 | if (unlikely((ret = ps_packet_read(&read, &msg_hdr, 142 | sizeof(glc_message_header_t))))) 143 | goto err; 144 | if (unlikely((ret = ps_packet_getsize(&read, &data_size)))) 145 | goto err; 146 | data_size -= sizeof(glc_message_header_t); 147 | if (unlikely((ret = ps_packet_dma(&read, &data, data_size, 148 | PS_ACCEPT_FAKE_DMA)))) 149 | goto err; 150 | 151 | target = copy->copy_target; 152 | while (target != NULL) { 153 | if ((target->type == 0) || 154 | (target->type == msg_hdr.type)) { 155 | if (unlikely((ret = ps_packet_open(&target->packet, 156 | PS_PACKET_WRITE)))) 157 | goto err; 158 | if (unlikely((ret = ps_packet_write(&target->packet, &msg_hdr, 159 | sizeof(glc_message_header_t))))) 160 | goto err; 161 | if (unlikely((ret = ps_packet_write(&target->packet, data, 162 | data_size)))) 163 | goto err; 164 | if (unlikely((ret = ps_packet_close(&target->packet)))) 165 | goto err; 166 | } 167 | target = target->next; 168 | } 169 | 170 | ps_packet_close(&read); 171 | } while ((!glc_state_test(copy->glc, GLC_STATE_CANCEL)) && 172 | (msg_hdr.type != GLC_MESSAGE_CLOSE)); 173 | 174 | finish: 175 | ps_packet_destroy(&read); 176 | 177 | if (glc_state_test(copy->glc, GLC_STATE_CANCEL)) { 178 | ps_buffer_cancel(copy->from); 179 | 180 | target = copy->copy_target; 181 | while (target != NULL) { 182 | ps_buffer_cancel(target->buffer); 183 | target = target->next; 184 | } 185 | } 186 | 187 | return NULL; 188 | err: 189 | if (ret != EINTR) { 190 | glc_log(copy->glc, GLC_ERROR, "copy", "%s (%d)", 191 | strerror(ret), ret); 192 | glc_state_set(copy->glc, GLC_STATE_CANCEL); 193 | } 194 | goto finish; 195 | } 196 | 197 | /** \} */ 198 | -------------------------------------------------------------------------------- /src/glc/core/copy.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/copy.h 3 | * \brief generic stream demuxer 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup core 11 | * \{ 12 | * \defgroup copy generic stream demuxer 13 | * \{ 14 | */ 15 | 16 | #ifndef _COPY_H 17 | #define _COPY_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief copy object 28 | */ 29 | typedef struct copy_s* copy_t; 30 | 31 | /** 32 | * \brief initialize copy object 33 | * \param copy copy object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int copy_init(copy_t *copy, glc_t *glc); 38 | 39 | /** 40 | * \brief destroy copy object 41 | * \param copy copy object 42 | * \return 0 on success otherwise an error code 43 | */ 44 | __PUBLIC int copy_destroy(copy_t copy); 45 | 46 | /** 47 | * \brief add copy target 48 | * 49 | * Only messages with selected type are copied into target buffer. 50 | * If type is 0 all messages are copied. A target can be added several times 51 | * so several message types can be selected for copying. 52 | * 53 | * Remember to add GLC_MESSAGE_CLOSE if you want to close objects behind 54 | * target buffer when stream ends. 55 | * \param copy copy object 56 | * \param target target buffer 57 | * \param type copy only selected messages or 58 | * if this is 0, all messages are copied 59 | * into this buffer 60 | * \return 0 on success otherwise an error code 61 | */ 62 | __PUBLIC int copy_add(copy_t copy, ps_buffer_t *target, glc_message_type_t type); 63 | 64 | /** 65 | * \brief start copy process 66 | * \param copy copy object 67 | * \param from source buffer 68 | * \return 0 on success otherwise an error code 69 | */ 70 | __PUBLIC int copy_process_start(copy_t copy, ps_buffer_t *from); 71 | 72 | /** 73 | * \brief block until copy process has finished 74 | * \param copy copy object 75 | * \return 0 on success otherwise an error code 76 | */ 77 | __PUBLIC int copy_process_wait(copy_t copy); 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif 84 | 85 | /** \} */ 86 | /** \} */ 87 | -------------------------------------------------------------------------------- /src/glc/core/file.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/file.c 3 | * \brief file io adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup core 28 | * \{ 29 | * \defgroup file file io 30 | * \{ 31 | */ 32 | 33 | #ifndef _FILE_H 34 | #define _FILE_H 35 | 36 | #include 37 | #include 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | /** 44 | * \brief initialize file sink object 45 | * Writing is done in its own thread. 46 | * \code 47 | * // writing example 48 | * file_sink_init(*file, glc); 49 | * file->ops->open_target(file, "/tmp/stream.glc"); 50 | * ... 51 | * file->ops->write_info(file, &info, name, date); 52 | * file->ops->write_process_start(file, buffer); 53 | * ... 54 | * file->ops->write_process_wait(file); 55 | * file->ops->close_target(file); 56 | * file->ops->destroy(file); 57 | * \endcode 58 | * 59 | * file->ops->write_info() must be called before starting write 60 | * process. 61 | * 62 | * One stream file can actually hold multiple individual 63 | * streams: [info0][stream0][info1][stream1]... 64 | * \param file file object 65 | * \param glc glc 66 | * \return 0 on success otherwise an error code 67 | */ 68 | __PUBLIC int file_sink_init(sink_t *sink, glc_t *glc); 69 | 70 | /** 71 | * \brief initialize file sink object 72 | * 73 | * Reading stream from file is done in same thread. 74 | * \code 75 | * // reading example 76 | * file_source_init(*file, glc); 77 | * file->ops->open_source(file, "/tmp/stream.glc"); 78 | * ... 79 | * file->ops->read_info(file, &info, &name, &date); 80 | * file->ops->read(file, buffer); 81 | * file->ops->close_source(file); 82 | * ... 83 | * file->ops->destroy(file); 84 | * free(name); 85 | * free(date); 86 | * \endcode 87 | * 88 | * Like in writing, file->read_info() must be called before 89 | * calling file->ops->read(). 90 | * 91 | * One stream file can actually hold multiple individual 92 | * streams: [info0][stream0][info1][stream1]... 93 | * \param file file object 94 | * \param glc glc 95 | * \return 0 on success otherwise an error code 96 | */ 97 | __PUBLIC int file_source_init(source_t *source, glc_t *glc); 98 | 99 | #ifdef __cplusplus 100 | } 101 | #endif 102 | 103 | #endif 104 | 105 | /** \} */ 106 | /** \} */ 107 | 108 | -------------------------------------------------------------------------------- /src/glc/core/frame_writers.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/frame_writers.h 3 | * \brief Abstract frame_writer interface 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | #include // For IOV_MAX 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include // for writev 32 | #include 33 | #include "frame_writers.h" 34 | 35 | typedef struct 36 | { 37 | struct frame_writer_s writer_base; 38 | int frame_size; 39 | int left; 40 | char *frame_ptr; 41 | } std_frame_writer_t; 42 | 43 | static int std_configure(frame_writer_t writer, int r_sz, int h); 44 | static int std_write_init(frame_writer_t writer, char *frame); 45 | static int std_write(frame_writer_t writer, int fd); 46 | static int std_destroy(frame_writer_t writer); 47 | 48 | /* 49 | * opengl buffers have image data from bottom 50 | * row to top row while video encoders expect the 51 | * opposite. You can flip the image in the external 52 | * program but doing it here is more efficient. 53 | */ 54 | typedef struct 55 | { 56 | struct frame_writer_s writer_base; 57 | int frame_size; 58 | int left; 59 | struct iovec *iov; 60 | size_t iov_capacity; 61 | unsigned cur_idx; 62 | int row_sz; 63 | int num_lines; 64 | } invert_frame_writer_t; 65 | 66 | static int invert_configure(frame_writer_t writer, int r_sz, int h); 67 | static int invert_write_init(frame_writer_t writer, char *frame); 68 | static int invert_write(frame_writer_t writer, int fd); 69 | static int invert_destroy(frame_writer_t writer); 70 | 71 | static write_ops_t std_ops = { 72 | .configure = std_configure, 73 | .write_init = std_write_init, 74 | .write = std_write, 75 | .destroy = std_destroy, 76 | }; 77 | 78 | int glcs_std_create( frame_writer_t *writer ) 79 | { 80 | std_frame_writer_t *std_writer = (std_frame_writer_t*)calloc(1,sizeof(std_frame_writer_t)); 81 | *writer = (frame_writer_t)std_writer; 82 | if (unlikely(!std_writer)) 83 | return ENOMEM; 84 | std_writer->writer_base.ops = &std_ops; 85 | return 0; 86 | } 87 | 88 | int std_configure(frame_writer_t writer, int r_sz, int h) 89 | { 90 | std_frame_writer_t *std_writer = (std_frame_writer_t *)writer; 91 | std_writer->frame_size = r_sz*h; 92 | return 0; 93 | } 94 | 95 | int std_write_init(frame_writer_t writer, char *frame) 96 | { 97 | std_frame_writer_t *std_writer = (std_frame_writer_t *)writer; 98 | std_writer->frame_ptr = frame; 99 | std_writer->left = std_writer->frame_size; 100 | return std_writer->left; 101 | } 102 | 103 | int std_write(frame_writer_t writer, int fd) 104 | { 105 | std_frame_writer_t *std_writer = (std_frame_writer_t *)writer; 106 | int ret = write(fd, std_writer->frame_ptr, std_writer->left); 107 | if (likely(ret >= 0)) { 108 | std_writer->left -= ret; 109 | std_writer->frame_ptr += ret; 110 | ret = std_writer->left; 111 | } 112 | return ret; 113 | } 114 | 115 | int std_destroy(frame_writer_t writer) 116 | { 117 | std_frame_writer_t *std_writer = (std_frame_writer_t *)writer; 118 | free(std_writer); 119 | return 0; 120 | } 121 | 122 | static write_ops_t invert_ops = { 123 | .configure = invert_configure, 124 | .write_init = invert_write_init, 125 | .write = invert_write, 126 | .destroy = invert_destroy, 127 | }; 128 | 129 | int glcs_invert_create( frame_writer_t *writer ) 130 | { 131 | invert_frame_writer_t *invert_writer = (invert_frame_writer_t*) 132 | calloc(1,sizeof(invert_frame_writer_t)); 133 | *writer = (frame_writer_t)invert_writer; 134 | if (unlikely(!invert_writer)) 135 | return ENOMEM; 136 | invert_writer->writer_base.ops = &invert_ops; 137 | return 0; 138 | } 139 | 140 | int invert_configure(frame_writer_t writer, int r_sz, int h) 141 | { 142 | int i; 143 | invert_frame_writer_t *invert_writer = (invert_frame_writer_t *)writer; 144 | if (unlikely(h > invert_writer->iov_capacity)) { 145 | struct iovec *ptr = (struct iovec *)realloc(invert_writer->iov, 146 | h*sizeof(struct iovec)); 147 | if (unlikely(!ptr)) 148 | return ENOMEM; 149 | invert_writer->iov = ptr; 150 | invert_writer->iov_capacity = h; 151 | } 152 | 153 | if (unlikely(r_sz != invert_writer->row_sz)) 154 | i = 0; 155 | else { 156 | i = invert_writer->num_lines; 157 | /* 158 | * If previous capture has been interrupted in the middle of writing 159 | * a frame, reset the size of the previous current line. 160 | */ 161 | if (invert_writer->cur_idx < invert_writer->num_lines) 162 | invert_writer->iov[invert_writer->cur_idx].iov_len = r_sz; 163 | } 164 | for (; i < h; ++i) 165 | invert_writer->iov[i].iov_len = r_sz; 166 | invert_writer->row_sz = r_sz; 167 | invert_writer->num_lines = h; 168 | invert_writer->frame_size = r_sz*h; 169 | return 0; 170 | } 171 | 172 | int invert_write_init(frame_writer_t writer, char *frame) 173 | { 174 | invert_frame_writer_t *invert_writer = (invert_frame_writer_t *)writer; 175 | int i; 176 | frame = &frame[(invert_writer->num_lines-1)*invert_writer->row_sz]; 177 | for (i = 0; i < invert_writer->num_lines; ++i) { 178 | invert_writer->iov[i].iov_base = frame; 179 | frame -= invert_writer->row_sz; 180 | } 181 | invert_writer->cur_idx = 0; 182 | invert_writer->left = invert_writer->frame_size; 183 | return invert_writer->left; 184 | } 185 | 186 | int invert_write(frame_writer_t writer, int fd) 187 | { 188 | invert_frame_writer_t *invert_writer = (invert_frame_writer_t *)writer; 189 | int iovcnt; 190 | int max_write; 191 | int ret; 192 | 193 | do { 194 | iovcnt = invert_writer->num_lines - invert_writer->cur_idx; 195 | if (iovcnt > IOV_MAX) 196 | iovcnt = IOV_MAX; 197 | max_write = (iovcnt-1)*invert_writer->row_sz + 198 | invert_writer->iov[invert_writer->cur_idx].iov_len; 199 | ret = writev(fd, &invert_writer->iov[invert_writer->cur_idx], iovcnt); 200 | 201 | if (likely(ret >= 0)) { 202 | int iov_remain; 203 | int num_written = ret; 204 | invert_writer->left -= num_written; 205 | 206 | // reset cur_idx iov_len if required. 207 | if (invert_writer->iov[invert_writer->cur_idx].iov_len != 208 | invert_writer->row_sz && 209 | num_written >= invert_writer->iov[invert_writer->cur_idx].iov_len) { 210 | num_written -= invert_writer->iov[invert_writer->cur_idx].iov_len; 211 | invert_writer->iov[invert_writer->cur_idx++].iov_len = 212 | invert_writer->row_sz; 213 | } 214 | if (!invert_writer->left) 215 | return 0; 216 | 217 | // perform iov adjustments if not over yet. 218 | invert_writer->cur_idx += num_written/invert_writer->row_sz; 219 | iov_remain = num_written%invert_writer->row_sz; 220 | invert_writer->iov[invert_writer->cur_idx].iov_base += iov_remain; 221 | invert_writer->iov[invert_writer->cur_idx].iov_len -= iov_remain; 222 | } 223 | } while(ret == max_write && invert_writer->left); 224 | 225 | if (ret >= 0) 226 | ret = invert_writer->left; 227 | 228 | return ret; 229 | } 230 | 231 | int invert_destroy(frame_writer_t writer) 232 | { 233 | invert_frame_writer_t *invert_writer = (invert_frame_writer_t *)writer; 234 | free(invert_writer->iov); 235 | free(invert_writer); 236 | return 0; 237 | } 238 | 239 | -------------------------------------------------------------------------------- /src/glc/core/frame_writers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/frame_writers.h 3 | * \brief Abstract frame_writer interface 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | #ifndef _FRAME_WRITERS_H 27 | #define _FRAME_WRITERS_H 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | typedef struct frame_writer_s* frame_writer_t; 34 | 35 | typedef struct 36 | { 37 | int (*configure)(frame_writer_t writer, int r_sz, int h); 38 | int (*write_init)(frame_writer_t writer, char *); 39 | /* 40 | * return value: -1 in case of error where you can consult errno to determine 41 | * the cause or else # of bytes to write left to complete the 42 | * frame write. 43 | */ 44 | int (*write)(frame_writer_t writer, int fd); 45 | int (*destroy)(frame_writer_t writer); 46 | } write_ops_t; 47 | 48 | struct frame_writer_s 49 | { 50 | write_ops_t *ops; 51 | }; 52 | 53 | int glcs_std_create( frame_writer_t *writer ); 54 | int glcs_invert_create( frame_writer_t *writer ); 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif 61 | 62 | -------------------------------------------------------------------------------- /src/glc/core/info.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/info.h 3 | * \brief stream information 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup core 11 | * \{ 12 | * \defgroup info stream information 13 | * \{ 14 | */ 15 | 16 | #ifndef _INFO_H 17 | #define _INFO_H 18 | 19 | /* FILE* ? */ 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /** 29 | * \brief rgb object 30 | */ 31 | typedef struct info_s* info_t; 32 | 33 | /** 34 | * \brief initialize info object 35 | * \param info info object 36 | * \param glc glc 37 | * \return 0 on success otherwise an error code 38 | */ 39 | __PUBLIC int info_init(info_t *info, glc_t *glc); 40 | 41 | /** 42 | * \brief destroy info object 43 | * \param info info object 44 | * \return 0 on success otherwise an error code 45 | */ 46 | __PUBLIC int info_destroy(info_t info); 47 | 48 | /** 49 | * \brief set verbosity level 50 | * 51 | * Default verbosity level is 1. Higher level means 52 | * more verbose output. 53 | * \param info info object 54 | * \param level verbosity level, starting from 1 55 | * \return 0 on success otherwise an error code 56 | */ 57 | __PUBLIC int info_set_level(info_t info, int level); 58 | 59 | /** 60 | * \brief set output stream 61 | * 62 | * By default info writes into standard output. 63 | * \param info info object 64 | * \param stream output stream 65 | * \return 0 on success otherwise an error code 66 | */ 67 | __PUBLIC int info_set_stream(info_t info, FILE *stream); 68 | 69 | /** 70 | * \brief start info process 71 | * 72 | * info collects and prints out detailed stream information according to 73 | * selected verbosity level. 74 | * \param info info object 75 | * \param from source buffer 76 | * \return 0 on success otherwise an error code 77 | */ 78 | __PUBLIC int info_process_start(info_t info, ps_buffer_t *from); 79 | 80 | /** 81 | * \brief block until process has finished 82 | * \param info info object 83 | * \return 0 on success otherwise an error code 84 | */ 85 | __PUBLIC int info_process_wait(info_t info); 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | 91 | #endif 92 | 93 | /** \} */ 94 | /** \} */ 95 | -------------------------------------------------------------------------------- /src/glc/core/pack.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/pack.h 3 | * \brief stream compression 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup core 11 | * \{ 12 | * \defgroup pack stream compression 13 | * \{ 14 | */ 15 | 16 | #ifndef _PACK_H 17 | #define _PACK_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief pack object 28 | */ 29 | typedef struct pack_s* pack_t; 30 | 31 | /** QuickLZ compression */ 32 | #define PACK_QUICKLZ 0x1 33 | /** LZO compression */ 34 | #define PACK_LZO 0x2 35 | /** LZJB compression */ 36 | #define PACK_LZJB 0x3 37 | 38 | /** 39 | * \brief unpack object 40 | */ 41 | typedef struct unpack_s* unpack_t; 42 | 43 | /** 44 | * \brief initialize pack object 45 | * \param pack pack object 46 | * \param glc glc 47 | * \return 0 on success otherwise an error code 48 | */ 49 | __PUBLIC int pack_init(pack_t *pack, glc_t *glc); 50 | 51 | /** 52 | * \brief set compression 53 | * 54 | * QuickLZ (PACK_QUICKLZ) and LZO (PACK_LZO) are currently supported. 55 | * Both are fast enough for stream compression. 56 | * LZO compresses marginally better but is slower. QuickLZ is default. 57 | * \param pack pack object 58 | * \param compression compression algorithm 59 | * \return 0 on success otherwise an error code 60 | */ 61 | __PUBLIC int pack_set_compression(pack_t pack, int compression); 62 | 63 | /** 64 | * \brief set compression threshold 65 | * 66 | * Packets smaller than compression threshold won't be compressed. 67 | * Default threshold is 1024. 68 | * \param pack pack object 69 | * \param min_size minimum packet size 70 | * \return 0 on success otherwise an error code 71 | */ 72 | __PUBLIC int pack_set_minimum_size(pack_t pack, size_t min_size); 73 | 74 | /** 75 | * \brief start processing threads 76 | * 77 | * pack compresses all data that is practical to compress (currently 78 | * pictures and audio data) and wraps compressed data into container 79 | * packets. 80 | * \param pack pack object 81 | * \param from source buffer 82 | * \param to target buffer 83 | * \return 0 on success otherwise an error code 84 | */ 85 | __PUBLIC int pack_process_start(pack_t pack, ps_buffer_t *from, ps_buffer_t *to); 86 | 87 | /** 88 | * \brief block until process has finished 89 | * \param pack pack object 90 | * \return 0 on success otherwise an error code 91 | */ 92 | __PUBLIC int pack_process_wait(pack_t pack); 93 | 94 | /** 95 | * \brief destroy pack object 96 | * \param pack pack object 97 | * \return 0 on success otherwise an error code 98 | */ 99 | __PUBLIC int pack_destroy(pack_t pack); 100 | 101 | 102 | /** 103 | * \brief initialize unpack object 104 | * \param unpack unpack object 105 | * \param glc glc 106 | * \return 0 on success otherwise an error code 107 | */ 108 | __PUBLIC int unpack_init(unpack_t *unpack, glc_t *glc); 109 | 110 | /** 111 | * \brief start processing threads 112 | * 113 | * unpack decompresses all supported compressed messages. 114 | * \param unpack unpack object 115 | * \param from source buffer 116 | * \param to target buffer 117 | * \return 0 on success otherwise an error code 118 | */ 119 | __PUBLIC int unpack_process_start(unpack_t unpack, ps_buffer_t *from, 120 | ps_buffer_t *to); 121 | 122 | /** 123 | * \brief block until process has finished 124 | * \param unpack unpack object 125 | * \return 0 on success otherwise an error code 126 | */ 127 | __PUBLIC int unpack_process_wait(unpack_t unpack); 128 | 129 | /** 130 | * \brief destroy unpack object 131 | * \param unpack unpack object 132 | * \return 0 on success otherwise an error code 133 | */ 134 | __PUBLIC int unpack_destroy(unpack_t unpack); 135 | 136 | #ifdef __cplusplus 137 | } 138 | #endif 139 | 140 | #endif 141 | 142 | /** \} */ 143 | /** \} */ 144 | -------------------------------------------------------------------------------- /src/glc/core/pipe.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/pipe.h 3 | * \brief Pipe implementation of the sink interface. 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | #ifndef _PIPE_H 27 | #define _PIPE_H 28 | 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | __PUBLIC int pipe_sink_init(sink_t *sink, glc_t *glc, const char *exec_file, 36 | int invert, unsigned delay_ms, 37 | int (*stop_capture_cb)()); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif 44 | 45 | -------------------------------------------------------------------------------- /src/glc/core/rgb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/rgb.h 3 | * \brief convert Y'CbCr to BGR 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup core 11 | * \{ 12 | * \defgroup rgb convert Y'CbCr to BGR 13 | * \{ 14 | */ 15 | 16 | #ifndef _BGR_H 17 | #define _BGR_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief rgb object 28 | */ 29 | typedef struct rgb_s* rgb_t; 30 | 31 | /** 32 | * \brief initialize rgb object 33 | * \param rgb rgb object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int rgb_init(rgb_t *rgb, glc_t *glc); 38 | 39 | /** 40 | * \brief destroy rgb object 41 | * \param rgb rgb object 42 | * \return 0 on success otherwise an error code 43 | */ 44 | __PUBLIC int rgb_destroy(rgb_t rgb); 45 | 46 | /** 47 | * \brief start rgb process 48 | * 49 | * rgb converts all Y'CbCr frames into RGB (BGR). 50 | * No scaling is currently supported. 51 | * \param rgb rgb object 52 | * \param from source buffer 53 | * \param to target buffer 54 | * \return 0 on success otherwise an error code 55 | */ 56 | __PUBLIC int rgb_process_start(rgb_t rgb, ps_buffer_t *from, ps_buffer_t *to); 57 | 58 | /** 59 | * \brief block until process has finished 60 | * \param rgb rgb object 61 | * \return 0 on success otherwise an error code 62 | */ 63 | __PUBLIC int rgb_process_wait(rgb_t rgb); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif 70 | 71 | /** \} */ 72 | /** \} */ 73 | -------------------------------------------------------------------------------- /src/glc/core/scale.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/scale.h 3 | * \brief software scaler 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup core 11 | * \{ 12 | * \defgroup scale software scaler 13 | * \{ 14 | */ 15 | 16 | #ifndef _SCALE_H 17 | #define _SCALE_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief scale object 28 | */ 29 | typedef struct scale_s* scale_t; 30 | 31 | /** 32 | * \brief initialize scale object 33 | * \param scale scale object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int scale_init(scale_t *scale, glc_t *glc); 38 | 39 | /** 40 | * \brief set scaling factor 41 | * 42 | * If scaling factor is set, frame dimensions are multiplied 43 | * with scaling factor. 44 | * \param scale scale object 45 | * \param factor scaling factor 46 | * \return 0 on success otherwise an error code 47 | */ 48 | __PUBLIC int scale_set_scale(scale_t scale, double factor); 49 | 50 | /** 51 | * \brief set scale size 52 | * 53 | * Scale frames to constant size. Aspect ratio is preserved so 54 | * black borders will appear if aspect ratio doesn't match. 55 | * \param scale scale object 56 | * \param width width 57 | * \param height height 58 | * \return 0 on success otherwise an error code 59 | */ 60 | __PUBLIC int scale_set_size(scale_t scale, unsigned int width, 61 | unsigned int height); 62 | 63 | /** 64 | * \brief process data 65 | * 66 | * scale rescales all YCBCR and RGB frames according to 67 | * active scaling configuration. 68 | * \param scale scale object 69 | * \param from source buffer 70 | * \param to target buffer 71 | * \return 0 on success otherwise an error code 72 | */ 73 | __PUBLIC int scale_process_start(scale_t scale, ps_buffer_t *from, 74 | ps_buffer_t *to); 75 | 76 | /** 77 | * \brief block until current process has finished 78 | * \param scale scale object 79 | * \return 0 on success otherwise an error code 80 | */ 81 | __PUBLIC int scale_process_wait(scale_t scale); 82 | 83 | /** 84 | * \brief destroy scale object 85 | * \param scale scale object 86 | * \return 0 on success otherwise an error code 87 | */ 88 | __PUBLIC int scale_destroy(scale_t scale); 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | #endif 95 | 96 | /** \} */ 97 | /** \} */ 98 | -------------------------------------------------------------------------------- /src/glc/core/sink.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/sink.h 3 | * \brief Abstract sink interface 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | #ifndef _SINK_H 27 | #define _SINK_H 28 | 29 | #include 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | typedef struct sink_s* sink_t; 37 | 38 | typedef struct 39 | { 40 | int (*can_resume)(sink_t sink); 41 | /** 42 | * \brief set sync mode 43 | * \note this must be set before opening sink 44 | * \param sink sink object 45 | * \param sync 0 = no forced synchronization, 1 = force writing immediately to device 46 | * \return 0 on success otherwise an error code 47 | */ 48 | int (*set_sync)(sink_t sink, int sync); 49 | /** 50 | * \brief set callback function 51 | * Callback is called when callback_request message is encountered 52 | * in stream. 53 | * \param sink sink object 54 | * \param callback callback function address 55 | * \return 0 on success otherwise an error code 56 | */ 57 | int (*set_callback)(sink_t sink, callback_request_func_t callback); 58 | /** 59 | * \brief open file for writing 60 | * \param sink sink object 61 | * \param filename target file 62 | * \return 0 on success otherwise an error code 63 | */ 64 | int (*open_target)(sink_t sink, const char *target_name); 65 | /** 66 | * \brief close target file descriptor 67 | * \param sink sink object 68 | * \return 0 on success otherwise an error code 69 | */ 70 | int (*close_target)(sink_t sink); 71 | /** 72 | * \brief write stream information header to file 73 | * \param sink sink object 74 | * \param info info structure 75 | * \param info_name app name 76 | * \param info_date date 77 | * \return 0 on success otherwise an error code 78 | */ 79 | int (*write_info)(sink_t sink, glc_stream_info_t *info, 80 | const char *info_name, const char *info_date); 81 | /** 82 | * \brief write EOF message to file 83 | * \param sink sink object 84 | * \return 0 on success otherwise an error code 85 | */ 86 | int (*write_eof)(sink_t sink); 87 | /** 88 | * \brief write current stream state to file 89 | * \param sink sink object 90 | * \return 0 on success otherwise an error code 91 | */ 92 | int (*write_state)(sink_t sink); 93 | /** 94 | * \brief start writing process 95 | * 96 | * sink will write all data from source buffer to target sink 97 | * in a custom format that can be read back using file_read() 98 | * \param sink sink object 99 | * \param from source buffer 100 | * \return 0 on success otherwise an error code 101 | */ 102 | int (*write_process_start)(sink_t sink, ps_buffer_t *from); 103 | /** 104 | * \brief block until process has finished 105 | * \param sink sink object 106 | * \return 0 on success otherwise an error code 107 | */ 108 | int (*write_process_wait)(sink_t sink); 109 | int (*destroy)(sink_t sink); 110 | } sink_ops_t; 111 | 112 | struct sink_s 113 | { 114 | sink_ops_t *ops; 115 | }; 116 | 117 | #ifdef __cplusplus 118 | } 119 | #endif 120 | 121 | #endif 122 | 123 | -------------------------------------------------------------------------------- /src/glc/core/source.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/source.h 3 | * \brief Abstract source interface 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | #ifndef _SOURCE_H 27 | #define _SOURCE_H 28 | 29 | #include 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | typedef struct source_s* source_t; 37 | 38 | typedef struct 39 | { 40 | /** 41 | * \brief open file for reading 42 | * 43 | * \param source source object 44 | * \param filename source file 45 | * \return 0 on success otherwise an error code 46 | */ 47 | int (*open_source)(source_t source, const char *filename); 48 | /** 49 | * \brief close source file 50 | * \param source source object 51 | * \return 0 on success otherwise an error code 52 | */ 53 | int (*close_source)(source_t source); 54 | /** 55 | * \brief read stream information 56 | * \note info_name and info_date are allocated but file_destroy() 57 | * won't free them. 58 | * \param source source object 59 | * \param info info structure 60 | * \param info_name app name 61 | * \param info_date date 62 | * \return 0 on success otherwise an error code 63 | */ 64 | int (*read_info)(source_t source, glc_stream_info_t *info, 65 | char **info_name, char **info_date); 66 | /** 67 | * \brief read stream from file and write it into buffer 68 | * \param source source object 69 | * \param to buffer 70 | * \return 0 on success otherwise an error code 71 | */ 72 | int (*read)(source_t source, ps_buffer_t *to); 73 | int (*destroy)(source_t source); 74 | } source_ops_t; 75 | 76 | struct source_s 77 | { 78 | source_ops_t *ops; 79 | }; 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | 85 | #endif 86 | 87 | -------------------------------------------------------------------------------- /src/glc/core/tracker.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/tracker.c 3 | * \brief glc state tracker adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup tracker 28 | * \{ 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | #include "tracker.h" 40 | 41 | #define TRACKER_VIDEO_FORMAT 0x01 42 | #define TRACKER_VIDEO_COLOR 0x02 43 | 44 | struct tracker_video_s { 45 | glc_stream_id_t id; 46 | glc_flags_t flags; 47 | glc_video_format_message_t format; 48 | glc_color_message_t color; 49 | struct tracker_video_s *next; 50 | }; 51 | 52 | #define TRACKER_AUDIO_FORMAT 0x01 53 | 54 | struct tracker_audio_s { 55 | glc_stream_id_t id; 56 | glc_flags_t flags; 57 | glc_audio_format_message_t format; 58 | struct tracker_audio_s *next; 59 | }; 60 | 61 | struct tracker_s { 62 | glc_t *glc; 63 | 64 | struct tracker_video_s *video_streams; 65 | struct tracker_audio_s *audio_streams; 66 | }; 67 | 68 | struct tracker_video_s *tracker_get_video_stream(tracker_t tracker, glc_stream_id_t id); 69 | struct tracker_audio_s *tracker_get_audio_stream(tracker_t tracker, glc_stream_id_t id); 70 | 71 | int tracker_init(tracker_t *tracker, glc_t *glc) 72 | { 73 | *tracker = (tracker_t) calloc(1, sizeof(struct tracker_s)); 74 | return 0; 75 | } 76 | 77 | int tracker_destroy(tracker_t tracker) 78 | { 79 | struct tracker_video_s *video_del; 80 | struct tracker_audio_s *audio_del; 81 | 82 | while (tracker->video_streams != NULL) { 83 | video_del = tracker->video_streams; 84 | tracker->video_streams = tracker->video_streams->next; 85 | free(video_del); 86 | } 87 | 88 | while (tracker->audio_streams != NULL) { 89 | audio_del = tracker->audio_streams; 90 | tracker->audio_streams = tracker->audio_streams->next; 91 | free(audio_del); 92 | } 93 | 94 | free(tracker); 95 | return 0; 96 | } 97 | 98 | struct tracker_video_s *tracker_get_video_stream(tracker_t tracker, glc_stream_id_t id) 99 | { 100 | struct tracker_video_s *video = tracker->video_streams; 101 | 102 | while (video != NULL) { 103 | if (video->id == id) 104 | break; 105 | video = video->next; 106 | } 107 | 108 | if (video == NULL) { 109 | video = (struct tracker_video_s *) calloc(1, sizeof(struct tracker_video_s)); 110 | 111 | video->next = tracker->video_streams; 112 | tracker->video_streams = video; 113 | } 114 | 115 | return video; 116 | } 117 | 118 | struct tracker_audio_s *tracker_get_audio_stream(tracker_t tracker, glc_stream_id_t id) 119 | { 120 | struct tracker_audio_s *audio = tracker->audio_streams; 121 | 122 | while (audio != NULL) { 123 | if (audio->id == id) 124 | break; 125 | audio = audio->next; 126 | } 127 | 128 | if (audio == NULL) { 129 | audio = (struct tracker_audio_s *) calloc(1, sizeof(struct tracker_audio_s)); 130 | 131 | audio->next = tracker->audio_streams; 132 | tracker->audio_streams = audio; 133 | } 134 | 135 | return audio; 136 | } 137 | 138 | 139 | int tracker_submit(tracker_t tracker, glc_message_header_t *header, 140 | void *message, size_t message_size) 141 | { 142 | struct tracker_video_s *video; 143 | struct tracker_audio_s *audio; 144 | 145 | if (header->type == GLC_MESSAGE_VIDEO_FORMAT) { 146 | video = tracker_get_video_stream(tracker, ((glc_video_format_message_t *) message)->id); 147 | memcpy(&video->format, message, sizeof(glc_video_format_message_t)); 148 | video->flags |= TRACKER_VIDEO_FORMAT; 149 | } else if (header->type == GLC_MESSAGE_AUDIO_FORMAT) { 150 | audio = tracker_get_audio_stream(tracker, ((glc_audio_format_message_t *) message)->id); 151 | memcpy(&audio->format, message, sizeof(glc_audio_format_message_t)); 152 | audio->flags |= TRACKER_AUDIO_FORMAT; 153 | } else if (header->type == GLC_MESSAGE_COLOR) { 154 | video = tracker_get_video_stream(tracker, ((glc_color_message_t *) message)->id); 155 | memcpy(&video->color, message, sizeof(glc_color_message_t)); 156 | video->flags |= TRACKER_VIDEO_COLOR; 157 | } 158 | 159 | return 0; 160 | } 161 | 162 | int tracker_iterate_state(tracker_t tracker, tracker_callback_t callback, 163 | void *arg) 164 | { 165 | int ret = 0; 166 | struct tracker_video_s *video = tracker->video_streams; 167 | struct tracker_audio_s *audio = tracker->audio_streams; 168 | glc_message_header_t header; 169 | 170 | while (video != NULL) { 171 | if (video->flags & TRACKER_VIDEO_FORMAT) { 172 | header.type = GLC_MESSAGE_VIDEO_FORMAT; 173 | if ((ret = callback(&header, &video->format, 174 | sizeof(glc_video_format_message_t), arg))) 175 | goto finish; 176 | } 177 | 178 | if (video->flags & TRACKER_VIDEO_COLOR) { 179 | header.type = GLC_MESSAGE_COLOR; 180 | if ((ret = callback(&header, &video->color, 181 | sizeof(glc_color_message_t), arg))) 182 | goto finish; 183 | } 184 | 185 | video = video->next; 186 | } 187 | 188 | while (audio != NULL) { 189 | if (audio->flags & TRACKER_AUDIO_FORMAT) { 190 | header.type = GLC_MESSAGE_AUDIO_FORMAT; 191 | if ((ret = callback(&header, &audio->format, 192 | sizeof(glc_audio_format_message_t), arg))) 193 | goto finish; 194 | } 195 | 196 | audio = audio->next; 197 | } 198 | 199 | finish: 200 | return ret; 201 | } 202 | 203 | -------------------------------------------------------------------------------- /src/glc/core/tracker.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/tracker.h 3 | * \brief glc state tracker interface 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup core 11 | * \{ 12 | * \defgroup tracker glc state tracker 13 | * \{ 14 | */ 15 | 16 | #ifndef _TRACKER_H 17 | #define _TRACKER_H 18 | 19 | #include 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | /** glc state tracker object */ 26 | typedef struct tracker_s* tracker_t; 27 | 28 | /** callback prototype for iterating */ 29 | typedef int (*tracker_callback_t)(glc_message_header_t *header, void *message, 30 | size_t message_size, void *arg); 31 | 32 | /** 33 | * \brief initialize glc state tracker 34 | * \param tracker state tracker object 35 | * \param glc glc 36 | * \return 0 on success otherwise an error code 37 | */ 38 | __PUBLIC int tracker_init(tracker_t *tracker, glc_t *glc); 39 | 40 | /** 41 | * \brief destroy glc state tracker 42 | * \param tracker state tracker object 43 | * \return 0 on success otherwise an error code 44 | */ 45 | __PUBLIC int tracker_destroy(tracker_t tracker); 46 | 47 | /** 48 | * \brief submit message to tracker 49 | * \param tracker state tracker object 50 | * \param header message header 51 | * \param message pointer to message data 52 | * \param message_size message size 53 | * \return 0 on success otherwise an error code 54 | */ 55 | __PUBLIC int tracker_submit(tracker_t tracker, glc_message_header_t *header, 56 | void *message, size_t message_size); 57 | 58 | /** 59 | * \brief iterate current state 60 | * \param tracker state tracker object 61 | * \param callback callback function 62 | * \param arg custom argument to callback 63 | * \return 0 on success otherwise an error code 64 | */ 65 | __PUBLIC int tracker_iterate_state(tracker_t tracker, tracker_callback_t callback, 66 | void *arg); 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif 73 | 74 | /** \} */ 75 | /** \} */ 76 | -------------------------------------------------------------------------------- /src/glc/core/ycbcr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/core/ycbcr.h 3 | * \brief convert BGR to Y'CbCr and scale 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup core 11 | * \{ 12 | * \defgroup ycbcr convert BGR to Y'CbCr and scale 13 | * \{ 14 | */ 15 | 16 | #ifndef _YCBCR_H 17 | #define _YCBCR_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief ycbcr object 28 | */ 29 | typedef struct ycbcr_s* ycbcr_t; 30 | 31 | /** 32 | * \brief initialize ycbcr object 33 | * \param ycbcr ycbcr object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int ycbcr_init(ycbcr_t *ycbcr, glc_t *glc); 38 | 39 | /** 40 | * \brief set scaling factor 41 | * \param ycbcr ycbr object 42 | * \param scale scale factor 43 | * \return 0 on success otherwise an error code 44 | */ 45 | __PUBLIC int ycbcr_set_scale(ycbcr_t ycbcr, double scale); 46 | 47 | /** 48 | * \brief process data and transfer between buffers 49 | * 50 | * ycbcr process converts all BGR and BGRA frames into 51 | * YCBCR_420JPEG and optionally does rescaling. Downscaling 52 | * is cheap operation and mostly makes actual conversion much 53 | * faster since smaller amount of data has to be converted. 54 | * 55 | * This returns immediately. Actual processing is done in 56 | * different thread. 57 | * \param ycbcr ycbcr object 58 | * \param from source buffer 59 | * \param to target buffer 60 | * \return 0 on success otherwise an error code 61 | */ 62 | __PUBLIC int ycbcr_process_start(ycbcr_t ycbcr, ps_buffer_t *from, 63 | ps_buffer_t *to); 64 | 65 | /** 66 | * \brief block until current process has finished 67 | * \param ycbcr ycbcr object 68 | * \return 0 on success otherwise an error code 69 | */ 70 | __PUBLIC int ycbcr_process_wait(ycbcr_t ycbcr); 71 | 72 | /** 73 | * \brief destroy ycbcr object 74 | * \param ycbcr ycbcr object to destroy 75 | * \return 0 on success otherwise an error code 76 | */ 77 | __PUBLIC int ycbcr_destroy(ycbcr_t ycbcr); 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif 84 | 85 | /** \} */ 86 | /** \} */ 87 | -------------------------------------------------------------------------------- /src/glc/export/img.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/export/img.c 3 | * \brief export to images adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup img 28 | * \{ 29 | */ 30 | 31 | /** \todo employ threads in image compression */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "img.h" 48 | 49 | struct img_private_s; 50 | typedef int (*img_write_proc)(img_t img, 51 | const unsigned char *pic, 52 | unsigned int w, 53 | unsigned int h, 54 | const char *filename); 55 | 56 | struct img_s { 57 | glc_t *glc; 58 | glc_thread_t thread; 59 | int running; 60 | 61 | glc_stream_id_t id; 62 | 63 | const char *filename_format; 64 | 65 | double fps; 66 | glc_utime_t fps_usec; 67 | 68 | unsigned int w, h; 69 | unsigned int row; 70 | unsigned char *prev_video_frame_message; 71 | glc_utime_t time; 72 | int i; 73 | 74 | img_write_proc write_proc; 75 | }; 76 | 77 | static void img_finish_callback(void *ptr, int err); 78 | static int img_read_callback(glc_thread_state_t *state); 79 | 80 | static int img_video_format_message(img_t img, glc_video_format_message_t *video_format); 81 | static int img_video_frame_message(img_t img, glc_video_frame_header_t *pic_hdr, 82 | const unsigned char *pic, size_t pic_size); 83 | 84 | static int img_write_bmp(img_t img, const unsigned char *pic, 85 | unsigned int w, unsigned int h, 86 | const char *filename); 87 | static int img_write_png(img_t img, const unsigned char *pic, 88 | unsigned int w, unsigned int h, 89 | const char *filename); 90 | 91 | int img_init(img_t *img, glc_t *glc) 92 | { 93 | *img = (img_t) calloc(1, sizeof(struct img_s)); 94 | 95 | (*img)->glc = glc; 96 | (*img)->fps = 30; 97 | (*img)->fps_usec = 1000000 / (*img)->fps; 98 | (*img)->write_proc = &img_write_png; 99 | (*img)->filename_format = "frame%08d.png"; 100 | (*img)->id = 1; 101 | 102 | (*img)->thread.flags = GLC_THREAD_READ; 103 | (*img)->thread.ptr = *img; 104 | (*img)->thread.read_callback = &img_read_callback; 105 | (*img)->thread.finish_callback = &img_finish_callback; 106 | (*img)->thread.threads = 1; 107 | 108 | return 0; 109 | } 110 | 111 | int img_destroy(img_t img) 112 | { 113 | free(img); 114 | return 0; 115 | } 116 | 117 | int img_process_start(img_t img, ps_buffer_t *from) 118 | { 119 | int ret; 120 | if (unlikely(img->running)) 121 | return EAGAIN; 122 | 123 | if (unlikely((ret = glc_thread_create(img->glc, &img->thread, from, NULL)))) 124 | return ret; 125 | img->running = 1; 126 | 127 | return 0; 128 | } 129 | 130 | int img_process_wait(img_t img) 131 | { 132 | if (unlikely(!img->running)) 133 | return EAGAIN; 134 | 135 | glc_thread_wait(&img->thread); 136 | img->running = 0; 137 | 138 | return 0; 139 | } 140 | 141 | int img_set_fps(img_t img, double fps) 142 | { 143 | img->fps = fps; 144 | img->fps_usec = 1000000 / img->fps; 145 | return 0; 146 | } 147 | 148 | int img_set_filename(img_t img, const char *filename) 149 | { 150 | img->filename_format = filename; 151 | return 0; 152 | } 153 | 154 | int img_set_format(img_t img, int format) 155 | { 156 | if (format == IMG_PNG) 157 | img->write_proc = &img_write_png; 158 | else if (format == IMG_BMP) 159 | img->write_proc = &img_write_bmp; 160 | else { 161 | glc_log(img->glc, GLC_ERROR, "img", 162 | "unknown format 0x%02x", format); 163 | return EINVAL; 164 | } 165 | 166 | return 0; 167 | } 168 | 169 | int img_set_stream_id(img_t img, glc_stream_id_t id) 170 | { 171 | img->id = id; 172 | return 0; 173 | } 174 | 175 | void img_finish_callback(void *ptr, int err) 176 | { 177 | img_t img = (img_t) ptr; 178 | 179 | glc_log(img->glc, GLC_INFO, "img", "%d images written", img->i); 180 | 181 | if (unlikely(err)) 182 | glc_log(img->glc, GLC_ERROR, "img", "%s (%d)", strerror(err), err); 183 | 184 | if (img->prev_video_frame_message) { 185 | free(img->prev_video_frame_message); 186 | img->prev_video_frame_message = NULL; 187 | } 188 | 189 | img->i = 0; 190 | img->time = 0; 191 | } 192 | 193 | int img_read_callback(glc_thread_state_t *state) 194 | { 195 | img_t img = state->ptr; 196 | int ret = 0; 197 | 198 | if (state->header.type == GLC_MESSAGE_VIDEO_FORMAT) { 199 | ret = img_video_format_message(img, 200 | (glc_video_format_message_t *) state->read_data); 201 | } else if (state->header.type == GLC_MESSAGE_VIDEO_FRAME) { 202 | ret = img_video_frame_message(img, (glc_video_frame_header_t *) state->read_data, 203 | (const unsigned char *) &state->read_data[sizeof(glc_video_frame_header_t)], 204 | state->read_size); 205 | } 206 | 207 | return ret; 208 | } 209 | 210 | int img_video_format_message(img_t img, glc_video_format_message_t *video_format) 211 | { 212 | if (video_format->id != img->id) 213 | return 0; 214 | 215 | if (unlikely(video_format->format != GLC_VIDEO_BGR)) { 216 | glc_log(img->glc, GLC_ERROR, "img", 217 | "video stream %d is in unsupported format", video_format->id); 218 | return ENOTSUP; 219 | } 220 | 221 | img->w = video_format->width; 222 | img->h = video_format->height; 223 | img->row = img->w * 3; 224 | 225 | if (video_format->flags & GLC_VIDEO_DWORD_ALIGNED) { 226 | if (img->row % 8 != 0) 227 | img->row += 8 - img->row % 8; 228 | } 229 | 230 | if (img->prev_video_frame_message) 231 | img->prev_video_frame_message = (unsigned char *) 232 | realloc(img->prev_video_frame_message, img->row * img->h); 233 | else 234 | img->prev_video_frame_message = (unsigned char *) malloc(img->row * img->h); 235 | memset(img->prev_video_frame_message, 0, img->row * img->h); 236 | 237 | return 0; 238 | } 239 | 240 | int img_video_frame_message(img_t img, glc_video_frame_header_t *pic_hdr, 241 | const unsigned char *pic, size_t pic_size) 242 | { 243 | int ret = 0; 244 | char filename[1024]; 245 | 246 | if (pic_hdr->id != img->id) 247 | return 0; 248 | 249 | if (img->time < pic_hdr->time) { 250 | /* write previous pic until we are 'fps' away from current time */ 251 | while (img->time + img->fps_usec < pic_hdr->time) { 252 | img->time += img->fps_usec; 253 | 254 | snprintf(filename, sizeof(filename) - 1, img->filename_format, img->i++); 255 | img->write_proc(img, img->prev_video_frame_message, 256 | img->w, img->h, filename); 257 | } 258 | 259 | img->time += img->fps_usec; 260 | 261 | snprintf(filename, sizeof(filename) - 1, img->filename_format, img->i++); 262 | ret = img->write_proc(img, pic, img->w, img->h, filename); 263 | } 264 | 265 | memcpy(img->prev_video_frame_message, pic, pic_size); 266 | 267 | return ret; 268 | } 269 | 270 | int img_write_bmp(img_t img, const unsigned char *pic, 271 | unsigned int w, unsigned int h, const char *filename) 272 | { 273 | FILE *fd; 274 | unsigned int val; 275 | unsigned int i; 276 | 277 | glc_log(img->glc, GLC_INFO, "img", 278 | "opening %s for writing (BMP)", filename); 279 | if (unlikely(!(fd = fopen(filename, "w")))) 280 | return errno; 281 | 282 | fwrite("BM", 1, 2, fd); 283 | val = w * h * 3 + 54; 284 | fwrite(&val, 1, 4, fd); 285 | fwrite("\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00", 1, 12, fd); 286 | fwrite(&w, 1, 4, fd); 287 | fwrite(&h, 1, 4, fd); 288 | fwrite("\x01\x00\x18\x00\x00\x00\x00\x00", 1, 8, fd); 289 | val -= 54; 290 | fwrite(&val, 1, 4, fd); 291 | fwrite("\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00", 1, 16, fd); 292 | 293 | for (i = 0; i < h; i++) { 294 | fwrite(&pic[i * img->row], 1, w * 3, fd); 295 | if ((w * 3) % 4 != 0) 296 | fwrite("\x00\x00\x00\x00", 1, 4 - ((w * 3) % 4), fd); 297 | } 298 | 299 | fclose(fd); 300 | 301 | return 0; 302 | } 303 | 304 | int img_write_png(img_t img, const unsigned char *pic, 305 | unsigned int w, unsigned int h, 306 | const char *filename) 307 | { 308 | png_structp png_ptr; 309 | png_infop info_ptr; 310 | png_bytep *row_pointers; 311 | unsigned int i; 312 | FILE *fd; 313 | 314 | glc_log(img->glc, GLC_INFO, "img", 315 | "opening %s for writing (PNG)", filename); 316 | if (unlikely(!(fd = fopen(filename, "w")))) 317 | return errno; 318 | 319 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 320 | (png_voidp) NULL, NULL, NULL); 321 | info_ptr = png_create_info_struct(png_ptr); 322 | setjmp(png_jmpbuf(png_ptr)); 323 | png_init_io(png_ptr, fd); 324 | png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB, 325 | PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, 326 | PNG_FILTER_TYPE_DEFAULT); 327 | png_set_bgr(png_ptr); 328 | row_pointers = (png_bytep *) png_malloc(png_ptr, h * sizeof(png_bytep)); 329 | 330 | for (i = 0; i < h; i++) 331 | row_pointers[i] = (png_bytep) &pic[(h - i - 1) * img->row]; 332 | 333 | png_set_rows(png_ptr, info_ptr, row_pointers); 334 | png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); 335 | png_free(png_ptr, row_pointers); 336 | png_destroy_write_struct(&png_ptr, &info_ptr); 337 | 338 | fclose(fd); 339 | 340 | return 0; 341 | } 342 | 343 | /** \} */ 344 | -------------------------------------------------------------------------------- /src/glc/export/img.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/export/img.h 3 | * \brief export to images 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup export 11 | * \{ 12 | * \defgroup img export to images 13 | * \{ 14 | */ 15 | 16 | #ifndef _IMG_H 17 | #define _IMG_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** BMP format */ 27 | #define IMG_BMP 0x1 28 | /** PNG format */ 29 | #define IMG_PNG 0x2 30 | 31 | /** 32 | * \brief img object 33 | */ 34 | typedef struct img_s* img_t; 35 | 36 | /** 37 | * \brief initialize img object 38 | * \param img img object 39 | * \param glc glc 40 | * \return 0 on success otherwise an error code 41 | */ 42 | __PUBLIC int img_init(img_t *img, glc_t *glc); 43 | 44 | /** 45 | * \brief destroy img object 46 | * \param img img object 47 | * \return 0 on success otherwise an error code 48 | */ 49 | __PUBLIC int img_destroy(img_t img); 50 | 51 | /** 52 | * \brief set filename format 53 | * 54 | * %d in filename is substituted with frame number. 55 | * 56 | * Default format is "frame%08d.png" 57 | * \param img img object 58 | * \param filename filename format 59 | * \return 0 on success otherwise an error code 60 | */ 61 | __PUBLIC int img_set_filename(img_t img, const char *filename); 62 | 63 | /** 64 | * \brief set video stream number 65 | * 66 | * Only frames from one video stream will be written. Default 67 | * stream number is 1. 68 | * \param img img object 69 | * \param id video stream id 70 | * \return 0 on success otherwise an error code 71 | */ 72 | __PUBLIC int img_set_stream_id(img_t img, glc_stream_id_t id); 73 | 74 | /** 75 | * \brief set fps 76 | * 77 | * Default fps is 30. 78 | * \param img img object 79 | * \param fps fps 80 | * \return 0 on success otherwise an error code 81 | */ 82 | __PUBLIC int img_set_fps(img_t img, double fps); 83 | 84 | /** 85 | * \brief set format 86 | * 87 | * Currently BMP (IMG_BMP) and PNG (IMG_PNG) are supported. 88 | * 89 | * Default format is PNG. 90 | * \param img img object 91 | * \param format image format 92 | * \return 0 on success otherwise an error code 93 | */ 94 | __PUBLIC int img_set_format(img_t img, int format); 95 | 96 | /** 97 | * \brief start img process 98 | * 99 | * img writes RGB (BGR only) frames in selected video stream 100 | * into separate image files. 101 | * \param img img object 102 | * \param from source buffer 103 | * \return 0 on success otherwise an error code 104 | */ 105 | __PUBLIC int img_process_start(img_t img, ps_buffer_t *from); 106 | 107 | /** 108 | * \brief block until process has finished 109 | * \param img img object 110 | * \return 0 on success otherwise an error code 111 | */ 112 | __PUBLIC int img_process_wait(img_t img); 113 | 114 | #ifdef __cplusplus 115 | } 116 | #endif 117 | 118 | #endif 119 | 120 | /** \} */ 121 | /** \} */ 122 | -------------------------------------------------------------------------------- /src/glc/export/wav.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/export/wav.c 3 | * \brief export audio to wav adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup wav 28 | * \{ 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "wav.h" 47 | 48 | struct wav_hdr { 49 | u_int32_t id; 50 | u_int32_t size; 51 | u_int32_t riff; 52 | } __attribute__((packed)); 53 | 54 | struct wav_fmt { 55 | u_int32_t id; 56 | u_int32_t size; 57 | u_int16_t compression; 58 | u_int16_t channels; 59 | u_int32_t rate; 60 | u_int32_t bps; 61 | u_int16_t align; 62 | u_int16_t bits_per_sample; 63 | } __attribute__((packed)); 64 | 65 | struct wav_data { 66 | u_int32_t id; 67 | u_int32_t size; 68 | } __attribute__((packed)); 69 | 70 | struct wav_s { 71 | glc_t *glc; 72 | glc_thread_t thread; 73 | int running; 74 | 75 | glc_stream_id_t id; 76 | int interpolate; 77 | 78 | unsigned int file_count; 79 | const char *filename_format; 80 | 81 | char *silence; 82 | size_t silence_size; 83 | glc_utime_t silence_threshold; 84 | 85 | FILE *to; 86 | 87 | glc_utime_t time; 88 | unsigned int rate, channels, interleaved; 89 | size_t bps; 90 | size_t sample_size; 91 | 92 | struct audio_stream_s *stream; 93 | }; 94 | 95 | static int wav_read_callback(glc_thread_state_t *state); 96 | static void wav_finish_callback(void *priv, int err); 97 | 98 | static int wav_write_hdr(wav_t wav, glc_audio_format_message_t *fmt_msg); 99 | static int wav_write_audio(wav_t wav, glc_audio_data_header_t *audio_msg, char *data); 100 | 101 | int wav_init(wav_t *wav, glc_t *glc) 102 | { 103 | *wav = (wav_t) calloc(1, sizeof(struct wav_s)); 104 | 105 | (*wav)->glc = glc; 106 | 107 | (*wav)->filename_format = "audio%02d.wav"; 108 | (*wav)->silence_threshold = 200000; /* 0.2s */ 109 | (*wav)->id = 1; 110 | (*wav)->interpolate = 1; 111 | 112 | (*wav)->silence_size = 1024; 113 | (*wav)->silence = (char *) calloc(1, (*wav)->silence_size); 114 | 115 | (*wav)->thread.flags = GLC_THREAD_READ; 116 | (*wav)->thread.ptr = *wav; 117 | (*wav)->thread.read_callback = &wav_read_callback; 118 | (*wav)->thread.finish_callback = &wav_finish_callback; 119 | (*wav)->thread.threads = 1; 120 | 121 | return 0; 122 | } 123 | 124 | int wav_destroy(wav_t wav) 125 | { 126 | free(wav->silence); 127 | free(wav); 128 | return 0; 129 | } 130 | 131 | int wav_process_start(wav_t wav, ps_buffer_t *from) 132 | { 133 | int ret; 134 | if (unlikely(wav->running)) 135 | return EAGAIN; 136 | 137 | if (unlikely((ret = glc_thread_create(wav->glc, &wav->thread, from, NULL)))) 138 | return ret; 139 | wav->running = 1; 140 | 141 | return 0; 142 | } 143 | 144 | int wav_process_wait(wav_t wav) 145 | { 146 | if (unlikely(!wav->running)) 147 | return EAGAIN; 148 | 149 | glc_thread_wait(&wav->thread); 150 | wav->running = 0; 151 | 152 | return 0; 153 | } 154 | 155 | int wav_set_interpolation(wav_t wav, int interpolate) 156 | { 157 | wav->interpolate = interpolate; 158 | return 0; 159 | } 160 | 161 | int wav_set_filename(wav_t wav, const char *filename) 162 | { 163 | wav->filename_format = filename; 164 | return 0; 165 | } 166 | 167 | int wav_set_stream_id(wav_t wav, glc_stream_id_t id) 168 | { 169 | wav->id = id; 170 | return 0; 171 | } 172 | 173 | int wav_set_silence_threshold(wav_t wav, glc_utime_t silence_threshold) 174 | { 175 | wav->silence_threshold = silence_threshold; 176 | return 0; 177 | } 178 | 179 | void wav_finish_callback(void *priv, int err) 180 | { 181 | wav_t wav = (wav_t ) priv; 182 | 183 | if (unlikely(err)) 184 | glc_log(wav->glc, GLC_ERROR, "wav", "%s (%d)", strerror(err), err); 185 | 186 | if (wav->to) { 187 | fclose(wav->to); 188 | wav->to = NULL; 189 | } 190 | 191 | wav->file_count = 0; 192 | } 193 | 194 | int wav_read_callback(glc_thread_state_t *state) 195 | { 196 | wav_t wav = (wav_t ) state->ptr; 197 | 198 | if (state->header.type == GLC_MESSAGE_AUDIO_FORMAT) 199 | return wav_write_hdr(wav, (glc_audio_format_message_t *) state->read_data); 200 | else if (state->header.type == GLC_MESSAGE_AUDIO_DATA) 201 | return wav_write_audio(wav, (glc_audio_data_header_t *) state->read_data, 202 | &state->read_data[sizeof(glc_audio_data_header_t)]); 203 | 204 | return 0; 205 | } 206 | 207 | int wav_write_hdr(wav_t wav, glc_audio_format_message_t *fmt_msg) 208 | { 209 | int sample_size; 210 | char *filename; 211 | 212 | if (fmt_msg->id != wav->id) 213 | return 0; 214 | 215 | if (fmt_msg->format == GLC_AUDIO_S16_LE) 216 | sample_size = 2; 217 | else if (fmt_msg->format == GLC_AUDIO_S24_LE) 218 | sample_size = 3; 219 | else if (fmt_msg->format == GLC_AUDIO_S32_LE) 220 | sample_size = 4; 221 | else { 222 | glc_log(wav->glc, GLC_ERROR, "wav", 223 | "unsupported format 0x%02x (stream %d)", fmt_msg->flags, fmt_msg->id); 224 | return ENOTSUP; 225 | } 226 | 227 | if (wav->to) { 228 | glc_log(wav->glc, GLC_ERROR, "wav", 229 | "configuration update msg to stream %d", fmt_msg->id); 230 | fclose(wav->to); 231 | } 232 | 233 | filename = (char *) malloc(1024); 234 | snprintf(filename, 1023, wav->filename_format, ++wav->file_count); 235 | glc_log(wav->glc, GLC_INFO, "wav", "opening %s for writing", filename); 236 | wav->to = fopen(filename, "w"); 237 | if (unlikely(!wav->to)) { 238 | glc_log(wav->glc, GLC_ERROR, "wav", "can't open %s", filename); 239 | free(filename); 240 | return EINVAL; 241 | } 242 | free(filename); 243 | 244 | struct wav_hdr hdr = {0x46464952, 0xffffffff, 0x45564157}; 245 | struct wav_fmt fmt = {0x20746D66, /* id */ 246 | 16, /* chunk size */ 247 | 1, /* compression */ 248 | fmt_msg->channels, /* channels */ 249 | fmt_msg->rate, /* rate */ 250 | fmt_msg->rate * sample_size * fmt_msg->channels, /* bps */ 251 | sample_size * 2, /* block align */ 252 | sample_size * 8 /* bits per sample */ }; 253 | struct wav_data data = {0x61746164, 0xffffffff}; 254 | 255 | fwrite(&hdr, 1, sizeof(struct wav_hdr), wav->to); 256 | fwrite(&fmt, 1, sizeof(struct wav_fmt), wav->to); 257 | fwrite(&data, 1, sizeof(struct wav_data), wav->to); 258 | 259 | wav->sample_size = sample_size; 260 | wav->bps = fmt.bps; 261 | wav->rate = fmt_msg->rate; 262 | wav->channels = fmt_msg->channels; 263 | if (fmt_msg->flags & GLC_AUDIO_INTERLEAVED) 264 | wav->interleaved = 1; 265 | else 266 | wav->interleaved = 0; 267 | return 0; 268 | } 269 | 270 | int wav_write_audio(wav_t wav, glc_audio_data_header_t *audio_hdr, char *data) 271 | { 272 | size_t need_silence, write_silence; 273 | unsigned int c; 274 | size_t samples, s; 275 | 276 | if (audio_hdr->id != wav->id) 277 | return 0; 278 | 279 | glc_utime_t duration = ((glc_utime_t) audio_hdr->size * (glc_utime_t) 1000000) / (glc_utime_t) wav->bps; 280 | 281 | if (unlikely(!wav->to)) { 282 | glc_log(wav->glc, GLC_ERROR, "wav", "broken stream %d", audio_hdr->id); 283 | return EINVAL; 284 | } 285 | 286 | wav->time += duration; 287 | 288 | if (wav->time + wav->silence_threshold < audio_hdr->time) { 289 | need_silence = ((audio_hdr->time - wav->time) * (glc_utime_t) wav->bps) / (glc_utime_t) 1000000; 290 | need_silence -= need_silence % ((size_t) wav->sample_size * (size_t) wav->channels); 291 | 292 | wav->time += ((glc_utime_t) need_silence * (glc_utime_t) 1000000) / (glc_utime_t) wav->bps; 293 | if (wav->interpolate) { 294 | glc_log(wav->glc, GLC_WARN, "wav", "writing %zd bytes of silence", need_silence); 295 | while (need_silence > 0) { 296 | write_silence = need_silence > wav->silence_size ? wav->silence_size : need_silence; 297 | fwrite(wav->silence, 1, write_silence, wav->to); 298 | need_silence -= write_silence; 299 | } 300 | } 301 | } 302 | 303 | if (wav->interleaved) 304 | fwrite(data, 1, audio_hdr->size, wav->to); 305 | else { 306 | samples = audio_hdr->size / (wav->sample_size * wav->channels); 307 | for (s = 0; s < samples; s++) { 308 | for (c = 0; c < wav->channels; c++) 309 | fwrite(&data[samples * wav->sample_size * c + wav->sample_size * s], 1, wav->sample_size, wav->to); 310 | } 311 | } 312 | 313 | return 0; 314 | } 315 | 316 | 317 | /** \} */ 318 | -------------------------------------------------------------------------------- /src/glc/export/wav.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/export/wav.h 3 | * \brief export audio to wav 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup export 11 | * \{ 12 | * \defgroup wav export audio to wav 13 | * \{ 14 | */ 15 | 16 | #ifndef _WAV_H 17 | #define _WAV_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief wav object 28 | */ 29 | typedef struct wav_s* wav_t; 30 | 31 | /** 32 | * \brief initialize wav object 33 | * \param wav wav object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int wav_init(wav_t *wav, glc_t *glc); 38 | 39 | /** 40 | * \brief destroy wav object 41 | * \param wav wav object 42 | * \return 0 on success otherwise an error code 43 | */ 44 | __PUBLIC int wav_destroy(wav_t wav); 45 | 46 | /** 47 | * \brief set filename format 48 | * 49 | * WAV format doesn't support changing data format so 50 | * if audio stream configuration changes, wav has to start 51 | * a new stream file. 52 | * 53 | * %d in filename is substituted with counter. 54 | * 55 | * Default format is "audio%02d.wav" 56 | * \param wav wav object 57 | * \param filename filename format 58 | * \return 0 on success otherwise an error code 59 | */ 60 | __PUBLIC int wav_set_filename(wav_t wav, const char *filename); 61 | 62 | /** 63 | * \brief set audio stream number 64 | * 65 | * Only audio from one audio stream will be written. Default 66 | * stream number is 1. 67 | * \param wav wav object 68 | * \param id audio stream id 69 | * \return 0 on success otherwise an error code 70 | */ 71 | __PUBLIC int wav_set_stream_id(wav_t wav, glc_stream_id_t id); 72 | 73 | /** 74 | * \brief set interpolation 75 | * 76 | * By default silence is written if audio data is missing 77 | * to preserve a/v sync. 78 | * \param wav wav object 79 | * \param interpolate 1 means missing data is interpolated (silence), 80 | * 0 disables interpolation and a/v sync is lost. 81 | * \return 0 on success otherwise an error code 82 | */ 83 | __PUBLIC int wav_set_interpolation(wav_t wav, int interpolate); 84 | 85 | /** 86 | * \brief set silence threshold 87 | * 88 | * Default silence threshold is 200 000 usec = 0.2s. 89 | * \param wav wav object 90 | * \param silence_threshold silence threshold 91 | * \return 0 on success otherwise an error code 92 | */ 93 | __PUBLIC int wav_set_silence_threshold(wav_t wav, glc_utime_t silence_threshold); 94 | 95 | /** 96 | * \brief start wav process 97 | * 98 | * wav writes audio data from selected audio stream into 99 | * WAV-formatted file. 100 | * \param wav wav object 101 | * \param from source buffer 102 | * \return 0 on success otherwise an error code 103 | */ 104 | __PUBLIC int wav_process_start(wav_t wav, ps_buffer_t *from); 105 | 106 | /** 107 | * \brief block until process has finished 108 | * \param wav wav object 109 | * \return 0 on success otherwise an error code 110 | */ 111 | __PUBLIC int wav_process_wait(wav_t wav); 112 | 113 | #ifdef __cplusplus 114 | } 115 | #endif 116 | 117 | #endif 118 | 119 | /** \} */ 120 | /** \} */ 121 | -------------------------------------------------------------------------------- /src/glc/export/yuv4mpeg.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/export/yuv4mpeg.c 3 | * \brief yuv4mpeg output adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \addtogroup yuv4mpeg 28 | * \{ 29 | */ 30 | 31 | #define _FILE_OFFSET_BITS 64 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "yuv4mpeg.h" 49 | 50 | struct yuv4mpeg_s { 51 | glc_t *glc; 52 | glc_thread_t thread; 53 | int running; 54 | 55 | unsigned int file_count; 56 | FILE *to; 57 | 58 | glc_utime_t time; 59 | glc_utime_t fps_usec; 60 | double fps; 61 | 62 | unsigned int size; 63 | char *prev_video_frame_message; 64 | int interpolate; 65 | 66 | const char *filename_format; 67 | glc_stream_id_t id; 68 | }; 69 | 70 | static int yuv4mpeg_read_callback(glc_thread_state_t *state); 71 | static void yuv4mpeg_finish_callback(void *priv, int err); 72 | 73 | static int yuv4mpeg_handle_hdr(yuv4mpeg_t yuv4mpeg, glc_video_format_message_t *video_format); 74 | static int yuv4mpeg_handle_video_frame_message(yuv4mpeg_t yuv4mpeg, 75 | glc_video_frame_header_t *pic_header, char *data); 76 | static int yuv4mpeg_write_video_frame_message(yuv4mpeg_t yuv4mpeg, char *pic); 77 | 78 | int yuv4mpeg_init(yuv4mpeg_t *yuv4mpeg, glc_t *glc) 79 | { 80 | *yuv4mpeg = (yuv4mpeg_t) calloc(1, sizeof(struct yuv4mpeg_s)); 81 | 82 | (*yuv4mpeg)->glc = glc; 83 | (*yuv4mpeg)->fps = 30; 84 | (*yuv4mpeg)->fps_usec = 1000000 / (*yuv4mpeg)->fps; 85 | (*yuv4mpeg)->filename_format = "video%02d.glc"; 86 | (*yuv4mpeg)->id = 1; 87 | (*yuv4mpeg)->interpolate = 1; 88 | 89 | (*yuv4mpeg)->thread.flags = GLC_THREAD_READ; 90 | (*yuv4mpeg)->thread.ptr = *yuv4mpeg; 91 | (*yuv4mpeg)->thread.read_callback = &yuv4mpeg_read_callback; 92 | (*yuv4mpeg)->thread.finish_callback = &yuv4mpeg_finish_callback; 93 | (*yuv4mpeg)->thread.threads = 1; 94 | 95 | return 0; 96 | } 97 | 98 | int yuv4mpeg_destroy(yuv4mpeg_t yuv4mpeg) 99 | { 100 | free(yuv4mpeg); 101 | return 0; 102 | } 103 | 104 | int yuv4mpeg_set_filename(yuv4mpeg_t yuv4mpeg, const char *filename) 105 | { 106 | yuv4mpeg->filename_format = filename; 107 | return 0; 108 | } 109 | 110 | int yuv4mpeg_set_stream_id(yuv4mpeg_t yuv4mpeg, glc_stream_id_t id) 111 | { 112 | yuv4mpeg->id = id; 113 | return 0; 114 | } 115 | 116 | int yuv4mpeg_set_fps(yuv4mpeg_t yuv4mpeg, double fps) 117 | { 118 | yuv4mpeg->fps = fps; 119 | yuv4mpeg->fps_usec = 1000000 / fps; 120 | return 0; 121 | } 122 | 123 | int yuv4mpeg_set_interpolation(yuv4mpeg_t yuv4mpeg, int interpolate) 124 | { 125 | yuv4mpeg->interpolate = interpolate; 126 | return 0; 127 | } 128 | 129 | int yuv4mpeg_process_start(yuv4mpeg_t yuv4mpeg, ps_buffer_t *from) 130 | { 131 | int ret; 132 | if (unlikely(yuv4mpeg->running)) 133 | return EAGAIN; 134 | 135 | if (unlikely((ret = glc_thread_create(yuv4mpeg->glc, &yuv4mpeg->thread, from, NULL)))) 136 | return ret; 137 | yuv4mpeg->running = 1; 138 | 139 | return 0; 140 | } 141 | 142 | int yuv4mpeg_process_wait(yuv4mpeg_t yuv4mpeg) 143 | { 144 | if (unlikely(!yuv4mpeg->running)) 145 | return EAGAIN; 146 | 147 | glc_thread_wait(&yuv4mpeg->thread); 148 | yuv4mpeg->running = 0; 149 | 150 | return 0; 151 | } 152 | 153 | void yuv4mpeg_finish_callback(void *priv, int err) 154 | { 155 | yuv4mpeg_t yuv4mpeg = (yuv4mpeg_t) priv; 156 | 157 | if (unlikely(err)) 158 | glc_log(yuv4mpeg->glc, GLC_ERROR, "yuv4mpeg", "%s (%d)", strerror(err), err); 159 | 160 | if (yuv4mpeg->to) { 161 | fclose(yuv4mpeg->to); 162 | yuv4mpeg->to = NULL; 163 | } 164 | 165 | if (yuv4mpeg->prev_video_frame_message) { 166 | free(yuv4mpeg->prev_video_frame_message); 167 | yuv4mpeg->prev_video_frame_message = NULL; 168 | } 169 | 170 | yuv4mpeg->file_count = 0; 171 | yuv4mpeg->time = 0; 172 | } 173 | 174 | int yuv4mpeg_read_callback(glc_thread_state_t *state) 175 | { 176 | yuv4mpeg_t yuv4mpeg = (yuv4mpeg_t) state->ptr; 177 | 178 | if (state->header.type == GLC_MESSAGE_VIDEO_FORMAT) 179 | return yuv4mpeg_handle_hdr(yuv4mpeg, 180 | (glc_video_format_message_t *) state->read_data); 181 | else if (state->header.type == GLC_MESSAGE_VIDEO_FRAME) 182 | return yuv4mpeg_handle_video_frame_message(yuv4mpeg, 183 | (glc_video_frame_header_t *) state->read_data, 184 | &state->read_data[sizeof(glc_video_frame_header_t)]); 185 | 186 | return 0; 187 | } 188 | 189 | int yuv4mpeg_handle_hdr(yuv4mpeg_t yuv4mpeg, glc_video_format_message_t *video_format) 190 | { 191 | char *filename; 192 | unsigned int p, q; 193 | 194 | if (video_format->id != yuv4mpeg->id) 195 | return 0; 196 | 197 | if (unlikely(!(video_format->format == GLC_VIDEO_YCBCR_420JPEG))) 198 | return ENOTSUP; 199 | 200 | if (yuv4mpeg->to) { 201 | fclose(yuv4mpeg->to); 202 | glc_log(yuv4mpeg->glc, GLC_WARN, "yuv4mpeg", 203 | "video stream configuration changed"); 204 | } 205 | 206 | filename = (char *) malloc(1024); 207 | snprintf(filename, 1023, yuv4mpeg->filename_format, ++yuv4mpeg->file_count); 208 | glc_log(yuv4mpeg->glc, GLC_INFO, "yuv4mpeg", "opening %s for writing", filename); 209 | 210 | yuv4mpeg->to = fopen(filename, "w"); 211 | if (unlikely(!yuv4mpeg->to)) { 212 | glc_log(yuv4mpeg->glc, GLC_ERROR, "yuv4mpeg", "can't open %s", filename); 213 | free(filename); 214 | return EINVAL; 215 | } 216 | free(filename); 217 | 218 | yuv4mpeg->size = video_format->width * video_format->height + 219 | (video_format->width * video_format->height) / 2; 220 | 221 | if (yuv4mpeg->interpolate) { 222 | if (yuv4mpeg->prev_video_frame_message) 223 | yuv4mpeg->prev_video_frame_message = (char *) 224 | realloc(yuv4mpeg->prev_video_frame_message, yuv4mpeg->size); 225 | else 226 | yuv4mpeg->prev_video_frame_message = (char *) malloc(yuv4mpeg->size); 227 | 228 | /* Set Y' 0 */ 229 | memset(yuv4mpeg->prev_video_frame_message, 0, 230 | video_format->width * video_format->height); 231 | /* Set CbCr 128 */ 232 | memset(&yuv4mpeg->prev_video_frame_message[video_format->width * video_format->height], 233 | 128, (video_format->width * video_format->height) / 2); 234 | } 235 | 236 | /* calculate fps in p/q */ 237 | /** \todo something more intelligent perhaps... */ 238 | p = yuv4mpeg->fps; 239 | q = 1; 240 | while ((p != q * yuv4mpeg->fps) && (q < 1000)) { 241 | q *= 10; 242 | p = q * yuv4mpeg->fps; 243 | } 244 | 245 | fprintf(yuv4mpeg->to, "YUV4MPEG2 W%d H%d F%d:%d Ip\n", 246 | video_format->width, video_format->height, p, q); 247 | return 0; 248 | } 249 | 250 | int yuv4mpeg_handle_video_frame_message(yuv4mpeg_t yuv4mpeg, glc_video_frame_header_t *pic_hdr, char *data) 251 | { 252 | if (pic_hdr->id != yuv4mpeg->id) 253 | return 0; 254 | 255 | if (yuv4mpeg->time < pic_hdr->time) { 256 | while (yuv4mpeg->time + yuv4mpeg->fps_usec < pic_hdr->time) { 257 | if (yuv4mpeg->interpolate) 258 | yuv4mpeg_write_video_frame_message(yuv4mpeg, 259 | yuv4mpeg->prev_video_frame_message); 260 | yuv4mpeg->time += yuv4mpeg->fps_usec; 261 | } 262 | yuv4mpeg_write_video_frame_message(yuv4mpeg, data); 263 | yuv4mpeg->time += yuv4mpeg->fps_usec; 264 | } 265 | 266 | if (yuv4mpeg->interpolate) 267 | memcpy(yuv4mpeg->prev_video_frame_message, data, yuv4mpeg->size); 268 | 269 | return 0; 270 | } 271 | 272 | int yuv4mpeg_write_video_frame_message(yuv4mpeg_t yuv4mpeg, char *pic) 273 | { 274 | fprintf(yuv4mpeg->to, "FRAME\n"); 275 | fwrite(pic, 1, yuv4mpeg->size, yuv4mpeg->to); 276 | return 0; 277 | } 278 | 279 | /** \} */ 280 | -------------------------------------------------------------------------------- /src/glc/export/yuv4mpeg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/export/yuv4mpeg.h 3 | * \brief yuv4mpeg output 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup export 11 | * \{ 12 | * \defgroup yuv4mpeg yuv4mpeg output 13 | * \{ 14 | */ 15 | 16 | #ifndef _YUV4MPEG_H 17 | #define _YUV4MPEG_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief yuv4mpeg object 28 | */ 29 | typedef struct yuv4mpeg_s* yuv4mpeg_t; 30 | 31 | /** 32 | * \brief initialize yuv4mpeg object 33 | * \param yuv4mpeg yuv4mpeg object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int yuv4mpeg_init(yuv4mpeg_t *yuv4mpeg, glc_t *glc); 38 | 39 | /** 40 | * \brief destroy yuv4mpeg object 41 | * \param yuv4mpeg yuv4mpeg object 42 | * \return 0 on success otherwise an error code 43 | */ 44 | __PUBLIC int yuv4mpeg_destroy(yuv4mpeg_t yuv4mpeg); 45 | 46 | /** 47 | * \brief set filename format 48 | * 49 | * Y4M format doesn't support changing picture sizes so 50 | * if stream configuration changes, yuv4mpeg has to start a new 51 | * stream file. %d in filename is substituted with counter. 52 | * 53 | * Default format is "video%02d.y4m" 54 | * \param yuv4mpeg yuv4mpeg object 55 | * \param filename filename format 56 | * \return 0 on success otherwise an error code 57 | */ 58 | __PUBLIC int yuv4mpeg_set_filename(yuv4mpeg_t yuv4mpeg, const char *filename); 59 | 60 | /** 61 | * \brief set video stream number 62 | * 63 | * Only frames from one video stream will be written. Default 64 | * stream number is 1. 65 | * \param yuv4mpeg yuv4mpeg object 66 | * \param id video stream id 67 | * \return 0 on success otherwise an error code 68 | */ 69 | __PUBLIC int yuv4mpeg_set_stream_id(yuv4mpeg_t yuv4mpeg, glc_stream_id_t id); 70 | 71 | /** 72 | * \brief set fps 73 | * 74 | * Default fps is 30. 75 | * \param yuv4mpeg yuv4mpeg object 76 | * \param fps fps 77 | * \return 0 on success otherwise an error code 78 | */ 79 | __PUBLIC int yuv4mpeg_set_fps(yuv4mpeg_t yuv4mpeg, double fps); 80 | 81 | /** 82 | * \brief set interpolation 83 | * 84 | * By default missing frames are copied from previous frame 85 | * to preserve a/v sync. 86 | * \param yuv4mpeg yuv4mpeg object 87 | * \param interpolate 1 means missing frames are interpolated, 88 | * 0 disables interpolation and a/v sync is lost. 89 | * \return 0 on success otherwise an error code 90 | */ 91 | __PUBLIC int yuv4mpeg_set_interpolation(yuv4mpeg_t yuv4mpeg, int interpolate); 92 | 93 | /** 94 | * \brief start yuv4mpeg process 95 | * 96 | * yuv4mpeg writes Y'CbCr frames in selected video stream 97 | * into yuv4mpeg formatted file. 98 | * \param yuv4mpeg yuv4mpeg object 99 | * \param from source buffer 100 | * \return 0 on success otherwise an error code 101 | */ 102 | __PUBLIC int yuv4mpeg_process_start(yuv4mpeg_t yuv4mpeg, ps_buffer_t *from); 103 | 104 | /** 105 | * \brief block until process has finished 106 | * \param yuv4mpeg yuv4mpeg object 107 | * \return 0 on success otherwise an error code 108 | */ 109 | __PUBLIC int yuv4mpeg_process_wait(yuv4mpeg_t yuv4mpeg); 110 | 111 | #ifdef __cplusplus 112 | } 113 | #endif 114 | 115 | #endif 116 | 117 | /** \} */ 118 | /** \} */ 119 | -------------------------------------------------------------------------------- /src/glc/play/alsa_play.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/play/alsa_play.h 3 | * \brief audio playback 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup play 11 | * \{ 12 | * \defgroup alsa_play audio playback 13 | * \{ 14 | */ 15 | 16 | #ifndef _ALSA_PLAY_H 17 | #define _ALSA_PLAY_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief alsa_play object 28 | */ 29 | typedef struct alsa_play_s* alsa_play_t; 30 | 31 | /** 32 | * \brief initialize alsa_play object 33 | * \param alsa_play alsa_play object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int alsa_play_init(alsa_play_t *alsa_play, glc_t *glc); 38 | 39 | /** 40 | * \brief destroy alsa_play object 41 | * \param alsa_play alsa_play object 42 | * \return 0 on success otherwise an error code 43 | */ 44 | __PUBLIC int alsa_play_destroy(alsa_play_t alsa_play); 45 | 46 | /** 47 | * \brief set audio stream id 48 | * 49 | * Default audio stream is 1. 50 | * \param alsa_play alsa_play object 51 | * \param id audio stream id 52 | * \return 0 on success otherwise an error code 53 | */ 54 | __PUBLIC int alsa_play_set_stream_id(alsa_play_t alsa_play, glc_stream_id_t id); 55 | 56 | /** 57 | * \brief set ALSA playback device 58 | * 59 | * Default ALSA playback device is "default". 60 | * \param alsa_play alsa_play object 61 | * \param device ALSA playback device 62 | * \return 0 on success otherwise an error code 63 | */ 64 | __PUBLIC int alsa_play_set_alsa_playback_device(alsa_play_t alsa_play, 65 | const char *device); 66 | 67 | /** 68 | * \brief start alsa_play process 69 | * 70 | * alsa_play plays audio data from selected audio stream. 71 | * \param alsa_play alsa_play object 72 | * \param from source buffer 73 | * \return 0 on success otherwise an error code 74 | */ 75 | __PUBLIC int alsa_play_process_start(alsa_play_t alsa_play, ps_buffer_t *from); 76 | 77 | /** 78 | * \brief block until process has finished 79 | * \param alsa_play alsa_play object 80 | * \return 0 on success otherwise an error code 81 | */ 82 | __PUBLIC int alsa_play_process_wait(alsa_play_t alsa_play); 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif 89 | 90 | /** \} */ 91 | /** \} */ 92 | -------------------------------------------------------------------------------- /src/glc/play/demux.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/play/demux.h 3 | * \brief audio/picture stream demuxer 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup play 11 | * \{ 12 | * \defgroup demux audio/picture stream demuxer 13 | * \{ 14 | */ 15 | 16 | #ifndef _DEMUX_H 17 | #define _DEMUX_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief demux object 28 | */ 29 | typedef struct demux_s* demux_t; 30 | 31 | /** 32 | * \brief initialize demux object 33 | * \param demux demux object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int demux_init(demux_t *demux, glc_t *glc); 38 | 39 | /** 40 | * \brief destroy demux object 41 | * \param demux demux object 42 | * \return 0 on success otherwise an error code 43 | */ 44 | __PUBLIC int demux_destroy(demux_t demux); 45 | 46 | /** 47 | * \brief set video stream buffer size 48 | * 49 | * Default buffer size for video streams is 10 MiB 50 | * \param demux demux object 51 | * \param size video stream buffer size 52 | * \return 0 on success otherwise an error code 53 | */ 54 | __PUBLIC int demux_set_video_buffer_size(demux_t demux, size_t size); 55 | 56 | /** 57 | * \brief set audio stream buffer size 58 | * 59 | * Default buffer size for audio streams is 1 MiB 60 | * \param demux demux object 61 | * \param size audio stream buffer size 62 | * \return 0 on success otherwise an error code 63 | */ 64 | __PUBLIC int demux_set_audio_buffer_size(demux_t demux, size_t size); 65 | 66 | /** 67 | * \brief set ALSA playback device 68 | * 69 | * Default ALSA playback device is "default". 70 | * \param demux demux object 71 | * \param device ALSA playback device 72 | * \return 0 on success otherwise an error code 73 | */ 74 | __PUBLIC int demux_set_alsa_playback_device(demux_t demux, const char *device); 75 | 76 | /** 77 | * \brief start demux process 78 | * 79 | * demux demuxes glc stream. For each video and audio stream is 80 | * created own gl_play/alsa_play object and stream buffer. 81 | * 82 | * demux takes care of initializing and cleaning up gl_play/alsa_play 83 | * objects. 84 | * \param demux demux object 85 | * \param from source buffer 86 | * \return 0 on success otherwise an error code 87 | */ 88 | __PUBLIC int demux_process_start(demux_t demux, ps_buffer_t *from); 89 | 90 | /** 91 | * \brief block until process has finished 92 | * \param demux demux object 93 | * \return 0 on success otherwise an error code 94 | */ 95 | __PUBLIC int demux_process_wait(demux_t demux); 96 | 97 | /** 98 | * demux as soon as possible to not disturb with audio packets processes 99 | * only interested video packets 100 | */ 101 | __PUBLIC int demux_insert_video_filter(demux_t demux, ps_buffer_t *in, ps_buffer_t *out); 102 | 103 | #ifdef __cplusplus 104 | } 105 | #endif 106 | 107 | #endif 108 | 109 | /** \} */ 110 | /** \} */ 111 | -------------------------------------------------------------------------------- /src/glc/play/gl_play.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file glc/play/gl_play.h 3 | * \brief OpenGL playback 4 | * \author Pyry Haulos 5 | * \date 2007-2008 6 | * For conditions of distribution and use, see copyright notice in glc.h 7 | */ 8 | 9 | /** 10 | * \addtogroup play 11 | * \{ 12 | * \defgroup gl_play OpenGL playback 13 | * \{ 14 | */ 15 | 16 | #ifndef _GL_PLAY_H 17 | #define _GL_PLAY_H 18 | 19 | #include 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** 27 | * \brief gl_play object 28 | */ 29 | typedef struct gl_play_s* gl_play_t; 30 | 31 | /** 32 | * \brief initialize gl_play object 33 | * \param gl_play gl_play object 34 | * \param glc glc 35 | * \return 0 on success otherwise an error code 36 | */ 37 | __PUBLIC int gl_play_init(gl_play_t *gl_play, glc_t *glc); 38 | 39 | /** 40 | * \brief destroy gl_play object 41 | * \param gl_play gl_play object 42 | * \return 0 on success otherwise an error code 43 | */ 44 | __PUBLIC int gl_play_destroy(gl_play_t gl_play); 45 | 46 | /** 47 | * \brief set video stream id 48 | * 49 | * Default video stream is 1. 50 | * \param gl_play gl_play object 51 | * \param id video stream id 52 | * \return 0 on success otherwise an error code 53 | */ 54 | __PUBLIC int gl_play_set_stream_id(gl_play_t gl_play, glc_stream_id_t id); 55 | 56 | /** 57 | * \brief start gl_play process 58 | * 59 | * gl_play plays RGB (BGR) video data from selected video stream. 60 | * \param gl_play gl_play object 61 | * \param from source buffer 62 | * \return 0 on success otherwise an error code 63 | */ 64 | __PUBLIC int gl_play_process_start(gl_play_t gl_play, ps_buffer_t *from); 65 | 66 | /** 67 | * \brief block until process has finished 68 | * \param gl_play gl_play object 69 | * \return 0 on success otherwise an error code 70 | */ 71 | __PUBLIC int gl_play_process_wait(gl_play_t gl_play); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | 79 | /** \} */ 80 | /** \} */ 81 | -------------------------------------------------------------------------------- /src/hook/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | FIND_PACKAGE(ELFHACKS) 2 | IF (ELFHACKS_FOUND) 3 | # TODO: Try to build local copy of library if no system version is found. 4 | INCLUDE_DIRECTORIES(${ELFHACKS_INCLUDE_DIR}) 5 | ENDIF (ELFHACKS_FOUND) 6 | 7 | ADD_LIBRARY("glc-hook" SHARED "lib.h" "alsa.c" "main.c" "opengl.c" "x11.c") 8 | TARGET_LINK_LIBRARIES("glc-hook" "glc-core" "glc-capture" 9 | ${ELFHACKS_LIBRARY} ${PACKETSTREAM_LIBRARY}) 10 | SET_TARGET_PROPERTIES("glc-hook" PROPERTIES OUTPUT_NAME "glc-hook" 11 | VERSION ${GLCS_VER} SOVERSION ${GLCS_SOVER}) 12 | 13 | IF (UNIX) 14 | INSTALL(TARGETS "glc-hook" LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}) 15 | ENDIF (UNIX) 16 | -------------------------------------------------------------------------------- /src/hook/lib.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file hook/lib.h 3 | * \brief wrapper library adapted from original work (glc) from Pyry Haulos 4 | * \author Olivier Langlois 5 | * \date 2014 6 | 7 | Copyright 2014 Olivier Langlois 8 | 9 | This file is part of glcs. 10 | 11 | glcs is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | glcs is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with glcs. If not, see . 23 | 24 | */ 25 | 26 | /** 27 | * \defgroup hook wrapper library 28 | * \{ 29 | */ 30 | 31 | #ifndef _LIB_H 32 | #define _LIB_H 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | 46 | #define LIB_CAPTURING 0x1 47 | 48 | typedef struct { 49 | void *(*dlopen)(const char *filename, int flag); 50 | void *(*dlsym)(void *, const char *); 51 | void *(*dlvsym)(void *, const char *, const char *); 52 | void *(*__libc_dlsym)(void *, const char *); 53 | int running; 54 | pthread_once_t init_once; 55 | glc_flags_t flags; 56 | } glc_lib_t; 57 | 58 | #define INIT_GLC pthread_once(&lib.init_once,init_glc); 59 | 60 | /** 61 | * \addtogroup main 62 | * \{ 63 | */ 64 | __PRIVATE extern glc_lib_t lib; 65 | __PRIVATE void init_glc(); 66 | __PRIVATE int start_glc(); 67 | __PRIVATE void get_real_dlsym(); 68 | __PRIVATE void *wrapped_func(const char *symbol); 69 | __PRIVATE int start_capture(); 70 | __PRIVATE int reload_capture(); 71 | __PRIVATE int stop_capture(); 72 | /** \} */ 73 | 74 | /** 75 | * \addtogroup alsa 76 | * \{ 77 | */ 78 | __PRIVATE int alsa_init(glc_t *glc); 79 | __PRIVATE int alsa_start(ps_buffer_t *buffer); 80 | __PRIVATE int alsa_close(); 81 | __PRIVATE int alsa_capture_start_all(); 82 | __PRIVATE int alsa_capture_stop_all(); 83 | __PRIVATE int alsa_unhook_so(const char *soname); 84 | /** \} */ 85 | 86 | /** 87 | * \addtogroup opengl 88 | * \{ 89 | */ 90 | __PRIVATE int opengl_init(glc_t *glc); 91 | __PRIVATE int opengl_start(ps_buffer_t *buffer); 92 | __PRIVATE int opengl_capture_start(); 93 | __PRIVATE int opengl_capture_stop(); 94 | __PRIVATE int opengl_refresh_color_correction(); 95 | __PRIVATE int opengl_close(); 96 | __PRIVATE int opengl_push_message(glc_message_header_t *hdr, void *message, size_t message_size); 97 | /** \} */ 98 | 99 | /** 100 | * \addtogroup x11 101 | * \{ 102 | */ 103 | __PRIVATE int x11_init(glc_t *glc); 104 | __PRIVATE int x11_close(); 105 | /** \} */ 106 | 107 | /** 108 | * \defgroup hooks Hooked functions 109 | * \{ 110 | */ 111 | __PRIVATE void *__main_dlopen(const char *filename, int flag); 112 | __PRIVATE void *__main_dlsym(void *handle, const char *symbol); 113 | __PRIVATE void *__main_dlvsym(void *handle, const char *symbol, const char *version); 114 | __PRIVATE void *__main___libc_dlsym(void *handle, const char *symbol); 115 | 116 | typedef void (*GLXextFuncPtr)(void); 117 | __PRIVATE GLXextFuncPtr __opengl_glXGetProcAddressARB(const GLubyte *proc_name); 118 | __PRIVATE void __opengl_glXSwapBuffers(Display *dpy, GLXDrawable drawable); 119 | __PRIVATE void __opengl_glFinish(void); 120 | __PRIVATE void __opengl_glXSwapBuffers(Display *dpy, GLXDrawable drawable); 121 | __PRIVATE GLXWindow __opengl_glXCreateWindow(Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); 122 | 123 | __PRIVATE int __x11_XNextEvent(Display *display, XEvent *event_return); 124 | __PRIVATE int __x11_XPeekEvent(Display *display, XEvent *event_return); 125 | __PRIVATE int __x11_XWindowEvent(Display *display, Window w, long event_mask, XEvent *event_return); 126 | __PRIVATE Bool __x11_XCheckWindowEvent(Display *display, Window w, long event_mask, XEvent *event_return); 127 | __PRIVATE int __x11_XMaskEvent(Display *display, long event_mask, XEvent *event_return); 128 | __PRIVATE Bool __x11_XCheckMaskEvent(Display *display, long event_mask, XEvent *event_return); 129 | __PRIVATE Bool __x11_XCheckTypedEvent(Display *display, int event_type, XEvent *event_return); 130 | __PRIVATE Bool __x11_XCheckTypedWindowEvent(Display *display, Window w, int event_type, XEvent *event_return); 131 | __PRIVATE int __x11_XIfEvent(Display *display, XEvent *event_return, Bool ( *predicate)(), XPointer arg); 132 | __PRIVATE Bool __x11_XCheckIfEvent(Display *display, XEvent *event_return, Bool ( *predicate)(), XPointer arg); 133 | __PRIVATE int __x11_XPeekIfEvent(Display *display, XEvent *event_return, Bool ( *predicate)(), XPointer arg); 134 | __PRIVATE Bool __x11_XF86VidModeSetGamma(Display *display, int screen, XF86VidModeGamma *Gamma); 135 | 136 | __PRIVATE int __alsa_snd_pcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode); 137 | __PRIVATE int __alsa_snd_pcm_open_lconf(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, snd_config_t *lconf); 138 | __PRIVATE int __alsa_snd_pcm_close(snd_pcm_t *pcm); 139 | __PRIVATE int __alsa_snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); 140 | __PRIVATE snd_pcm_sframes_t __alsa_snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); 141 | __PRIVATE snd_pcm_sframes_t __alsa_snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); 142 | __PRIVATE snd_pcm_sframes_t __alsa_snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); 143 | __PRIVATE snd_pcm_sframes_t __alsa_snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); 144 | __PRIVATE int __alsa_snd_pcm_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames); 145 | __PRIVATE snd_pcm_sframes_t __alsa_snd_pcm_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames); 146 | /** \} */ 147 | 148 | #endif 149 | 150 | /** \} */ 151 | --------------------------------------------------------------------------------