Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Libvisual/libvisual into bin-rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
kaixiong committed Jan 30, 2025
2 parents b4bd090 + 53b86b6 commit 73c8493
Show file tree
Hide file tree
Showing 12 changed files with 488 additions and 116 deletions.
5 changes: 4 additions & 1 deletion libvisual/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ IF(NOT HAVE_STDC_MATH)
MESSAGE(FATAL_ERROR "Libvisual requires libm to build")
ENDIF()

# Check for Zlib
FIND_PACKAGE(ZLIB 1.2 REQUIRED)

# Check for libpng
FIND_PACKAGE(PNG REQUIRED)
FIND_PACKAGE(PNG 1.4 REQUIRED)

# Internationalization
SET(GETTEXT_PACKAGE "libvisual-${LV_VERSION_SUFFIX}")
Expand Down
1 change: 1 addition & 0 deletions libvisual/libvisual/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ TARGET_LINK_LIBRARIES(libvisual
PkgConfig::ORC
PNG::PNG
Threads::Threads
ZLIB::ZLIB
)

IF(WIN32)
Expand Down
115 changes: 106 additions & 9 deletions libvisual/libvisual/lv_video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,87 @@
#include "lv_color.h"
#include "lv_common.h"
#include "lv_cpu.h"
#include "private/lv_string_hash.hpp"
#include "private/lv_video_private.hpp"
#include "private/lv_video_blit.hpp"
#include "private/lv_video_convert.hpp"
#include "private/lv_video_fill.hpp"
#include "private/lv_video_transform.hpp"
#include "private/lv_video_bmp.hpp"
#include "private/lv_video_png.hpp"
#include <algorithm>
#include <cctype>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <functional>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>

namespace LV {

namespace fs = std::filesystem;

namespace {

using BitmapReader = std::function<VideoPtr (std::istream&)>;
using BitmapWriter = std::function<bool (Video const&, std::ostream&)>;

struct ImageFormatInfo
{
std::string name;
BitmapReader reader;
BitmapWriter writer;
std::vector<std::string> extensions;
};

using ImageFormatExtensionLookup = std::unordered_map<
std::string, ImageFormat, StringHash, std::equal_to<>>;

std::unordered_map<ImageFormat, ImageFormatInfo> const supported_image_formats
{
{ImageFormat::BMP, {"BMP", bitmap_load_bmp, nullptr, {".bmp"}}},
{ImageFormat::PNG, {"PNG", bitmap_load_png, bitmap_save_png, {".png"}}}
};

ImageFormatExtensionLookup build_image_format_extension_lookup ()
{
ImageFormatExtensionLookup map;

for (auto const& entry : supported_image_formats)
for (auto const& extension : entry.second.extensions)
map.emplace (extension, entry.first);

return map;
}

std::optional<ImageFormat> find_image_format_by_extension (std::string_view extension)
{
static auto const lookup {build_image_format_extension_lookup ()};

auto match {lookup.find (extension)};
if (match == lookup.end ())
return std::nullopt;
return match->second;
}

bool is_valid_scale_method (VisVideoScaleMethod scale_method)
{
return scale_method == VISUAL_VIDEO_SCALE_NEAREST
|| scale_method == VISUAL_VIDEO_SCALE_BILINEAR;
}

// TODO: Factor this out into a string utility library
std::string to_lower_ascii (std::string const& s)
{
auto result {s};
for (auto& c : result)
c = std::tolower (c);
return result;
}

} // anonymous namespace


Expand Down Expand Up @@ -191,17 +252,16 @@ namespace LV {

VideoPtr Video::create_from_stream (std::istream& input)
{
auto image = bitmap_load_bmp (input);
if (image) {
return image;
}

image = bitmap_load_png (input);
if (image) {
return image;
for (auto entry : supported_image_formats) {
if (entry.second.reader) {
auto image {entry.second.reader (input)};
if (image) {
return image;
}
}
}

return {};
return nullptr;
}

VideoPtr Video::create_scale_depth (VideoConstPtr const& src,
Expand Down Expand Up @@ -260,6 +320,43 @@ namespace LV {
return m_impl->buffer->is_allocated ();
}

bool Video::save_to_file (std::string const& path) const
{
auto extension {fs::path {path}.extension ()};
auto extension_lower (to_lower_ascii (extension.string ()));

auto format {find_image_format_by_extension (extension_lower)};
if (!format.has_value ()) {
visual_log (VISUAL_LOG_ERROR, "Could not deduce format from filename (%s)", path.c_str ());
return false;
}

std::ofstream output {path};
if (!output) {
visual_log (VISUAL_LOG_ERROR, "Could not create file '%s'", path.c_str ());
return false;
}

return save_to_stream (output, format.value ());
}

bool Video::save_to_stream (std::ostream& output, ImageFormat format) const
{
auto entry {supported_image_formats.find (format)};

if (entry == supported_image_formats.end ()) {
visual_log (VISUAL_LOG_ERROR, "Saving to unknown format (%d).", static_cast<int> (format));
return false;
}

if (!entry->second.writer) {
visual_log (VISUAL_LOG_ERROR, "Saving to %s is unsupported.", entry->second.name.c_str ());
return false;
}

return entry->second.writer (*this, output);
}

void Video::copy_attrs (VideoConstPtr const& src)
{
set_depth (src->m_impl->depth);
Expand Down
38 changes: 38 additions & 0 deletions libvisual/libvisual/lv_video.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ typedef enum {
VISUAL_VIDEO_COMPOSE_TYPE_CUSTOM /**< Custom compose function (looks up on the source VisVideo. */
} VisVideoComposeType;

/**
* The set of known and supported image formats.
*/
typedef enum {
VISUAL_IMAGE_FORMAT_BMP = 0,
VISUAL_IMAGE_FORMAT_PNG
} VisImageFormat;

typedef struct _VisVideoAttrOptions VisVideoAttrOptions;

#ifdef __cplusplus
Expand Down Expand Up @@ -125,6 +133,15 @@ struct _VisVideoAttrOptions {

namespace LV {

/**
* The set of known and supported image formats.
*/
enum class ImageFormat
{
BMP = VISUAL_IMAGE_FORMAT_BMP,
PNG = VISUAL_IMAGE_FORMAT_PNG
};

class Video;

typedef IntrusivePtr<Video> VideoPtr;
Expand Down Expand Up @@ -259,6 +276,25 @@ namespace LV {
*/
BufferPtr get_buffer () const;

/**
* Saves contents to a file.
*
* @param path Path name of file to save to. Specify the file format by using the appropriate extension.
*
* @return true if file was successfully saved, false otherwise.
*/
bool save_to_file (std::string const& path) const;

/**
* Saves contents to a stream.
*
* @param output stream to write contents to.
* @param format image file format to encode contents in.
*
* @return true if file was successfully saved, false otherwise.
*/
bool save_to_stream (std::ostream& output, ImageFormat format) const;

/**
* Sets all attributes.
*
Expand Down Expand Up @@ -513,6 +549,8 @@ LV_NODISCARD LV_API VisVideo *visual_video_new_with_buffer (int width, int heigh
LV_NODISCARD LV_API VisVideo *visual_video_new_wrap_buffer (void *buffer, int owner, int width, int height, VisVideoDepth depth, int pitch);
LV_NODISCARD LV_API VisVideo *visual_video_load_from_file (const char *path);

LV_API int visual_video_save_to_file (VisVideo *video);

LV_API void visual_video_ref (VisVideo *video);
LV_API void visual_video_unref (VisVideo *video);

Expand Down
8 changes: 8 additions & 0 deletions libvisual/libvisual/lv_video_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ VisVideo *visual_video_load_from_file (const char *path)
return self.get ();
}

int visual_video_save_to_file (VisVideo *self, const char *path)
{
visual_return_val_if_fail (self != nullptr, FALSE);
visual_return_val_if_fail (path != nullptr, FALSE);

return self->save_to_file (path);
}

int visual_video_has_allocated_buffer (VisVideo *self)
{
visual_return_val_if_fail (self != nullptr, FALSE);
Expand Down
Loading

0 comments on commit 73c8493

Please sign in to comment.