Projects
Multimedia
nordlicht
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 22
View file
nordlicht.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Tue Mar 31 18:30:21 UTC 2020 - Olaf Hering <olaf@aepfle.de> + +- Bump to v0.4.5 + +------------------------------------------------------------------- Sat Oct 08 11:36:17 UTC 2016 - joerg.lorenzen@ki.tng.de - Removed service file because build often fails with 'bad temdir'
View file
nordlicht.spec
Changed
@@ -1,23 +1,24 @@ %define soname 0 Name: nordlicht -Version: %{soname}.4.4 +Version: 0.4.5 Release: 0 License: GPL-2.0+ Summary: Creates colorful barcodes from video files Url: https://nordlicht.github.io Group: Productivity/Multimedia/Editors and Convertors -Source0: https://github.com/nordlicht/%{name}/archive/%{name}-%{version}.tar.gz +Source0: %{name}-%{version}.tar.xz BuildRequires: cmake BuildRequires: help2man BuildRequires: pkg-config -BuildRequires: pkgconfig(libavcodec) = 56.60.100 -BuildRequires: pkgconfig(libavformat) = 56.40.101 -BuildRequires: pkgconfig(libavutil) = 54.31.100 -BuildRequires: pkgconfig(libswscale) = 3.1.101 +BuildRequires: pkgconfig(libavcodec) +BuildRequires: pkgconfig(libavformat) +BuildRequires: pkgconfig(libavutil) +BuildRequires: pkgconfig(libswscale) BuildRequires: popt-devel +Requires: lib%{name}%{soname} = %{version}-%{release} ExclusiveArch: %ix86 x86_64 %description @@ -44,8 +45,7 @@ %package devel Summary: Development files for nordlicht Group: Development/Libraries/C and C++ -Requires: lib%{name}%{soname} >= %{version} -Provides: pkgconfig(nordlicht) +Requires: lib%{name}%{soname} = %{version}-%{release} %description devel This package contains all necessary include files and @@ -56,29 +56,24 @@ %setup -q %build -cmake . \ - -DCMAKE_C_FLAGS:STRING="%{optflags}" \ - -DCMAKE_INSTALL_PREFIX:PATH=%{_prefix} \ - -DLIB_INSTALL_DIR:PATH=%{_libdir} -make %{?_smp_mflags} +CFLAGS='%{optflags} -Wno-deprecated-declarations' +%cmake +%cmake_build %install -%make_install +%cmake_install %post -n lib%{name}%{soname} -p /sbin/ldconfig %postun -n lib%{name}%{soname} -p /sbin/ldconfig %files -%defattr(-,root,root) -%doc %{_mandir}/man1/%{name}.1%{ext_man} +%{_mandir}/man1/%{name}.1%{ext_man} %{_bindir}/%{name} %files -n lib%{name}%{soname} -%defattr(-,root,root) %{_libdir}/lib%{name}.so.%{version} %files devel -%defattr(-,root,root) %{_libdir}/lib%{name}.so %{_libdir}/lib%{name}.so.%{soname} %{_libdir}/pkgconfig/%{name}.pc
View file
_service
Added
@@ -0,0 +1,17 @@ +<services> + <service name="tar_scm" mode="disabled"> + <param name="filename">nordlicht</param> + <param name="revision">7ad3f008afe803037b332822028faed64b1751bd</param> + <param name="scm">git</param> + <param name="submodules">disable</param> + <param name="url">https://github.com/nordlicht/nordlicht.git</param> + <param name="versionformat">@PARENT_TAG@</param> + <param name="versionrewrite-pattern">v?(^++)(.*)</param> + <param name="versionrewrite-replacement">\1</param> + </service> + <service name="recompress" mode="disabled"> + <param name="file">*.tar</param> + <param name="compression">xz</param> + </service> + <service name="set_version" mode="disabled"/> +</services>
View file
nordlicht-0.4.4.tar.gz/.gitignore
Deleted
@@ -1,18 +0,0 @@ -# Build products -CMakeCache.txt -CMakeFiles/ -cmake_install.cmake -CTestTestfile.cmake -libnordlicht.so -libnordlicht.so.* -Makefile -nordlicht -nordlicht.1 -nordlicht.pc -testsuite -version.h - -# Testing -test_tmp_* -video.mp4 -*.png
View file
nordlicht-0.4.4.tar.gz/image.c
Deleted
@@ -1,286 +0,0 @@ -#include "image.h" -#include "error.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <libswscale/swscale.h> - -#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0) -#define av_frame_alloc avcodec_alloc_frame -#define av_frame_free av_freep -void av_frame_get_buffer(AVFrame *frame, int magic) { avpicture_alloc((AVPicture *)frame, frame->format, frame->width, frame->height); } -void av_frame_copy(AVFrame *dst, AVFrame *src) { memcpy(dst->data0, src->data0, sizeof(uint8_t)*avpicture_get_size(PIX_FMT_RGB24, dst->width, dst->height)); } -#endif - -#define MAX_FILTER_SIZE 256 - -struct image { - AVFrame *frame; -}; - -image *image_init(const int width, const int height) { - image *i; - i = (image *) malloc(sizeof(image)); - - i->frame = (AVFrame *) av_frame_alloc(); - i->frame->width = width; - i->frame->height = height; - i->frame->format = PIX_FMT_RGB24; // best choice? - av_frame_get_buffer(i->frame, 16); // magic number? - return i; -} - -int image_width(const image *i) { - return i->frame->width; -} - -int image_height(const image *i) { - return i->frame->height; -} - -void image_set(const image *i, const int x, const int y, const unsigned char r, const unsigned char g, const unsigned char b) { - *(i->frame->data0+y*i->frame->linesize0+x*3+0) = r; - *(i->frame->data0+y*i->frame->linesize0+x*3+1) = g; - *(i->frame->data0+y*i->frame->linesize0+x*3+2) = b; -} - -unsigned char image_get_r(const image *i, const int x, const int y) { - return *(i->frame->data0+y*i->frame->linesize0+x*3+0); -} - -unsigned char image_get_g(const image *i, const int x, const int y) { - return *(i->frame->data0+y*i->frame->linesize0+x*3+1); -} - -unsigned char image_get_b(const image *i, const int x, const int y) { - return *(i->frame->data0+y*i->frame->linesize0+x*3+2); -} - -void image_to_bgra(unsigned char *target, const int width, const int height, const image *i, const int offset_x, const int offset_y) { - int x, y; - for (y = 0; y < image_height(i) && offset_y+y < height ; y++) { - for (x = 0; x < image_width(i) && offset_x+x < width; x++) { - *(target+width*4*(offset_y+y)+4*(offset_x+x)+0) = image_get_b(i, x, y); - *(target+width*4*(offset_y+y)+4*(offset_x+x)+1) = image_get_g(i, x, y); - *(target+width*4*(offset_y+y)+4*(offset_x+x)+2) = image_get_r(i, x, y); - *(target+width*4*(offset_y+y)+4*(offset_x+x)+3) = 255; - } - } -} - -image *image_from_bgra(const unsigned char *source, const int width, const int height) { - image *i = image_init(width, height); - int x, y; - for (y = 0; y < image_height(i); y++) { - for (x = 0; x < image_width(i); x++) { - image_set(i, x, y, *(source+width*4*y+4*x+2), *(source+width*4*y+4*x+1), *(source+width*4*y+4*x+0)); - } - } - return i; -} - -image* image_clone(const image *i) { - image *i2 = image_init(image_width(i), image_height(i)); - av_frame_copy(i2->frame, i->frame); - return i2; -} - -void image_copy_avframe(const image *i, AVFrame *frame) { - av_frame_copy(i->frame, frame); -} - -image* image_dumb_scale(const image *i, const int width, const int height) { - image *i2 = image_init(width, height); - - float x_factor = 1.0*image_width(i)/width; - float y_factor = 1.0*image_height(i)/height; - - int x, y; - for (x = 0; x < width; x++) { - int x_lower = x_factor*x + 0.5; - int x_upper = x_factor*(x+1) - 0.5; - - if (x_lower > x_upper) { - // this can happen when upscaling. pick nearest-neighbour entry - x_lower = x_upper = x_factor*(x+0.5); - } - - for (y = 0; y < height; y++) { - int y_lower = y_factor*y + 0.5; - int y_upper = y_factor*(y+1) - 0.5; - - if (y_lower > y_upper) { - // this can happen when upscaling. pick nearest-neighbour entry - y_lower = y_upper = y_factor*(y+0.5); - } - - int rsum = 0; - int gsum = 0; - int bsum = 0; - int xx, yy; - for (xx = x_lower; xx <= x_upper; xx++) { - for (yy = y_lower; yy <= y_upper; yy++) { - rsum += image_get_r(i, xx, yy); - gsum += image_get_g(i, xx, yy); - bsum += image_get_b(i, xx, yy); - } - } - int n = (x_upper-x_lower+1)*(y_upper-y_lower+1); - image_set(i2, x, y, rsum/n, gsum/n, bsum/n); - } - } - - return i2; -} - -image* image_scale(const image *i, int width, int height) { - int target_width = width; - int target_height = height; - - if (width == image_width(i) && height == image_height(i)) { - return image_clone(i); - } - - image *i2 = NULL; - image *tmp = (image *) i; - do { - width = target_width; - height = target_height; - -#if LIBSWSCALE_VERSION_MICRO < 100 || LIBSWSCALE_VERSION_INT < AV_VERSION_INT(2, 1, 103) - if (width < 8) { - // libav and old FFmpeg versions don't allow scaling to a width of less than 8 - if (image_width(tmp) > 8) { - // but we can use it to go down to 8 - width = 8; - } else { - // all hope ist lost - image *i3 = image_dumb_scale(tmp, width, height); - if (tmp != i) { - image_free(tmp); - } - return i3; - } - } - - if (height < 2) { - // This doesn't seem to work on libav... - if (image_height(tmp) > 2) { - height = 2; - } else { - image *i3 = image_dumb_scale(tmp, width, height); - if (tmp != i) { - image_free(tmp); - } - return i3; - } - } -#endif - - // When scaling from a high width directly to 1, FFmpeg sometimes (?) - // introduces noise. So we avoid this situation. - if (width == 1 && image_width(tmp) > 2) { - width = 2; - } - - if (image_width(tmp)/width > MAX_FILTER_SIZE) { - width = image_width(tmp)/MAX_FILTER_SIZE+1; - } - if (image_height(tmp)/height > MAX_FILTER_SIZE) { - height = image_height(tmp)/MAX_FILTER_SIZE+1; - } - - - i2 = image_init(width, height); - - struct SwsContext *sws_context = sws_getContext(image_width(tmp), image_height(tmp), tmp->frame->format, - image_width(i2), image_height(i2), i2->frame->format, - SWS_AREA, NULL, NULL, NULL); - sws_scale(sws_context, (uint8_t const * const *)tmp->frame->data, - tmp->frame->linesize, 0, tmp->frame->height, i2->frame->data, - i2->frame->linesize); - sws_freeContext(sws_context); - - if (tmp != i) { - image_free(tmp); - } - - tmp = i2; - } while (image_width(i2) != target_width || image_height(i2) != target_height); - - return i2; -} - -image *image_flip(const image *i) { - image *i2 = image_init(image_height(i), image_width(i)); - int x, y; - for (x = 0; x < image_width(i2); x++) { - for (y = 0; y < image_height(i2); y++) { - image_set(i2, x, y, image_get_r(i, y, x), image_get_g(i, y, x), image_get_b(i, y, x)); - } - } - return i2; -} - -image* image_column(const image *i, double percent) { - image *i2 = image_init(1, image_height(i)); - - int y; - const int x = image_width(i)*percent; - for (y = 0; y < image_height(i); y++) { - image_set(i2, 0, y, image_get_r(i, x, y), image_get_g(i, x, y), image_get_b(i, x, y)); - } - - return i2; -} - -int image_write_png(const image *i, const char *file_path) { - AVCodec *encoder = avcodec_find_encoder_by_name("png"); - AVCodecContext *encoder_context; - encoder_context = avcodec_alloc_context3(encoder); - encoder_context->width = i->frame->width; - encoder_context->height = i->frame->height; - encoder_context->pix_fmt = PIX_FMT_RGB24; - if (avcodec_open2(encoder_context, encoder, NULL) < 0) { - error("Could not open output codec."); - return -1; - } - - AVPacket packet; - av_init_packet(&packet); - packet.data = NULL; - packet.size = 0; - -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 28, 0) - uint8_t buffer200000; // TODO: Why this size? - packet.size = avcodec_encode_video(encoder_context, buffer, 200000, i->frame); - packet.data = buffer; -#else - int got_packet = 0; - avcodec_encode_video2(encoder_context, &packet, i->frame, &got_packet); - if (! got_packet) { - error("Encoding error."); - return -1; - } -#endif - - FILE *file; - file = fopen(file_path, "wb"); - if (! file) { - error("Could not open output file."); - return -1; - } - fwrite(packet.data, 1, packet.size, file); - fclose(file); - - av_free_packet(&packet); - - avcodec_close(encoder_context); - av_free(encoder_context); - return 0; -} - -void image_free(image *i) { - av_frame_free(&i->frame); - free(i); -}
View file
nordlicht-0.4.4.tar.gz/main.c
Deleted
@@ -1,298 +0,0 @@ -#include <pthread.h> -#include <sys/file.h> -#include <sys/mman.h> -#include <stdarg.h> -#include <unistd.h> -#include <string.h> -#include <popt.h> -#include "nordlicht.h" -#include "version.h" - -#ifdef _WIN32 -// from http://stackoverflow.com/a/8514474/248734 -char* strsep(char** stringp, const char* delim) { - char* start = *stringp; - char* p; - - p = (start != NULL) ? strpbrk(start, delim) : NULL; - - if (p == NULL) { - *stringp = NULL; - } else { - *p = '\0'; - *stringp = p + 1; - } - - return start; -} -#endif - -typedef struct { - const char *name; - const char *description; - nordlicht_style style; -} style; - -const style style_table = { - {"horizontal", "compress frames to vertical lines and append them", NORDLICHT_STYLE_HORIZONTAL}, - {"vertical", "compress frames to horizontal lines and rotate them counterclockwise by 90 degrees", NORDLICHT_STYLE_VERTICAL}, - {"slitscan", "take single columns while constantly moving to the right (and wrapping back to the left)", NORDLICHT_STYLE_SLITSCAN}, - {"middlecolumn", "take the middlemost column of each frame", NORDLICHT_STYLE_MIDDLECOLUMN}, - {"thumbnails", "display small thumbnails at regular intervals", NORDLICHT_STYLE_THUMBNAILS}, - {"spectrogram", "spectrogram of the first audio track (not all sample formats are supported yet)", NORDLICHT_STYLE_SPECTROGRAM}, - {NULL, NULL, NORDLICHT_STYLE_LAST} -}; - -void print_error(const char *message, ...) { - fprintf(stderr, "nordlicht: "); - va_list arglist; - va_start(arglist, message); - vfprintf(stderr, message, arglist); - va_end(arglist); - fprintf(stderr, "\n"); -} - -const char *filename_ext(const char *path) { - const char *dot = strrchr(path, '.'); - if (!dot || dot == path) return ""; - return dot+1; -} - -void print_help(const poptContext popt, const int ret) { - poptPrintHelp(popt, ret == 0 ? stdout : stderr, 0); - - printf("\nStyles:\n"); - int i; - for (i = 0; style_tablei.name; i++) { - printf(" %-14s %s\n", style_tablei.name, style_tablei.description); - } - - printf("\n\ -Examples:\n\ - nordlicht video.mp4 generate video.mp4.png of 1000 x 100 pixels size\n\ - nordlicht video.mp4 --style=vertical compress individual frames to columns\n\ - nordlicht video.mp4 -w 1920 -h 200 -o barcode.png override size and name of the output file\n"); - - exit(ret); -} - -int main(const int argc, const char **argv) { - int width = -1; - int height = -1; - float start = 0.0; - float end = 1.0; - char *output_file = NULL; - char *styles_string = NULL; - nordlicht_strategy strategy; - int free_output_file = 0; - - int quiet = 0; - int help = 0; - int version = 0; - - const struct poptOption optionsTable = { - {"width", 'w', POPT_ARG_INT, &width, 0, "set the barcode's width; by default it's \"height*10\", or 1920 pixels, if both are undefined", NULL}, - {"height", 'h', POPT_ARG_INT, &height, 0, "set the barcode's height; by default it's \"width/10\"", NULL}, - {"output", 'o', POPT_ARG_STRING, &output_file, 0, "set output filename, the default is VIDEOFILE.png; when you specify an *.bgra file, you'll get a raw 32-bit BGRA file that is updated as the barcode is generated", "FILENAME"}, - {"style", 's', POPT_ARG_STRING, &styles_string, 0, "default is 'horizontal', see \"Styles\" section below. You can specify more than one style, separated by '+', to get multiple tracks", "STYLE"}, - {"start", '\0', POPT_ARG_FLOAT, &start, 0, "specify where to start the barcode (in percent between 0 and 1)", NULL}, - {"end", '\0', POPT_ARG_FLOAT, &end, 0, "specify where to end the barcode (in percent between 0 and 1)", NULL}, - {"quiet", 'q', 0, &quiet, 0, "don't show progress indicator", NULL}, - {"help", '\0', 0, &help, 0, "display this help and exit", NULL}, - {"version", '\0', 0, &version, 0, "output version information and exit", NULL}, - POPT_TABLEEND - }; - - const poptContext popt = poptGetContext(NULL, argc, argv, optionsTable, 0); - poptSetOtherOptionHelp(popt, "OPTION... VIDEOFILE\n\nOptions:"); - - char c; - - // The next line leaks 3 bytes, blame popt! - while ((c = poptGetNextOpt(popt)) >= 0) { } - - if (c < -1) { - fprintf(stderr, "nordlicht: %s: %s\n", poptBadOption(popt, POPT_BADOPTION_NOALIAS), poptStrerror(c)); - return 1; - } - - if (version) { - printf("nordlicht %s\n\nWritten by Sebastian Morr and contributors.\n", NORDLICHT_VERSION); - return 0; - } - - if (help) { - print_help(popt, 0); - } - - const char *filename = (char*)poptGetArg(popt); - - if (filename == NULL) { - print_error("Please specify an input file."); - exit(1); - } - - if (poptGetArg(popt) != NULL) { - print_error("Please specify only one input file."); - exit(1); - } - - if (output_file == NULL) { - size_t len = snprintf(NULL, 0, "%s.nordlicht.png", filename) + 1; - output_file = (char *) malloc(len); - snprintf(output_file, len, "%s.nordlicht.png", filename); - free_output_file = 1; - } - - if (width == -1 && height != -1) { - width = height*10; - } - if (height == -1 && width != -1) { - height = width/10; - if (height < 1) { - height = 1; - } - } - if (height == -1 && width == -1) { - width = 1920; - height = 192; - } - - if (styles_string == NULL) { - styles_string = "horizontal"; - } - - // count the occurrences of "+" in the styles_string - const char *s = styles_string; - int num_tracks; - for (num_tracks=0; snum_tracks; snum_tracks=='+' ? num_tracks++ : *s++); - num_tracks++; - - nordlicht_style *styles; - styles = (nordlicht_style *) malloc(num_tracks * sizeof(nordlicht_style)); - - const char *style_string; - num_tracks = 0; - while ((style_string = strsep(&styles_string, "+"))) { - int i; - for (i = 0; style_tablei.name; i++) { - if (strcmp(style_string, style_tablei.name) == 0) { - stylesnum_tracks = style_tablei.style; - break; - } - } - - if (!style_tablei.name) { - print_error("Unknown style '%s'. Use '--help' to display available styles.", style_string); - exit(1); - } - num_tracks++; - } - - const char *ext = filename_ext(output_file); - if (strcmp(ext, "png") == 0) { - strategy = NORDLICHT_STRATEGY_FAST; - } else if (strcmp(ext, "bgra") == 0) { - strategy = NORDLICHT_STRATEGY_LIVE; - } else { - print_error("Unsupported file extension '%s'.", ext); - exit(1); - } - - // Interesting stuff begins here! - - nordlicht *n = nordlicht_init(filename, width, height); - unsigned char *data = NULL; - - if (n == NULL) { - print_error(nordlicht_error()); - exit(1); - } - - nordlicht_set_start(n, start); - nordlicht_set_end(n, end); - nordlicht_set_styles(n, styles, num_tracks); - nordlicht_set_strategy(n, strategy); - - if (nordlicht_error() != NULL) { - print_error(nordlicht_error()); - exit(1); - } - - if (strategy == NORDLICHT_STRATEGY_LIVE) { - int fd = open(output_file, O_CREAT | O_TRUNC | O_RDWR, 0666); - if (fd == -1) { - print_error("Could not open '%s'.", output_file); - exit(1); - } - ftruncate(fd, nordlicht_buffer_size(n)); - data = (unsigned char *) mmap(NULL, nordlicht_buffer_size(n), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == (void *) -1) { - print_error("Could not mmap %d bytes.", nordlicht_buffer_size(n)); - exit(1); - } - nordlicht_set_buffer(n, data); - close(fd); - } else { - // Try to write the empty buffer to fail early if this does not work - if (nordlicht_write(n, output_file) != 0) { - print_error(nordlicht_error()); - exit(1); - } - } - - pthread_t thread; - pthread_create(&thread, NULL, (void*(*)(void*))nordlicht_generate, n); - - if (! quiet) { - float progress = 0; - - printf("nordlicht: Building keyframe index... "); - fflush(stdout); - while (progress == 0) { - progress = nordlicht_progress(n); - nanosleep((const struct timespec){{0, 100000000L}}, NULL); - } - printf("done.\n"); - - while (progress < 1) { - progress = nordlicht_progress(n); - printf("\rnordlicht: %02.0f%%", progress*100); - fflush(stdout); - nanosleep((const struct timespec){{0, 100000000L}}, NULL); - } - } - - pthread_join(thread, NULL); - - if (nordlicht_error() != NULL) { - print_error(nordlicht_error()); - exit(1); - } - - if (strategy != NORDLICHT_STRATEGY_LIVE) { - if (nordlicht_write(n, output_file) != 0) { - print_error(nordlicht_error()); - exit(1); - } - } - - free(styles); - - if (strategy == NORDLICHT_STRATEGY_LIVE) { - munmap(data, nordlicht_buffer_size(n)); - } - - nordlicht_free(n); - - if (! quiet) { - printf(" -> '%s'\n", output_file); - } - - if (free_output_file) { - free(output_file); - } - - poptFreeContext(popt); - return 0; -}
View file
nordlicht-0.4.4.tar.gz/nordlicht.c
Deleted
@@ -1,331 +0,0 @@ -#include "nordlicht.h" -#include <string.h> -#include "error.h" -#include "source.h" - -#ifdef _WIN32 -#define realpath(N,R) _fullpath((R),(N),_MAX_PATH) -#endif - -typedef struct { - nordlicht_style style; - int height; -} track; - -struct nordlicht { - int width, height; - const char *filename; - track *tracks; - int num_tracks; - unsigned char *data; - - int owns_data; - int modifiable; - nordlicht_strategy strategy; - float progress; - source *source; -}; - -NORDLICHT_API size_t nordlicht_buffer_size(const nordlicht *n) { - return n->width * n->height * 4; -} - -NORDLICHT_API nordlicht* nordlicht_init(const char *filename, const int width, const int height) { - if (width < 1 || height < 1) { - error("Dimensions must be positive (got %dx%d)", width, height); - return NULL; - } - nordlicht *n; - n = (nordlicht *) malloc(sizeof(nordlicht)); - - n->width = width; - n->height = height; - n->filename = filename; - - n->data = (unsigned char *) calloc(nordlicht_buffer_size(n), 1); - if (n->data == 0) { - error("Not enough memory to allocate %d bytes", nordlicht_buffer_size(n)); - return NULL; - } - - n->owns_data = 1; - - n->num_tracks = 1; - n->tracks = (track *) malloc(sizeof(track)); - n->tracks0.style = NORDLICHT_STYLE_HORIZONTAL; - n->tracks0.height = n->height; - - n->strategy = NORDLICHT_STRATEGY_FAST; - n->modifiable = 1; - n->progress = 0; - n->source = source_init(filename); - - if (n->source == NULL) { - error("Could not open video file '%s'", filename); - free(n); - return NULL; - } - - return n; -} - -NORDLICHT_API void nordlicht_free(nordlicht *n) { - if (n->owns_data) { - free(n->data); - } - free(n->tracks); - source_free(n->source); - free(n); -} - -NORDLICHT_API const char *nordlicht_error() { - return get_error(); -} - -NORDLICHT_API int nordlicht_set_start(nordlicht *n, const float start) { - if (! n->modifiable) { - return -1; - } - - if (start < 0) { - error("'start' has to be >= 0."); - return -1; - } - - if (start >= source_end(n->source)) { - error("'start' has to be smaller than 'end'."); - return -1; - } - - source_set_start(n->source, start); - return 0; -} - -NORDLICHT_API int nordlicht_set_end(nordlicht *n, const float end) { - if (! n->modifiable) { - return -1; - } - - if (end > 1) { - error("'end' has to be <= 1."); - return -1; - } - - if (source_start(n->source) >= end) { - error("'start' has to be smaller than 'end'."); - return -1; - } - - source_set_end(n->source, end); - return 0; -} - -NORDLICHT_API int nordlicht_set_style(nordlicht *n, const nordlicht_style style) { - if (! n->modifiable) { - return -1; - } - - nordlicht_style styles1 = {style}; - return nordlicht_set_styles(n, styles, 1); -} - -NORDLICHT_API int nordlicht_set_styles(nordlicht *n, const nordlicht_style *styles, const int num_tracks) { - if (! n->modifiable) { - return -1; - } - - n->num_tracks = num_tracks; - - if (n->num_tracks > n->height) { - error("Height of %d px is too low for %d styles", n->height, n->num_tracks); - return -1; - } - - free(n->tracks); - n->tracks = (track *) malloc(n->num_tracks*sizeof(track)); - - int height_of_each_track = n->height/n->num_tracks; - int i; - for (i=0; i<num_tracks; i++) { - nordlicht_style s = stylesi; - if (s > NORDLICHT_STYLE_LAST-1) { - return -1; - } - - n->tracksi.style = s; - n->tracksi.height = height_of_each_track; - } - n->tracks0.height = n->height - (n->num_tracks-1)*height_of_each_track; - - return 0; -} - -NORDLICHT_API int nordlicht_set_strategy(nordlicht *n, const nordlicht_strategy s) { - if (! n->modifiable) { - return -1; - } - if (s > NORDLICHT_STRATEGY_LIVE) { - return -1; - } - n->strategy = s; - return 0; -} - -NORDLICHT_API int nordlicht_generate(nordlicht *n) { - n->modifiable = 0; - - source_build_keyframe_index(n->source, n->width); - - int x, exact; - - const int do_a_fast_pass = (n->strategy == NORDLICHT_STRATEGY_LIVE) || !source_exact(n->source); - const int do_an_exact_pass = source_exact(n->source); - - for (exact = (!do_a_fast_pass); exact <= do_an_exact_pass; exact++) { - int i; - int y_offset = 0; - for(i = 0; i < n->num_tracks; i++) { - // call this for each track, to seek to the beginning - source_set_exact(n->source, exact); - - for (x = 0; x < n->width; x++) { - image *frame; - - if (n->tracksi.style == NORDLICHT_STYLE_SPECTROGRAM) { - if (!source_has_audio(n->source)) { - error("File contains no audio, please select an appropriate style"); - n->progress = 1; - return -1; - } - frame = source_get_audio_frame(n->source, 1.0*(x+0.5-COLUMN_PRECISION/2.0)/n->width, - 1.0*(x+0.5+COLUMN_PRECISION/2.0)/n->width); - } else { - if (!source_has_video(n->source)) { - error("File contains no video, please select an appropriate style"); - n->progress = 1; - return -1; - } - frame = source_get_video_frame(n->source, 1.0*(x+0.5-COLUMN_PRECISION/2.0)/n->width, - 1.0*(x+0.5+COLUMN_PRECISION/2.0)/n->width); - } - if (frame == NULL) { - continue; - } - - int thumbnail_width = 1.0*(image_width(frame)*n->tracksi.height/image_height(frame)); - image *column = NULL; - image *tmp = NULL; - switch (n->tracksi.style) { - case NORDLICHT_STYLE_THUMBNAILS: - column = image_scale(frame, thumbnail_width, n->tracksi.height); - break; - case NORDLICHT_STYLE_HORIZONTAL: - column = image_scale(frame, 1, n->tracksi.height); - break; - case NORDLICHT_STYLE_VERTICAL: - tmp = image_scale(frame, n->tracksi.height, 1); - column = image_flip(tmp); - image_free(tmp); - break; - case NORDLICHT_STYLE_SLITSCAN: - tmp = image_column(frame, 1.0*(x%thumbnail_width)/thumbnail_width); - - column = image_scale(tmp, 1, n->tracksi.height); - image_free(tmp); - break; - case NORDLICHT_STYLE_MIDDLECOLUMN: - tmp = image_column(frame, 0.5); - column = image_scale(tmp, 1, n->tracksi.height); - image_free(tmp); - break; - case NORDLICHT_STYLE_SPECTROGRAM: - column = image_scale(frame, 1, n->tracksi.height); - break; - default: - // cannot happen (TM) - return -1; - break; - } - - image_to_bgra(n->data, n->width, n->height, column, x, y_offset); - - n->progress = (i+1.0*x/n->width)/n->num_tracks; - x = x + image_width(column) - 1; - - image_free(column); - } - - y_offset += n->tracksi.height; - } - } - - n->progress = 1.0; - return 0; -} - -NORDLICHT_API int nordlicht_write(const nordlicht *n, const char *filename) { - int code = 0; - - if (filename == NULL) { - error("Output filename must not be NULL"); - return -1; - } - - if (strcmp(filename, "") == 0) { - error("Output filename must not be empty"); - return -1; - } - - char *realpath_output = realpath(filename, NULL); - if (realpath_output != NULL) { - // output file exists - char *realpath_input = realpath(n->filename, NULL); - if (realpath_input != NULL) { - // otherwise, input filename is probably a URL - - if (strcmp(realpath_input, realpath_output) == 0) { - error("Will not overwrite input file"); - code = -1; - } - free(realpath_input); - } - free(realpath_output); - - if (code != 0) { - return code; - } - } - - image *i = image_from_bgra(n->data, n->width, n->height); - if (image_write_png(i, filename) != 0) { - return -1; - } - image_free(i); - - return code; -} - -NORDLICHT_API float nordlicht_progress(const nordlicht *n) { - return n->progress; -} - -NORDLICHT_API const unsigned char* nordlicht_buffer(const nordlicht *n) { - return n->data; -} - -NORDLICHT_API int nordlicht_set_buffer(nordlicht *n, unsigned char *data) { - if (! n->modifiable) { - return -1; - } - - if (data == NULL) { - return -1; - } - - if (n->owns_data) { - free(n->data); - } - n->owns_data = 0; - n->data = data; - return 0; -}
View file
nordlicht-0.4.4.tar.gz/nordlicht.h
Deleted
@@ -1,101 +0,0 @@ -#ifndef INCLUDE_nordlicht_h__ -#define INCLUDE_nordlicht_h__ -#include <stdlib.h> // for size_t - - -#ifndef NORDLICHT_API -# ifdef _WIN32 -# if defined(NORDLICHT_BUILD_SHARED) /* build dll */ -# define NORDLICHT_API __declspec(dllexport) -# elif !defined(NORDLICHT_BUILD_STATIC) /* use dll */ -# define NORDLICHT_API __declspec(dllimport) -# else /* static library */ -# define NORDLICHT_API -# endif -# else -# if __GNUC__ >= 4 -# define NORDLICHT_API __attribute__((visibility("default"))) -# else -# define NORDLICHT_API -# endif -# endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct nordlicht nordlicht; - -typedef enum nordlicht_style { - NORDLICHT_STYLE_THUMBNAILS, - NORDLICHT_STYLE_HORIZONTAL, // compress frames to columns, "move to the right" - NORDLICHT_STYLE_VERTICAL, // compress frames to rows, "move downwards" - NORDLICHT_STYLE_SLITSCAN, // take single columns, while moving to the right (and wrapping to the left) - NORDLICHT_STYLE_MIDDLECOLUMN, // take the frames' middlemost column - NORDLICHT_STYLE_SPECTROGRAM, // spectrogram of the first audio track (not all sample formats are supported yet) - NORDLICHT_STYLE_LAST -} nordlicht_style; - -typedef enum nordlicht_strategy { - NORDLICHT_STRATEGY_FAST, // generate barcode in a single pass as fast as possible - NORDLICHT_STRATEGY_LIVE, // generate a fast approximation first, good for live display -} nordlicht_strategy; - -// Returns a description of the last error, or NULL if the was no error. -NORDLICHT_API const char *nordlicht_error(); - -// Allocate a new nordlicht of specific width and height, for a given video -// file. When `live` is true, give a fast approximation before starting the -// slow, exact generation. Use `nordlicht_free` to free the nordlicht again. -// Returns NULL on errors. -NORDLICHT_API nordlicht* nordlicht_init(const char *filename, const int width, const int height); - -// Free a nordlicht. -NORDLICHT_API void nordlicht_free(nordlicht *n); - -// Specify where to start the nordlicht, in percent between 0 and 1. -NORDLICHT_API int nordlicht_set_start(nordlicht *n, const float start); - -// Specify where to end the nordlicht, in percent between 0 and 1. -NORDLICHT_API int nordlicht_set_end(nordlicht *n, const float end); - -// Set the output style of the nordlicht. Default is NORDLICHT_STYLE_HORIZONTAL. -// Returns 0 on success. To set multiple styles at once, use `nordlicht_set_styles`. -NORDLICHT_API int nordlicht_set_style(nordlicht *n, const nordlicht_style style); - -// Set multiple output styles, which will be displayed on top of each other. -// Expects a pointer to an array of nordlicht_style-s of length `num_styles`. -// Returns 0 on success. -NORDLICHT_API int nordlicht_set_styles(nordlicht *n, const nordlicht_style *styles, const int num_styles); - -// Set the generation strategy of the nordlicht. Default is NORDLICHT_STRATEGY_FAST. -// Returns 0 on success. This function will be removed in the future. -NORDLICHT_API int nordlicht_set_strategy(nordlicht *n, const nordlicht_strategy strategy); - -// Returns a pointer to the nordlicht's internal buffer. You can use it to draw -// the barcode while it is generated. The pixel format is 32-bit BGRA. -NORDLICHT_API const unsigned char* nordlicht_buffer(const nordlicht *n); - -// Replace the internal nordlicht's internal buffer. The data pointer is owned -// by the caller and must be freed after `nordlicht_free`. Returns 0 on success. -NORDLICHT_API int nordlicht_set_buffer(nordlicht *n, unsigned char *data); - -// Returns the size of this nordlicht's buffer in bytes. -NORDLICHT_API size_t nordlicht_buffer_size(const nordlicht *n); - -// Generate the nordlicht. Calling this will freeze the nordlicht: -// "set" functions will fail. Returns 0 on success. -NORDLICHT_API int nordlicht_generate(nordlicht *n); - -// Returns a value between 0 and 1 indicating how much of the nordlicht is done. -NORDLICHT_API float nordlicht_progress(const nordlicht *n); - -// Write the nordlicht to a PNG file. Returns 0 on success. -NORDLICHT_API int nordlicht_write(const nordlicht *n, const char *filename); - -#ifdef __cplusplus -} -#endif - -#endif
View file
nordlicht-0.4.4.tar.gz/source.c
Deleted
@@ -1,467 +0,0 @@ -#include "source.h" -#include "error.h" -#include <libavcodec/avcodec.h> -#include <libavcodec/avfft.h> -#include <libavformat/avformat.h> -#include <libavutil/avutil.h> -#include <libswscale/swscale.h> - -#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0) -#define av_frame_alloc avcodec_alloc_frame -#define av_frame_free av_freep -#endif - -#define HEURISTIC_NUMBER_OF_FRAMES 1800 // how many frames will the heuristic look at? -#define HEURISTIC_KEYFRAME_FACTOR 1 // lower bound for the actual/required keyframe ratio - -#define SAMPLES_PER_FRAME 1024 - -typedef struct { - int stream; - AVCodecContext *codec; - image *last_frame; - - double time_base; - double fps; - AVFrame *frame; - long current_frame; -} stream; - -struct source { - int exact; - float start, end; - - AVFormatContext *format; - stream *video; - stream *audio; - - uint8_t *buffer; - AVFrame *scaleframe; - struct SwsContext *sws_context; - AVPacket packet; - - // audio specific - RDFTContext *rdft; - - int *keyframes; - int number_of_keyframes; - int has_index; -}; - -long packet_pts(stream *st, const AVPacket *packet) { - long pts = packet->pts != 0 ? packet->pts : packet->dts; - double sec = st->time_base*pts; - return (int64_t)(st->fps*sec + 0.5); -} - -int grab_next_frame(source *s, stream *st) { - int valid = 0; - int got_frame = 0; - - long pts; - - while (!valid) { - if (av_read_frame(s->format, &s->packet) >= 0) { - if (s->packet.stream_index == st->stream) { - switch (st->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - avcodec_decode_video2(st->codec, st->frame, &got_frame, &s->packet); - break; - case AVMEDIA_TYPE_AUDIO: - avcodec_decode_audio4(st->codec, st->frame, &got_frame, &s->packet); - break; - default: - error("Stream has unknown media type."); - return 1; - } - - if (got_frame) { - if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - if (st->frame->data0 == 0) { - return 1; - } - } - pts = packet_pts(st, &s->packet); - valid = 1; - } - } - av_free_packet(&s->packet); - } else { - av_free_packet(&s->packet); - st->current_frame = -1; - return 1; - } - } - - av_free_packet(&s->packet); - st->current_frame = pts; - return 0; -} - -int seek_keyframe(source *s, stream *st, const long frame) { - av_seek_frame(s->format, st->stream, frame/st->fps/st->time_base, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(st->codec); - return grab_next_frame(s, st) != 0; -} - -int total_number_of_frames(const source *s, stream *st) { - double duration_sec = 1.0*s->format->duration/AV_TIME_BASE; - return st->fps*duration_sec; -} - -void source_build_keyframe_index(source *s, const int width) { - if (! s->video) { - return; - } - - s->keyframes = (int *) malloc(sizeof(long)*60*60*3); // TODO: dynamic datastructure! - s->number_of_keyframes = 0; - - int frame = 0; - - s->has_index = 0; - s->exact = 1; - seek_keyframe(s, s->video, 0); - - while (av_read_frame(s->format, &s->packet) >= 0) { - if (s->packet.stream_index == s->video->stream) { - if (!!(s->packet.flags & AV_PKT_FLAG_KEY)) { - s->number_of_keyframes++; - - long pts = packet_pts(s->video, &s->packet); - if (pts < 1 && s->number_of_keyframes > 0) { - pts = frame; - } - - s->keyframess->number_of_keyframes = pts; - } - if (frame == HEURISTIC_NUMBER_OF_FRAMES) { - const float density = 1.0*s->number_of_keyframes/HEURISTIC_NUMBER_OF_FRAMES; - const float required_density = 1.0*HEURISTIC_KEYFRAME_FACTOR/COLUMN_PRECISION*width/total_number_of_frames(s, s->video)/(s->end-s->start); - if (density > required_density) { - // The keyframe density in the first `HEURISTIC_NUMBER_OF_FRAMES` - // frames is HEURISTIC_KEYFRAME_FACTOR times higher than - // the density we need overall. - s->exact = 0; - av_free_packet(&s->packet); - return; - } - } - frame++; - } - av_free_packet(&s->packet); - } - av_free_packet(&s->packet); - s->has_index = 1; -} - -stream* stream_init(source *s, enum AVMediaType type) { - stream *st; - st = (stream *) malloc(sizeof(stream)); - - st->last_frame = NULL; - - st->stream = av_find_best_stream(s->format, type, -1, -1, NULL, 0); - if (st->stream < 0) { - free(st); - return NULL; - } - st->codec = s->format->streamsst->stream->codec; - AVCodec *codec = NULL; - codec = avcodec_find_decoder(st->codec->codec_id); - if (codec == NULL) { - error("Unsupported codec!"); - free(st); - return NULL; - } - if (avcodec_open2(st->codec, codec, NULL) < 0) { - free(st); - return NULL; - } - - st->time_base = av_q2d(s->format->streamsst->stream->time_base); - - switch (st->codec->codec_type) { - case AVMEDIA_TYPE_VIDEO: - st->fps = av_q2d(s->format->streamsst->stream->avg_frame_rate); - break; - case AVMEDIA_TYPE_AUDIO: - st->fps = st->codec->sample_rate; - break; - default: - error("Stream has unknown media type."); - free(st); - return NULL; - } - - st->frame = av_frame_alloc(); - st->current_frame = -1; - - if (grab_next_frame(s, st) != 0) { - free(st); - return NULL; - } - - return st; -} - -source* source_init(const char *filename) { - if (filename == NULL) { - return NULL; - } - - av_log_set_level(AV_LOG_FATAL); - av_register_all(); - - source *s; - s = (source *) malloc(sizeof(source)); - s->exact = 1; - s->start = 0.0; - s->end = 1.0; - s->format = NULL; - - if (avformat_open_input(&s->format, filename, NULL, NULL) != 0) { - free(s); - return NULL; - } - if (avformat_find_stream_info(s->format, NULL) < 0) { - avformat_close_input(&s->format); - return NULL; - } - - s->video = stream_init(s, AVMEDIA_TYPE_VIDEO); - s->audio = stream_init(s, AVMEDIA_TYPE_AUDIO); - - if (!s->video && !s->audio) { - error("File contains neither video nor audio"); - avformat_close_input(&s->format); - return NULL; - } - - s->has_index = 0; - - if (s->video) { - s->scaleframe = av_frame_alloc(); - s->scaleframe->width = s->video->frame->width; - s->scaleframe->height = s->video->frame->height; - s->scaleframe->format = PIX_FMT_RGB24; - - s->buffer = (uint8_t *)av_malloc(sizeof(uint8_t)*avpicture_get_size(PIX_FMT_RGB24, s->scaleframe->width, s->scaleframe->height)); - avpicture_fill((AVPicture *)s->scaleframe, s->buffer, PIX_FMT_RGB24, s->video->frame->width, s->video->frame->height); - - s->sws_context = sws_getCachedContext(NULL, s->video->frame->width, s->video->frame->height, s->video->frame->format, - s->scaleframe->width, s->scaleframe->height, PIX_FMT_RGB24, SWS_AREA, NULL, NULL, NULL); - } - - s->keyframes = NULL; - - // audio specific - if (s->audio) { - s->rdft = av_rdft_init(log2(SAMPLES_PER_FRAME), DFT_R2C); - } - - return s; -} - -int source_has_video(source *s) { - return s->video != NULL; -} - -int source_has_audio(source *s) { - return s->audio != NULL; -} - -long preceding_keyframe(source *s, const long frame_nr) { - int i; - long best_keyframe = -1; - for (i = 0; i < s->number_of_keyframes; i++) { - if (s->keyframesi <= frame_nr) { - best_keyframe = s->keyframesi; - } - } - return best_keyframe; -} - -int seek(source *s, stream *st, const long min_frame_nr, const long max_frame_nr) { - if (s->exact && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - long keyframe = preceding_keyframe(s, max_frame_nr); - - if (keyframe > st->current_frame) { - if (seek_keyframe(s, st, keyframe) != 0) { - return 1; - } - } - - while (st->current_frame < min_frame_nr) { - if (st->current_frame > max_frame_nr) { - error("Target frame is in the past. This shoudn't happen. Please file a bug."); - } - if (grab_next_frame(s, st) != 0) { - return 1; - } - } - } else { - if (seek_keyframe(s, st, (min_frame_nr+max_frame_nr)/2) != 0) { - return 1; - } - } - return 0; -} - -int colormap_r(float dbfs) { - if (dbfs >= -30) return 255; - if (dbfs <= -40) return 0; - return (dbfs+40)/10.0*255; -} - -int colormap_g(float dbfs) { - if (dbfs >= -10) return (dbfs+10)/10.0*255; - if (dbfs < -20 && dbfs >= -30) return 255-(dbfs+30)/10.0*255; - if (dbfs < -30 && dbfs >= -50) return 255; - if (dbfs < -50 && dbfs >= -60) return (dbfs+60)/10.0*255; - return 0; -} - -int colormap_b(float dbfs) { - if (dbfs >= -10) return 255; - if (dbfs < -10 && dbfs >= -20) return (dbfs+20)/10.0*255; - if (dbfs < -40 && dbfs >= -50) return 255-(dbfs+50)/10.0*255; - if (dbfs < -50 && dbfs >= -60) return 255; - if (dbfs < -60 && dbfs >= -70) return (dbfs+70)/10.0*255; - return 0; -} - -image* get_frame(source *s, stream *st, const double min_percent, const double max_percent) { - float proportion = s->end-s->start; - const long min_frame = (min_percent*proportion + s->start)*total_number_of_frames(s, st); - const long max_frame = (max_percent*proportion + s->start)*total_number_of_frames(s, st); - - if (st->last_frame != NULL && !s->exact && s->has_index) { - if (st->current_frame >= preceding_keyframe(s, (max_frame+min_frame)/2)) { - return st->last_frame; - } - } - - if (seek(s, st, min_frame, max_frame) != 0) { - return NULL; - } - - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - if (st->last_frame == NULL) { - st->last_frame = image_init(st->frame->width, st->frame->height); - } - - sws_scale(s->sws_context, (uint8_t const * const *)st->frame->data, - st->frame->linesize, 0, st->frame->height, s->scaleframe->data, - s->scaleframe->linesize); - - image_copy_avframe(st->last_frame, s->scaleframe); - } else { - if (s->audio->last_frame == NULL) { - s->audio->last_frame = image_init(1, 100); - } - - float *data; - int i; - switch(st->codec->sample_fmt) { - case AV_SAMPLE_FMT_FLTP: - data = (float *) s->audio->frame->data0; - break; - case AV_SAMPLE_FMT_S16P: - data = (float *) malloc(sizeof(float)*SAMPLES_PER_FRAME); - for (i = 0; i < SAMPLES_PER_FRAME; i++) { - float val = ((int16_t *) s->audio->frame->data0)i/100000.0; - datai = val; - } - - break; - default: - error("Unsupported sample format (%d), see https://github.com/nordlicht/nordlicht/issues/26", st->codec->sample_fmt); - return NULL; - } - - av_rdft_calc(s->rdft, data); - - int f; - for (f = 0; f < 100; f++) { - double absval = data2*f+0*data2*f+0+data2*f+1*data2*f+1; - double dbfs = 10*log10(absval/10000.0); // TODO: finetune - image_set(s->audio->last_frame, 0, 100-f-1, colormap_r(dbfs), colormap_g(dbfs), colormap_b(dbfs)); - } - } - - return st->last_frame; -} - -image* source_get_video_frame(source *s, const double min_percent, const double max_percent) { - return get_frame(s, s->video, min_percent, max_percent); -} - -image* source_get_audio_frame(source *s, const double min_percent, const double max_percent) { - return get_frame(s, s->audio, min_percent, max_percent); -} - -int source_exact(const source *s) { - return s->exact; -} - -void source_set_exact(source *s, const int exact) { - s->exact = exact; - if (s->video) { - s->video->current_frame = -1; - } - if (s->audio) { - s->audio->current_frame = -1; - } -} - -float source_start(const source *s) { - return s->start; -} - -void source_set_start(source *s, const float start) { - s->start = start; -} - -float source_end(const source *s) { - return s->end; -} - -void source_set_end(source *s, const float end) { - s->end = end; -} - -void stream_free(stream *st) { - avcodec_close(st->codec); - - if (st->last_frame != NULL) { - image_free(st->last_frame); - } - - av_frame_free(&st->frame); - - free(st); -} - -void source_free(source *s) { - av_rdft_end(s->rdft); - - if (s->video) { - av_free(s->buffer); - av_frame_free(&s->scaleframe); - sws_freeContext(s->sws_context); - stream_free(s->video); - } - - if (s->audio) { - stream_free(s->audio); - } - - avformat_close_input(&s->format); - - if (s->keyframes) { - free(s->keyframes); - } - - free(s); -}
View file
nordlicht-0.4.4.tar.gz/source.h
Deleted
@@ -1,37 +0,0 @@ -#ifndef INCLUDE_source_h__ -#define INCLUDE_source_h__ - -#include "nordlicht.h" -#include "image.h" - -#define COLUMN_PRECISION 0.95 // choose a frame from this percentage at the middle of each column - -typedef struct source source; - -source* source_init(const char *filename); - -int source_has_video(source *s); - -int source_has_audio(source *s); - -image* source_get_video_frame(source *s, const double min_percent, const double max_percent); - -image* source_get_audio_frame(source *s, const double min_percent, const double max_percent); - -void source_build_keyframe_index(source *s, const int width); - -int source_exact(const source *s); - -void source_set_exact(source *s, const int exact); - -float source_start(const source *s); - -void source_set_start(source *s, const float start); - -float source_end(const source *s); - -void source_set_end(source *s, const float end); - -void source_free(source *s); - -#endif
View file
nordlicht-0.4.4.tar.gz/testsuite.c
Deleted
@@ -1,199 +0,0 @@ -#include "cheat.h" -#include "nordlicht.h" - -#ifdef _WIN32 -#include <io.h> -#define F_OK 0 -#define access _access -#endif - -#define cheat_null(x) cheat_assert(NULL == (x)) -#define cheat_not_null(x) cheat_assert(NULL != (x)) -#define cheat_fail(x) cheat_assert(0 != (x)) -#define cheat_ok(x) cheat_assert(0 == (x)) - -CHEAT_DECLARE( - nordlicht *n; - - int tool(char *args) { - char c200; - snprintf(c, 200, "./nordlicht %s >/dev/null 2>/dev/null", args); - return system(c); - } -) - -CHEAT_SET_UP( - n = NULL; -) - -CHEAT_TEAR_DOWN( - if (n != NULL) { - nordlicht_free(n); - } -) - -CHEAT_TEST(testfile_exists, - cheat_assert(-1 != access("video.mp4", F_OK)); -) - -CHEAT_TEST(invalid_input_file, - cheat_null(nordlicht_init(NULL, 100, 100)); - cheat_null(nordlicht_init("", 100, 100)); - cheat_null(nordlicht_init("\0", 100, 100)); - cheat_null(nordlicht_init(".", 100, 100)); - cheat_null(nordlicht_init("..", 100, 100)); - cheat_null(nordlicht_init("nonexistent_file.123", 100, 100)); -) - -CHEAT_TEST(invalid_size, - cheat_null(nordlicht_init("video.mp4", 0, 100)); - cheat_null(nordlicht_init("video.mp4", 100, 0)); - cheat_null(nordlicht_init("video.mp4", 0, 0)); - cheat_null(nordlicht_init("video.mp4", -1, 1)); - cheat_null(nordlicht_init("video.mp4", 1, -1)); - cheat_null(nordlicht_init("video.mp4", -100, 100)); - cheat_null(nordlicht_init("video.mp4", 100, -100)); - cheat_null(nordlicht_init("video.mp4", INT_MIN, INT_MIN)); -) - - -CHEAT_TEST(valid_size, - cheat_not_null(nordlicht_init("video.mp4", 1, 1)); - cheat_not_null(nordlicht_init("video.mp4", INT_MAX, INT_MAX)); -) - -CHEAT_TEST(invalid_output, - n = nordlicht_init("video.mp4", 1, 100); - cheat_not_null(n); - cheat_fail(nordlicht_write(n, NULL)); - cheat_fail(nordlicht_write(n, "")); - cheat_fail(nordlicht_write(n, "\0")); - cheat_fail(nordlicht_write(n, ".")); - cheat_fail(nordlicht_write(n, "..")); - cheat_fail(nordlicht_write(n, "video.mp4")); -) - -CHEAT_TEST(style, - n = nordlicht_init("video.mp4", 1, 100); - cheat_not_null(n); - cheat_ok(nordlicht_set_style(n, NORDLICHT_STYLE_HORIZONTAL)); - cheat_ok(nordlicht_set_style(n, NORDLICHT_STYLE_VERTICAL)); - cheat_fail(nordlicht_set_style(n, 10000000)); -) - -CHEAT_TEST(styles, - n = nordlicht_init("video.mp4", 1, 100); - cheat_not_null(n); - nordlicht_style styles2; - styles0 = NORDLICHT_STYLE_HORIZONTAL; - styles1 = NORDLICHT_STYLE_VERTICAL; - cheat_ok(nordlicht_set_styles(n, styles, 2)); - styles0 = NORDLICHT_STYLE_THUMBNAILS; - cheat_ok(nordlicht_set_styles(n, styles, 2)); - styles0 = 10000000; - cheat_fail(nordlicht_set_styles(n, styles, 2)); -) - -CHEAT_TEST(strategy, - n = nordlicht_init("video.mp4", 1, 100); - cheat_not_null(n); - cheat_ok(nordlicht_set_strategy(n, NORDLICHT_STRATEGY_FAST)); - cheat_ok(nordlicht_set_strategy(n, NORDLICHT_STRATEGY_LIVE)); - cheat_fail(nordlicht_set_strategy(n, 2)); - cheat_fail(nordlicht_set_strategy(n, 1000000)); - cheat_fail(nordlicht_set_strategy(n, -1)); -) - -CHEAT_TEST(buffer, - const unsigned char *buffer = NULL; - n = nordlicht_init("video.mp4", 2, 100); - cheat_not_null(n); - buffer = nordlicht_buffer(n); - cheat_not_null(buffer); - cheat_assert(2*100*4 == nordlicht_buffer_size(n)); - unsigned char *buffer2 = NULL; - cheat_fail(nordlicht_set_buffer(n, buffer2)); - buffer2 = malloc(nordlicht_buffer_size(n)); - cheat_ok(nordlicht_set_buffer(n, buffer2)); - cheat_ok(nordlicht_set_buffer(n, buffer2)); - cheat_ok(nordlicht_set_buffer(n, buffer2)); - buffer = nordlicht_buffer(n); - cheat_assert(buffer == buffer2); - free(buffer2); -) - -CHEAT_TEST(complete_run, - unsigned char *buffer2 = NULL; - n = nordlicht_init("video.mp4", 1, 100); - cheat_not_null(n); - cheat_ok(nordlicht_progress(n)); - cheat_ok(nordlicht_generate(n)); - cheat_assert(1 == nordlicht_progress(n)); - buffer2 = malloc(nordlicht_buffer_size(n)); - cheat_fail(nordlicht_set_buffer(n, buffer2)); - free(buffer2); -) - -CHEAT_TEST(tool_argument_parsing, - cheat_ok(tool("--help")); - cheat_ok(tool("--version")); - cheat_fail(tool("")); - cheat_fail(tool("--fubar")); - cheat_fail(tool("one.mp4 two.mp4")); - cheat_fail(tool("does_not_exist.mp4")); -) - -CHEAT_TEST(tool_size, - cheat_ok(tool("video.mp4 -w 1 -h 1")); - cheat_ok(tool("video.mp4 -w 1 -h 10000")); - cheat_fail(tool("video.mp4 -w huuuge")); - cheat_fail(tool("video.mp4 -w 0")); - cheat_fail(tool("video.mp4 -h 0")); - cheat_fail(tool("video.mp4 -w ''")); - cheat_fail(tool("video.mp4 -h ''")); - cheat_fail(tool("video.mp4 -w -100")); - cheat_fail(tool("video.mp4 -h -100")); - cheat_fail(tool("video.mp4 -w 1.1")); - cheat_fail(tool("video.mp4 -h 1.1")); - cheat_fail(tool("video.mp4 -w 1,1")); - cheat_fail(tool("video.mp4 -h 1,1")); -) - -CHEAT_TEST(tool_output, - cheat_ok(tool("video.mp4 -w 1")); - cheat_assert(-1 != access("video.mp4.nordlicht.png", F_OK)); - cheat_ok(tool("video.mp4 -w 1 -o ünîç⌀də.png")); - cheat_assert(-1 != access("ünîç⌀də.png", F_OK)); - cheat_fail(tool("video.mp4 -o video.mp4")); - cheat_fail(tool("video.mp4 -o ''")); - cheat_ok(tool("video.mp4 -w 1 -o barcode.bgra")); - cheat_fail(tool("video.mp4 -o barcode.abc")); - cheat_fail(tool("video.mp4 -o barcode")); -) - -CHEAT_TEST(tool_style, - cheat_ok(tool("video.mp4 -w 1 -s vertical")); - cheat_ok(tool("video.mp4 -w 1 -s horizontal")); - cheat_fail(tool("video.mp4 -h 1 -s horizontal+vertical")); - cheat_fail(tool("video.mp4 -h 2 -s horizontal+vertical+horizontal")); - cheat_ok(tool("video.mp4 -h 2 -s horizontal+vertical")); - cheat_fail(tool("video.mp4 -s horizontal+")); - cheat_fail(tool("video.mp4 -s +")); - cheat_fail(tool("video.mp4 -s horizontal++horizontal")); - cheat_fail(tool("video.mp4 -s nope")); - cheat_fail(tool("video.mp4 -s ''")); -) - -CHEAT_TEST(tool_region, - cheat_ok(tool("video.mp4 -w 1 --start=0.5")); - cheat_ok(tool("video.mp4 -w 1 --end=0.5")); - cheat_ok(tool("video.mp4 -w 1 --start=0.1 --end=0.2")); - cheat_ok(tool("video.mp4 -w 1 --start=0 --end=1")); - cheat_fail(tool("video.mp4 -w 1 --start=-1")); - cheat_fail(tool("video.mp4 -w 1 --start=1")); - cheat_fail(tool("video.mp4 -w 1 --start=2")); - cheat_fail(tool("video.mp4 -w 1 --end=-1")); - cheat_fail(tool("video.mp4 -w 1 --end=0")); - cheat_fail(tool("video.mp4 -w 1 --end=2")); - cheat_fail(tool("video.mp4 -w 1 --start=0.2 --end=0.1")); -)
View file
nordlicht-0.4.4.tar.gz/CHANGELOG.md -> nordlicht-0.4.5.tar.xz/CHANGELOG.md
Changed
@@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. *nordlicht* uses Semantic Versioning(http://semver.org/). +## 0.4.5 - 2017-01-09 + +- introduce `nordlicht_generate_step` and `nordlicht_done` to the API, for simple, non-blocking applications +- improve FFmpeg backwards compability down to v3.0 (thanks, Manuel!) +- fix build on ARM platforms +- correctly open files which contain a colon (thanks, Roland!) +- various bug fixes and stability improvements + +- tool: when the user specifies a non-PNG file as output, warn them but don't fail + ## 0.4.4 - 2016-01-24 - introduce the convention that the nordlicht is always written to `VIDEOFILE.nordlicht.png`
View file
nordlicht-0.4.4.tar.gz/CMakeLists.txt -> nordlicht-0.4.5.tar.xz/CMakeLists.txt
Changed
@@ -3,7 +3,7 @@ project(nordlicht C) set(MAJOR_VERSION 0) set(MINOR_VERSION 4) -set(PATCH_VERSION 4) +set(PATCH_VERSION 5) set(NORDLICHT_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}") option (BUILD_SHARED_LIBS "Build shared libraries." ON) @@ -12,6 +12,8 @@ include(GNUInstallDirs) +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG") + if (BUILD_SHARED_LIBS) add_definitions(-DNORDLICHT_BUILD_SHARED) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") @@ -20,7 +22,6 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") endif() -find_package(Threads REQUIRED) find_package(FFmpeg COMPONENTS AVUTIL AVFORMAT AVCODEC SWSCALE REQUIRED) find_package(Popt REQUIRED) @@ -33,22 +34,22 @@ include_directories(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} ${FFMPEG_INCLUDE_DIRS} ${POPT_INCLUDES}) -add_library(libnordlicht error.c image.c nordlicht.c source.c) +add_library(libnordlicht src/error.c src/image.c src/nordlicht.c src/source.c) set_target_properties(libnordlicht PROPERTIES OUTPUT_NAME nordlicht) set_target_properties(libnordlicht PROPERTIES SOVERSION ${MAJOR_VERSION} VERSION ${NORDLICHT_VERSION}) set_target_properties(libnordlicht PROPERTIES C_VISIBILITY_PRESET hidden) target_link_libraries(libnordlicht m ${FFMPEG_LIBRARIES}) -add_executable(nordlicht main.c) -target_link_libraries(nordlicht libnordlicht ${POPT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +add_executable(nordlicht src/main.c) +target_link_libraries(nordlicht libnordlicht ${POPT_LIBRARIES}) if (WIN32) target_link_libraries(nordlicht mman) endif() -add_executable(testsuite testsuite.c) +add_executable(testsuite src/testsuite.c) target_link_libraries(testsuite libnordlicht) -configure_file(version.h.in version.h @ONLY) +configure_file(src/version.h.in version.h @ONLY) if (NOT WIN32) configure_file(cmake/nordlicht.pc.in nordlicht.pc @ONLY) @@ -60,10 +61,10 @@ install(TARGETS libnordlicht DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS nordlicht DESTINATION bin) -install(FILES nordlicht.h DESTINATION include) +install(FILES ${CMAKE_SOURCE_DIR}/src/nordlicht.h DESTINATION include) if (NOT WIN32) - install(FILES ${CMAKE_BINARY_DIR}/nordlicht.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(FILES ${CMAKE_BINARY_DIR}/nordlicht.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(FILES ${CMAKE_BINARY_DIR}/nordlicht.1 DESTINATION share/man/man1) endif()
View file
nordlicht-0.4.4.tar.gz/README.md -> nordlicht-0.4.5.tar.xz/README.md
Changed
@@ -21,4 +21,4 @@ ## License: GPLv2+ -See LICENSE.md for details. +See LICENSE.md(LICENSE.md) for details.
View file
nordlicht-0.4.4.tar.gz/cmake/download_testfile.cmake -> nordlicht-0.4.5.tar.xz/cmake/download_testfile.cmake
Changed
@@ -1,4 +1,4 @@ if(NOT EXISTS ${CMAKE_BINARY_DIR}/video.mp4) - message("Downloading 20 MB test file, just a sec...") - file(DOWNLOAD https://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv ${CMAKE_BINARY_DIR}/video.mp4 EXPECTED_MD5 9f701e645fd55e1ae8d35b7671002881) + message("Downloading 3 MB test file, just a sec...") + file(DOWNLOAD https://upload.wikimedia.org/wikipedia/commons/0/07/Sintel_excerpt.OGG ${CMAKE_BINARY_DIR}/video.mp4 EXPECTED_MD5 be22cb1f83f6f3620d8048df12f9f52d) endif()
View file
nordlicht-0.4.5.tar.xz/src
Added
+(directory)
View file
nordlicht-0.4.5.tar.xz/src/cheat.h
Changed
(renamed from cheat.h)
View file
nordlicht-0.4.5.tar.xz/src/error.c
Changed
(renamed from error.c)
View file
nordlicht-0.4.5.tar.xz/src/error.h
Changed
(renamed from error.h)
View file
nordlicht-0.4.5.tar.xz/src/image.c
Added
@@ -0,0 +1,313 @@ +#include "image.h" +#include "error.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libswscale/swscale.h> + +// Changes for ffmpeg 3.0 +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,24,0) +# include <libavutil/imgutils.h> +# define av_free_packet av_packet_unref +# define avpicture_get_size(fmt,w,h) av_image_get_buffer_size(fmt,w,h,1) +#endif + +// PIX_FMT was renamed to AV_PIX_FMT on this version +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51,74,100) +# define AVPixelFormat PixelFormat +# define AV_PIX_FMT_RGB24 PIX_FMT_RGB24 +# define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P +# define AV_PIX_FMT_YUVJ422P PIX_FMT_YUVJ422P +# define AV_PIX_FMT_YUVJ440P PIX_FMT_YUVJ440P +# define AV_PIX_FMT_YUVJ444P PIX_FMT_YUVJ444P +# define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P +# define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P +# define AV_PIX_FMT_YUV440P PIX_FMT_YUV440P +# define AV_PIX_FMT_YUV444P PIX_FMT_YUV444P +#endif + +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0) +# define av_frame_alloc avcodec_alloc_frame +# if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54,59,100) +# define av_frame_free av_freep +# else +# define av_frame_free avcodec_free_frame +# endif +void av_frame_get_buffer(AVFrame *frame, int magic) { avpicture_alloc((AVPicture *)frame, frame->format, frame->width, frame->height); } +void av_frame_copy(AVFrame *dst, AVFrame *src) { memcpy(dst->data0, src->data0, sizeof(uint8_t)*avpicture_get_size(AV_PIX_FMT_RGB24, dst->width, dst->height)); } +#endif + +#define MAX_FILTER_SIZE 256 + +struct image { + AVFrame *frame; +}; + +image *image_init(const int width, const int height) { + image *i; + i = (image *) malloc(sizeof(image)); + + i->frame = (AVFrame *) av_frame_alloc(); + i->frame->width = width; + i->frame->height = height; + i->frame->format = AV_PIX_FMT_RGB24; // best choice? + av_frame_get_buffer(i->frame, 16); // magic number? + return i; +} + +int image_width(const image *i) { + return i->frame->width; +} + +int image_height(const image *i) { + return i->frame->height; +} + +void image_set(const image *i, const int x, const int y, const unsigned char r, const unsigned char g, const unsigned char b) { + *(i->frame->data0+y*i->frame->linesize0+x*3+0) = r; + *(i->frame->data0+y*i->frame->linesize0+x*3+1) = g; + *(i->frame->data0+y*i->frame->linesize0+x*3+2) = b; +} + +unsigned char image_get_r(const image *i, const int x, const int y) { + return *(i->frame->data0+y*i->frame->linesize0+x*3+0); +} + +unsigned char image_get_g(const image *i, const int x, const int y) { + return *(i->frame->data0+y*i->frame->linesize0+x*3+1); +} + +unsigned char image_get_b(const image *i, const int x, const int y) { + return *(i->frame->data0+y*i->frame->linesize0+x*3+2); +} + +void image_to_bgra(unsigned char *target, const int width, const int height, const image *i, const int offset_x, const int offset_y) { + int x, y; + for (y = 0; y < image_height(i) && offset_y+y < height ; y++) { + for (x = 0; x < image_width(i) && offset_x+x < width; x++) { + *(target+width*4*(offset_y+y)+4*(offset_x+x)+0) = image_get_b(i, x, y); + *(target+width*4*(offset_y+y)+4*(offset_x+x)+1) = image_get_g(i, x, y); + *(target+width*4*(offset_y+y)+4*(offset_x+x)+2) = image_get_r(i, x, y); + *(target+width*4*(offset_y+y)+4*(offset_x+x)+3) = 255; + } + } +} + +image *image_from_bgra(const unsigned char *source, const int width, const int height) { + image *i = image_init(width, height); + int x, y; + for (y = 0; y < image_height(i); y++) { + for (x = 0; x < image_width(i); x++) { + image_set(i, x, y, *(source+width*4*y+4*x+2), *(source+width*4*y+4*x+1), *(source+width*4*y+4*x+0)); + } + } + return i; +} + +image* image_clone(const image *i) { + image *i2 = image_init(image_width(i), image_height(i)); + av_frame_copy(i2->frame, i->frame); + return i2; +} + +void image_copy_avframe(const image *i, AVFrame *frame) { + av_frame_copy(i->frame, frame); +} + +image* image_dumb_scale(const image *i, const int width, const int height) { + image *i2 = image_init(width, height); + + float x_factor = 1.0*image_width(i)/width; + float y_factor = 1.0*image_height(i)/height; + + int x, y; + for (x = 0; x < width; x++) { + int x_lower = x_factor*x + 0.5; + int x_upper = x_factor*(x+1) - 0.5; + + if (x_lower > x_upper) { + // this can happen when upscaling. pick nearest-neighbour entry + x_lower = x_upper = x_factor*(x+0.5); + } + + for (y = 0; y < height; y++) { + int y_lower = y_factor*y + 0.5; + int y_upper = y_factor*(y+1) - 0.5; + + if (y_lower > y_upper) { + // this can happen when upscaling. pick nearest-neighbour entry + y_lower = y_upper = y_factor*(y+0.5); + } + + int rsum = 0; + int gsum = 0; + int bsum = 0; + int xx, yy; + for (xx = x_lower; xx <= x_upper; xx++) { + for (yy = y_lower; yy <= y_upper; yy++) { + rsum += image_get_r(i, xx, yy); + gsum += image_get_g(i, xx, yy); + bsum += image_get_b(i, xx, yy); + } + } + int n = (x_upper-x_lower+1)*(y_upper-y_lower+1); + image_set(i2, x, y, rsum/n, gsum/n, bsum/n); + } + } + + return i2; +} + +image* image_scale(const image *i, int width, int height) { + int target_width = width; + int target_height = height; + + if (width == image_width(i) && height == image_height(i)) { + return image_clone(i); + } + + image *i2 = NULL; + image *tmp = (image *) i; + do { + width = target_width; + height = target_height; + +#if LIBSWSCALE_VERSION_MICRO < 100 || LIBSWSCALE_VERSION_INT < AV_VERSION_INT(2, 1, 103) + if (width < 8) { + // libav and old FFmpeg versions don't allow scaling to a width of less than 8 + if (image_width(tmp) > 8) { + // but we can use it to go down to 8 + width = 8; + } else { + // all hope ist lost + image *i3 = image_dumb_scale(tmp, width, height); + if (tmp != i) { + image_free(tmp); + } + return i3; + } + } + + if (height < 2) { + // This doesn't seem to work on libav... + if (image_height(tmp) > 2) { + height = 2; + } else { + image *i3 = image_dumb_scale(tmp, width, height); + if (tmp != i) { + image_free(tmp); + } + return i3; + } + } +#endif + + // When scaling from a high width directly to 1, FFmpeg sometimes (?) + // introduces noise. So we avoid this situation. + if (width == 1 && image_width(tmp) > 2) { + width = 2; + } + + if (image_width(tmp)/width > MAX_FILTER_SIZE) { + width = image_width(tmp)/MAX_FILTER_SIZE+1; + } + if (image_height(tmp)/height > MAX_FILTER_SIZE) { + height = image_height(tmp)/MAX_FILTER_SIZE+1; + } + + + i2 = image_init(width, height); + + struct SwsContext *sws_context = sws_getContext(image_width(tmp), image_height(tmp), tmp->frame->format, + image_width(i2), image_height(i2), i2->frame->format, + SWS_AREA, NULL, NULL, NULL); + sws_scale(sws_context, (uint8_t const * const *)tmp->frame->data, + tmp->frame->linesize, 0, tmp->frame->height, i2->frame->data, + i2->frame->linesize); + sws_freeContext(sws_context); + + if (tmp != i) { + image_free(tmp); + } + + tmp = i2; + } while (image_width(i2) != target_width || image_height(i2) != target_height); + + return i2; +} + +image *image_flip(const image *i) { + image *i2 = image_init(image_height(i), image_width(i)); + int x, y; + for (x = 0; x < image_width(i2); x++) { + for (y = 0; y < image_height(i2); y++) { + image_set(i2, x, y, image_get_r(i, y, x), image_get_g(i, y, x), image_get_b(i, y, x)); + } + } + return i2; +} + +image* image_column(const image *i, double percent) { + image *i2 = image_init(1, image_height(i)); + + int y; + const int x = image_width(i)*percent; + for (y = 0; y < image_height(i); y++) { + image_set(i2, 0, y, image_get_r(i, x, y), image_get_g(i, x, y), image_get_b(i, x, y)); + } + + return i2; +} + +int image_write_png(const image *i, const char *file_path) { + AVCodec *encoder = avcodec_find_encoder_by_name("png"); + AVCodecContext *encoder_context; + encoder_context = avcodec_alloc_context3(encoder); + encoder_context->width = i->frame->width; + encoder_context->height = i->frame->height; + encoder_context->pix_fmt = AV_PIX_FMT_RGB24; + encoder_context->time_base.num = 1; + encoder_context->time_base.den = 1; + if (avcodec_open2(encoder_context, encoder, NULL) < 0) { + error("Could not open output codec."); + return -1; + } + + AVPacket packet; + av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 28, 0) + uint8_t buffer200000; // TODO: Why this size? + packet.size = avcodec_encode_video(encoder_context, buffer, 200000, i->frame); + packet.data = buffer; +#else + int got_packet = 0; + avcodec_encode_video2(encoder_context, &packet, i->frame, &got_packet); + if (! got_packet) { + error("Encoding error."); + return -1; + } +#endif + + FILE *file; + file = fopen(file_path, "wb"); + if (! file) { + error("Could not open output file."); + return -1; + } + fwrite(packet.data, 1, packet.size, file); + fclose(file); + + av_free_packet(&packet); + + avcodec_close(encoder_context); + av_free(encoder_context); + return 0; +} + +void image_free(image *i) { + av_frame_free(&i->frame); + free(i); +}
View file
nordlicht-0.4.5.tar.xz/src/image.h
Changed
(renamed from image.h)
View file
nordlicht-0.4.5.tar.xz/src/main.c
Added
@@ -0,0 +1,304 @@ +#include <sys/file.h> +#include <sys/mman.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <popt.h> +#include "nordlicht.h" +#include "version.h" + +#ifdef _WIN32 +// from http://stackoverflow.com/a/8514474/248734 +char* strsep(char** stringp, const char* delim) { + char* start = *stringp; + char* p; + + p = (start != NULL) ? strpbrk(start, delim) : NULL; + + if (p == NULL) { + *stringp = NULL; + } else { + *p = '\0'; + *stringp = p + 1; + } + + return start; +} +#endif + +typedef struct { + const char *name; + const char *description; + nordlicht_style style; +} style; + +const style style_table = { + {"horizontal", "compress frames to vertical lines and append them", NORDLICHT_STYLE_HORIZONTAL}, + {"vertical", "compress frames to horizontal lines and rotate them counterclockwise by 90 degrees", NORDLICHT_STYLE_VERTICAL}, + {"slitscan", "take single columns while constantly moving to the right (and wrapping back to the left)", NORDLICHT_STYLE_SLITSCAN}, + {"middlecolumn", "take the middlemost column of each frame", NORDLICHT_STYLE_MIDDLECOLUMN}, + {"thumbnails", "display small thumbnails at regular intervals", NORDLICHT_STYLE_THUMBNAILS}, + {"spectrogram", "spectrogram of the first audio track (not all sample formats are supported yet)", NORDLICHT_STYLE_SPECTROGRAM}, + {NULL, NULL, NORDLICHT_STYLE_LAST} +}; + +void print_error(const char *message, ...) { + fprintf(stderr, "nordlicht: "); + va_list arglist; + va_start(arglist, message); + vfprintf(stderr, message, arglist); + va_end(arglist); + fprintf(stderr, "\n"); +} + +const char *filename_ext(const char *path) { + const char *dot = strrchr(path, '.'); + if (!dot || dot == path) return ""; + return dot+1; +} + +void print_help(const poptContext popt, const int ret) { + poptPrintHelp(popt, ret == 0 ? stdout : stderr, 0); + + printf("\nStyles:\n"); + int i; + for (i = 0; style_tablei.name; i++) { + printf(" %-14s %s\n", style_tablei.name, style_tablei.description); + } + + printf("\n\ +Examples:\n\ + nordlicht video.mp4 generate video.mp4.nordlicht.png of default size\n\ + nordlicht video.mp4 -s vertical compress individual frames to columns\n\ + nordlicht video.mp4 -w 1000 -h 1000 -o barcode.png override size and name of the output file\n"); + + exit(ret); +} + +int main(const int argc, const char **argv) { + int width = -1; + int height = -1; + float start = 0.0; + float end = 1.0; + char *output_file = NULL; + char *styles_string = NULL; + nordlicht_strategy strategy; + int free_output_file = 0; + + int quiet = 0; + int help = 0; + int version = 0; + + const struct poptOption optionsTable = { + {"width", 'w', POPT_ARG_INT, &width, 0, "set the barcode's width; by default it's \"height*10\", or 1920 pixels, if both are undefined", NULL}, + {"height", 'h', POPT_ARG_INT, &height, 0, "set the barcode's height; by default it's \"width/10\"", NULL}, + {"output", 'o', POPT_ARG_STRING, &output_file, 0, "set output filename, the default is VIDEOFILE.png; when you specify an *.bgra file, you'll get a raw 32-bit BGRA file that is updated as the barcode is generated", "FILENAME"}, + {"style", 's', POPT_ARG_STRING, &styles_string, 0, "default is 'horizontal', see \"Styles\" section below. You can specify more than one style, separated by '+', to get multiple tracks", "STYLE"}, + {"start", '\0', POPT_ARG_FLOAT, &start, 0, "specify where to start the barcode (ratio between 0 and 1)", NULL}, + {"end", '\0', POPT_ARG_FLOAT, &end, 0, "specify where to end the barcode (ratio between 0 and 1)", NULL}, + {"quiet", 'q', 0, &quiet, 0, "don't show progress indicator", NULL}, + {"help", '\0', 0, &help, 0, "display this help and exit", NULL}, + {"version", '\0', 0, &version, 0, "output version information and exit", NULL}, + POPT_TABLEEND + }; + + const poptContext popt = poptGetContext(NULL, argc, argv, optionsTable, 0); + poptSetOtherOptionHelp(popt, "OPTION... VIDEOFILE\n\nOptions:"); + + if (argc == 1) { + print_help(popt, 1); + } + + int option; + + // The next line leaks 2 bytes, blame popt! + while ((option = poptGetNextOpt(popt)) >= 0) { } + + if (option < -1) { + fprintf(stderr, "nordlicht: %s: %s\n", poptBadOption(popt, POPT_BADOPTION_NOALIAS), poptStrerror(option)); + return 1; + } + + if (version) { + printf("nordlicht %s\n\nWritten by Sebastian Morr and contributors.\n", NORDLICHT_VERSION); + return 0; + } + + if (help) { + print_help(popt, 0); + } + + const char *filename = (char*)poptGetArg(popt); + + if (filename == NULL) { + print_error("Please specify an input file."); + exit(1); + } + + if (poptGetArg(popt) != NULL) { + print_error("Please specify only one input file."); + exit(1); + } + + if (output_file == NULL) { + size_t len = snprintf(NULL, 0, "%s.nordlicht.png", filename) + 1; + output_file = (char *) malloc(len); + snprintf(output_file, len, "%s.nordlicht.png", filename); + free_output_file = 1; + } + + if (width == -1 && height != -1) { + width = height*10; + } + if (height == -1 && width != -1) { + height = width/10; + if (height < 1) { + height = 1; + } + } + if (height == -1 && width == -1) { + width = 1920; + height = 192; + } + + if (styles_string == NULL) { + styles_string = "horizontal"; + } + + // count the occurrences of "+" in the styles_string + const char *s = styles_string; + int num_tracks; + for (num_tracks=0; snum_tracks; snum_tracks=='+' ? num_tracks++ : *s++); + num_tracks++; + + nordlicht_style *styles; + styles = (nordlicht_style *) malloc(num_tracks * sizeof(nordlicht_style)); + + const char *style_string; + num_tracks = 0; + while ((style_string = strsep(&styles_string, "+"))) { + int i; + for (i = 0; style_tablei.name; i++) { + if (strcmp(style_string, style_tablei.name) == 0) { + stylesnum_tracks = style_tablei.style; + break; + } + } + + if (!style_tablei.name) { + print_error("Unknown style '%s'. Use '--help' to display available styles.", style_string); + exit(1); + } + num_tracks++; + } + + const char *ext = filename_ext(output_file); + if (strcmp(ext, "bgra") == 0) { + strategy = NORDLICHT_STRATEGY_LIVE; + } else if (strcmp(ext, "png") == 0) { + strategy = NORDLICHT_STRATEGY_FAST; + } else { + strategy = NORDLICHT_STRATEGY_FAST; + fprintf(stderr, "nordlicht: Unsupported file extension '%s', will write a PNG.\n", ext); + } + + // Interesting stuff begins here! + + nordlicht *n = nordlicht_init(filename, width, height); + unsigned char *data = NULL; + + if (n == NULL) { + print_error(nordlicht_error()); + exit(1); + } + + nordlicht_set_start(n, start); + nordlicht_set_end(n, end); + nordlicht_set_styles(n, styles, num_tracks); + nordlicht_set_strategy(n, strategy); + + if (nordlicht_error() != NULL) { + print_error(nordlicht_error()); + exit(1); + } + + if (strategy == NORDLICHT_STRATEGY_LIVE) { + int fd = open(output_file, O_CREAT | O_TRUNC | O_RDWR, 0666); + if (fd == -1) { + print_error("Could not open '%s'.", output_file); + exit(1); + } + if (ftruncate(fd, nordlicht_buffer_size(n)) == -1) { + print_error("Could not truncate '%s'.", output_file); + exit(1); + } + data = (unsigned char *) mmap(NULL, nordlicht_buffer_size(n), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == (void *) -1) { + print_error("Could not mmap %d bytes.", nordlicht_buffer_size(n)); + exit(1); + } + nordlicht_set_buffer(n, data); + close(fd); + } else { + // Try to write the empty buffer to fail early if this does not work + if (nordlicht_write(n, output_file) != 0) { + print_error(nordlicht_error()); + exit(1); + } + } + + int phase = -1; + while(!nordlicht_done(n)) { + if (nordlicht_generate_step(n) == 0) { + if (! quiet) { + float progress = nordlicht_progress(n); + if (progress == 0) { + if (phase == -1) { + phase = 0; + printf("nordlicht: Building keyframe index... "); + fflush(stdout); + } + } else { + if (phase == 0) { + phase = 1; + printf("done.\n"); + } + printf("\rnordlicht: %02.0f%%", progress*100); +#ifdef DEBUG + printf("\n"); +#endif + fflush(stdout); + } + } + } else { + print_error(nordlicht_error()); + exit(1); + } + } + + if (strategy != NORDLICHT_STRATEGY_LIVE) { + if (nordlicht_write(n, output_file) != 0) { + print_error(nordlicht_error()); + exit(1); + } + } + + free(styles); + + if (strategy == NORDLICHT_STRATEGY_LIVE) { + munmap(data, nordlicht_buffer_size(n)); + } + + nordlicht_free(n); + + if (! quiet) { + printf(" -> '%s'\n", output_file); + } + + if (free_output_file) { + free(output_file); + } + + poptFreeContext(popt); + return 0; +}
View file
nordlicht-0.4.5.tar.xz/src/nordlicht.c
Added
@@ -0,0 +1,385 @@ +#include "nordlicht.h" +#include <string.h> +#include "error.h" +#include "source.h" + +#ifdef _WIN32 +#define realpath(N,R) _fullpath((R),(N),_MAX_PATH) +#endif + +typedef struct { + nordlicht_style style; + int height; +} track; + +struct nordlicht { + int width, height; + char *filename; + track *tracks; + int num_tracks; + unsigned char *data; + + int owns_data; + int modifiable; + nordlicht_strategy strategy; + source *source; + + int current_pass; + int current_track; + int current_column; + int current_y_offset; + float progress; +}; + +NORDLICHT_API size_t nordlicht_buffer_size(const nordlicht *n) { + return n->width * n->height * 4; +} + +NORDLICHT_API nordlicht* nordlicht_init(const char *filename, const int width, const int height) { + if (width < 1 || height < 1) { + error("Dimensions must be positive (got %dx%d)", width, height); + return NULL; + } + if (width > 100000 || height > 100000) { + error("Both dimensions may be at most 100000 (got %dx%d)", width, height); + return NULL; + } + nordlicht *n; + n = (nordlicht *) malloc(sizeof(nordlicht)); + + n->width = width; + n->height = height; + + // prepend "file:" if filename contains a colon and is not a URL, + // otherwise ffmpeg will fail to open the file + if (filename && strstr(filename, ":") != 0 && strstr(filename, "://") == 0) { + size_t filename_len = strlen(filename); + n->filename = malloc(filename_len + 5 + 1); + strncpy(n->filename, "file:", 5); + strncpy(n->filename + 5, filename, filename_len); + n->filenamefilename_len + 5 = '\0'; + } else { + n->filename = (char *) filename; + } + + n->data = (unsigned char *) calloc(nordlicht_buffer_size(n), 1); + if (n->data == 0) { + error("Not enough memory to allocate %d bytes", nordlicht_buffer_size(n)); + return NULL; + } + + n->owns_data = 1; + + n->num_tracks = 1; + n->tracks = (track *) malloc(sizeof(track)); + n->tracks0.style = NORDLICHT_STYLE_HORIZONTAL; + n->tracks0.height = n->height; + + n->strategy = NORDLICHT_STRATEGY_FAST; + n->modifiable = 1; + n->source = source_init(n->filename); + + n->current_pass = -1; + n->current_track = 0; + n->current_column = 0; + n->current_y_offset = 0; + n->progress = 0; + + if (n->source == NULL) { + error("Could not open video file '%s'", filename); + free(n); + return NULL; + } + + return n; +} + +NORDLICHT_API void nordlicht_free(nordlicht *n) { + if (n->owns_data) { + free(n->data); + } + free(n->tracks); + source_free(n->source); + free(n); +} + +NORDLICHT_API const char *nordlicht_error() { + return get_error(); +} + +NORDLICHT_API int nordlicht_set_start(nordlicht *n, const float start) { + if (! n->modifiable) { + return -1; + } + + if (start < 0) { + error("'start' has to be greater than or equal to 0."); + return -1; + } + + if (start >= source_end(n->source)) { + error("'start' has to be less than 'end'."); + return -1; + } + + source_set_start(n->source, start); + return 0; +} + +NORDLICHT_API int nordlicht_set_end(nordlicht *n, const float end) { + if (! n->modifiable) { + return -1; + } + + if (end > 1) { + error("'end' has to less than or equal to 1."); + return -1; + } + + if (source_start(n->source) >= end) { + error("'start' has to be less than 'end'."); + return -1; + } + + source_set_end(n->source, end); + return 0; +} + +NORDLICHT_API int nordlicht_set_style(nordlicht *n, const nordlicht_style style) { + if (! n->modifiable) { + return -1; + } + + nordlicht_style styles1 = {style}; + return nordlicht_set_styles(n, styles, 1); +} + +NORDLICHT_API int nordlicht_set_styles(nordlicht *n, const nordlicht_style *styles, const int num_tracks) { + if (! n->modifiable) { + return -1; + } + + n->num_tracks = num_tracks; + + if (n->num_tracks > n->height) { + error("Height of %d px is too low for %d styles", n->height, n->num_tracks); + return -1; + } + + free(n->tracks); + n->tracks = (track *) malloc(n->num_tracks*sizeof(track)); + + int height_of_each_track = n->height/n->num_tracks; + int i; + for (i=0; i<num_tracks; i++) { + nordlicht_style s = stylesi; + if (s > NORDLICHT_STYLE_LAST-1) { + return -1; + } + + n->tracksi.style = s; + n->tracksi.height = height_of_each_track; + } + n->tracks0.height = n->height - (n->num_tracks-1)*height_of_each_track; + + return 0; +} + +NORDLICHT_API int nordlicht_set_strategy(nordlicht *n, const nordlicht_strategy s) { + if (! n->modifiable) { + return -1; + } + if (s > NORDLICHT_STRATEGY_LIVE) { + return -1; + } + n->strategy = s; + return 0; +} + +NORDLICHT_API int nordlicht_generate_step(nordlicht *n) { + n->modifiable = 0; + + if (nordlicht_done(n)) { + return 0; + } else if (n->current_pass == -1) { + // we don't have a (finished) keyframe index yet + if (source_build_keyframe_index_step(n->source, n->width) == 0) { + // keyframe index building is done + if (n->strategy == NORDLICHT_STRATEGY_LIVE || !source_has_index(n->source)) { + n->current_pass = 0; + } else { + n->current_pass = 1; + } + source_set_exact(n->source, n->current_pass); + } + } else { + image *frame; + + if (n->tracksn->current_track.style == NORDLICHT_STYLE_SPECTROGRAM) { + if (!source_has_audio(n->source)) { + error("File contains no audio, please select an appropriate style"); + n->progress = 1; + return -1; + } + frame = source_get_audio_frame(n->source, 1.0*(n->current_column+0.5-COLUMN_PRECISION/2.0)/n->width, + 1.0*(n->current_column+0.5+COLUMN_PRECISION/2.0)/n->width); + } else { + if (!source_has_video(n->source)) { + error("File contains no video, please select an appropriate style"); + n->progress = 1; + return -1; + } + frame = source_get_video_frame(n->source, 1.0*(n->current_column+0.5-COLUMN_PRECISION/2.0)/n->width, + 1.0*(n->current_column+0.5+COLUMN_PRECISION/2.0)/n->width); + } + + if (frame != NULL) { + int thumbnail_width = 1.0*(image_width(frame)*n->tracksn->current_track.height/image_height(frame)); + image *column = NULL; + image *tmp = NULL; + switch (n->tracksn->current_track.style) { + case NORDLICHT_STYLE_THUMBNAILS: + column = image_scale(frame, thumbnail_width, n->tracksn->current_track.height); + break; + case NORDLICHT_STYLE_HORIZONTAL: + column = image_scale(frame, 1, n->tracksn->current_track.height); + break; + case NORDLICHT_STYLE_VERTICAL: + tmp = image_scale(frame, n->tracksn->current_track.height, 1); + column = image_flip(tmp); + image_free(tmp); + break; + case NORDLICHT_STYLE_SLITSCAN: + tmp = image_column(frame, 1.0*(n->current_column%thumbnail_width)/thumbnail_width); + + column = image_scale(tmp, 1, n->tracksn->current_track.height); + image_free(tmp); + break; + case NORDLICHT_STYLE_MIDDLECOLUMN: + tmp = image_column(frame, 0.5); + column = image_scale(tmp, 1, n->tracksn->current_track.height); + image_free(tmp); + break; + case NORDLICHT_STYLE_SPECTROGRAM: + column = image_scale(frame, 1, n->tracksn->current_track.height); + break; + default: + // cannot happen (TM) + return -1; + break; + } + + image_to_bgra(n->data, n->width, n->height, column, n->current_column, n->current_y_offset); + + n->current_column = n->current_column + image_width(column) - 1; + if (n->current_column >= n->width) { + n->current_column = n->width - 1; + } + n->progress = (n->current_track+1.0*n->current_column/n->width)/n->num_tracks; + + image_free(column); + } + + n->current_column++; + if (n->current_column == n->width) { + n->current_column = 0; + n->current_y_offset += n->tracksn->current_track.height; + n->current_track++; + if (n->current_track == n->num_tracks) { + n->current_track = 0; + n->current_y_offset = 0; + n->current_pass++; + if (n->current_pass == 2 || !source_has_index(n->source)) { + // we're done :) + n->progress = 1.0; + n->current_pass = 2; + return 0; + } else { + source_set_exact(n->source, n->current_pass); + } + } + } + } + + return 0; +} + +NORDLICHT_API int nordlicht_generate(nordlicht *n) { + while(!nordlicht_done(n)) { + if (nordlicht_generate_step(n) != 0) { + return -1; + } + } + return 0; +} + +NORDLICHT_API int nordlicht_write(const nordlicht *n, const char *filename) { + int code = 0; + + if (filename == NULL) { + error("Output filename must not be NULL"); + return -1; + } + + if (strcmp(filename, "") == 0) { + error("Output filename must not be empty"); + return -1; + } + + char *realpath_output = realpath(filename, NULL); + if (realpath_output != NULL) { + // output file exists + char *realpath_input = realpath(n->filename, NULL); + if (realpath_input != NULL) { + // otherwise, input filename is probably a URL + + if (strcmp(realpath_input, realpath_output) == 0) { + error("Will not overwrite input file"); + code = -1; + } + free(realpath_input); + } + free(realpath_output); + + if (code != 0) { + return code; + } + } + + image *i = image_from_bgra(n->data, n->width, n->height); + if (image_write_png(i, filename) != 0) { + return -1; + } + image_free(i); + + return code; +} + +NORDLICHT_API int nordlicht_done(const nordlicht *n) { + return n->current_pass == 2; +} + +NORDLICHT_API float nordlicht_progress(const nordlicht *n) { + return n->progress; +} + +NORDLICHT_API const unsigned char* nordlicht_buffer(const nordlicht *n) { + return n->data; +} + +NORDLICHT_API int nordlicht_set_buffer(nordlicht *n, unsigned char *data) { + if (! n->modifiable) { + return -1; + } + + if (data == NULL) { + return -1; + } + + if (n->owns_data) { + free(n->data); + } + n->owns_data = 0; + n->data = data; + return 0; +}
View file
nordlicht-0.4.5.tar.xz/src/nordlicht.h
Added
@@ -0,0 +1,116 @@ +#ifndef INCLUDE_nordlicht_h__ +#define INCLUDE_nordlicht_h__ +#include <stdlib.h> // for size_t + +#ifndef NORDLICHT_API +# ifdef _WIN32 +# if defined(NORDLICHT_BUILD_SHARED) /* build dll */ +# define NORDLICHT_API __declspec(dllexport) +# elif !defined(NORDLICHT_BUILD_STATIC) /* use dll */ +# define NORDLICHT_API __declspec(dllimport) +# else /* static library */ +# define NORDLICHT_API +# endif +# else +# if __GNUC__ >= 4 +# define NORDLICHT_API __attribute__((visibility("default"))) +# else +# define NORDLICHT_API +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct nordlicht nordlicht; + +typedef enum nordlicht_style { + NORDLICHT_STYLE_THUMBNAILS, // a row of thumbnails + NORDLICHT_STYLE_HORIZONTAL, // compress frames to columns + NORDLICHT_STYLE_VERTICAL, // compress frames to rows and rotate them counterclockwise + NORDLICHT_STYLE_SLITSCAN, // take single columns, while moving to the right (and wrapping to the left) + NORDLICHT_STYLE_MIDDLECOLUMN, // take the frames' middlemost column + NORDLICHT_STYLE_SPECTROGRAM, // spectrogram of the first audio track (not all sample formats are supported yet) + NORDLICHT_STYLE_LAST // just a marker so that we can count the number of available styles +} nordlicht_style; + +typedef enum nordlicht_strategy { + NORDLICHT_STRATEGY_FAST, // generate barcode in a single pass as fast as possible + NORDLICHT_STRATEGY_LIVE, // generate a fast approximation first, good for live display +} nordlicht_strategy; + +// Returns a description of the last error, or NULL if there was no error. +NORDLICHT_API const char *nordlicht_error(); + +// Allocate a new nordlicht of specified width and height, for a given video +// file. Use `nordlicht_free` to free the nordlicht again. +// Returns NULL on errors. +NORDLICHT_API nordlicht* nordlicht_init(const char *filename, const int width, const int height); + +// Free a nordlicht. +NORDLICHT_API void nordlicht_free(nordlicht *n); + +// Specify where to start the nordlicht in the file, as a ratio between 0 and 1. +NORDLICHT_API int nordlicht_set_start(nordlicht *n, const float start); + +// Specify where to end the nordlicht in the file, as a ratio between 0 and 1. +NORDLICHT_API int nordlicht_set_end(nordlicht *n, const float end); + +// Set the output style of the nordlicht, see above. Default is NORDLICHT_STYLE_HORIZONTAL. +// To set multiple styles at once, use `nordlicht_set_styles`. +// Returns 0 on success. +NORDLICHT_API int nordlicht_set_style(nordlicht *n, const nordlicht_style style); + +// Set multiple output styles, which will be displayed on top of each other. +// Expects a pointer to an array of nordlicht_style-s of length `num_styles`. +// Returns 0 on success. +NORDLICHT_API int nordlicht_set_styles(nordlicht *n, const nordlicht_style *styles, const int num_styles); + +// Set the generation strategy of the nordlicht, see above. Default is NORDLICHT_STRATEGY_FAST. +// Returns 0 on success. +NORDLICHT_API int nordlicht_set_strategy(nordlicht *n, const nordlicht_strategy strategy); + +// Return a pointer to the nordlicht's internal buffer. You can use it to draw +// the barcode while it is generated. The pixel format is 32-bit BGRA. +NORDLICHT_API const unsigned char* nordlicht_buffer(const nordlicht *n); + +// Replace the internal nordlicht's internal buffer. The data pointer is owned +// by the caller and must be freed after `nordlicht_free`. You can use this to +// render the nordlicht into caller-owned data structures, like mmap-ed files. +// The pixel format is 32-bit BGRA. +// Returns 0 on success. +NORDLICHT_API int nordlicht_set_buffer(nordlicht *n, unsigned char *data); + +// Returns the size of this nordlicht's buffer in bytes. +NORDLICHT_API size_t nordlicht_buffer_size(const nordlicht *n); + +// Generate the nordlicht in one pass. Use this function from a thread if you don't +// want to block execution. Calling this will freeze the nordlicht: "set" +// functions will fail. +// Returns 0 on success. +NORDLICHT_API int nordlicht_generate(nordlicht *n); + +// Do one step of generation, which will be as small as possible. Use this +// if you don't want to start a seperate thread, but be aware that this +// function might still take too long for real-time applications. Calling this +// will freeze the nordlicht: "set" functions will fail. +// Returns 0 on success. +NORDLICHT_API int nordlicht_generate_step(nordlicht *n); + +// Returns 1 if the nordlicht has been completely generated, and 0 otherwise. +NORDLICHT_API int nordlicht_done(const nordlicht *n); + +// Returns a value between 0 and 1 indicating how much of the nordlicht has been +// generated. +NORDLICHT_API float nordlicht_progress(const nordlicht *n); + +// Write the nordlicht to a PNG file. Returns 0 on success. +NORDLICHT_API int nordlicht_write(const nordlicht *n, const char *filename); + +#ifdef __cplusplus +} +#endif + +#endif
View file
nordlicht-0.4.5.tar.xz/src/source.c
Added
@@ -0,0 +1,547 @@ +#include "source.h" +#include "error.h" +#include <libavcodec/avcodec.h> +#include <libavcodec/avfft.h> +#include <libavformat/avformat.h> +#include <libavutil/avutil.h> +#include <libswscale/swscale.h> + +// Changes for ffmpeg 3.0 +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,24,0) +# include <libavutil/imgutils.h> +# define av_free_packet av_packet_unref +# define avpicture_get_size(fmt,w,h) av_image_get_buffer_size(fmt,w,h,1) +#endif + +// PIX_FMT was renamed to AV_PIX_FMT on this version +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51,74,100) +# define AVPixelFormat PixelFormat +# define AV_PIX_FMT_RGB24 PIX_FMT_RGB24 +# define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P +# define AV_PIX_FMT_YUVJ422P PIX_FMT_YUVJ422P +# define AV_PIX_FMT_YUVJ440P PIX_FMT_YUVJ440P +# define AV_PIX_FMT_YUVJ444P PIX_FMT_YUVJ444P +# define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P +# define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P +# define AV_PIX_FMT_YUV440P PIX_FMT_YUV440P +# define AV_PIX_FMT_YUV444P PIX_FMT_YUV444P +#endif + +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0) +# define av_frame_alloc avcodec_alloc_frame +# if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54,59,100) +# define av_frame_free av_freep +# else +# define av_frame_free avcodec_free_frame +# endif +#endif + +#define HEURISTIC_NUMBER_OF_FRAMES 1800 // how many frames will the heuristic look at? +#define HEURISTIC_KEYFRAME_FACTOR 1 // lower bound for the actual/required keyframe ratio + +#define SAMPLES_PER_FRAME 1024 + +typedef struct { + int stream; + AVCodecContext *codec; + image *last_frame; + + double time_base; + double fps; + AVFrame *frame; + long current_frame; +} stream; + +struct source { + int exact; + float start, end; + + AVFormatContext *format; + stream *video; + stream *audio; + + uint8_t *buffer; + AVFrame *scaleframe; + struct SwsContext *sws_context; + AVPacket packet; + + // audio specific + RDFTContext *rdft; + + int *keyframes; + int number_of_keyframes; + int has_index; + int current_frame; +}; + +long packet_pts(stream *st, const AVPacket *packet) { + long pts = packet->pts != 0 ? packet->pts : packet->dts; + double sec = st->time_base*pts; + return (int64_t)(st->fps*sec + 0.5); +} + +int grab_next_frame(source *s, stream *st) { + int valid = 0; + int got_frame = 0; + + long pts; + + while (!valid) { + if (av_read_frame(s->format, &s->packet) >= 0) { + if (s->packet.stream_index == st->stream) { + switch (st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: + avcodec_decode_video2(st->codec, st->frame, &got_frame, &s->packet); + break; + case AVMEDIA_TYPE_AUDIO: + avcodec_decode_audio4(st->codec, st->frame, &got_frame, &s->packet); + break; + default: + error("Stream has unknown media type."); +#ifdef DEBUG + printf("Unknown media type?\n"); +#endif + return 1; + } + + if (got_frame) { + if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + if (st->frame->data0 == 0) { +#ifdef DEBUG + printf("grab_next_frame: st->frame->data0 == 0\n"); +#endif + return 1; + } + } + pts = packet_pts(st, &s->packet); + valid = 1; + } + } + av_free_packet(&s->packet); + } else { + av_free_packet(&s->packet); + st->current_frame = -1; +#ifdef DEBUG + printf("grab_next_frame: av_read_frame() == 0\n"); +#endif + return 1; + } + } + + av_free_packet(&s->packet); + st->current_frame = pts; +#ifdef DEBUG + printf("grab_next_frame() grabbed frame %d\n", pts); +#endif + return 0; +} + +int seek_keyframe(source *s, stream *st, const long frame) { +#ifdef DEBUG + printf("seek_keyframe(%ld)\n", frame); +#endif + av_seek_frame(s->format, st->stream, frame/st->fps/st->time_base, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(st->codec); + return grab_next_frame(s, st) != 0; +} + +int total_number_of_frames(const source *s, stream *st) { + double duration_sec = 1.0*s->format->duration/AV_TIME_BASE; + return st->fps*duration_sec; +} + +// Returns 0 if done +int source_build_keyframe_index_step(source *s, const int width) { + if (s->keyframes == NULL) { + if (! s->video) { + return 0; + } + s->keyframes = (int *) malloc(sizeof(long)*60*60*3); // TODO: dynamic datastructure! + s->keyframes0 = 0; + s->number_of_keyframes = 1; + + s->current_frame = 0; + + s->has_index = 0; + s->exact = 1; + } + + if (av_read_frame(s->format, &s->packet) >= 0) { + if (s->packet.stream_index == s->video->stream) { + if (!!(s->packet.flags & AV_PKT_FLAG_KEY)) { + s->number_of_keyframes++; + + long pts = packet_pts(s->video, &s->packet); + if (pts < 1 && s->number_of_keyframes > 0) { + pts = s->current_frame; + } + +#ifdef DEBUG + printf("Found a keyframe: %ld\n", pts); +#endif + s->keyframess->number_of_keyframes = pts; + } + if (s->current_frame == HEURISTIC_NUMBER_OF_FRAMES) { + const float density = 1.0*s->number_of_keyframes/HEURISTIC_NUMBER_OF_FRAMES; + const float required_density = 1.0*HEURISTIC_KEYFRAME_FACTOR/COLUMN_PRECISION*width/total_number_of_frames(s, s->video)/(s->end-s->start); + if (density > required_density) { + // The keyframe density in the first `HEURISTIC_NUMBER_OF_FRAMES` + // frames is HEURISTIC_KEYFRAME_FACTOR times higher than + // the density we need overall. This means that we can abort build + // the keyframe index and just seek inexactly to get good results. + av_free_packet(&s->packet); +#ifdef DEBUG + printf("Keyframe indexing not necessary. Aborting.\n"); +#endif + return 0; + } + } + s->current_frame++; + } + av_free_packet(&s->packet); + return 1; + } else { + // we read through the whole file + av_free_packet(&s->packet); + s->has_index = 1; +#ifdef DEBUG + printf("Keyframe indexing complete.\n"); +#endif + return 0; + } +} + +stream* stream_init(source *s, enum AVMediaType type) { + stream *st; + st = (stream *) malloc(sizeof(stream)); + + st->last_frame = NULL; + + st->stream = av_find_best_stream(s->format, type, -1, -1, NULL, 0); + if (st->stream < 0) { + free(st); + return NULL; + } + st->codec = s->format->streamsst->stream->codec; + AVCodec *codec = NULL; + codec = avcodec_find_decoder(st->codec->codec_id); + if (codec == NULL) { + error("Unsupported codec!"); + free(st); + return NULL; + } + if (avcodec_open2(st->codec, codec, NULL) < 0) { + free(st); + return NULL; + } + + st->time_base = av_q2d(s->format->streamsst->stream->time_base); + + switch (st->codec->codec_type) { + case AVMEDIA_TYPE_VIDEO: + st->fps = av_q2d(s->format->streamsst->stream->avg_frame_rate); + break; + case AVMEDIA_TYPE_AUDIO: + st->fps = st->codec->sample_rate; + break; + default: + error("Stream has unknown media type."); + free(st); + return NULL; + } + + st->frame = av_frame_alloc(); + st->current_frame = -1; + + if (grab_next_frame(s, st) != 0) { + free(st); + return NULL; + } + + return st; +} + +source* source_init(const char *filename) { + if (filename == NULL) { + return NULL; + } + + av_log_set_level(AV_LOG_FATAL); + av_register_all(); + if (strstr(filename, "://") != 0) { + avformat_network_init(); + } + + source *s; + s = (source *) malloc(sizeof(source)); + s->exact = 1; + s->start = 0.0; + s->end = 1.0; + s->format = NULL; + + if (avformat_open_input(&s->format, filename, NULL, NULL) != 0) { + free(s); + return NULL; + } + if (avformat_find_stream_info(s->format, NULL) < 0) { + avformat_close_input(&s->format); + free(s); + return NULL; + } + + s->video = stream_init(s, AVMEDIA_TYPE_VIDEO); + s->audio = stream_init(s, AVMEDIA_TYPE_AUDIO); + + if (!s->video && !s->audio) { + error("File contains neither video nor audio"); + avformat_close_input(&s->format); + free(s); + return NULL; + } + + s->has_index = 0; + + if (s->video) { + s->scaleframe = av_frame_alloc(); + s->scaleframe->width = s->video->frame->width; + s->scaleframe->height = s->video->frame->height; + s->scaleframe->format = AV_PIX_FMT_RGB24; + + s->buffer = (uint8_t *)av_malloc(sizeof(uint8_t)*avpicture_get_size(s->scaleframe->format, s->scaleframe->width, s->scaleframe->height)); + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,24,0) + av_image_fill_arrays(s->scaleframe->data, s->scaleframe->linesize, s->buffer, s->scaleframe->format, s->video->frame->width, s->video->frame->height, 1); + #else + avpicture_fill((AVPicture *)s->scaleframe, s->buffer, s->scaleframe->format, s->video->frame->width, s->video->frame->height); + #endif + + s->sws_context = sws_getCachedContext(NULL, s->video->frame->width, s->video->frame->height, s->video->frame->format, + s->scaleframe->width, s->scaleframe->height, s->scaleframe->format, SWS_AREA, NULL, NULL, NULL); + } + + s->keyframes = NULL; + + // audio specific + if (s->audio) { + s->rdft = av_rdft_init(log2(SAMPLES_PER_FRAME), DFT_R2C); + } + + return s; +} + +int source_has_video(source *s) { + return s->video != NULL; +} + +int source_has_audio(source *s) { + return s->audio != NULL; +} + +long preceding_keyframe(source *s, const long frame_nr) { + int i; + long best_keyframe = -1; + for (i = 0; i < s->number_of_keyframes; i++) { + if (s->keyframesi <= frame_nr) { + best_keyframe = s->keyframesi; + } + } +#ifdef DEBUG + printf("preceding_keyframe(%ld) -> %ld\n", frame_nr, best_keyframe); +#endif + return best_keyframe; +} + +int seek(source *s, stream *st, const long min_frame_nr, const long max_frame_nr) { +#ifdef DEBUG + printf("seek(%ld, %ld)\n", min_frame_nr, max_frame_nr); +#endif + if (s->exact && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + long keyframe = preceding_keyframe(s, max_frame_nr); + + if (keyframe > st->current_frame || max_frame_nr < st->current_frame) { + if (seek_keyframe(s, st, keyframe) != 0) { +#ifdef DEBUG + printf("seek_keyframe() == 0\n"); +#endif + return 1; + } + } + + while (st->current_frame < min_frame_nr) { + if (st->current_frame > max_frame_nr) { + error("Target frame is in the past. This shouldn't happen. Please file a bug."); + } + if (grab_next_frame(s, st) != 0) { +#ifdef DEBUG + printf("grab_next_frame() == 0\n"); +#endif + return 1; + } + } + } else { + if (seek_keyframe(s, st, (min_frame_nr+max_frame_nr)/2) != 0) { +#ifdef DEBUG + printf("seek_keyframe() == 0\n"); +#endif + return 1; + } + } + return 0; +} + +int colormap_r(float dbfs) { + if (dbfs >= -30) return 255; + if (dbfs <= -40) return 0; + return (dbfs+40)/10.0*255; +} + +int colormap_g(float dbfs) { + if (dbfs >= -10) return (dbfs+10)/10.0*255; + if (dbfs < -20 && dbfs >= -30) return 255-(dbfs+30)/10.0*255; + if (dbfs < -30 && dbfs >= -50) return 255; + if (dbfs < -50 && dbfs >= -60) return (dbfs+60)/10.0*255; + return 0; +} + +int colormap_b(float dbfs) { + if (dbfs >= -10) return 255; + if (dbfs < -10 && dbfs >= -20) return (dbfs+20)/10.0*255; + if (dbfs < -40 && dbfs >= -50) return 255-(dbfs+50)/10.0*255; + if (dbfs < -50 && dbfs >= -60) return 255; + if (dbfs < -60 && dbfs >= -70) return (dbfs+70)/10.0*255; + return 0; +} + +image* get_frame(source *s, stream *st, const double min_percent, const double max_percent) { + float proportion = s->end-s->start; + const long min_frame = (min_percent*proportion + s->start)*total_number_of_frames(s, st); + const long max_frame = (max_percent*proportion + s->start)*total_number_of_frames(s, st); + + if (st->last_frame != NULL && !s->exact && s->has_index) { + if (st->current_frame >= preceding_keyframe(s, (max_frame+min_frame)/2)) { + return st->last_frame; + } + } + + if (seek(s, st, min_frame, max_frame) != 0) { + return NULL; + } + + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (st->last_frame == NULL) { + st->last_frame = image_init(st->frame->width, st->frame->height); + } + + sws_scale(s->sws_context, (uint8_t const * const *)st->frame->data, + st->frame->linesize, 0, st->frame->height, s->scaleframe->data, + s->scaleframe->linesize); + + image_copy_avframe(st->last_frame, s->scaleframe); + } else { + if (s->audio->last_frame == NULL) { + s->audio->last_frame = image_init(1, 100); + } + + float *data; + int i; + switch(st->codec->sample_fmt) { + case AV_SAMPLE_FMT_FLTP: + data = (float *) s->audio->frame->data0; + break; + case AV_SAMPLE_FMT_S16P: + data = (float *) malloc(sizeof(float)*SAMPLES_PER_FRAME); + for (i = 0; i < SAMPLES_PER_FRAME; i++) { + float val = ((int16_t *) s->audio->frame->data0)i/100000.0; + datai = val; + } + + break; + default: + error("Unsupported sample format (%d), see https://github.com/nordlicht/nordlicht/issues/26", st->codec->sample_fmt); + return NULL; + } + + av_rdft_calc(s->rdft, data); + + int f; + for (f = 0; f < 100; f++) { + double absval = data2*f+0*data2*f+0+data2*f+1*data2*f+1; + double dbfs = 10*log10(absval/10000.0); // TODO: finetune + image_set(s->audio->last_frame, 0, 100-f-1, colormap_r(dbfs), colormap_g(dbfs), colormap_b(dbfs)); + } + } + + return st->last_frame; +} + +image* source_get_video_frame(source *s, const double min_percent, const double max_percent) { + return get_frame(s, s->video, min_percent, max_percent); +} + +image* source_get_audio_frame(source *s, const double min_percent, const double max_percent) { + return get_frame(s, s->audio, min_percent, max_percent); +} + +int source_has_index(const source *s) { + return s->has_index; +} + +void source_set_exact(source *s, const int exact) { + s->exact = exact; + if (s->video) { + s->video->current_frame = -1; + } + if (s->audio) { + s->audio->current_frame = -1; + } +} + +float source_start(const source *s) { + return s->start; +} + +void source_set_start(source *s, const float start) { + s->start = start; +} + +float source_end(const source *s) { + return s->end; +} + +void source_set_end(source *s, const float end) { + s->end = end; +} + +void stream_free(stream *st) { + avcodec_close(st->codec); + + if (st->last_frame != NULL) { + image_free(st->last_frame); + } + + av_frame_free(&st->frame); + + free(st); +} + +void source_free(source *s) { + av_rdft_end(s->rdft); + + if (s->video) { + av_free(s->buffer); + av_frame_free(&s->scaleframe); + sws_freeContext(s->sws_context); + stream_free(s->video); + } + + if (s->audio) { + stream_free(s->audio); + } + + avformat_close_input(&s->format); + + if (s->keyframes) { + free(s->keyframes); + } + + free(s); +}
View file
nordlicht-0.4.5.tar.xz/src/source.h
Added
@@ -0,0 +1,37 @@ +#ifndef INCLUDE_source_h__ +#define INCLUDE_source_h__ + +#include "nordlicht.h" +#include "image.h" + +#define COLUMN_PRECISION 0.95 // choose a frame from this percentage at the middle of each column + +typedef struct source source; + +source* source_init(const char *filename); + +int source_has_video(source *s); + +int source_has_audio(source *s); + +image* source_get_video_frame(source *s, const double min_percent, const double max_percent); + +image* source_get_audio_frame(source *s, const double min_percent, const double max_percent); + +int source_build_keyframe_index_step(source *s, const int width); + +int source_has_index(const source *s); + +void source_set_exact(source *s, const int exact); + +float source_start(const source *s); + +void source_set_start(source *s, const float start); + +float source_end(const source *s); + +void source_set_end(source *s, const float end); + +void source_free(source *s); + +#endif
View file
nordlicht-0.4.5.tar.xz/src/testsuite.c
Added
@@ -0,0 +1,242 @@ +#include "cheat.h" +#include "nordlicht.h" + +#ifdef _WIN32 +#include <io.h> +#define F_OK 0 +#define access _access +#endif + +#define cheat_null(x) cheat_assert(NULL == (x)) +#define cheat_not_null(x) cheat_assert(NULL != (x)) +#define cheat_fail(x) cheat_assert(0 != (x)) +#define cheat_ok(x) cheat_assert(0 == (x)) + +CHEAT_DECLARE( + nordlicht *n; + + int tool(char *args) { + char c200; + snprintf(c, 200, "./nordlicht %s >/dev/null 2>/dev/null", args); + return system(c); + } +) + +CHEAT_SET_UP( + n = NULL; +) + +CHEAT_TEAR_DOWN( + if (n != NULL) { + nordlicht_free(n); + } +) + +CHEAT_TEST(testfile_exists, + cheat_assert(-1 != access("video.mp4", F_OK)); +) + +CHEAT_TEST(invalid_input_file, + cheat_null(nordlicht_init(NULL, 100, 100)); + cheat_null(nordlicht_init("", 100, 100)); + cheat_null(nordlicht_init("\0", 100, 100)); + cheat_null(nordlicht_init(".", 100, 100)); + cheat_null(nordlicht_init("..", 100, 100)); + cheat_null(nordlicht_init("/", 100, 100)); + cheat_null(nordlicht_init("\\", 100, 100)); + cheat_null(nordlicht_init("nonexistent_file.123", 100, 100)); + cheat_null(nordlicht_init("video.mp4.", 100, 100)); +) + +CHEAT_TEST(invalid_size, + cheat_null(nordlicht_init("video.mp4", 0, 100)); + cheat_null(nordlicht_init("video.mp4", 100, 0)); + cheat_null(nordlicht_init("video.mp4", 0, 0)); + cheat_null(nordlicht_init("video.mp4", -1, 1)); + cheat_null(nordlicht_init("video.mp4", 1, -1)); + cheat_null(nordlicht_init("video.mp4", -100, 100)); + cheat_null(nordlicht_init("video.mp4", 100, -100)); + cheat_null(nordlicht_init("video.mp4", INT_MIN, INT_MIN)); + cheat_null(nordlicht_init("video.mp4", 100001, 100001)); + cheat_null(nordlicht_init("video.mp4", 100001, 1)); + cheat_null(nordlicht_init("video.mp4", 1, 100001)); +) + + +CHEAT_TEST(valid_size, + cheat_not_null(nordlicht_init("video.mp4", 1, 1)); + cheat_not_null(nordlicht_init("video.mp4", 100, 100)); + cheat_not_null(nordlicht_init("video.mp4", 100000, 100000)); + cheat_not_null(nordlicht_init("video.mp4", 100000, 1)); + cheat_not_null(nordlicht_init("video.mp4", 1, 100000)); +) + +CHEAT_TEST(invalid_output, + n = nordlicht_init("video.mp4", 100, 100); + cheat_not_null(n); + cheat_fail(nordlicht_write(n, NULL)); + cheat_fail(nordlicht_write(n, "")); + cheat_fail(nordlicht_write(n, "\0")); + cheat_fail(nordlicht_write(n, ".")); + cheat_fail(nordlicht_write(n, "..")); + cheat_fail(nordlicht_write(n, "/")); + cheat_fail(nordlicht_write(n, "video.mp4")); +) + +CHEAT_TEST(style, + n = nordlicht_init("video.mp4", 100, 100); + cheat_not_null(n); + cheat_ok(nordlicht_set_style(n, NORDLICHT_STYLE_HORIZONTAL)); + cheat_ok(nordlicht_set_style(n, NORDLICHT_STYLE_VERTICAL)); + cheat_ok(nordlicht_set_style(n, NORDLICHT_STYLE_LAST-1)); + cheat_fail(nordlicht_set_style(n, -1)); + cheat_fail(nordlicht_set_style(n, INT_MAX)); + cheat_fail(nordlicht_set_style(n, INT_MIN)); +) + +CHEAT_TEST(styles, + n = nordlicht_init("video.mp4", 100, 2); + cheat_not_null(n); + nordlicht_style styles3; + styles0 = NORDLICHT_STYLE_HORIZONTAL; + styles1 = NORDLICHT_STYLE_VERTICAL; + cheat_ok(nordlicht_set_styles(n, styles, 2)); + styles0 = NORDLICHT_STYLE_LAST-1; + cheat_ok(nordlicht_set_styles(n, styles, 2)); + styles0 = INT_MAX; + cheat_fail(nordlicht_set_styles(n, styles, 2)); + styles0 = INT_MIN; + cheat_fail(nordlicht_set_styles(n, styles, 2)); + styles2 = NORDLICHT_STYLE_HORIZONTAL; + cheat_fail(nordlicht_set_styles(n, styles, 3)); +) + +CHEAT_TEST(strategy, + n = nordlicht_init("video.mp4", 100, 100); + cheat_not_null(n); + cheat_ok(nordlicht_set_strategy(n, NORDLICHT_STRATEGY_FAST)); + cheat_ok(nordlicht_set_strategy(n, NORDLICHT_STRATEGY_LIVE)); + cheat_fail(nordlicht_set_strategy(n, 2)); + cheat_fail(nordlicht_set_strategy(n, -1)); + cheat_fail(nordlicht_set_strategy(n, INT_MAX)); + cheat_fail(nordlicht_set_strategy(n, INT_MIN)); +) + +CHEAT_TEST(buffer, + const unsigned char *buffer = NULL; + n = nordlicht_init("video.mp4", 2, 100); + cheat_not_null(n); + buffer = nordlicht_buffer(n); + cheat_not_null(buffer); + cheat_assert(2*100*4 == nordlicht_buffer_size(n)); + unsigned char *buffer2 = NULL; + cheat_fail(nordlicht_set_buffer(n, buffer2)); + buffer2 = malloc(nordlicht_buffer_size(n)); + cheat_ok(nordlicht_set_buffer(n, buffer2)); + cheat_ok(nordlicht_set_buffer(n, buffer2)); + cheat_ok(nordlicht_set_buffer(n, buffer2)); + buffer = nordlicht_buffer(n); + cheat_assert(buffer == buffer2); + free(buffer2); +) + +CHEAT_TEST(generate_step, + n = nordlicht_init("video.mp4", 1, 100); + cheat_assert(0 == nordlicht_progress(n)); + cheat_assert(!nordlicht_done(n)); + cheat_ok(nordlicht_set_start(n, 0.5)); + cheat_assert(0 == nordlicht_generate_step(n)); + cheat_assert(!nordlicht_done(n)); + cheat_fail(nordlicht_set_start(n, 0.5)); + cheat_assert(0 == nordlicht_generate_step(n)); + cheat_assert(0 == nordlicht_generate_step(n)); + cheat_ok(nordlicht_generate(n)); + cheat_assert(nordlicht_done(n)); + cheat_assert(0 == nordlicht_generate_step(n)); + cheat_assert(nordlicht_done(n)); +) + +CHEAT_TEST(complete_run, + unsigned char *buffer2 = NULL; + n = nordlicht_init("video.mp4", 1, 100); + cheat_not_null(n); + cheat_ok(nordlicht_progress(n)); + cheat_ok(nordlicht_generate(n)); + cheat_assert(1 == nordlicht_progress(n)); + buffer2 = malloc(nordlicht_buffer_size(n)); + cheat_fail(nordlicht_set_buffer(n, buffer2)); + free(buffer2); +) + +CHEAT_TEST(tool_argument_parsing, + cheat_ok(tool("--help")); + cheat_ok(tool("--version")); + cheat_fail(tool("")); + cheat_fail(tool("--fubar")); + cheat_fail(tool("-1")); + cheat_fail(tool("one.mp4 two.mp4")); + cheat_fail(tool("does_not_exist.mp4")); +) + +CHEAT_TEST(tool_size, + cheat_ok(tool("video.mp4 -w 1 -h 1")); + cheat_ok(tool("video.mp4 -w 1 -h 100000")); + cheat_fail(tool("video.mp4 -w 1 -h 100001")); + cheat_fail(tool("video.mp4 -w huuuge")); + cheat_fail(tool("video.mp4 -w 0")); + cheat_fail(tool("video.mp4 -h 0")); + cheat_fail(tool("video.mp4 -w ''")); + cheat_fail(tool("video.mp4 -h ''")); + cheat_fail(tool("video.mp4 -w -100")); + cheat_fail(tool("video.mp4 -h -100")); + cheat_fail(tool("video.mp4 -w 1.1")); + cheat_fail(tool("video.mp4 -h 1.1")); + cheat_fail(tool("video.mp4 -w 1,1")); + cheat_fail(tool("video.mp4 -h 1,1")); +) + +CHEAT_TEST(tool_output, + cheat_ok(tool("video.mp4 -w 1")); + cheat_assert(-1 != access("video.mp4.nordlicht.png", F_OK)); + cheat_ok(tool("video.mp4 -w 1 -o ünîç⌀də.png")); + cheat_assert(-1 != access("ünîç⌀də.png", F_OK)); + cheat_fail(tool("video.mp4 -o video.mp4")); + cheat_fail(tool("video.mp4 -o ''")); + cheat_fail(tool("video.mp4 -o .")); + cheat_fail(tool("video.mp4 -o ..")); + cheat_fail(tool("video.mp4 -o /")); + cheat_ok(tool("video.mp4 -w 1 -o barcode.bgra")); + // fall back to PNG in these two cases: + cheat_ok(tool("video.mp4 -w 1 -o barcode.abc")); + cheat_ok(tool("video.mp4 -w 1 -o barcode")); +) + +CHEAT_TEST(tool_style, + cheat_ok(tool("video.mp4 -w 1 -s vertical")); + cheat_ok(tool("video.mp4 -w 1 -s horizontal")); + cheat_fail(tool("video.mp4 -h 1 -s horizontal+vertical")); + cheat_fail(tool("video.mp4 -h 2 -s horizontal+vertical+horizontal")); + cheat_ok(tool("video.mp4 -h 2 -s horizontal+vertical")); + cheat_fail(tool("video.mp4 -s horizontal+")); + cheat_fail(tool("video.mp4 -s +")); + cheat_fail(tool("video.mp4 -s ++")); + cheat_fail(tool("video.mp4 -s horizontal++horizontal")); + cheat_fail(tool("video.mp4 -s nope")); + cheat_fail(tool("video.mp4 -s ''")); + cheat_fail(tool("video.mp4 -s")); +) + +CHEAT_TEST(tool_region, + cheat_ok(tool("video.mp4 -w 1 --start=0.5")); + cheat_ok(tool("video.mp4 -w 1 --end=0.5")); + cheat_ok(tool("video.mp4 -w 1 --start=0.1 --end=0.2")); + cheat_ok(tool("video.mp4 -w 1 --start=0 --end=1")); + cheat_fail(tool("video.mp4 -w 1 --start=-1")); + cheat_fail(tool("video.mp4 -w 1 --start=1")); + cheat_fail(tool("video.mp4 -w 1 --start=2")); + cheat_fail(tool("video.mp4 -w 1 --end=-1")); + cheat_fail(tool("video.mp4 -w 1 --end=0")); + cheat_fail(tool("video.mp4 -w 1 --end=2")); + cheat_fail(tool("video.mp4 -w 1 --start=0.2 --end=0.1")); + cheat_fail(tool("video.mp4 -w 1 --start=0.5 --end=0.5")); +)
View file
nordlicht-0.4.5.tar.xz/src/version.h.in
Changed
(renamed from version.h.in)
View file
nordlicht-0.4.4.tar.gz/utils/mpv-nordlicht.lua -> nordlicht-0.4.5.tar.xz/utils/mpv-nordlicht.lua
Changed
@@ -25,6 +25,10 @@ function shutdown() off() kill() + + if buffer and buffer:len() > 0 then + os.remove(buffer) + end end function kill() @@ -41,7 +45,13 @@ video = mp.get_property("path") nordlicht = video..".nordlicht.png" - buffer = "/tmp/nordlicht.bgra" + + if buffer and buffer:len() > 0 then + os.remove(buffer) + end + local tmpbuffer = os.tmpname() + buffer = tmpbuffer .. ".nordlicht.mpv.bgra" + os.rename(tmpbuffer, buffer) local f = io.open(nordlicht, "r") if f ~= nil then @@ -49,6 +59,7 @@ io.close(f) local cmd = {"convert", nordlicht, "-depth", "8", "-resize", width.."x"..height.."!", buffer} utils.subprocess({args=cmd}) + utils.subprocess({args={"chmod", "600", buffer}}) if was_on then on() @@ -114,7 +125,14 @@ function regenerate() local was_on = is_on off() - local cmd = "(nice nordlicht -s "..styles.." \""..video.."\" -o "..buffer.." -w "..width.." -h "..height.." && convert -depth 8 -size "..width.."x"..height.." "..buffer.." \""..nordlicht.."\") &" + + local safe_buffer = buffer:gsub('"', '\\"') + local safe_video = video:gsub('"', '\\"') + local safe_nordlicht = nordlicht:gsub('"', '\\"') + local cmd = ('(nice nordlicht -s %s "%s" -o "%s" -w %d -h %d' .. + ' && convert -depth 8 -size %dx%d "%s" "%s") &') + :format(styles, safe_video, safe_buffer, width, height, + width, height, safe_buffer, safe_nordlicht) os.execute(cmd) if was_on then on() @@ -122,11 +140,14 @@ end function jump(e) - local mouseX, mouseY = mp.get_mouse_pos() - local osdX, osdY = mp.get_osd_resolution() - mouseX = 100.0*mouseX/osdX + local mouse_x, mouse_y = mp.get_mouse_pos() + local osd_x, osd_y = mp.get_osd_resolution() + local screen_y = mp.get_property("osd-height") + local absolute_mouse_y = 1.0*mouse_y/osd_y*screen_y - mp.commandv("seek", mouseX, "absolute-percent", "exact") + if absolute_mouse_y <= mh+height and is_on then + mp.commandv("seek", 100.0*mouse_x/osd_x, "absolute-percent", "exact") + end end -- wait until the osd-width is > 0, then init
View file
nordlicht-0.4.5.tar.xz/utils/nordlicht.thumbnailer
Added
@@ -0,0 +1,4 @@ +Thumbnailer Entry +TryExec=nordlicht +Exec=nordlicht --quiet %i --output %o --width %s --height %s +MimeType=video/jpeg;video/mp4;video/mpeg;video/quicktime;video/x-ms-asf;video/x-ms-wm;video/x-ms-wmv;video/x-msvideo;video/x-flv;video/x-matroska;video/webm;
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.