Add animated thumbnail support for animations and videos

GitOrigin-RevId: a9026a32be9a9ddf2597c6244e112fd853d81b1f
This commit is contained in:
levlam 2020-05-30 01:48:56 +03:00
parent e8cb1dfeb5
commit 4a1e2ee34c
15 changed files with 223 additions and 46 deletions

View File

@ -181,6 +181,9 @@ inputFileGenerated original_path:string conversion:string expected_size:int32 =
//@description Photo description @type Thumbnail type (see https://core.telegram.org/constructor/photoSize) @photo Information about the photo file @width Photo width @height Photo height
photoSize type:string photo:file width:int32 height:int32 = PhotoSize;
//@description A short animated thumbnail of a file in the MPEG4 format @width Animation width @height Animation height @animation The thumbnail
animatedThumbnail width:int32 height:int32 animation:file = AnimatedThumbnail;
//@description Thumbnail image of a very poor quality and low resolution @width Thumbnail width, usually doesn't exceed 40 @height Thumbnail height, usually doesn't exceed 40 @data The thumbnail in JPEG format
minithumbnail width:int32 height:int32 data:bytes = Minithumbnail;
@ -225,8 +228,9 @@ pollTypeQuiz correct_option_id:int32 explanation:formattedText = PollType;
//@description Describes an animation file. The animation must be encoded in GIF or MPEG4 format @duration Duration of the animation, in seconds; as defined by the sender @width Width of the animation @height Height of the animation
//@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file, usually "image/gif" or "video/mp4"
//@has_stickers True, if stickers were added to the animation. The list of corresponding sticker set can be received using getAttachedStickerSets
//@minithumbnail Animation minithumbnail; may be null @thumbnail Animation thumbnail; may be null @animation File containing the animation
animation duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool minithumbnail:minithumbnail thumbnail:photoSize animation:file = Animation;
//@minithumbnail Animation minithumbnail; may be null @thumbnail Animation thumbnail; may be null
//@animated_thumbnail A short animated thumbnail of the animation in the MPEG4 format; may be null @animation File containing the animation
animation duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool minithumbnail:minithumbnail thumbnail:photoSize animated_thumbnail:animatedThumbnail animation:file = Animation;
//@description Describes an audio file. Audio is usually in MP3 or M4A format @duration Duration of the audio, in seconds; as defined by the sender @title Title of the audio; as defined by the sender @performer Performer of the audio; as defined by the sender
//@file_name Original name of the file; as defined by the sender @mime_type The MIME type of the file; as defined by the sender @album_cover_minithumbnail The minithumbnail of the album cover; may be null @album_cover_thumbnail The thumbnail of the album cover; as defined by the sender. The full size thumbnail should be extracted from the downloaded file; may be null @audio File containing the audio
@ -247,8 +251,9 @@ sticker set_id:int64 width:int32 height:int32 emoji:string is_animated:Bool is_m
//@description Describes a video file @duration Duration of the video, in seconds; as defined by the sender @width Video width; as defined by the sender @height Video height; as defined by the sender
//@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file; as defined by the sender
//@has_stickers True, if stickers were added to the video. The list of corresponding sticker sets can be received using getAttachedStickerSets
//@supports_streaming True, if the video should be tried to be streamed @minithumbnail Video minithumbnail; may be null @thumbnail Video thumbnail; as defined by the sender; may be null @video File containing the video
video duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool supports_streaming:Bool minithumbnail:minithumbnail thumbnail:photoSize video:file = Video;
//@supports_streaming True, if the video should be tried to be streamed @minithumbnail Video minithumbnail; may be null @thumbnail Video thumbnail; as defined by the sender; may be null
//@animated_thumbnail A short animated thumbnail of the video in the MPEG4 format; may be null @video File containing the video
video duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool supports_streaming:Bool minithumbnail:minithumbnail thumbnail:photoSize animated_thumbnail:animatedThumbnail video:file = Video;
//@description Describes a video note. The video must be equal in width and height, cropped to a circle, and stored in MPEG4 format @duration Duration of the video, in seconds; as defined by the sender @length Video width and height; as defined by the sender @minithumbnail Video minithumbnail; may be null @thumbnail Video thumbnail; as defined by the sender; may be null @video File containing the video
videoNote duration:int32 length:int32 minithumbnail:minithumbnail thumbnail:photoSize video:file = VideoNote;

Binary file not shown.

View File

@ -159,11 +159,12 @@ tl_object_ptr<td_api::animation> AnimationsManager::get_animation_object(FileId
<< static_cast<int32>(td_->file_manager_->get_file_view(file_id).get_type());
// TODO can we make that function const?
animation->is_changed = false;
return make_tl_object<td_api::animation>(animation->duration, animation->dimensions.width,
animation->dimensions.height, animation->file_name, animation->mime_type,
animation->has_stickers, get_minithumbnail_object(animation->minithumbnail),
get_photo_size_object(td_->file_manager_.get(), &animation->thumbnail),
td_->file_manager_->get_file_object(file_id));
return make_tl_object<td_api::animation>(
animation->duration, animation->dimensions.width, animation->dimensions.height, animation->file_name,
animation->mime_type, animation->has_stickers, get_minithumbnail_object(animation->minithumbnail),
get_photo_size_object(td_->file_manager_.get(), &animation->thumbnail),
get_animated_thumbnail_object(td_->file_manager_.get(), &animation->animated_thumbnail),
td_->file_manager_->get_file_object(file_id));
}
FileId AnimationsManager::on_get_animation(unique_ptr<Animation> new_animation, bool replace) {
@ -210,6 +211,16 @@ FileId AnimationsManager::on_get_animation(unique_ptr<Animation> new_animation,
a->thumbnail = new_animation->thumbnail;
a->is_changed = true;
}
if (a->animated_thumbnail != new_animation->animated_thumbnail) {
if (!a->animated_thumbnail.file_id.is_valid()) {
LOG(DEBUG) << "Animation " << file_id << " animated thumbnail has changed";
} else {
LOG(INFO) << "Animation " << file_id << " animated thumbnail has changed from " << a->animated_thumbnail
<< " to " << new_animation->animated_thumbnail;
}
a->animated_thumbnail = new_animation->animated_thumbnail;
a->is_changed = true;
}
if (a->has_stickers != new_animation->has_stickers && new_animation->has_stickers) {
a->has_stickers = new_animation->has_stickers;
a->is_changed = true;
@ -239,10 +250,17 @@ FileId AnimationsManager::get_animation_thumbnail_file_id(FileId file_id) const
return animation->thumbnail.file_id;
}
FileId AnimationsManager::get_animation_animated_thumbnail_file_id(FileId file_id) const {
auto animation = get_animation(file_id);
CHECK(animation != nullptr);
return animation->animated_thumbnail.file_id;
}
void AnimationsManager::delete_animation_thumbnail(FileId file_id) {
auto &animation = animations_[file_id];
CHECK(animation != nullptr);
animation->thumbnail = PhotoSize();
animation->animated_thumbnail = PhotoSize();
}
FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) {
@ -254,6 +272,8 @@ FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) {
new_animation = make_unique<Animation>(*old_animation);
new_animation->file_id = new_id;
new_animation->thumbnail.file_id = td_->file_manager_->dup_file_id(new_animation->thumbnail.file_id);
new_animation->animated_thumbnail.file_id =
td_->file_manager_->dup_file_id(new_animation->animated_thumbnail.file_id);
return new_id;
}
@ -296,7 +316,8 @@ bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_
return true;
}
void AnimationsManager::create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, bool has_stickers,
void AnimationsManager::create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail,
PhotoSize animated_thumbnail, bool has_stickers,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type,
int32 duration, Dimensions dimensions, bool replace) {
auto a = make_unique<Animation>();
@ -307,6 +328,7 @@ void AnimationsManager::create_animation(FileId file_id, string minithumbnail, P
a->dimensions = dimensions;
a->minithumbnail = std::move(minithumbnail);
a->thumbnail = std::move(thumbnail);
a->animated_thumbnail = std::move(animated_thumbnail);
a->has_stickers = has_stickers;
a->sticker_file_ids = std::move(sticker_file_ids);
on_get_animation(std::move(a), replace);
@ -787,9 +809,13 @@ void AnimationsManager::send_update_saved_animations(bool from_database) {
if (are_saved_animations_loaded_) {
vector<FileId> new_saved_animation_file_ids = saved_animation_ids_;
for (auto &animation_id : saved_animation_ids_) {
auto thumbnail_file_id = get_animation_thumbnail_file_id(animation_id);
if (thumbnail_file_id.is_valid()) {
new_saved_animation_file_ids.push_back(thumbnail_file_id);
auto animation = get_animation(animation_id);
CHECK(animation != nullptr);
if (animation->thumbnail.file_id.is_valid()) {
new_saved_animation_file_ids.push_back(animation->thumbnail.file_id);
}
if (animation->animated_thumbnail.file_id.is_valid()) {
new_saved_animation_file_ids.push_back(animation->animated_thumbnail.file_id);
}
}
std::sort(new_saved_animation_file_ids.begin(), new_saved_animation_file_ids.end());

View File

@ -35,9 +35,9 @@ class AnimationsManager : public Actor {
tl_object_ptr<td_api::animation> get_animation_object(FileId file_id, const char *source);
void create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, bool has_stickers,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type, int32 duration,
Dimensions dimensions, bool replace);
void create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, PhotoSize animated_thumbnail,
bool has_stickers, vector<FileId> &&sticker_file_ids, string file_name, string mime_type,
int32 duration, Dimensions dimensions, bool replace);
tl_object_ptr<telegram_api::InputMedia> get_input_media(FileId file_id,
tl_object_ptr<telegram_api::InputFile> input_file,
@ -49,6 +49,8 @@ class AnimationsManager : public Actor {
FileId get_animation_thumbnail_file_id(FileId file_id) const;
FileId get_animation_animated_thumbnail_file_id(FileId file_id) const;
void delete_animation_thumbnail(FileId file_id);
FileId dup_animation(FileId new_id, FileId old_id);
@ -98,6 +100,7 @@ class AnimationsManager : public Actor {
Dimensions dimensions;
string minithumbnail;
PhotoSize thumbnail;
PhotoSize animated_thumbnail;
bool has_stickers = false;
vector<FileId> sticker_file_ids;

View File

@ -22,8 +22,10 @@ void AnimationsManager::store_animation(FileId file_id, StorerT &storer) const {
auto it = animations_.find(file_id);
CHECK(it != animations_.end());
const Animation *animation = it->second.get();
bool has_animated_thumbnail = animation->animated_thumbnail.file_id.is_valid();
BEGIN_STORE_FLAGS();
STORE_FLAG(animation->has_stickers);
STORE_FLAG(has_animated_thumbnail);
END_STORE_FLAGS();
store(animation->duration, storer);
store(animation->dimensions, storer);
@ -35,14 +37,19 @@ void AnimationsManager::store_animation(FileId file_id, StorerT &storer) const {
if (animation->has_stickers) {
store(animation->sticker_file_ids, storer);
}
if (has_animated_thumbnail) {
store(animation->animated_thumbnail, storer);
}
}
template <class ParserT>
FileId AnimationsManager::parse_animation(ParserT &parser) {
auto animation = make_unique<Animation>();
bool has_animated_thumbnail = false;
if (parser.version() >= static_cast<int32>(Version::AddAnimationStickers)) {
BEGIN_PARSE_FLAGS();
PARSE_FLAG(animation->has_stickers);
PARSE_FLAG(has_animated_thumbnail);
END_PARSE_FLAGS();
}
if (parser.version() >= static_cast<int32>(Version::AddDurationToAnimation)) {
@ -59,6 +66,9 @@ FileId AnimationsManager::parse_animation(ParserT &parser) {
if (animation->has_stickers) {
parse(animation->sticker_file_ids, parser);
}
if (has_animated_thumbnail) {
parse(animation->animated_thumbnail, parser);
}
if (parser.get_error() != nullptr || !animation->file_id.is_valid()) {
return FileId();
}

View File

@ -35,6 +35,7 @@ void Document::append_file_ids(const Td *td, vector<FileId> &file_ids) const {
}
file_ids.push_back(file_id);
FileId thumbnail_file_id = [&] {
switch (type) {
case Type::Animation:
@ -54,6 +55,20 @@ void Document::append_file_ids(const Td *td, vector<FileId> &file_ids) const {
if (thumbnail_file_id.is_valid()) {
file_ids.push_back(thumbnail_file_id);
}
FileId animated_thumbnail_file_id = [&] {
switch (type) {
case Type::Animation:
return td->animations_manager_->get_animation_animated_thumbnail_file_id(file_id);
case Type::Video:
return td->videos_manager_->get_video_animated_thumbnail_file_id(file_id);
default:
return FileId();
}
}();
if (animated_thumbnail_file_id.is_valid()) {
file_ids.push_back(animated_thumbnail_file_id);
}
}
bool operator==(const Document &lhs, const Document &rhs) {

View File

@ -214,6 +214,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
string file_reference;
string minithumbnail;
PhotoSize thumbnail;
PhotoSize animated_thumbnail;
FileEncryptionKey encryption_key;
bool is_animated_sticker = false;
bool is_web = false;
@ -269,6 +270,16 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
}
}
}
for (auto &thumb : document->video_thumbs_) {
if (thumb->type_ == "v") {
animated_thumbnail =
get_video_photo_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, id, access_hash, file_reference,
DcId::create(dc_id), owner_dialog_id, std::move(thumb));
if (animated_thumbnail.file_id.is_valid()) {
break;
}
}
}
} else if (remote_document.secret_file != nullptr) {
CHECK(remote_document.secret_document != nullptr);
auto file = std::move(remote_document.secret_file);
@ -297,7 +308,11 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
id = Random::fast(0, std::numeric_limits<int32>::max());
dc_id = 0;
access_hash = 0;
thumbnail = std::move(remote_document.thumbnail);
if (remote_document.thumbnail.type == 'v') {
animated_thumbnail = std::move(remote_document.thumbnail);
} else {
thumbnail = std::move(remote_document.thumbnail);
}
auto web_document_ptr = std::move(remote_document.web_document);
switch (web_document_ptr->get_id()) {
@ -388,9 +403,9 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
switch (document_type) {
case Document::Type::Animation:
td_->animations_manager_->create_animation(file_id, std::move(minithumbnail), std::move(thumbnail), has_stickers,
vector<FileId>(), std::move(file_name), std::move(mime_type),
video_duration, dimensions, !is_web);
td_->animations_manager_->create_animation(
file_id, std::move(minithumbnail), std::move(thumbnail), std::move(animated_thumbnail), has_stickers,
vector<FileId>(), std::move(file_name), std::move(mime_type), video_duration, dimensions, !is_web);
break;
case Document::Type::Audio: {
int32 duration = 0;
@ -415,9 +430,10 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
is_animated_sticker, load_data_multipromise_ptr);
break;
case Document::Type::Video:
td_->videos_manager_->create_video(file_id, std::move(minithumbnail), std::move(thumbnail), has_stickers,
vector<FileId>(), std::move(file_name), std::move(mime_type), video_duration,
dimensions, supports_streaming, !is_web);
td_->videos_manager_->create_video(file_id, std::move(minithumbnail), std::move(thumbnail),
std::move(animated_thumbnail), has_stickers, vector<FileId>(),
std::move(file_name), std::move(mime_type), video_duration, dimensions,
supports_streaming, !is_web);
break;
case Document::Type::VideoNote:
td_->video_notes_manager_->create_video_note(file_id, std::move(minithumbnail), std::move(thumbnail),

View File

@ -865,6 +865,11 @@ tl_object_ptr<td_api::photoSize> copy(const td_api::photoSize &obj) {
return make_tl_object<td_api::photoSize>(obj.type_, copy(obj.photo_), obj.width_, obj.height_);
}
template <>
tl_object_ptr<td_api::animatedThumbnail> copy(const td_api::animatedThumbnail &obj) {
return make_tl_object<td_api::animatedThumbnail>(obj.width_, obj.height_, copy(obj.animation_));
}
static tl_object_ptr<td_api::photoSize> copy_photo_size(const tl_object_ptr<td_api::photoSize> &obj) {
return copy(obj);
}
@ -895,7 +900,7 @@ template <>
tl_object_ptr<td_api::animation> copy(const td_api::animation &obj) {
return make_tl_object<td_api::animation>(obj.duration_, obj.width_, obj.height_, obj.file_name_, obj.mime_type_,
obj.has_stickers_, copy(obj.minithumbnail_), copy(obj.thumbnail_),
copy(obj.animation_));
copy(obj.animated_thumbnail_), copy(obj.animation_));
}
template <>
@ -928,7 +933,7 @@ template <>
tl_object_ptr<td_api::video> copy(const td_api::video &obj) {
return make_tl_object<td_api::video>(obj.duration_, obj.width_, obj.height_, obj.file_name_, obj.mime_type_,
obj.has_stickers_, obj.supports_streaming_, copy(obj.minithumbnail_),
copy(obj.thumbnail_), copy(obj.video_));
copy(obj.thumbnail_), copy(obj.animated_thumbnail_), copy(obj.video_));
}
template <>
@ -1065,7 +1070,7 @@ tl_object_ptr<td_api::photoSize> InlineQueriesManager::register_thumbnail(
tl_object_ptr<telegram_api::WebDocument> &&web_document_ptr) const {
PhotoSize thumbnail = get_web_document_photo_size(td_->file_manager_.get(), FileType::Thumbnail, DialogId(),
std::move(web_document_ptr));
if (!thumbnail.file_id.is_valid()) {
if (!thumbnail.file_id.is_valid() || thumbnail.type == 'v') {
return nullptr;
}
@ -1390,7 +1395,7 @@ void InlineQueriesManager::on_get_inline_query_results(UserId bot_user_id, uint6
PhotoSize photo_size = get_web_document_photo_size(td_->file_manager_.get(), FileType::Temp, DialogId(),
std::move(result->content_));
if (!photo_size.file_id.is_valid()) {
if (!photo_size.file_id.is_valid() || photo_size.type == 'v') {
LOG(ERROR) << "Receive invalid web document photo";
continue;
}
@ -1398,7 +1403,7 @@ void InlineQueriesManager::on_get_inline_query_results(UserId bot_user_id, uint6
Photo new_photo;
PhotoSize thumbnail = get_web_document_photo_size(td_->file_manager_.get(), FileType::Thumbnail, DialogId(),
std::move(result->thumb_));
if (thumbnail.file_id.is_valid()) {
if (thumbnail.file_id.is_valid() && thumbnail.type != 'v') {
new_photo.photos.push_back(std::move(thumbnail));
}
new_photo.photos.push_back(std::move(photo_size));

View File

@ -1474,10 +1474,10 @@ static Result<InputMessageContent> create_input_message_content(
auto input_animation = static_cast<td_api::inputMessageAnimation *>(input_message_content.get());
bool has_stickers = !sticker_file_ids.empty();
td->animations_manager_->create_animation(file_id, string(), thumbnail, has_stickers, std::move(sticker_file_ids),
std::move(file_name), std::move(mime_type), input_animation->duration_,
get_dimensions(input_animation->width_, input_animation->height_),
false);
td->animations_manager_->create_animation(
file_id, string(), thumbnail, PhotoSize(), has_stickers, std::move(sticker_file_ids), std::move(file_name),
std::move(mime_type), input_animation->duration_,
get_dimensions(input_animation->width_, input_animation->height_), false);
content = make_unique<MessageAnimation>(file_id, std::move(caption));
break;
@ -1577,10 +1577,10 @@ static Result<InputMessageContent> create_input_message_content(
ttl = input_video->ttl_;
bool has_stickers = !sticker_file_ids.empty();
td->videos_manager_->create_video(file_id, string(), thumbnail, has_stickers, std::move(sticker_file_ids),
std::move(file_name), std::move(mime_type), input_video->duration_,
get_dimensions(input_video->width_, input_video->height_),
input_video->supports_streaming_, false);
td->videos_manager_->create_video(
file_id, string(), thumbnail, PhotoSize(), has_stickers, std::move(sticker_file_ids), std::move(file_name),
std::move(mime_type), input_video->duration_, get_dimensions(input_video->width_, input_video->height_),
input_video->supports_streaming_, false);
content = make_unique<MessageVideo>(file_id, std::move(caption));
break;
@ -4705,6 +4705,20 @@ FileId get_message_content_thumbnail_file_id(const MessageContent *content, cons
return FileId();
}
FileId get_message_content_animated_thumbnail_file_id(const MessageContent *content, const Td *td) {
switch (content->get_type()) {
case MessageContentType::Animation:
return td->animations_manager_->get_animation_animated_thumbnail_file_id(
static_cast<const MessageAnimation *>(content)->file_id);
case MessageContentType::Video:
return td->videos_manager_->get_video_animated_thumbnail_file_id(
static_cast<const MessageVideo *>(content)->file_id);
default:
break;
}
return FileId();
}
vector<FileId> get_message_content_file_ids(const MessageContent *content, const Td *td) {
switch (content->get_type()) {
case MessageContentType::Photo:
@ -4725,6 +4739,10 @@ vector<FileId> get_message_content_file_ids(const MessageContent *content, const
if (thumbnail_file_id.is_valid()) {
result.push_back(thumbnail_file_id);
}
FileId animated_thumbnail_file_id = get_message_content_animated_thumbnail_file_id(content, td);
if (animated_thumbnail_file_id.is_valid()) {
result.push_back(animated_thumbnail_file_id);
}
return result;
}
case MessageContentType::Sticker:

View File

@ -199,6 +199,8 @@ void update_message_content_file_id_remote(MessageContent *content, FileId file_
FileId get_message_content_thumbnail_file_id(const MessageContent *content, const Td *td);
FileId get_message_content_animated_thumbnail_file_id(const MessageContent *content, const Td *td);
vector<FileId> get_message_content_file_ids(const MessageContent *content, const Td *td);
string get_message_content_search_text(const Td *td, const MessageContent *content);

View File

@ -105,6 +105,8 @@ static StringBuilder &operator<<(StringBuilder &string_builder, PhotoFormat form
return string_builder << "webp";
case PhotoFormat::Tgs:
return string_builder << "tgs";
case PhotoFormat::Mpeg4:
return string_builder << "mp4";
default:
UNREACHABLE();
return string_builder;
@ -362,6 +364,27 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
return std::move(res);
}
PhotoSize get_video_photo_size(FileManager *file_manager, PhotoSizeSource source, int64 id, int64 access_hash,
std::string file_reference, DcId dc_id, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::videoSize> &&size) {
CHECK(size != nullptr);
PhotoSize res;
if (size->type_ != "v") {
LOG(ERROR) << "Wrong videoSize \"" << size->type_ << "\" in " << to_string(size);
}
res.type = static_cast<uint8>('v');
res.dimensions = get_dimensions(size->w_, size->h_);
res.size = size->size_;
if (source.get_type() == PhotoSizeSource::Type::Thumbnail) {
source.thumbnail().thumbnail_type = res.type;
}
res.file_id = register_photo(file_manager, source, id, access_hash, file_reference, std::move(size->location_),
owner_dialog_id, res.size, dc_id, PhotoFormat::Mpeg4);
return res;
}
PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_type, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::WebDocument> web_document_ptr) {
if (web_document_ptr == nullptr) {
@ -371,6 +394,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
FileId file_id;
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
int32 size = 0;
string mime_type;
switch (web_document_ptr->get_id()) {
case telegram_api::webDocument::ID: {
auto web_document = move_tl_object_as<telegram_api::webDocument>(web_document_ptr);
@ -385,6 +409,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
FileLocationSource::FromServer, owner_dialog_id, 0, web_document->size_,
get_url_query_file_name(http_url.query_));
size = web_document->size_;
mime_type = std::move(web_document->mime_type_);
attributes = std::move(web_document->attributes_);
break;
}
@ -403,6 +428,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
file_id = r_file_id.move_as_ok();
size = web_document->size_;
mime_type = std::move(web_document->mime_type_);
attributes = std::move(web_document->attributes_);
break;
}
@ -410,6 +436,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
UNREACHABLE();
}
CHECK(file_id.is_valid());
bool is_animation = mime_type == "video/mp4";
Dimensions dimensions;
for (auto &attribute : attributes) {
@ -434,7 +461,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
}
PhotoSize s;
s.type = file_type == FileType::Thumbnail ? 't' : 'u';
s.type = is_animation ? 'v' : (file_type == FileType::Thumbnail ? 't' : 'u');
s.dimensions = dimensions;
s.size = size;
s.file_id = file_id;
@ -452,6 +479,16 @@ tl_object_ptr<td_api::photoSize> get_photo_size_object(FileManager *file_manager
file_manager->get_file_object(photo_size->file_id), photo_size->dimensions.width, photo_size->dimensions.height);
}
td_api::object_ptr<td_api::animatedThumbnail> get_animated_thumbnail_object(FileManager *file_manager,
const PhotoSize *photo_size) {
if (photo_size == nullptr || !photo_size->file_id.is_valid()) {
return nullptr;
}
return td_api::make_object<td_api::animatedThumbnail>(photo_size->dimensions.width, photo_size->dimensions.height,
file_manager->get_file_object(photo_size->file_id));
}
vector<td_api::object_ptr<td_api::photoSize>> get_photo_sizes_object(FileManager *file_manager,
const vector<PhotoSize> &photo_sizes) {
auto sizes = transform(photo_sizes, [file_manager](const PhotoSize &photo_size) {
@ -572,7 +609,7 @@ Photo get_web_document_photo(FileManager *file_manager, tl_object_ptr<telegram_a
DialogId owner_dialog_id) {
PhotoSize s = get_web_document_photo_size(file_manager, FileType::Photo, owner_dialog_id, std::move(web_document));
Photo photo;
if (!s.file_id.is_valid()) {
if (!s.file_id.is_valid() || s.type == 'v') {
photo.id = -2;
} else {
photo.id = 0;

View File

@ -90,7 +90,7 @@ bool operator!=(const DialogPhoto &lhs, const DialogPhoto &rhs);
StringBuilder &operator<<(StringBuilder &string_builder, const DialogPhoto &dialog_photo);
enum class PhotoFormat : int32 { Jpeg, Png, Webp, Tgs };
enum class PhotoFormat : int32 { Jpeg, Png, Webp, Tgs, Mpeg4 };
PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice bytes, DialogId owner_dialog_id,
int32 width, int32 height);
@ -98,11 +98,16 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
int64 access_hash, string file_reference, DcId dc_id,
DialogId owner_dialog_id, tl_object_ptr<telegram_api::PhotoSize> &&size_ptr,
PhotoFormat format);
PhotoSize get_video_photo_size(FileManager *file_manager, PhotoSizeSource source, int64 id, int64 access_hash,
string file_reference, DcId dc_id, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::videoSize> &&size);
PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_type, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::WebDocument> web_document_ptr);
td_api::object_ptr<td_api::photoSize> get_photo_size_object(FileManager *file_manager, const PhotoSize *photo_size);
vector<td_api::object_ptr<td_api::photoSize>> get_photo_sizes_object(FileManager *file_manager,
const vector<PhotoSize> &photo_sizes);
td_api::object_ptr<td_api::animatedThumbnail> get_animated_thumbnail_object(FileManager *file_manager,
const PhotoSize *photo_size);
bool operator==(const PhotoSize &lhs, const PhotoSize &rhs);
bool operator!=(const PhotoSize &lhs, const PhotoSize &rhs);

View File

@ -40,7 +40,9 @@ tl_object_ptr<td_api::video> VideosManager::get_video_object(FileId file_id) {
return make_tl_object<td_api::video>(
video->duration, video->dimensions.width, video->dimensions.height, video->file_name, video->mime_type,
video->has_stickers, video->supports_streaming, get_minithumbnail_object(video->minithumbnail),
get_photo_size_object(td_->file_manager_.get(), &video->thumbnail), td_->file_manager_->get_file_object(file_id));
get_photo_size_object(td_->file_manager_.get(), &video->thumbnail),
get_animated_thumbnail_object(td_->file_manager_.get(), &video->animated_thumbnail),
td_->file_manager_->get_file_object(file_id));
}
FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
@ -84,6 +86,16 @@ FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
v->thumbnail = new_video->thumbnail;
v->is_changed = true;
}
if (v->animated_thumbnail != new_video->animated_thumbnail) {
if (!v->animated_thumbnail.file_id.is_valid()) {
LOG(DEBUG) << "Video " << file_id << " animated thumbnail has changed";
} else {
LOG(INFO) << "Video " << file_id << " animated thumbnail has changed from " << v->animated_thumbnail << " to "
<< new_video->animated_thumbnail;
}
v->animated_thumbnail = new_video->animated_thumbnail;
v->is_changed = true;
}
if (v->has_stickers != new_video->has_stickers && new_video->has_stickers) {
v->has_stickers = new_video->has_stickers;
v->is_changed = true;
@ -112,10 +124,17 @@ FileId VideosManager::get_video_thumbnail_file_id(FileId file_id) const {
return video->thumbnail.file_id;
}
FileId VideosManager::get_video_animated_thumbnail_file_id(FileId file_id) const {
auto video = get_video(file_id);
CHECK(video != nullptr);
return video->animated_thumbnail.file_id;
}
void VideosManager::delete_video_thumbnail(FileId file_id) {
auto &video = videos_[file_id];
CHECK(video != nullptr);
video->thumbnail = PhotoSize();
video->animated_thumbnail = PhotoSize();
}
FileId VideosManager::dup_video(FileId new_id, FileId old_id) {
@ -126,6 +145,7 @@ FileId VideosManager::dup_video(FileId new_id, FileId old_id) {
new_video = make_unique<Video>(*old_video);
new_video->file_id = new_id;
new_video->thumbnail.file_id = td_->file_manager_->dup_file_id(new_video->thumbnail.file_id);
new_video->animated_thumbnail.file_id = td_->file_manager_->dup_file_id(new_video->animated_thumbnail.file_id);
return new_id;
}
@ -172,9 +192,10 @@ bool VideosManager::merge_videos(FileId new_id, FileId old_id, bool can_delete_o
return true;
}
void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail, bool has_stickers,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type, int32 duration,
Dimensions dimensions, bool supports_streaming, bool replace) {
void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail,
PhotoSize animated_thumbnail, bool has_stickers, vector<FileId> &&sticker_file_ids,
string file_name, string mime_type, int32 duration, Dimensions dimensions,
bool supports_streaming, bool replace) {
auto v = make_unique<Video>();
v->file_id = file_id;
v->file_name = std::move(file_name);
@ -183,6 +204,7 @@ void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize
v->dimensions = dimensions;
v->minithumbnail = std::move(minithumbnail);
v->thumbnail = std::move(thumbnail);
v->animated_thumbnail = std::move(animated_thumbnail);
v->supports_streaming = supports_streaming;
v->has_stickers = has_stickers;
v->sticker_file_ids = std::move(sticker_file_ids);

View File

@ -30,9 +30,9 @@ class VideosManager {
tl_object_ptr<td_api::video> get_video_object(FileId file_id);
void create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail, bool has_stickers,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type, int32 duration,
Dimensions dimensions, bool supports_streaming, bool replace);
void create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail, PhotoSize animated_thumbnail,
bool has_stickers, vector<FileId> &&sticker_file_ids, string file_name, string mime_type,
int32 duration, Dimensions dimensions, bool supports_streaming, bool replace);
tl_object_ptr<telegram_api::InputMedia> get_input_media(FileId file_id,
tl_object_ptr<telegram_api::InputFile> input_file,
@ -45,6 +45,8 @@ class VideosManager {
FileId get_video_thumbnail_file_id(FileId file_id) const;
FileId get_video_animated_thumbnail_file_id(FileId file_id) const;
void delete_video_thumbnail(FileId file_id);
FileId dup_video(FileId new_id, FileId old_id);
@ -68,6 +70,7 @@ class VideosManager {
Dimensions dimensions;
string minithumbnail;
PhotoSize thumbnail;
PhotoSize animated_thumbnail;
bool supports_streaming = false;

View File

@ -22,9 +22,11 @@ void VideosManager::store_video(FileId file_id, StorerT &storer) const {
auto it = videos_.find(file_id);
CHECK(it != videos_.end());
const Video *video = it->second.get();
bool has_animated_thumbnail = video->animated_thumbnail.file_id.is_valid();
BEGIN_STORE_FLAGS();
STORE_FLAG(video->has_stickers);
STORE_FLAG(video->supports_streaming);
STORE_FLAG(has_animated_thumbnail);
END_STORE_FLAGS();
store(video->file_name, storer);
store(video->mime_type, storer);
@ -36,14 +38,19 @@ void VideosManager::store_video(FileId file_id, StorerT &storer) const {
if (video->has_stickers) {
store(video->sticker_file_ids, storer);
}
if (has_animated_thumbnail) {
store(video->animated_thumbnail, storer);
}
}
template <class ParserT>
FileId VideosManager::parse_video(ParserT &parser) {
auto video = make_unique<Video>();
bool has_animated_thumbnail;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(video->has_stickers);
PARSE_FLAG(video->supports_streaming);
PARSE_FLAG(has_animated_thumbnail);
END_PARSE_FLAGS();
parse(video->file_name, parser);
parse(video->mime_type, parser);
@ -57,6 +64,9 @@ FileId VideosManager::parse_video(ParserT &parser) {
if (video->has_stickers) {
parse(video->sticker_file_ids, parser);
}
if (has_animated_thumbnail) {
parse(video->animated_thumbnail, parser);
}
if (parser.get_error() != nullptr || !video->file_id.is_valid()) {
return FileId();
}