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);