diff --git a/.gitignore b/.gitignore
index fb715d7..f95818a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ lib*.so
lib*.a
matrix-send
.scripts
+windows_bs
diff --git a/doc/TODO b/doc/TODO
index 95f3337..d8386ba 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -1,8 +1,6 @@
general/other:
5:thorough error checking
- 2:move libav/freeimage calls from matrix to standalone functions or a singleton
1:use libmagic to determine file types for uploading?
- 1:raii swscontext
matrix:
session:
@@ -18,6 +16,7 @@ matrix:
3:set presence
2:query other users' data
1:download media
+ 1:thumbnail images and videos from server
1:query/set custom user data
1:query/addto public room directory
1:deactivate account
diff --git a/include/matrix/image_thumbnail_maker.hpp b/include/matrix/image_thumbnail_maker.hpp
deleted file mode 100644
index c23f46b..0000000
--- a/include/matrix/image_thumbnail_maker.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- This file is a part of rexy's matrix client
- Copyright (C) 2019 rexy712
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-#ifndef MATRIX_IMAGE_THUMBNAIL_MAKER_HPP
-#define MATRIX_IMAGE_THUMBNAIL_MAKER_HPP
-
-#include
-#include
-#include //size_t
-#include "matrix/upload_info.hpp"
-
-#define THUMBSIZE 500
-
-namespace matrix::internal{
-
- static std::vector _create_image_thumbnail(fipImage& image, FREE_IMAGE_FORMAT type, size_t target_size){
- image.makeThumbnail(target_size);
- FreeImageIO fileout;
- std::vector buffer;
- fileout.write_proc = [](void* ptr, unsigned int size, unsigned int nmemb, void* fp) -> unsigned int{
- std::vector& buffer = *reinterpret_cast*>(fp);
- buffer.insert(buffer.end(), (char*)ptr, ((char*)ptr)+size*nmemb);
- return size*nmemb;
- };
- switch(type){
- case FIF_JPEG:
- return image.saveToHandle(type, &fileout, &buffer, JPEG_QUALITYGOOD | JPEG_SUBSAMPLING_411) ? buffer : std::vector();
- case FIF_PNG:
- return image.saveToHandle(type, &fileout, &buffer, PNG_Z_BEST_COMPRESSION) ? buffer : std::vector();
- default:
- return image.saveToHandle(type, &fileout, &buffer) ? buffer : std::vector();
- };
- }
- static std::vector _load_image_thumbnail_info(fipImage& image, image_info& info, FREE_IMAGE_FORMAT type){
- //create and upload thumbnail
- if(info.width > THUMB_SIZE || info.height > THUMB_SIZE){
- std::vector thumb_data = _create_image_thumbnail(image, type, THUMB_SIZE);
- if(!thumb_data.size()){
- info.thumb_width = info.width;
- info.thumb_height = info.height;
- info.thumbsize = info.filesize;
- }else{
- info.thumb_width = image.getWidth();
- info.thumb_height = image.getHeight();
- info.thumbsize = thumb_data.size();
- return thumb_data;
- }
- }else{
- info.thumb_width = info.width;
- info.thumb_height = info.height;
- info.thumbsize = info.filesize;
- }
- return {};
- }
-
-}
-
-#endif
diff --git a/include/matrix/video_thumbnail_maker.hpp b/include/matrix/video_thumbnail_maker.hpp
deleted file mode 100644
index d5efb3a..0000000
--- a/include/matrix/video_thumbnail_maker.hpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/**
- This file is a part of rexy's matrix client
- Copyright (C) 2019 rexy712
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see .
-*/
-
-# include "libav/frame.hpp"
-# include "libav/codec/context.hpp"
-# include "libav/fmt/context.hpp"
-# include "libav/packet.hpp"
-
-extern "C"{
-# include //sws_scale
-# include //av_image_alloc
-}
-
-#include //size_t
-
-namespace matrix::internal{
- struct libav_initializer{
- libav_initializer(void){
- REGISTER_LIBAV();
- }
- };
- static int initlibav(void){
- static libav_initializer init;
- return 0;
- }
-
- static libavcodec::context _get_libav_jpg_context(AVRational src, size_t w, size_t h){
- AVCodec* jpg_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
- libavcodec::context jctx(jpg_codec);
- jctx->pix_fmt = AV_PIX_FMT_YUVJ420P;
- jctx->width = w;
- jctx->height = h;
- jctx->codec_id = AV_CODEC_ID_MJPEG;
- jctx->codec_type = AVMEDIA_TYPE_VIDEO;
- if(src.num == 0 || src.den == 0)
- jctx->time_base = AVRational{1, 30};
- else
- jctx->time_base = src;
- jctx.open();
- return jctx;
- }
-
- [[maybe_unused]]
- static void _change_color_range(SwsContext* sws_ctx){
- int dummy[4];
- int src_range, dest_range;
- int br, con, sat;
- sws_getColorspaceDetails(sws_ctx, (int**)&dummy, &src_range, (int**)&dummy, &dest_range, &br, &con, &sat);
- const int* coefs = sws_getCoefficients(SWS_CS_DEFAULT);
- src_range = 2;
- sws_setColorspaceDetails(sws_ctx, coefs, src_range, coefs, dest_range, br, con, sat);
- }
- static void _calc_video_thumbnail_dims(size_t target, size_t src_w, size_t src_h, size_t* w, size_t* h){
- size_t target_width = src_w;
- size_t target_height = src_h;
- if(target_width > target_height){
- if(target_width > target){
- target_height = target_height * ((float)target / target_width);
- target_width = target;
- }
- }else{
- if(target_height > target){
- target_width = target_width * ((float)target / target_height);
- target_height = target;
- }
- }
- *w = target_width;
- *h = target_height;
- }
- static libav::packet _create_video_thumbnail(libavfmt::input_context& src, libavcodec::context& src_ctx, int index, size_t targw, size_t targh){
- libavcodec::context jpg_context = _get_libav_jpg_context(src_ctx->time_base, targw, targh);
- libav::frame src_frame(src_ctx->width, src_ctx->height, src_ctx->pix_fmt);
- libav::frame jpg_frame(src_ctx->width, src_ctx->height, jpg_context->pix_fmt);
-
- libav::packet packet;
-
- SwsContext* sws_ctx = sws_getContext(src_ctx->width, src_ctx->height, src_ctx->pix_fmt,
- targw, targh, AV_PIX_FMT_YUV420P,
- SWS_BILINEAR, NULL, NULL, NULL);
- //_change_color_range(sws_ctx);
-
- av_image_alloc(jpg_frame->data, jpg_frame->linesize, targw, targh, jpg_context->pix_fmt, 32);
- jpg_frame.set_freep();
- while(av_read_frame(src, packet) >= 0){
- if(packet->stream_index == index){
- avcodec_send_packet(src_ctx, packet);
- if(avcodec_receive_frame(src_ctx, src_frame) >= 0)
- break;
- }
- av_packet_unref(packet);
- }
- sws_scale(sws_ctx, src_frame->data, src_frame->linesize, 0, src_ctx->height, jpg_frame->data, jpg_frame->linesize);
-
- sws_freeContext(sws_ctx);
-
- if(avcodec_send_frame(jpg_context, jpg_frame) < 0){
- return libav::packet(nullptr);
- }
- if(avcodec_receive_packet(jpg_context, packet) < 0){
- return libav::packet(nullptr);
- }
- return packet;
- }
- static raii::string get_libav_mimetype(const libav::fmt::input_context& ctx){
- const char* first = strstr(ctx->iformat->name, ",");
- if(first)
- return raii::string("video/" + raii::static_string(ctx->iformat->name, first - ctx->iformat->name));
- return raii::string("video/" + raii::static_string(ctx->iformat->name));
- }
-}
-
-#endif
diff --git a/makefile b/makefile
index 7addc03..b8e0f7b 100644
--- a/makefile
+++ b/makefile
@@ -15,72 +15,110 @@
ifeq ($(OS),Windows_NT)
- WINDOWS=1
+ WINDOWS::=1
endif
-SOURCE_DIRS:=src/raii src/matrix
-OBJDIR:=obj
-DEPDIR:=$(OBJDIR)/dep
-INCLUDE_DIRS:=include
-EXT:=cpp
-MAIN_LIBRARY:=librmatrix.so
-
-CXXFLAGS:=-g -std=c++17 -Wall -pedantic -Wextra -fPIC
+SOURCE_DIRS::=src/raii src/matrix
+OBJDIR::=obj
+DEPDIR::=$(OBJDIR)/dep
+LIBDIR::=lib
+INCLUDE_DIRS::=include
+CXXFLAGS::=-g -std=c++17 -Wall -pedantic -Wextra
+EXT::=cpp
+MAIN_LIBRARY::=rmatrix
+SHARED?=1
ifneq ($(WINDOWS),1)
- CXX:=g++
- AR:=ar
- RANLIB:=ranlib
- LDFLAGS:=-shared
- LDLIBS:=-lcurl -lrjp -lavformat -lavcodec -lavutil -lswresample -lswscale -lfreeimageplus
- STRIP:=strip
+ CXX::=g++
+ LDLIBS::=-lcurl -lrjp
+ LDFLAGS::=
+ STRIP::=strip
+ RANLIB::=ranlib
+ AR::=ar
+ AS::=as
+else #windows
+ MINGW_PREFIX::=x86_64-w64-mingw32-
+ CXX::=$(MINGW_PREFIX)g++
+ LDLIBS::=-lcurl -lrjp
+ LDFLAGS::=-static-libgcc -static-libstdc++
+ STRIP::=$(MINGW_PREFIX)strip
+ RANLIB::=$(MINGW_PREFIX)ranlib
+ AR::=$(MINGW_PREFIX)ar
+ AS::=$(MINGW_PREFIX)as
+ DLLOUT::=$(MAIN_LIBRARY).dll
+endif #windows
+
+ifeq ($(SHARED),1)
+ ifeq ($(OS),Windows_NT)
+ INTERNAL_MAIN_LIBRARY::=lib$(MAIN_LIBRARY).a
+ else
+ INTERNAL_MAIN_LIBRARY::=lib$(MAIN_LIBRARY).so
+ endif
else
- CXX:=x86_64-w64-mingw32-g++
- AR:=x86_64-w64-mingw32-ar
- RANLIB:=x86_64-w64-mingw32-ranlib
- LDFLAGS:=
- LDLIBS:=-lcurl -lrjp -lavformat -lavcodec -lavutil -lswresample -lswscale -lfreeimageplus
- STRIP:=x86_64-w64-mingw32-strip
+ INTERNAL_MAIN_LIBRARY::=lib$(MAIN_LIBRARY).a
endif
+
+
all: CXXFLAGS+=-O0
release: CXXFLAGS+=-O2
-memchk:LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
-memchk:CXXFLAGS+=-O0 -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
+memchk: LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
+memchk: CXXFLAGS+=-O0 -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
ifeq ($(OS),Windows_NT)
mkdir=mkdir $(subst /,\,$(1)) > NUL 2>&1
rm=del /F $(1) > NUL 2>&1
- rmdir=rd /s /q $(1) > NUL 2>&1
- move=move /y $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1
- MAIN_EXECUTABLE:=$(MAIN_EXECUTABLE).exe
- LDLIBS:=-lglfw3 -lSOIL -lgl3w -lm -lopengl32 -lglu32 -lgdi32 -lkernel32
+ rmdir=rd /S /Q $(1) > NUL 2>&1
+ move=move /Y $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1
+ copy=copy /Y /B $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1
else
mkdir=mkdir -p $(1)
rm=rm -f $(1)
rmdir=rm -rf $(1)
move=mv $(1) $(2)
+ copy=cp $(1) $(2)
endif
INTERNAL_CXXFLAGS=-c $(foreach dir,$(INCLUDE_DIRS),-I"$(dir)") -MMD -MP -MF"$(DEPDIR)/$(notdir $(patsubst %.o,%.d,$@))"
-SOURCES:=$(foreach source,$(SOURCE_DIRS),$(foreach ext,$(EXT),$(wildcard $(source)/*.$(ext))))
-OBJECTS:=$(addprefix $(OBJDIR)/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(SOURCES)))))
+ifeq ($(SHARED),1)
+ INTERNAL_CXXFLAGS+=-fPIC
+endif
+SOURCES::=$(foreach source,$(SOURCE_DIRS),$(foreach ext,$(EXT),$(wildcard $(source)/*.$(ext))))
+OBJECTS::=$(addprefix $(OBJDIR)/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(SOURCES)))))
+
+.PHONY: all
+
+ifeq ($(SHARED),1)
+ifeq ($(WINDOWS),1)
+all: $(DLLOUT)
+$(INTERNAL_MAIN_LIBRARY): $(OBJECTS)
+ $(CXX) -shared -o "$(DLLOUT)" $^ -Wl,--out-implib,"lib$(MAIN_LIBRARY).a" $(LDLIBS) $(LDFLAGS)
+$(DLLOUT): $(INTERNAL_MAIN_LIBRARY)
+else #windows
+all: $(INTERNAL_MAIN_LIBRARY)
+$(INTERNAL_MAIN_LIBRARY): $(OBJECTS)
+ $(CXX) -shared -o "$@" $^ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
+endif #windows
+else #shared
+all: $(INTERNAL_MAIN_LIBRARY)
+$(INTERNAL_MAIN_LIBRARY): $(OBJECTS)
+ $(AR) rcs "$@" $^
+ $(RANLIB) "$@"
+endif #shared
-all: $(MAIN_LIBRARY)
.PHONY: memchk
-memchk: all
.PHONY: release
+memchk: all
release: all
+
.PHONY: utils
utils: matrix-send
-tester: $(MAIN_LIBRARY) $(OBJDIR)/src.test.cpp.o
- $(CXX) -L. -o "$@" $(OBJDIR)/src.test.cpp.o -lrmatrix -lpthread
+tester: all $(OBJDIR)/src.test.cpp.o
+ $(CXX) -L. -o "$@" $(OBJDIR)/src.test.cpp.o -l$(MAIN_LIBRARY) $(LDLIBS) -lpthread -Iinclude
-matrix-send: $(MAIN_LIBRARY) $(OBJDIR)/util.matrix-send.cpp.o
- $(CXX) -L. -o "$@" $(OBJDIR)/util.matrix-send.cpp.o -lrmatrix
+matrix-send: all $(OBJDIR)/util.matrix-send.cpp.o
+ $(CXX) -L. -o "$@" $(OBJDIR)/util.matrix-send.cpp.o -l$(MAIN_LIBRARY) $(LDLIBS) -Iinclude
-$(MAIN_LIBRARY): $(OBJECTS)
- $(CXX) -o "$@" $^ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
define GENERATE_OBJECTS
@@ -103,11 +141,11 @@ $(DEPDIR):
clean:
$(call rmdir,"$(DEPDIR)")
$(call rmdir,"$(OBJDIR)")
- $(call rm,"$(MAIN_LIBRARY)")
-.PHONY: utilsclean
-fullclean: clean
- $(call rm,"matrix-send")
+ $(call rm,"lib$(MAIN_LIBRARY).so")
+ $(call rm,"lib$(MAIN_LIBRARY).a")
$(call rm,"tester")
+ $(call rm,"matrix-send")
+ $(call rm,"$(DLLOUT)")
-include $(wildcard $(DEPDIR)/*.d)
diff --git a/src/matrix/client.cpp b/src/matrix/client.cpp
index 48cecf6..d30a903 100644
--- a/src/matrix/client.cpp
+++ b/src/matrix/client.cpp
@@ -23,15 +23,6 @@
#include "raii/rjp_ptr.hpp"
#include "raii/util.hpp"
-#ifdef HAS_FREEIMAGE
-# include "matrix/image_thumbnail_maker.hpp"
-#endif
-
-#ifdef HAS_FFMPEG
-# define THUMBSIZE 500
-# include "matrix/video_thumbnail_maker.hpp"
-#endif
-
namespace matrix{
//Ctor
@@ -109,117 +100,17 @@ namespace matrix{
image_info client::upload_image(const raii::string_base& filename)const{
return upload_image(filename, raii::static_string());
}
-#ifdef HAS_FREEIMAGE
- image_info client::upload_image(const raii::string_base& filename, const raii::string_base& alias)const{
- image_info ret;
- FREE_IMAGE_FORMAT type = fipImage::identifyFIF(filename.get());
- ret.mimetype = FreeImage_GetFIFMimeType(type);
- raii::curl_llist header(raii::string("Content-Type: " + ret.mimetype));
-
- {
- raii::filerd fd(filename, "rb");
- if(!fd)
- return ret;
-
- ret.filesize = fd.length();
- ret.fileurl = _upload_file(fd, header);
- }
- fipImage image;
- image.load(filename.get());
- if(!image.isValid())
- return {};
- ret.width = image.getWidth();
- ret.height = image.getHeight();
- ret.filename = alias ? alias : filename;
- std::vector thumb_data = internal::_load_image_thumbnail_info(image, ret, type);
-
- if(thumb_data.size())
- ret.thumburl = _post_and_find(raii::static_string(thumb_data.data(), thumb_data.size()), m_ses->urls.file_upload(), header, "content_uri"_ss);
-
- return ret;
- }
-
-#else //HAS_FREEIMAGE
image_info client::upload_image(const raii::string_base& filename, const raii::string_base& alias)const{
image_info ret = {};
ret = upload_file(filename, alias);
return ret;
}
-#endif //HAS_FREEIMAGE
video_info client::upload_video(const raii::string_base& filename)const{
return upload_video(filename, raii::static_string());
}
audio_info client::upload_audio(const raii::string_base& filename)const{
return upload_audio(filename, raii::static_string());
}
-#ifdef HAS_FFMPEG
- video_info client::upload_video(const raii::string_base& filename, const raii::string_base& alias)const{
- internal::initlibav();
- video_info ret = {};
-
- libav::fmt::input_context in(filename);
- if(!in) return {};
-
- int stream_index = -1;
- for(size_t i = 0;i < in->nb_streams;++i){
- if(in->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
- stream_index = i;
- break;
- }
- }
- if(stream_index == -1) return {};
-
- libavcodec::context src_ctx(in, stream_index);
- if(!src_ctx) return {};
-
- src_ctx.open();
- if(!src_ctx.is_open()) return {};
-
- size_t thumbw, thumbh;
- internal::_calc_video_thumbnail_dims(THUMB_SIZE, src_ctx->width, src_ctx->height, &thumbw, &thumbh);
- libav::packet packet = internal::_create_video_thumbnail(in, src_ctx, stream_index, thumbw, thumbh);
-
- if(packet){
- raii::curl_llist header("Content-Type: image/jpeg");
- ret.thumb_width = thumbw;
- ret.thumb_height = thumbh;
- ret.thumbsize = packet->size;
- ret.thumburl = _post_and_find(raii::static_string((char*)packet->data, packet->size), m_ses->urls.file_upload(), header, "content_uri"_ss);
- packet.reset();
- }
-
- ret.width = src_ctx->width;
- ret.height = src_ctx->height;
- ret.mimetype = internal::get_libav_mimetype(in);
- src_ctx.reset();
- in.reset();
-
- raii::curl_llist header(raii::string("Content-Type:" + ret.mimetype));
- header += "Transfer-Encoding: chunked";
- raii::filerd fd(filename);
- if(!fd) return {};
- ret.filesize = fd.length();
- ret.fileurl = _upload_file(fd, header);
- ret.filename = alias ? alias : filename;
- return ret;
- }
- audio_info client::upload_audio(const raii::string_base& filename, const raii::string_base& alias)const{
- audio_info ret = {};
-
- libav::fmt::input_context in(filename);
- ret.mimetype = internal::get_libav_mimetype(in);
- in.reset();
-
- raii::curl_llist header(raii::string("Content-Type:" + ret.mimetype));
- raii::filerd fd(filename);
- if(!fd) return {};
- ret.filesize = fd.length();
- ret.fileurl = _upload_file(fd, header);
- ret.filename = alias ? alias : filename;
-
- return ret;
- }
-#else //HAS_FFMPEG
video_info client::upload_video(const raii::string_base& filename, const raii::string_base& alias)const{
video_info ret = {};
ret = upload_file(filename, alias);
@@ -230,7 +121,6 @@ namespace matrix{
ret = upload_file(filename, alias);
return ret;
}
-#endif //HAS_FFMPEG
/*******************************
diff --git a/src/matrix/connection.cpp b/src/matrix/connection.cpp
index b5195aa..8dccf10 100644
--- a/src/matrix/connection.cpp
+++ b/src/matrix/connection.cpp
@@ -135,6 +135,10 @@ namespace matrix{
return raii::rjp_string(res.value);
}
void connection::_set_curl_defaults(const raii::string_base& useragent)const{
+#ifdef _WIN32
+ //temporary measure to make ssl connections work on wine
+ m_curl.setopt(CURLOPT_CAINFO, "./cacert.pem");
+#endif
m_curl.setopt(CURLOPT_BUFFERSIZE, 102400L);
m_curl.setopt(CURLOPT_NOPROGRESS, 1L);
m_curl.setuseragent(useragent);