mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Dive video: paint duration-bar above thumbnail in profile plot
Paint a rectangle on top of thumbnails indicating the run-time of the video. Use the z=100.0-101.0 range for painting the thumbnails, whereby the z-value increases uniformly from first to last thumbnail (sorted by timestamp). The duration-bars are placed at z-values midway between those of the thumbnails. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
c742885984
commit
b3feaa80e2
9 changed files with 163 additions and 76 deletions
|
@ -93,40 +93,36 @@ Thumbnailer::Thumbnail Thumbnailer::fetchImage(const QString &filename, const QS
|
|||
mediatype_t type = get_metadata(qPrintable(filename), &md);
|
||||
|
||||
// For io error or video, return early with the appropriate dummy-icon.
|
||||
if (type == MEDIATYPE_IO_ERROR) {
|
||||
return { failImage, MEDIATYPE_IO_ERROR };
|
||||
} else if (type == MEDIATYPE_VIDEO) {
|
||||
addVideoThumbnailToCache(originalFilename, md.duration);
|
||||
return { videoImage, MEDIATYPE_VIDEO };
|
||||
}
|
||||
if (type == MEDIATYPE_IO_ERROR)
|
||||
return { failImage, MEDIATYPE_IO_ERROR, 0 };
|
||||
else if (type == MEDIATYPE_VIDEO)
|
||||
return addVideoThumbnailToCache(originalFilename, md.duration);
|
||||
|
||||
// Try if Qt can parse this image. If it does, use this as a thumbnail.
|
||||
QImage thumb(filename);
|
||||
if (!thumb.isNull()) {
|
||||
addPictureThumbnailToCache(originalFilename, thumb);
|
||||
return { thumb, MEDIATYPE_PICTURE };
|
||||
int size = maxThumbnailSize();
|
||||
thumb = thumb.scaled(size, size, Qt::KeepAspectRatio);
|
||||
return addPictureThumbnailToCache(originalFilename, thumb);
|
||||
}
|
||||
|
||||
// Neither our code, nor Qt could determine the type of this object from looking at the data.
|
||||
// Try to check for a video-file extension. Since we couldn't parse the video file,
|
||||
// we pass 0 as the duration.
|
||||
if (hasVideoFileExtension(filename)) {
|
||||
addVideoThumbnailToCache(originalFilename, {0} );
|
||||
return { videoImage, MEDIATYPE_VIDEO };
|
||||
}
|
||||
if (hasVideoFileExtension(filename))
|
||||
return addVideoThumbnailToCache(originalFilename, {0} );
|
||||
|
||||
// Give up: we simply couldn't determine what this thing is.
|
||||
// But since we managed to read this file, mark this file in the cache as unknown.
|
||||
addUnknownThumbnailToCache(originalFilename);
|
||||
return { unknownImage, MEDIATYPE_UNKNOWN };
|
||||
return addUnknownThumbnailToCache(originalFilename);
|
||||
} else if (tryDownload) {
|
||||
// This has to be done in UI main thread, because QNetworkManager refuses
|
||||
// to treat requests from other threads. invokeMethod() is Qt's way of calling a
|
||||
// function in a different thread, namely the thread the called object is associated to.
|
||||
QMetaObject::invokeMethod(ImageDownloader::instance(), "load", Qt::AutoConnection, Q_ARG(QUrl, url), Q_ARG(QString, originalFilename));
|
||||
return { QImage(), MEDIATYPE_STILL_LOADING };
|
||||
return { QImage(), MEDIATYPE_STILL_LOADING, 0 };
|
||||
}
|
||||
return { QImage(), MEDIATYPE_IO_ERROR };
|
||||
return { QImage(), MEDIATYPE_IO_ERROR, 0 };
|
||||
}
|
||||
|
||||
// Fetch a picture based on its original filename. If there is a translated filename (obtained either
|
||||
|
@ -142,7 +138,7 @@ Thumbnailer::Thumbnail Thumbnailer::getHashedImage(const QString &filename, bool
|
|||
// If there is a translated filename, try that first.
|
||||
// Note that we set the default type to io-error, so that if we didn't try
|
||||
// the local filename first, we will load the file from the canonical filename.
|
||||
Thumbnail thumbnail { QImage(), MEDIATYPE_IO_ERROR };
|
||||
Thumbnail thumbnail { QImage(), MEDIATYPE_IO_ERROR, 0 };
|
||||
if (localFilename != filename)
|
||||
thumbnail = fetchImage(localFilename, filename, tryDownload);
|
||||
|
||||
|
@ -199,7 +195,9 @@ Thumbnailer::Thumbnail Thumbnailer::getVideoThumbnailFromStream(QDataStream &str
|
|||
|
||||
// If reading did not succeed, schedule for recalculation - this thumbnail might
|
||||
// have been written by an older version, which couldn't extract the duration.
|
||||
if (stream.status() != QDataStream::Ok)
|
||||
// Likewise test the duration and number of pictures for sanity (no videos longer than 10 h,
|
||||
// no more than 10000 pictures).
|
||||
if (stream.status() != QDataStream::Ok || duration > 36000 || numPics > 10000)
|
||||
return { QImage(), MEDIATYPE_VIDEO, 0 };
|
||||
|
||||
// Currently, we support only one picture
|
||||
|
@ -211,7 +209,7 @@ Thumbnailer::Thumbnail Thumbnailer::getVideoThumbnailFromStream(QDataStream &str
|
|||
}
|
||||
|
||||
// No picture -> show dummy-icon
|
||||
return { res.isNull() ? videoImage : res, MEDIATYPE_VIDEO, {(int32_t)duration} };
|
||||
return { res.isNull() ? videoImage : res, MEDIATYPE_VIDEO, (int32_t)duration };
|
||||
}
|
||||
|
||||
// Fetch a thumbnail from cache.
|
||||
|
@ -220,7 +218,7 @@ Thumbnailer::Thumbnail Thumbnailer::getThumbnailFromCache(const QString &picture
|
|||
{
|
||||
QString filename = thumbnailFileName(picture_filename);
|
||||
if (filename.isEmpty())
|
||||
return { QImage(), MEDIATYPE_UNKNOWN };
|
||||
return { QImage(), MEDIATYPE_UNKNOWN, 0 };
|
||||
QFile file(filename);
|
||||
|
||||
if (prefs.auto_recalculate_thumbnails) {
|
||||
|
@ -256,7 +254,7 @@ Thumbnailer::Thumbnail Thumbnailer::getThumbnailFromCache(const QString &picture
|
|||
}
|
||||
}
|
||||
|
||||
void Thumbnailer::addVideoThumbnailToCache(const QString &picture_filename, duration_t duration)
|
||||
Thumbnailer::Thumbnail Thumbnailer::addVideoThumbnailToCache(const QString &picture_filename, duration_t duration)
|
||||
{
|
||||
// The format of video thumbnails:
|
||||
// uint32 MEDIATYPE_VIDEO
|
||||
|
@ -267,43 +265,43 @@ void Thumbnailer::addVideoThumbnailToCache(const QString &picture_filename, dura
|
|||
// QImage frame
|
||||
QString filename = thumbnailFileName(picture_filename);
|
||||
QSaveFile file(filename);
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
return;
|
||||
QDataStream stream(&file);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
QDataStream stream(&file);
|
||||
|
||||
stream << (quint32)MEDIATYPE_VIDEO;
|
||||
stream << (quint32)duration.seconds;
|
||||
stream << (quint32)0; // Currently, we don't support extraction of images
|
||||
file.commit();
|
||||
stream << (quint32)MEDIATYPE_VIDEO;
|
||||
stream << (quint32)duration.seconds;
|
||||
stream << (quint32)0; // Currently, we don't support extraction of images
|
||||
file.commit();
|
||||
}
|
||||
return { videoImage, MEDIATYPE_VIDEO, duration };
|
||||
}
|
||||
|
||||
void Thumbnailer::addPictureThumbnailToCache(const QString &picture_filename, const QImage &thumbnail)
|
||||
Thumbnailer::Thumbnail Thumbnailer::addPictureThumbnailToCache(const QString &picture_filename, const QImage &thumbnail)
|
||||
{
|
||||
if (thumbnail.isNull())
|
||||
return;
|
||||
|
||||
// The format of a picture-thumbnail is very simple:
|
||||
// uint32 MEDIATYPE_PICTURE
|
||||
// QImage thumbnail
|
||||
QString filename = thumbnailFileName(picture_filename);
|
||||
QSaveFile file(filename);
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
return;
|
||||
QDataStream stream(&file);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
QDataStream stream(&file);
|
||||
|
||||
stream << (quint32)MEDIATYPE_PICTURE;
|
||||
stream << thumbnail;
|
||||
file.commit();
|
||||
stream << (quint32)MEDIATYPE_PICTURE;
|
||||
stream << thumbnail;
|
||||
file.commit();
|
||||
}
|
||||
return { thumbnail, MEDIATYPE_PICTURE, 0 };
|
||||
}
|
||||
|
||||
void Thumbnailer::addUnknownThumbnailToCache(const QString &picture_filename)
|
||||
Thumbnailer::Thumbnail Thumbnailer::addUnknownThumbnailToCache(const QString &picture_filename)
|
||||
{
|
||||
QString filename = thumbnailFileName(picture_filename);
|
||||
QSaveFile file(filename);
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
return;
|
||||
QDataStream stream(&file);
|
||||
stream << (quint32)MEDIATYPE_UNKNOWN;
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
QDataStream stream(&file);
|
||||
stream << (quint32)MEDIATYPE_UNKNOWN;
|
||||
}
|
||||
return { unknownImage, MEDIATYPE_UNKNOWN, 0 };
|
||||
}
|
||||
|
||||
void Thumbnailer::recalculate(QString filename)
|
||||
|
@ -317,7 +315,7 @@ void Thumbnailer::recalculate(QString filename)
|
|||
return;
|
||||
|
||||
QMutexLocker l(&lock);
|
||||
emit thumbnailChanged(filename, thumbnail.img);
|
||||
emit thumbnailChanged(filename, thumbnail.img, thumbnail.duration);
|
||||
workingOn.remove(filename);
|
||||
}
|
||||
|
||||
|
@ -339,7 +337,7 @@ void Thumbnailer::processItem(QString filename, bool tryDownload)
|
|||
}
|
||||
|
||||
QMutexLocker l(&lock);
|
||||
emit thumbnailChanged(filename, thumbnail.img);
|
||||
emit thumbnailChanged(filename, thumbnail.img, thumbnail.duration);
|
||||
workingOn.remove(filename);
|
||||
}
|
||||
|
||||
|
@ -352,7 +350,7 @@ void Thumbnailer::imageDownloaded(QString filename)
|
|||
|
||||
void Thumbnailer::imageDownloadFailed(QString filename)
|
||||
{
|
||||
emit thumbnailChanged(filename, failImage);
|
||||
emit thumbnailChanged(filename, failImage, duration_t{ 0 });
|
||||
QMutexLocker l(&lock);
|
||||
workingOn.remove(filename);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue