update to 10.10.0 (4571)
9
.gitignore
vendored
|
@ -4,3 +4,12 @@ build/
|
|||
obj/
|
||||
*.iml
|
||||
local.properties
|
||||
TMessagesProj/.cxx/
|
||||
TMessagesProj/jniLibs/
|
||||
TMessagesProj/jniRes/
|
||||
**/.DS_Store
|
||||
TMessagesProj/afat/
|
||||
TMessagesProj_App/afat/
|
||||
TMessagesProj_AppHockeyApp/afat/
|
||||
TMessagesProj_AppStandalone/afat/
|
||||
TMessagesProj_AppHuawei/afat/
|
||||
|
|
|
@ -25,6 +25,7 @@ dependencies {
|
|||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation "androidx.sharetarget:sharetarget:1.2.0"
|
||||
implementation 'androidx.interpolator:interpolator:1.0.0'
|
||||
implementation 'androidx.biometric:biometric:1.1.0'
|
||||
|
||||
compileOnly 'org.checkerframework:checker-qual:2.5.2'
|
||||
compileOnly 'org.checkerframework:checker-compat-qual:2.5.0'
|
||||
|
|
|
@ -425,12 +425,13 @@ target_include_directories(breakpad PUBLIC
|
|||
#voip
|
||||
include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt)
|
||||
|
||||
set(NATIVE_LIB "tmessages.48")
|
||||
set(NATIVE_LIB "tmessages.49")
|
||||
|
||||
#tmessages
|
||||
add_library(${NATIVE_LIB} SHARED
|
||||
jni.c
|
||||
audio.c
|
||||
webm_encoder.c
|
||||
image.cpp
|
||||
video.c
|
||||
intro/IntroRenderer.c
|
||||
|
|
|
@ -30,6 +30,7 @@ jmethodID jclass_ConnectionsManager_onRequestNewServerIpAndPort;
|
|||
jmethodID jclass_ConnectionsManager_onProxyError;
|
||||
jmethodID jclass_ConnectionsManager_getHostByName;
|
||||
jmethodID jclass_ConnectionsManager_getInitFlags;
|
||||
jmethodID jclass_ConnectionsManager_onPremiumFloodWait;
|
||||
|
||||
bool check_utf8(const char *data, size_t len);
|
||||
|
||||
|
@ -319,6 +320,10 @@ class Delegate : public ConnectiosManagerDelegate {
|
|||
int32_t getInitFlags(int32_t instanceNum) {
|
||||
return (int32_t) jniEnv[instanceNum]->CallStaticIntMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_getInitFlags);
|
||||
}
|
||||
|
||||
void onPremiumFloodWait(int32_t instanceNum, int32_t requestToken, bool isUpload) {
|
||||
jniEnv[instanceNum]->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onPremiumFloodWait, instanceNum, requestToken, isUpload);
|
||||
}
|
||||
};
|
||||
|
||||
void onHostNameResolved(JNIEnv *env, jclass c, jstring host, jlong address, jstring ip) {
|
||||
|
@ -568,6 +573,10 @@ extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) {
|
|||
if (jclass_ConnectionsManager_getInitFlags == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
jclass_ConnectionsManager_onPremiumFloodWait = env->GetStaticMethodID(jclass_ConnectionsManager, "onPremiumFloodWait", "(IIZ)V");
|
||||
if (jclass_ConnectionsManager_onPremiumFloodWait == 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ typedef struct {
|
|||
ogg_int64_t last_granulepos;
|
||||
opus_int32 min_bytes;
|
||||
int max_frame_bytes;
|
||||
int serialno;
|
||||
} resume_data;
|
||||
|
||||
static int write_uint32(Packet *p, ogg_uint32_t val) {
|
||||
|
@ -261,6 +262,7 @@ ogg_int64_t enc_granulepos;
|
|||
ogg_int64_t last_granulepos;
|
||||
int size_segments;
|
||||
int last_segments;
|
||||
int serialno;
|
||||
|
||||
void cleanupRecorder() {
|
||||
|
||||
|
@ -381,7 +383,7 @@ int initRecorder(const char *path, opus_int32 sampleRate) {
|
|||
header.preskip = (int)(inopt.skip * (48000.0 / coding_rate));
|
||||
inopt.extraout = (int)(header.preskip * (rate / 48000.0));
|
||||
|
||||
if (ogg_stream_init(&os, rand()) == -1) {
|
||||
if (ogg_stream_init(&os, serialno = rand()) == -1) {
|
||||
LOGE("Error: stream init failed");
|
||||
return 0;
|
||||
}
|
||||
|
@ -465,6 +467,7 @@ void saveResumeData() {
|
|||
data.last_granulepos = last_granulepos;
|
||||
data.min_bytes = min_bytes;
|
||||
data.max_frame_bytes = max_frame_bytes;
|
||||
data.serialno = serialno;
|
||||
|
||||
if (fwrite(&data, sizeof(resume_data), 1, resumeFile) != 1) {
|
||||
LOGE("error writing resume data to file: %s", _resumeFilePath);
|
||||
|
@ -527,6 +530,7 @@ int resumeRecorder(const char *path, opus_int32 sampleRate) {
|
|||
last_granulepos = resumeData.last_granulepos;
|
||||
min_bytes = resumeData.min_bytes;
|
||||
max_frame_bytes = resumeData.max_frame_bytes;
|
||||
serialno = resumeData.serialno;
|
||||
|
||||
_fileOs = fopen(path, "a");
|
||||
if (!_fileOs) {
|
||||
|
@ -557,7 +561,7 @@ int resumeRecorder(const char *path, opus_int32 sampleRate) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (ogg_stream_init(&os, rand()) == -1) {
|
||||
if (ogg_stream_init(&os, serialno) == -1) {
|
||||
LOGE("Error: stream init failed");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -76,6 +76,10 @@ LIBS=" -L${PREFIX}/lib"
|
|||
\
|
||||
--enable-libvpx \
|
||||
--enable-decoder=libvpx_vp9 \
|
||||
--enable-encoder=libvpx_vp9 \
|
||||
--enable-muxer=matroska \
|
||||
--enable-bsf=vp9_superframe \
|
||||
--enable-bsf=vp9_raw_reorder \
|
||||
--enable-runtime-cpudetect \
|
||||
--enable-pthreads \
|
||||
--enable-avresample \
|
||||
|
|
|
@ -68,6 +68,8 @@ fi
|
|||
--disable-examples \
|
||||
--disable-tools \
|
||||
--disable-debug \
|
||||
--disable-neon-asm \
|
||||
--disable-neon-dotprod \
|
||||
--disable-unit-tests || exit 1
|
||||
|
||||
make -j${HOST_NUM_CORES} install
|
||||
|
|
|
@ -1324,12 +1324,24 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
|
|||
request->startTime = 0;
|
||||
request->startTimeMillis = 0;
|
||||
request->minStartTime = (int32_t) (getCurrentTimeMonotonicMillis() / 1000 + 2);
|
||||
} else if (error->error_code == 420 && (request->requestFlags & RequestFlagIgnoreFloodWait) == 0 && error->error_message.find("STORY_SEND_FLOOD") == std::string::npos) {
|
||||
} else if (
|
||||
error->error_code == 420 && (request->requestFlags & RequestFlagIgnoreFloodWait) == 0 &&
|
||||
error->error_message.find("STORY_SEND_FLOOD") == std::string::npos
|
||||
) {
|
||||
int32_t waitTime = 2;
|
||||
static std::string floodWait = "FLOOD_WAIT_";
|
||||
static std::string premiumFloodWait = "FLOOD_PREMIUM_WAIT_";
|
||||
static std::string slowmodeWait = "SLOWMODE_WAIT_";
|
||||
bool isPremiumFloodWait = false;
|
||||
discardResponse = true;
|
||||
if (error->error_message.find(floodWait) != std::string::npos) {
|
||||
if (error->error_message.find(premiumFloodWait) != std::string::npos) {
|
||||
isPremiumFloodWait = true;
|
||||
std::string num = error->error_message.substr(premiumFloodWait.size(), error->error_message.size() - premiumFloodWait.size());
|
||||
waitTime = atoi(num.c_str());
|
||||
if (waitTime <= 0) {
|
||||
waitTime = 2;
|
||||
}
|
||||
} else if (error->error_message.find(floodWait) != std::string::npos) {
|
||||
std::string num = error->error_message.substr(floodWait.size(), error->error_message.size() - floodWait.size());
|
||||
waitTime = atoi(num.c_str());
|
||||
if (waitTime <= 0) {
|
||||
|
@ -1343,10 +1355,14 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag
|
|||
}
|
||||
discardResponse = false;
|
||||
}
|
||||
request->premiumFloodWait = isPremiumFloodWait;
|
||||
request->failedByFloodWait = waitTime;
|
||||
request->startTime = 0;
|
||||
request->startTimeMillis = 0;
|
||||
request->minStartTime = (int32_t) (getCurrentTimeMonotonicMillis() / 1000 + waitTime);
|
||||
if (isPremiumFloodWait && delegate != nullptr) {
|
||||
delegate->onPremiumFloodWait(instanceNum, request->requestToken, (request->connectionType & ConnectionTypeUpload) != 0);
|
||||
}
|
||||
} else if (error->error_code == 400) {
|
||||
static std::string waitFailed = "MSG_WAIT_FAILED";
|
||||
static std::string bindFailed = "ENCRYPTED_MESSAGE_INVALID";
|
||||
|
@ -2496,7 +2512,7 @@ void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t
|
|||
retryMax = 6;
|
||||
}
|
||||
}
|
||||
if (request->retryCount >= retryMax) {
|
||||
if (request->retryCount >= retryMax && !request->premiumFloodWait) {
|
||||
if (LOGS_ENABLED) DEBUG_E("timed out %s, message_id = 0x%" PRIx64, typeInfo.name(), request->messageId);
|
||||
auto error = new TL_error();
|
||||
error->code = -123;
|
||||
|
|
|
@ -153,6 +153,7 @@ typedef struct ConnectiosManagerDelegate {
|
|||
virtual void onProxyError(int32_t instanceNum) = 0;
|
||||
virtual void getHostByName(std::string domain, int32_t instanceNum, ConnectionSocket *socket) = 0;
|
||||
virtual int32_t getInitFlags(int32_t instanceNum) = 0;
|
||||
virtual void onPremiumFloodWait(int32_t instanceNum, int32_t requestToken, bool isUpload) = 0;
|
||||
} ConnectiosManagerDelegate;
|
||||
|
||||
typedef struct HandshakeDelegate {
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
uint32_t retryCount = 0;
|
||||
bool failedBySalt = false;
|
||||
int32_t failedByFloodWait = 0;
|
||||
bool premiumFloodWait = false;
|
||||
ConnectionType connectionType;
|
||||
uint32_t requestFlags;
|
||||
bool completedSent = false;
|
||||
|
|
245
TMessagesProj/jni/webm_encoder.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
#include <jni.h>
|
||||
#include "libavformat/avio.h"
|
||||
#include "libavcodec/codec.h"
|
||||
#include "libavformat/avformat.h"
|
||||
#include "c_utils.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libswscale/swscale.h"
|
||||
|
||||
typedef struct {
|
||||
AVCodecContext *codec_ctx;
|
||||
AVFormatContext *fmt_ctx;
|
||||
AVStream *video_stream;
|
||||
AVFrame *frame;
|
||||
int frame_count;
|
||||
struct SwsContext *sws_ctx;
|
||||
} EncoderContext;
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_org_telegram_messenger_video_WebmEncoder_createEncoder(
|
||||
JNIEnv *env, jobject obj,
|
||||
jstring outputPath_,
|
||||
jint width, jint height,
|
||||
jint fps,
|
||||
jlong bitrate
|
||||
) {
|
||||
|
||||
int ret;
|
||||
const char* outputPath = (*env)->GetStringUTFChars(env, outputPath_, 0);
|
||||
|
||||
EncoderContext* ctx = (EncoderContext*) malloc(sizeof(EncoderContext));
|
||||
if (!ctx) {
|
||||
LOGE("vp9: failed to alloc context");
|
||||
return (jlong)0;
|
||||
}
|
||||
memset(ctx, 0, sizeof(EncoderContext));
|
||||
|
||||
avformat_alloc_output_context2(&ctx->fmt_ctx, NULL, "matroska", outputPath);
|
||||
if (!ctx->fmt_ctx) {
|
||||
LOGE("vp9: no context created!");
|
||||
return (jlong)0;
|
||||
}
|
||||
|
||||
if (!(ctx->fmt_ctx->oformat->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&ctx->fmt_ctx->pb, outputPath, AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
LOGE("vp9: failed to write open file %d", ret);
|
||||
return (jlong) 0;
|
||||
}
|
||||
}
|
||||
|
||||
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_VP9);
|
||||
if (!codec) {
|
||||
LOGE("vp9: no encoder found!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->codec_ctx = avcodec_alloc_context3(codec);
|
||||
if (!ctx->codec_ctx) {
|
||||
LOGE("vp9: failed to create codec ctx");
|
||||
return (jlong) 0;
|
||||
}
|
||||
|
||||
ctx->codec_ctx->codec_id = AV_CODEC_ID_VP9;
|
||||
ctx->codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
ctx->codec_ctx->width = width;
|
||||
ctx->codec_ctx->height = height;
|
||||
ctx->codec_ctx->pix_fmt = AV_PIX_FMT_YUVA420P;
|
||||
ctx->codec_ctx->color_range = AVCOL_RANGE_MPEG;
|
||||
ctx->codec_ctx->color_primaries = AVCOL_PRI_BT709;
|
||||
ctx->codec_ctx->colorspace = AVCOL_SPC_BT709;
|
||||
ctx->codec_ctx->time_base = (AVRational){ 1, fps };
|
||||
ctx->codec_ctx->framerate = (AVRational){ fps, 1 };
|
||||
ctx->codec_ctx->bit_rate = bitrate;
|
||||
ctx->codec_ctx->gop_size = 10;
|
||||
ctx->codec_ctx->max_b_frames = 1;
|
||||
|
||||
if (ctx->fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||
ctx->codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
|
||||
ctx->video_stream = avformat_new_stream(ctx->fmt_ctx, codec);
|
||||
if (!ctx->video_stream) {
|
||||
LOGE("vp9: failed to create stream");
|
||||
return (jlong) 0;
|
||||
}
|
||||
|
||||
ctx->video_stream->codecpar->codec_id = ctx->codec_ctx->codec_id;
|
||||
ctx->video_stream->codecpar->codec_type = ctx->codec_ctx->codec_type;
|
||||
ctx->video_stream->codecpar->width = ctx->codec_ctx->width;
|
||||
ctx->video_stream->codecpar->height = ctx->codec_ctx->height;
|
||||
ctx->video_stream->codecpar->format = ctx->codec_ctx->pix_fmt;
|
||||
ctx->video_stream->time_base = ctx->codec_ctx->time_base;
|
||||
|
||||
ret = avcodec_open2(ctx->codec_ctx, codec, NULL);
|
||||
if (ret < 0) {
|
||||
LOGE("vp9: failed to open codec %s", av_err2str(ret));
|
||||
return (jlong) 0;
|
||||
}
|
||||
|
||||
ctx->sws_ctx = sws_getContext(width, height, AV_PIX_FMT_RGBA, width, height, AV_PIX_FMT_YUVA420P, 0, 0, 0, 0);
|
||||
if (!ctx->sws_ctx) {
|
||||
LOGE("vp9: failed to sws_ctx");
|
||||
return (jlong) 0;
|
||||
}
|
||||
|
||||
ctx->frame = av_frame_alloc();
|
||||
if (!ctx->frame) {
|
||||
LOGE("vp9: failed to alloc frame");
|
||||
return (jlong)0;
|
||||
}
|
||||
|
||||
ctx->frame->format = ctx->codec_ctx->pix_fmt;
|
||||
ctx->frame->width = ctx->codec_ctx->width;
|
||||
ctx->frame->height = ctx->codec_ctx->height;
|
||||
ret = av_frame_get_buffer(ctx->frame, 0);
|
||||
if (ret < 0) {
|
||||
LOGE("vp9: failed to get frame buffer %d", ret);
|
||||
return (jlong)0;
|
||||
}
|
||||
|
||||
if (avcodec_parameters_from_context(ctx->video_stream->codecpar, ctx->codec_ctx) < 0) {
|
||||
LOGE("vp9: failed to copy codec parameters to stream");
|
||||
return (jlong) 0;
|
||||
}
|
||||
|
||||
ret = avformat_write_header(ctx->fmt_ctx, NULL);
|
||||
if (ret < 0) {
|
||||
LOGE("vp9: failed to write header %d", ret);
|
||||
return (jlong) 0;
|
||||
}
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, outputPath_, outputPath);
|
||||
|
||||
return (jlong)ctx;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_telegram_messenger_video_WebmEncoder_writeFrame(
|
||||
JNIEnv *env, jobject obj,
|
||||
jlong ptr,
|
||||
jobject argbPixels,
|
||||
jint width, jint height
|
||||
) {
|
||||
EncoderContext *ctx = (EncoderContext *) ptr;
|
||||
|
||||
uint8_t *pixels = (*env)->GetDirectBufferAddress(env, argbPixels);
|
||||
|
||||
if (!ctx || !pixels) {
|
||||
LOGE("vp9: no ctx or no pixels");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
int ret;
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = NULL;
|
||||
pkt.size = 0;
|
||||
|
||||
ret = av_frame_make_writable(ctx->frame);
|
||||
if (ret < 0) {
|
||||
LOGE("vp9: failed to make writable %d", ret);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
const uint8_t* srcSlice[1] = { pixels };
|
||||
int srcStride[1] = { 4 * width };
|
||||
sws_scale(ctx->sws_ctx, srcSlice, srcStride, 0, ctx->codec_ctx->height, ctx->frame->data, ctx->frame->linesize);
|
||||
|
||||
ctx->frame->pts = ctx->frame_count++;
|
||||
|
||||
ret = avcodec_send_frame(ctx->codec_ctx, ctx->frame);
|
||||
if (ret < 0) {
|
||||
LOGE("vp9: failed to send packet %d", ret);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
while (ret >= 0) {
|
||||
ret = avcodec_receive_packet(ctx->codec_ctx, &pkt);
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||
break;
|
||||
} else if (ret < 0) {
|
||||
LOGE("vp9: failed to receive packet %d", ret);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
av_packet_rescale_ts(&pkt, ctx->codec_ctx->time_base, ctx->video_stream->time_base);
|
||||
pkt.stream_index = ctx->video_stream->index;
|
||||
|
||||
ret = av_interleaved_write_frame(ctx->fmt_ctx, &pkt);
|
||||
av_packet_unref(&pkt);
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_telegram_messenger_video_WebmEncoder_stop(
|
||||
JNIEnv *env, jobject obj,
|
||||
jlong ptr
|
||||
) {
|
||||
EncoderContext *ctx = (EncoderContext *) ptr;
|
||||
if (!ctx || !ctx->fmt_ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
avcodec_send_frame(ctx->codec_ctx, NULL);
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = NULL;
|
||||
pkt.size = 0;
|
||||
|
||||
int ret;
|
||||
while (1) {
|
||||
ret = avcodec_receive_packet(ctx->codec_ctx, &pkt);
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||
break;
|
||||
} else if (ret < 0) {
|
||||
LOGE("vp9: failed to receive packet %d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
av_packet_rescale_ts(&pkt, ctx->codec_ctx->time_base, ctx->video_stream->time_base);
|
||||
pkt.stream_index = ctx->video_stream->index;
|
||||
|
||||
ret = av_interleaved_write_frame(ctx->fmt_ctx, &pkt);
|
||||
av_packet_unref(&pkt);
|
||||
}
|
||||
|
||||
av_write_trailer(ctx->fmt_ctx);
|
||||
|
||||
if (ctx->frame) {
|
||||
av_frame_free(&ctx->frame);
|
||||
}
|
||||
if (ctx->codec_ctx) {
|
||||
avcodec_free_context(&ctx->codec_ctx);
|
||||
}
|
||||
if (ctx->sws_ctx) {
|
||||
sws_freeContext(ctx->sws_ctx);
|
||||
}
|
||||
if (ctx->fmt_ctx) {
|
||||
if (!(ctx->fmt_ctx->oformat->flags & AVFMT_NOFILE)) {
|
||||
avio_closep(&ctx->fmt_ctx->pb);
|
||||
}
|
||||
avformat_free_context(ctx->fmt_ctx);
|
||||
}
|
||||
|
||||
free(ctx);
|
||||
}
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.7 KiB |