118 lines
4.1 KiB
C++
118 lines
4.1 KiB
C++
/**
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
# include "libav/frame.hpp"
|
|
# include "libav/codec/context.hpp"
|
|
# include "libav/fmt/context.hpp"
|
|
# include "libav/packet.hpp"
|
|
|
|
extern "C"{
|
|
# include <libswscale/swscale.h> //sws_scale
|
|
# include <libavutil/imgutils.h> //av_image_alloc
|
|
}
|
|
|
|
#include <cstdlib> //size_t
|
|
|
|
namespace matrix::internal{
|
|
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
|