11#include <exiv2/exiv2.hpp>
15#include "libavformat/avformat.h"
21#define LOC QString("ImageMetaData: ")
155 if (degrees ==
"0")
return 1;
156 if (degrees ==
"90")
return 6;
157 if (degrees ==
"180")
return 3;
158 if (degrees ==
"270")
return 8;
187 case 1:
return tr(
"1 (Normal)");
188 case 2:
return tr(
"2 (H Mirror)");
189 case 3:
return tr(
"3 (Rotate 180°)");
190 case 4:
return tr(
"4 (V Mirror)");
191 case 5:
return tr(
"5 (H Mirror, Rot 270°)");
192 case 6:
return tr(
"6 (Rotate 90°)");
193 case 7:
return tr(
"7 (H Mirror, Rot 90°)");
194 case 8:
return tr(
"8 (Rotate 270°)");
195 default:
return tr(
"%1 (Undefined)").arg(orientation);
217 std::string
GetTag(
const QString &key,
bool *
exists =
nullptr);
233 m_image = Exiv2::ImageFactory::open(filePath.toStdString());
242 LOG(VB_GENERAL, LOG_ERR,
LOC +
243 QString(
"Exiv2 error: Could not open file %1").arg(filePath));
246 catch (Exiv2::Error &e)
248 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Exiv2 exception %1").arg(e.what()));
266 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Found %1 tag(s) for file %2")
269 Exiv2::ExifData::const_iterator i;
272 QString label = QString::fromStdString(i->tagLabel());
278 QString key = QString::fromStdString(i->key());
281 if (i->size() >= 256)
283 LOG(VB_FILE, LOG_DEBUG,
LOC +
284 QString(
"Ignoring %1 (%2, %3) : Too big")
285 .arg(key, i->typeName()).arg(i->size()));
290 LOG(VB_FILE, LOG_DEBUG,
LOC +
291 QString(
"Ignoring %1 (%2, %3) : Undecodable")
292 .arg(key, i->typeName()).arg(i->size()));
305 if (value.contains(QChar::Null))
307 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
308 QString(
"Corrupted Exif detected in %1").arg(
m_filePath));
313 QString str =
ToString(key, label, value);
316#ifdef DUMP_METADATA_TAGS
317 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"%1 (%2, %3)")
318 .arg(str, i->typeName()).arg(i->size()));
342 Exiv2::ExifKey exifKey = Exiv2::ExifKey(key.toStdString());
352 return exifIt->value().toString();
364 return QString::fromStdString(value).toInt();
376 QString dt = QString::fromStdString(value);
392 bool comExists =
false;
393 bool desExists =
false;
401 *
exists = comExists || desExists;
415 Exiv2::CommentValue comVal = Exiv2::CommentValue(rawValue);
416 if (comVal.charsetId() != Exiv2::CommentValue::undefined)
417 rawValue = comVal.comment();
418 return QString::fromStdString(rawValue);
441 QString
GetTag(
const QString &key,
bool *
exists =
nullptr);
456 AVInputFormat* p_inputformat =
nullptr;
459 if (avformat_open_input(&
m_context, filePath.toLatin1().constData(),
460 p_inputformat,
nullptr) < 0)
464 int vidStream = av_find_best_stream(
m_context, AVMEDIA_TYPE_VIDEO, -1, -1,
nullptr, 0);
503 args <<
"-loglevel quiet"
504 <<
"-print_format compact"
507 "format=format_long_name,duration,bit_rate:format_tags:"
508 "stream=codec_long_name,codec_type,width,height,pix_fmt,color_space,avg_frame_rate"
509 ",codec_tag_string,sample_rate,channels,channel_layout,bit_rate:stream_tags"
518 LOG(VB_GENERAL, LOG_ERR,
LOC +
519 QString(
"Timeout or Failed: %2 %3").arg(cmd,
args.join(
" ")));
523 QByteArray result = ffprobe.
ReadAll();
524 QTextStream ostream(result);
526 while (!ostream.atEnd())
528 QStringList fields = ostream.readLine().split(
'|');
530 if (fields.size() <= 1)
536 QString group = fields.takeFirst();
537 if (group ==
"stream")
540 prefix = QString::number(stream++) +
":";
544 for (
const auto& field : std::as_const(fields))
547 QStringList parts = field.split(
'=');
548 if (parts.size() != 2)
552 QString label = parts[0].remove(
"tag:");
553 QString value = parts[1];
556 QString key = QString(
"FFmpeg.%1.%2").arg(group, label);
562#ifdef DUMP_METADATA_TAGS
563 LOG(VB_FILE, LOG_DEBUG,
LOC + str);
581 AVDictionaryEntry *tag =
nullptr;
582 while ((tag = av_dict_get(
m_dict,
"\0", tag, AV_DICT_IGNORE_SUFFIX)))
584 if (QString(tag->key) == key)
588 return QString::fromUtf8(tag->value);
667 for (
const auto& token : std::as_const(tagStrings))
671 if (parts.size() == 3)
675 QString group = parts[0].section(
'.', 0, 1);
676 tags.insert(group, parts);
678#ifdef DUMP_METADATA_TAGS
679 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"%1 = %2").arg(group, token));
uint Wait(std::chrono::seconds timeout=0s)
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
static QString AsText(int orientation)
Converts orientation code to text description for info display.
int Transform(int transform)
Adjust orientation to apply a transform to an image.
int Composite() const
Encode original & current orientation to a single Db field.
int m_current
The orientation to use: the file orientation with user transformations applied.
static int FromRotation(const QString °rees)
Convert degrees of rotation into Exif orientation code.
int Apply(int transform) const
Adjust current orientation code to apply a transform to an image.
int m_file
The orientation of the raw file image, as specified by the camera.
int GetCurrent() const
Determines orientation required for an image.
QString Description() const
Generate text description of orientation.
@ GENERIC_EXIT_OK
Exited with no error.
static constexpr const char * MYTH_APPNAME_MYTHFFPROBE
QString GetAppBinDir(void)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
@ kMSStdOut
allow access to stdout
@ kMSRunShell
run process through shell
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.