// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- // // Quick hack based on ffmpeg // tutorial http://dranger.com/ffmpeg/tutorial01.html // in turn based on a tutorial by // Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de) // // HELP NEEDED // Note, this is known to not be optimal, causing flicker etc. It is at this // point merely a demonstration of what is possible. It also serves as a // converter to a 'stream' (-O option) which then can be played quickly with // the led-image-viewer. // // Pull requests are welcome to address // * Use hardware acceleration if possible. The Pi does have some // acceleration features IIRC, so if we could use these, that would be // great. // * Other improvements that could reduce the flicker on a Raspberry Pi. // Currently it seems to create flicker in particular when decoding larger // videos due to memory bandwidth overload (?). Might already be fixed // with using hardware acceleration. // * Add sound ? Right now, we don't decode the sound. It is usually // not very useful as the builtin-sound is disabled when running the // LED matrix, but if there is an external USB sound adapter, it might // be nice. // Ancient AV versions forgot to set this. #define __STDC_CONSTANT_MACROS // libav: "U NO extern C in header ?" extern "C" { # include # include # include # include } #include #include #include #include #include #include #include #include #include #include #include "led-matrix.h" #include "content-streamer.h" using rgb_matrix::FrameCanvas; using rgb_matrix::RGBMatrix; using rgb_matrix::StreamWriter; using rgb_matrix::StreamIO; volatile bool interrupt_received = false; static void InterruptHandler(int) { interrupt_received = true; } struct LedPixel { uint8_t r, g, b; }; void CopyFrame(AVFrame *pFrame, FrameCanvas *canvas, int offset_x, int offset_y, int width, int height) { for (int y = 0; y < height; ++y) { LedPixel *pix = (LedPixel*) (pFrame->data[0] + y*pFrame->linesize[0]); for (int x = 0; x < width; ++x, ++pix) { canvas->SetPixel(x + offset_x, y + offset_y, pix->r, pix->g, pix->b); } } } // Scale "width" and "height" to fit within target rectangle of given size. void ScaleToFitKeepAscpet(int fit_in_width, int fit_in_height, int *width, int *height) { if (*height < fit_in_height && *width < fit_in_width) return; // Done. const float height_ratio = 1.0 * (*height) / fit_in_height; const float width_ratio = 1.0 * (*width) / fit_in_width; const float ratio = (height_ratio > width_ratio) ? height_ratio : width_ratio; *width = roundf(*width / ratio); *height = roundf(*height / ratio); } static int usage(const char *progname, const char *msg = NULL) { if (msg) { fprintf(stderr, "%s\n", msg); } fprintf(stderr, "Show one or a sequence of video files on the RGB-Matrix\n"); fprintf(stderr, "usage: %s [options]