/** 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