diff options
author | James Houghton | 2017-06-29 14:08:42 -0400 |
---|---|---|
committer | James Houghton | 2017-06-29 14:08:42 -0400 |
commit | 910317f82949d53cdf44717c202f7957bd8edf9e (patch) | |
tree | 034757c2472a3217f51653159dbcc374d2f2e477 | |
parent | 21cb16514487978fa6a684810a2933ae4bebdd92 (diff) | |
download | aur-ttyvideo.tar.gz |
Follow twa022's instructions
-rw-r--r-- | .SRCINFO | 12 | ||||
-rw-r--r-- | .gitignore | 10 | ||||
-rw-r--r-- | CMakeLists.txt | 21 | ||||
-rw-r--r-- | PKGBUILD | 26 | ||||
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | handle.c | 174 | ||||
-rw-r--r-- | handle.h | 30 | ||||
-rw-r--r-- | ttyvideo.cpp | 306 |
8 files changed, 19 insertions, 581 deletions
@@ -1,16 +1,16 @@ pkgbase = ttyvideo - pkgdesc = ttyvideo displays videos in the terminal. + pkgdesc = Play video in the terminal pkgver = 0.0.1 - pkgrel = 1 + pkgrel = 2 url = https://github.com/jamesthoughton/ttyvideo - arch = any + arch = i686 + arch = x86_64 license = MIT makedepends = cmake depends = opencv - depends = gstreamer depends = gst-plugins-base - source = https://github.com/jamesthoughton/ttyvideo/archive/0.0.1.tar.gz - md5sums = 862c8cf756ad896f82654565ffc7f5ad + source = ttyvideo-0.0.1.tar.gz::https://github.com/jamesthoughton/ttyvideo/archive/0.0.1.tar.gz + sha256sums = ecceca05dcfd94cadd0f17f58e3e98a93f5ee7ffe70a72e6935edf5e4a73fcc2 pkgname = ttyvideo diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0c7f348b2bfc..000000000000 --- a/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -opencv/ -CMake* -!CMakeLists.txt -cmake_install.cmake -*.a -*.o -*.so -ttyvideo -Makefile -install_manifest.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 2cc034700bdd..000000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -project(ttyvideo) -find_package(OpenCV REQUIRED) - -if(MSVC) - # Visual Studio -- /W4 - if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") - string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") - endif() -elseif(CMAKE_COMPILER_IS_GNUXX OR CMAKE_COMPILER_IS_GNUCC) - # GCC -- -Wall -pedantic - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic") -endif() - -add_library(handle STATIC handle.c) -add_executable(ttyvideo ttyvideo.cpp) -target_link_libraries(ttyvideo ${OpenCV_LIBS} -lm handle) - -install(TARGETS ttyvideo DESTINATION bin) @@ -1,22 +1,22 @@ pkgname=ttyvideo -pkgver='0.0.1' -pkgrel='1' -pkgdesc="ttyvideo displays videos in the terminal." -arch=('any') +pkgver=0.0.1 +pkgrel=2 +pkgdesc="Play video in the terminal" +arch=('i686' 'x86_64') license=('MIT') -depends=(opencv gstreamer gst-plugins-base) -makedepends=(cmake) -source=("https://github.com/jamesthoughton/ttyvideo/archive/0.0.1.tar.gz") +depends=('opencv' 'gst-plugins-base') +makedepends=('cmake') +source=("${pkgname}-${pkgver}.tar.gz::https://github.com/jamesthoughton/${pkgname}/archive/${pkgver}.tar.gz") url='https://github.com/jamesthoughton/ttyvideo' -md5sums=('862c8cf756ad896f82654565ffc7f5ad') +sha256sums=('ecceca05dcfd94cadd0f17f58e3e98a93f5ee7ffe70a72e6935edf5e4a73fcc2') build() { - cd $srcdir/$pkgname-$pkgver - cmake . - make + cd "${pkgname}-${pkgver}" + cmake . -DCMAKE_INSTALL_PREFIX=/usr + make } package() { - cd $srcdir/$pkgname-$pkgver - install -Dm 755 ttyvideo $pkgdir/usr/bin/ttyvideo + cd "${pkgname}-${pkgver}" + make DESTDIR="${pkgdir}" install } diff --git a/README.md b/README.md deleted file mode 100644 index 671d6f9be322..000000000000 --- a/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# ttyvideo -Pushing the limits of resolution and color depth... backwards! -ttyvideo is a video player that runs in a 256-color terminal. -## Dependencies -ttyvideo requires OpenCV (2 or 3) compiled with video codecs. If your package manager doesn't carry a version of OpenCV like this, you're going to need to download and compile its [source code](https://github.com/opencv/opencv "OpenCV source") before you can use ttyvideo. -ttyvideo also uses CMake>=2.8 to generate files used in the installation process. -## Installation -You can compile ttyvideo with CMake and Make. -```shell -cmake . -make -``` -After compiling, it can be installed by performing -```shell -sudo make install -``` - -## How it works -ttyvideo works with most visual media types: videos, images, GIFs, etc. This is due to the usage of OpenCV to read media. -Right now, ttyvideo doesn't do anything special when rendering videos. -ttyvideo will scale any video to fit the aspect ratio of the terminal it's running in. ttyvideo also does not perform any smoothing operations; each character slot in the terminal corresponds to exactly one pixel in the source video, not a combination of them. Feel free to add smoothing ttyvideo! diff --git a/handle.c b/handle.c deleted file mode 100644 index 1d18b8c2fc82..000000000000 --- a/handle.c +++ /dev/null @@ -1,174 +0,0 @@ -#include "handle.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> - -int error(char* message) { - - fprintf(stderr, "%s: %s\n", "ttyvideo", message); - - return 1; - -} - -static int numOptionsSpecified = 0; -static int numUniqueOptionsSpecified = 0; -static char** argumentCallMap = NULL; -static char** argumentMemStore = NULL; -static int* argumentNumStore = NULL; -static char** helpMessages = NULL; -static char* defaultArg = NULL; -static char* defaultArgHelp = NULL; - -#define MAX_ARG_SIZE 200 - -char* setDefaultArgument(char* helpText) { - - defaultArg = (char*)malloc(sizeof(char) * MAX_ARG_SIZE); - defaultArgHelp = (char*)malloc(sizeof(char) * strlen(helpText)); - strcpy(defaultArgHelp, helpText); - - defaultArg[0] = '\0'; - - return defaultArg; - -} - -#define MAX_ACCESS_MAP_SIZE 100 -#define MAX_HELP_MESSAGE_ARRAY_SIZE 100 - -char* addArgument(char* helpText, int numArguments, char* firstCall, char* secondCall) { - - if(firstCall == NULL) { - fprintf(stderr, "No option specified for parameter\n"); - return NULL; - } - if(firstCall[0] != '-') { - fprintf(stderr, "Option '%s' does not start with a '-'\n", firstCall); - return NULL; - } - if(secondCall != NULL && secondCall[0] != '-') { - fprintf(stderr, "Option '%s' does not start with a '-'\n", secondCall); - } - - if(argumentCallMap == NULL) { - argumentCallMap = (char**)malloc(sizeof(char*) * MAX_ACCESS_MAP_SIZE); - } - if(argumentMemStore == NULL) { - argumentMemStore = (char**)malloc(sizeof(char*) * MAX_ACCESS_MAP_SIZE); - } - if(argumentNumStore == NULL) { - argumentNumStore = (int*)malloc(sizeof(int*) * MAX_ACCESS_MAP_SIZE); - } - if(helpMessages == NULL) { - helpMessages = (char**)malloc(sizeof(char*) * MAX_HELP_MESSAGE_ARRAY_SIZE); - } - - // TODO: Add ability to allocate lots of these - char* argumentMemLocation = (char*)malloc(sizeof(char) * MAX_ARG_SIZE); - if(argumentMemLocation == NULL) { - fprintf(stderr, "Couldn't allocate memory to store argument to pass to %s", firstCall); - return NULL; - } - argumentMemLocation[0] = '\0'; - - int argumentAccessLocation = numOptionsSpecified++; - argumentCallMap[argumentAccessLocation] = (char*)malloc(sizeof(char) * strlen(firstCall)); - strcpy(argumentCallMap[argumentAccessLocation], firstCall); - argumentMemStore[argumentAccessLocation] = argumentMemLocation; - argumentNumStore[argumentAccessLocation] = numArguments; - - - if(secondCall == NULL) { - - helpMessages[numUniqueOptionsSpecified] = (char*)malloc(sizeof(char) * (strlen(helpText) + strlen(firstCall) + 4)); - - strcpy(helpMessages[numUniqueOptionsSpecified], firstCall); - strcat(helpMessages[numUniqueOptionsSpecified], ":\t"); - strcat(helpMessages[numUniqueOptionsSpecified], helpText); - - numUniqueOptionsSpecified++; - - return argumentMemLocation; - } - - helpMessages[numUniqueOptionsSpecified] = (char*)malloc(sizeof(char) * (strlen(helpText) + strlen(firstCall) + 2 + 4 + strlen(secondCall))); - - strcpy(helpMessages[numUniqueOptionsSpecified], firstCall); - strcat(helpMessages[numUniqueOptionsSpecified], ", "); - strcat(helpMessages[numUniqueOptionsSpecified], secondCall); - strcat(helpMessages[numUniqueOptionsSpecified], ":\t"); - strcat(helpMessages[numUniqueOptionsSpecified], helpText); - - numUniqueOptionsSpecified++; - - argumentAccessLocation = numOptionsSpecified++; - argumentCallMap[argumentAccessLocation] = (char*)malloc(sizeof(char) * strlen(secondCall)); - strcpy(argumentCallMap[argumentAccessLocation], secondCall); - argumentMemStore[argumentAccessLocation] = argumentMemLocation; - argumentNumStore[argumentAccessLocation] = numArguments; - - return argumentMemLocation; -} - -void printUsage() { - - if(helpMessages != NULL) { - register int i; - for(i = 0; i < numUniqueOptionsSpecified; ++i) { - printf("%s\n", helpMessages[i]); - } - } else { - printf("No options to display\n"); - } - -} - -int handle(int argc, char** argv) { - - register int i, j; - int numArguments; - for(i = 1; i < argc; ++i) { - for(j = 0; j < numOptionsSpecified; ++j) { - if(argv[i][0] != '-') { - if(defaultArg == NULL) { - fprintf(stderr, "Argument '%s' was passed without an option, and no default argument has been set\n", argv[0]); - return 1; - } - if(defaultArg[0] != '\0') { - fprintf(stderr, "Unrecognized option '%s'\n", argv[i]); - return 1; - } - strcpy(defaultArg, argv[i]); - break; - } - if(strcmp(argv[i], argumentCallMap[j])) - continue; - numArguments = argumentNumStore[j]; - if(numArguments) { - if(i < argc - 1 && argv[i+1][0] != '-') { - strcpy(argumentMemStore[j], argv[++i]); - } else { - fprintf(stderr, "Option '%s' requires an argument\n", argv[i]); - return 1; - } - } - else - strcpy(argumentMemStore[j], "1"); // The option is present - break; - } - if(j == numOptionsSpecified) { - fprintf(stderr, "Unrecognized option '%s'\n", argv[i]); - return 1; - } - } - - return 0; - -} - -void sig_handler(int signo) { - if(signo == SIGINT) - terminate = 1; -} diff --git a/handle.h b/handle.h deleted file mode 100644 index 5a8f6806628e..000000000000 --- a/handle.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef HANDLE_H -#define HANDLE_H - -#ifdef __cplusplus -extern "C" { -#endif - -char* filename; - -char* setDefaultArgument(char* helpText); - -char* addArgument(char* helpText, int numArguments, char* firstCall, char* secondCall); - -void printUsage(); - -int error(char* message); -int handle(int argc, char** argv); - -int terminate; - -#define TAKES_NO_ARGUMENTS 0 -#define TAKES_ONE_ARGUMENT 1 - -void sig_handler(int signo); - -#ifdef __cplusplus -} -#endif - -#endif // HANDLE_H diff --git a/ttyvideo.cpp b/ttyvideo.cpp deleted file mode 100644 index 361eaf20373b..000000000000 --- a/ttyvideo.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// #include <opencv2/core/core_c.h> -// #include <opencv2/videoio/videoio_c.h> -// #include <opencv2/videoio/videoio.hpp> -#include <opencv2/core.hpp> -#include <opencv2/video.hpp> -#include <opencv2/highgui.hpp> -#include <opencv2/opencv.hpp> -#include <math.h> -#include <stdlib.h> -#include <stdio.h> -#include "handle.h" -#include <sys/ioctl.h> -#include <time.h> -#include <unistd.h> -#include <signal.h> - -#ifdef __MACH__ -#include <mach/clock.h> -#include <mach/mach.h> -#endif - -#define NANO_CONV_FACTOR 1000000000 - -#define COLOR_TEXT_FORMAT "\x1B[48;05;%um\x1B[38;05;%um%c" -#define COLOR_FORMAT "\x1B[48;05;%um " -#define COLOR_RESET "\x1B[0m" - -int waitFrame(uint64_t, uint64_t); -unsigned char generateANSIColor(unsigned char, unsigned char, unsigned char); -void getTTYDims(); -int play(char*, char*, char*, int); -void getSystemTime(struct timespec*); - -int tty_width; -int tty_height; -int tty_width_custom = 0; -int tty_height_custom = 0; - -int no_interrupts = 0; - -#define C (char*) - -int main(int argc, char** argv) { - - char* filename = setDefaultArgument(C"infile"); - char* width_option = addArgument(C"Output width", TAKES_ONE_ARGUMENT, C"-w", C"--width"); - char* height_option = addArgument(C"Output height", TAKES_ONE_ARGUMENT, C"-h", C"--height"); - char* sleep_option = addArgument(C"Add a pause between loops or after plays (seconds)", TAKES_ONE_ARGUMENT, C"-s", C"--sleep"); - char* noexit_option = addArgument(C"Prevent the program for exiting", TAKES_NO_ARGUMENTS, C"--no-exit", NULL); - char* loop_option = addArgument(C"Loop videos", TAKES_NO_ARGUMENTS, C"-l", C"--loop"); - char* help_option = addArgument(C"Print usage", TAKES_NO_ARGUMENTS, C"--help", NULL); - char* nointer_option = addArgument(C"No interrupts", TAKES_NO_ARGUMENTS, C"--no-interrupts", NULL); - char* fps_option = addArgument(C"FPS", TAKES_ONE_ARGUMENT, C"--fps", NULL); - char* string_option = addArgument(C"String to place in the foreground", TAKES_ONE_ARGUMENT, C"--string", NULL); - char* info_option = addArgument(C"Print terminal dimensions", TAKES_NO_ARGUMENTS, C"-i", C"--info"); - - int argError; - argError = handle(argc, argv); - if(argError) { - error((char*)"Run ttyvideo --help for more information"); - return argError; - } - - if(help_option[0] != '\0') { - printUsage(); - return 0; - } - - if(info_option[0] != '\0') { - getTTYDims(); - printf("Height: %d\nWidth: %d\n", - tty_height, tty_width); - return 0; - } - - if(filename[0] == '\0') - return error((char*)"No input file specified"); - - getTTYDims(); // get initial dims - - tty_height_custom = atoi(height_option); - tty_width_custom = atoi(width_option); - - if(tty_height == 0 && tty_width == 0) { - if(tty_height_custom == 0 || tty_width_custom == 0) { - error((char*)"Could not detect terminal dimensions and specified dimensions are incomplete"); - return 1; - } - } else { - if(tty_height_custom > tty_height || tty_width_custom > tty_width) { - error((char*)"The specified dimensions are too large, but we will play the video anyway"); - } - } - - getTTYDims(); // get real dims -- including user specification - - int sleep_time = sleep_option[0] == '\0' ? 0 : atoi(sleep_option); - - int noexit = noexit_option[0] == '\0' ? 0 : 1; - - int loop = loop_option[0] == '\0' ? 0 : 1; - - setvbuf(stdout, NULL, _IOFBF, 0); - - signal(SIGINT, sig_handler); - - no_interrupts = nointer_option[0] == '\0' ? 0 : 1; - - register int frameNum = 0; - do { - frameNum = play(filename, string_option, fps_option, frameNum); - - if(frameNum < 0) - return 1; - - if(terminate && !no_interrupts) { - printf("\n"); - fflush(stdout); - return 0; - } - - if(sleep_time) - sleep(sleep_time); - - } while(loop && frameNum > 1); - - if((loop && frameNum == 1) || noexit) { - terminate = 0; // Terminate to 0 so we can work with it - while(true) { - sleep(1); - // When SIG_INT is sent to a frozen frame, - // re-render the frame - if(terminate) { - if(!no_interrupts) return 0; - frameNum = play(filename, string_option, fps_option, frameNum); - terminate = 0; - } - } - } - - printf("\n"); - fflush(stdout); - return 0; - -} - -int play(char* filename, char* string, char* fps_option, int subsequentPlay) { - cv::VideoCapture cap(filename); - if(!cap.isOpened()) return -1 * error((char*)"Can't read input"); - - double fps = fps_option[0] == '\0' ? cap.get(CV_CAP_PROP_FPS) : atof(fps_option); - - struct timespec start, end; - - uint64_t delta_ns; - uint64_t delayNecessary = fps == 0 || isnan(fps) ? 0 : NANO_CONV_FACTOR/fps; - - register int frameNum = 0; - - register int width, height, nchannels, step, offset; - register int i, j; - register unsigned char r_ch, b_ch, g_ch; - cv::Mat frame; - int ansiColor, ansiTextColor; - unsigned char* data; - - int stringLength = strlen(string); - - int stopAfterFrame = 0; - - for(;;) { - - getSystemTime(&start); - - if(!frame.empty() || subsequentPlay) { - - cap >> frame; - - if(frame.empty()) break; - - for(i = 0; i < tty_height - 1; ++i) - printf("\x1B[F"); - - } else { - - cap >> frame; - - if(frame.empty()) break; - - } - - if(frame.depth() != CV_8U) { - return -1 * error((char*)"Frame has incorrect depth"); - } - - width = frame.cols; - height = frame.rows; - nchannels = frame.channels(); - step = width * nchannels; - - getTTYDims(); - - register int stringIter = 0; - - for(i = 0; i < tty_height; ++i) { - data = (unsigned char*)(frame.data + ((int)((float)i*height/tty_height)*step)); - for(j = 0; j < tty_width; ++j) { - offset = (int)((float)j*width/tty_width) * nchannels; - b_ch = data[offset]; - g_ch = data[offset+1]; - r_ch = data[offset+2]; - - ansiColor = generateANSIColor(r_ch, g_ch, b_ch); - - if(stringLength) { - ansiTextColor = b_ch + g_ch + r_ch > 0x17F ? generateANSIColor(r_ch - 50, g_ch - 50, b_ch - 50) : - generateANSIColor(r_ch + 50, g_ch + 50, b_ch + 50); - - printf(COLOR_TEXT_FORMAT, ansiColor, ansiTextColor, string[stringIter++%stringLength]); - } else { - printf(COLOR_FORMAT, ansiColor); - } - } - printf(COLOR_RESET); - if(i < tty_height - 1) { - printf("\n"); - } else { - printf("\x1B[m"); - fflush(stdout); - } - } - - if(stopAfterFrame) { - break; - } - - if(terminate && !no_interrupts) { - stopAfterFrame = 1; - } - - getSystemTime(&end); - - delta_ns = (end.tv_sec - start.tv_sec) * NANO_CONV_FACTOR + (end.tv_nsec - start.tv_nsec); - - waitFrame(delayNecessary, delta_ns); - - frameNum++; - - } - - return frameNum; - -} - -int waitFrame(uint64_t delayNecessary, uint64_t delta_ns) { - - struct timespec ts; - long totalNanoSec; - - totalNanoSec = (delayNecessary - delta_ns); - - if(totalNanoSec < 0) return 1; - - ts.tv_sec = totalNanoSec/NANO_CONV_FACTOR; - ts.tv_nsec = totalNanoSec%NANO_CONV_FACTOR; - nanosleep(&ts, NULL); - - return 0; - -} - -unsigned char generateANSIColor(unsigned char r, unsigned char g, unsigned char b) { - - return 16 + (36 * lround(r*5.0/256)) + (6 * lround(g*5.0/256)) + lround(b*5.0/256); - -} - -void getTTYDims() { - - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - tty_width = tty_width_custom > 0 ? tty_width_custom : w.ws_col; - tty_height = tty_height_custom > 0 ? tty_height_custom : w.ws_row; - -} - -void getSystemTime(struct timespec* tv) { - - #ifdef __MACH__ - - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - - tv->tv_sec = mts.tv_sec; - tv->tv_nsec = mts.tv_nsec; - - #else - - clock_gettime(CLOCK_REALTIME, tv); - - #endif - -} |