From 1e0e68f9cda51c881b32a54d9eece71c1428f7ac Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 22 Apr 2018 05:58:44 +0200 Subject: Add video and gif support Gif streams from url. Todo: Add play controls to video --- src/Gif.cpp | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/Gif.cpp (limited to 'src/Gif.cpp') diff --git a/src/Gif.cpp b/src/Gif.cpp new file mode 100644 index 0000000..3f7216e --- /dev/null +++ b/src/Gif.cpp @@ -0,0 +1,169 @@ +#include "../include/Gif.hpp" +#include "../include/FileUtil.hpp" + +using namespace std; + +namespace dchat +{ + void* bitmapCreate(int width, int height) + { + return calloc(width * height, 4); + } + + void bitmapDestroy(void *bitmap) + { + free(bitmap); + } + + unsigned char* bitmapGetBuffer(void *bitmap) + { + return (unsigned char*)bitmap; + } + + void bitmapSetOpaque(void *bitmap, bool opaque) + { + + } + + bool bitmapTestOpaque(void *bitmap) + { + return false; + } + + void bitmapModified(void *bitmap) + { + + } + + const char* gifResultToString(gif_result code) + { + switch(code) + { + case GIF_INSUFFICIENT_FRAME_DATA: + return "GIF_INSUFFICIENT_FRAME_DATA"; + case GIF_FRAME_DATA_ERROR: + return "GIF_FRAME_DATA_ERROR"; + case GIF_INSUFFICIENT_DATA: + return "GIF_INSUFFICIENT_DATA"; + case GIF_DATA_ERROR: + return "GIF_DATA_ERROR"; + case GIF_INSUFFICIENT_MEMORY: + return "GIF_INSUFFICIENT_MEMORY"; + default: + return "Unknown gif result code"; + } + } + + Gif::Gif(const boost::filesystem::path &filepath) : + currentFrame(0), + timeElapsedCs(0.0) + { + try + { + fileContent = getFileContent(filepath); + } + catch(FileException &e) + { + throw GifLoadException(e.what()); + } + init(); + } + + Gif::Gif(StringView &&_fileContent) : + fileContent(move(_fileContent)), + currentFrame(0), + timeElapsedCs(0.0) + { + init(); + } + + void Gif::init() + { + gif_bitmap_callback_vt bitmapCallbacks = + { + bitmapCreate, + bitmapDestroy, + bitmapGetBuffer, + bitmapSetOpaque, + bitmapTestOpaque, + bitmapModified + }; + + gif_create(&gif, &bitmapCallbacks); + + gif_result code; + do + { + code = gif_initialise(&gif, fileContent.size, (unsigned char*)fileContent.data); + if(code != GIF_OK && code != GIF_WORKING) + { + string errMsg = "Failed to initialize gif, reason: "; + errMsg += gifResultToString(code); + throw GifLoadException(errMsg); + } + } + while(code != GIF_OK); + + if(!texture.create(gif.width, gif.height)) + throw GifLoadException("Failed to create texture for gif"); + + sprite.setTexture(texture, true); + } + + Gif::~Gif() + { + gif_finalise(&gif); + delete fileContent.data; + } + + void Gif::setPosition(const sf::Vector2f &position) + { + sprite.setPosition(position); + } + + void Gif::setSize(const sf::Vector2f &size) + { + sf::Vector2u textureSize = sprite.getTexture()->getSize(); + sprite.setScale(size.x / (float)textureSize.x, size.y / (float)textureSize.y); + } + + void Gif::draw(sf::RenderWindow &window) + { + double frameDeltaCs = (double)frameTimer.getElapsedTime().asMilliseconds() * 0.1; // Centisecond + frameTimer.restart(); + timeElapsedCs += frameDeltaCs; + + unsigned char *image = nullptr; + u32 startFrame = currentFrame; + while(true) + { + int i = currentFrame % gif.frame_count; + gif_result code = gif_decode_frame(&gif, i); + if(code != GIF_OK) + printf("Warning: gif_decode_frame: %s\n", gifResultToString(code)); + + gif_frame &frame = gif.frames[i]; + // frame_delay is in centiseconds + double frameDelay = (double)frame.frame_delay; + if(timeElapsedCs >= frameDelay) + timeElapsedCs -= frameDelay; + else + break; + + image = (unsigned char*)gif.frame_image; + ++currentFrame; + } + + if(currentFrame != startFrame) + { + texture.update(image); + sprite.setTexture(texture, true); + } + window.draw(sprite); + } + + bool Gif::isDataGif(const StringView &data) + { + return data.size >= 6 && (memcmp(data.data, "GIF87a", 6) == 0 || memcmp(data.data, "GIF89a", 6) == 0); + } +} -- cgit v1.2.3