MythTV  master
imagemetadata.cpp
Go to the documentation of this file.
1 #include "imagemetadata.h"
2 
4 #include "libmythbase/mythdirs.h" // for GetAppBinDir
5 #include "libmythbase/mythsystemlegacy.h" // for ffprobe
6 
7 // libexiv2 for Exif metadata
8 #include <exiv2/exiv2.hpp>
9 
10 // To read FFMPEG Metadata
11 extern "C" {
12 #include "libavformat/avformat.h"
13 }
14 
15 // Uncomment this to log raw metadata from exif/ffmpeg
16 //#define DUMP_METADATA_TAGS yes
17 
18 #define LOC QString("ImageMetaData: ")
19 
20 
26 int Orientation::Transform(int transform)
27 {
28  m_current = Apply(transform);
29  return Composite();
30 }
31 
32 
39 {
40  Orientation::Matrix matrix;
41 
42  if (krunningQt541)
43  {
44  // Each row/string defines codes for a single file orientation
45  // Each col/value defines applicable code for corresponding current orientation
46  // As current orientation is applicable to raw camera image, these codes
47  // define the current orientation relative to 1/Normal (as Qt 5.4.1 has already
48  // applied the file orientation)
49  QStringList vals = QStringList()
50  << "0 1 2 3 4 5 6 7 8"
51  << "0 1 2 3 4 5 6 7 8"
52  << "0 2 1 4 3 8 7 6 5"
53  << "0 3 4 1 2 7 8 5 6"
54  << "0 4 3 2 1 6 5 8 7"
55  << "0 5 6 7 8 1 2 3 4"
56  << "0 8 7 6 5 2 1 4 3"
57  << "0 7 8 5 6 3 4 1 2"
58  << "0 6 5 8 7 4 3 2 1";
59 
60  for (int row = 0; row < vals.size(); ++row)
61  {
62  QStringList rowVals = vals.at(row).split(' ');
63  for (int col = 0; col < rowVals.size(); ++col)
64  matrix[row][col] = rowVals.at(col).toInt();
65  }
66  }
67  return matrix;
68 }
69 
70 const bool Orientation::krunningQt541 = (strcmp(qVersion(), "5.4.1") == 0);
73 
74 
83 int Orientation::GetCurrent(bool compensate)
84 {
85  // Qt 5.4.1 automatically applies the file orientation when loading images
86  // Ref: https://codereview.qt-project.org/#/c/111398/
87  // Ref: https://codereview.qt-project.org/#/c/110685/
88  // https://bugreports.qt.io/browse/QTBUG-37946
89  if (compensate && krunningQt541)
90  {
91  // Deduce orientation relative to 1/Normal from file & current orientations
92  int old = m_current;
94 
95  LOG(VB_FILE, LOG_DEBUG, LOC +
96  QString("Adjusted orientation %1 to %2 for Qt 5.4.1")
97  .arg(old).arg(m_current));
98  }
99  return m_current;
100 }
101 
102 
112 int Orientation::Apply(int transform) const
113 {
114  if (transform == kResetToExif)
115  return m_file;
116 
117  // https://github.com/recurser/exif-orientation-examples is a useful resource.
118  switch (m_current)
119  {
120  case 0: // The image has no orientation info
121  case 1: // The image is in its original state
122  switch (transform)
123  {
124  case kRotateCW: return 6;
125  case kRotateCCW: return 8;
126  case kFlipHorizontal: return 2;
127  case kFlipVertical: return 4;
128  }
129  break;
130 
131  case 2: // The image is horizontally flipped
132  switch (transform)
133  {
134  case kRotateCW: return 7;
135  case kRotateCCW: return 5;
136  case kFlipHorizontal: return 1;
137  case kFlipVertical: return 3;
138  }
139  break;
140 
141  case 3: // The image is rotated 180°
142  switch (transform)
143  {
144  case kRotateCW: return 8;
145  case kRotateCCW: return 6;
146  case kFlipHorizontal: return 4;
147  case kFlipVertical: return 2;
148  }
149  break;
150 
151  case 4: // The image is vertically flipped
152  switch (transform)
153  {
154  case kRotateCW: return 5;
155  case kRotateCCW: return 7;
156  case kFlipHorizontal: return 3;
157  case kFlipVertical: return 1;
158  }
159  break;
160 
161  case 5: // The image is rotated 90° CW and flipped horizontally
162  switch (transform)
163  {
164  case kRotateCW: return 2;
165  case kRotateCCW: return 4;
166  case kFlipHorizontal: return 6;
167  case kFlipVertical: return 8;
168  }
169  break;
170 
171  case 6: // The image is rotated 90° CCW
172  switch (transform)
173  {
174  case kRotateCW: return 3;
175  case kRotateCCW: return 1;
176  case kFlipHorizontal: return 5;
177  case kFlipVertical: return 7;
178  }
179  break;
180 
181  case 7: // The image is rotated 90° CW and flipped vertically
182  switch (transform)
183  {
184  case kRotateCW: return 4;
185  case kRotateCCW: return 2;
186  case kFlipHorizontal: return 8;
187  case kFlipVertical: return 6;
188  }
189  break;
190 
191  case 8: // The image is rotated 90° CW
192  switch (transform)
193  {
194  case kRotateCW: return 1;
195  case kRotateCCW: return 3;
196  case kFlipHorizontal: return 7;
197  case kFlipVertical: return 5;
198  }
199  break;
200  }
201  return m_current;
202 }
203 
204 
210 int Orientation::FromRotation(const QString &degrees)
211 {
212  if (degrees == "0") return 1;
213  if (degrees == "90") return 6;
214  if (degrees == "180") return 3;
215  if (degrees == "270") return 8;
216  return 0;
217 }
218 
219 
227 {
228  return (m_file == m_current)
229  ? AsText(m_file)
230  : tr("File: %1, Db: %2").arg(AsText(m_file),
231  AsText(m_current));
232 }
233 
234 
240 QString Orientation::AsText(int orientation)
241 {
242  switch (orientation)
243  {
244  case 1: return tr("1 (Normal)");
245  case 2: return tr("2 (H Mirror)");
246  case 3: return tr("3 (Rotate 180°)");
247  case 4: return tr("4 (V Mirror)");
248  case 5: return tr("5 (H Mirror, Rot 270°)");
249  case 6: return tr("6 (Rotate 90°)");
250  case 7: return tr("7 (H Mirror, Rot 90°)");
251  case 8: return tr("8 (Rotate 270°)");
252  default: return tr("%1 (Undefined)").arg(orientation);
253  }
254 }
255 
256 
259 {
260 public:
261  explicit PictureMetaData(const QString &filePath);
262  ~PictureMetaData() override = default; // libexiv2 closes file, cleans up via autoptrs
263 
264  bool IsValid() override // ImageMetaData
265  { return m_image.get(); }
266  QStringList GetAllTags() override; // ImageMetaData
267  int GetOrientation(bool *exists = nullptr) override; // ImageMetaData
268  QDateTime GetOriginalDateTime(bool *exists = nullptr) override; // ImageMetaData
269  QString GetComment(bool *exists = nullptr) override; // ImageMetaData
270 
271 protected:
272  static QString DecodeComment(std::string rawValue);
273 
274  std::string GetTag(const QString &key, bool *exists = nullptr);
275 
276  Exiv2::Image::UniquePtr m_image;
277  Exiv2::ExifData m_exifData;
278 };
279 
280 
285 PictureMetaData::PictureMetaData(const QString &filePath)
286  : ImageMetaData(filePath), m_image(nullptr)
287 {
288  try
289  {
290  m_image = Exiv2::ImageFactory::open(filePath.toStdString());
291 
293  {
294  m_image->readMetadata();
295  m_exifData = m_image->exifData();
296  }
297  else
298  {
299  LOG(VB_GENERAL, LOG_ERR, LOC +
300  QString("Exiv2 error: Could not open file %1").arg(filePath));
301  }
302  }
303  catch (Exiv2::Error &e)
304  {
305  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Exiv2 exception %1").arg(e.what()));
306  }
307 }
308 
309 
318 {
319  QStringList tags;
320  if (!IsValid())
321  return tags;
322 
323  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Found %1 tag(s) for file %2")
324  .arg(m_exifData.count()).arg(m_filePath));
325 
326  Exiv2::ExifData::const_iterator i;
327  for (i = m_exifData.begin(); i != m_exifData.end(); ++i)
328  {
329  QString label = QString::fromStdString(i->tagLabel());
330 
331  // Ignore empty labels
332  if (label.isEmpty())
333  continue;
334 
335  QString key = QString::fromStdString(i->key());
336 
337  // Ignore large values (binary/private tags)
338  if (i->size() >= 256)
339  {
340  LOG(VB_FILE, LOG_DEBUG, LOC +
341  QString("Ignoring %1 (%2, %3) : Too big")
342  .arg(key, i->typeName()).arg(i->size()));
343  }
344  // Ignore 'Print Image Matching'
345  else if (i->tag() == EXIF_PRINT_IMAGE_MATCHING)
346  {
347  LOG(VB_FILE, LOG_DEBUG, LOC +
348  QString("Ignoring %1 (%2, %3) : Undecodable")
349  .arg(key, i->typeName()).arg(i->size()));
350  }
351  else
352  {
353  // Use interpreted values
354  std::string val = i->print(&m_exifData);
355 
356  // Comment needs charset decoding
357  QString value = (key == EXIF_TAG_USERCOMMENT)
358  ? DecodeComment(val) : QString::fromStdString(val);
359 
360  // Nulls can arise from corrupt metadata (MakerNote)
361  // Remove them as they disrupt socket comms between BE & remote FE's
362  if (value.contains(QChar::Null))
363  {
364  LOG(VB_GENERAL, LOG_NOTICE, LOC +
365  QString("Corrupted Exif detected in %1").arg(m_filePath));
366  value = "????";
367  }
368 
369  // Encode tag
370  QString str = ToString(key, label, value);
371  tags << str;
372 
373 #ifdef DUMP_METADATA_TAGS
374  LOG(VB_FILE, LOG_DEBUG, LOC + QString("%1 (%2, %3)")
375  .arg(str, i->typeName()).arg(i->size()));
376 #endif
377  }
378  }
379  return tags;
380 }
381 
382 
390 std::string PictureMetaData::GetTag(const QString &key, bool *exists)
391 {
392  std::string value;
393  if (exists)
394  *exists = false;
395 
396  if (!IsValid())
397  return value;
398 
399  Exiv2::ExifKey exifKey = Exiv2::ExifKey(key.toStdString());
400  auto exifIt = m_exifData.findKey(exifKey);
401 
402  if (exifIt == m_exifData.end())
403  return value;
404 
405  if (exists)
406  *exists = true;
407 
408  // Use raw value
409  return exifIt->value().toString();
410 }
411 
412 
419 {
420  std::string value = GetTag(EXIF_TAG_ORIENTATION, exists);
421  return QString::fromStdString(value).toInt();
422 }
423 
424 
431 {
432  std::string value = GetTag(EXIF_TAG_DATETIME, exists);
433  QString dt = QString::fromStdString(value);
434 
435  // Exif time has no timezone
437 }
438 
439 
447 {
448  // Use User Comment or else Image Description
449  bool comExists = false;
450  bool desExists = false;
451 
452  std::string comment = GetTag(EXIF_TAG_USERCOMMENT, &comExists);
453 
454  if (comment.empty())
455  comment = GetTag(EXIF_TAG_IMAGEDESCRIPTION, &desExists);
456 
457  if (exists)
458  *exists = comExists || desExists;
459 
460  return DecodeComment(comment);
461 }
462 
463 
469 QString PictureMetaData::DecodeComment(std::string rawValue)
470 {
471  // Decode charset
472  Exiv2::CommentValue comVal = Exiv2::CommentValue(rawValue);
473  if (comVal.charsetId() != Exiv2::CommentValue::undefined)
474  rawValue = comVal.comment();
475  return QString::fromStdString(rawValue);
476 }
477 
478 
485 {
486 public:
487  explicit VideoMetaData(const QString &filePath);
488  ~VideoMetaData() override;
489 
490  bool IsValid() override // ImageMetaData
491  { return m_dict; }
492  QStringList GetAllTags() override; // ImageMetaData
493  int GetOrientation(bool *exists = nullptr) override; // ImageMetaData
494  QDateTime GetOriginalDateTime(bool *exists = nullptr) override; // ImageMetaData
495  QString GetComment(bool *exists = nullptr) override; // ImageMetaData
496 
497 protected:
498  QString GetTag(const QString &key, bool *exists = nullptr);
499 
500  AVFormatContext *m_context { nullptr };
502  AVDictionary *m_dict { nullptr };
503 };
504 
505 
510 VideoMetaData::VideoMetaData(const QString &filePath)
511  : ImageMetaData(filePath)
512 {
513  AVInputFormat* p_inputformat = nullptr;
514 
515  // Open file
516  if (avformat_open_input(&m_context, filePath.toLatin1().constData(),
517  p_inputformat, nullptr) < 0)
518  return;
519 
520  // Locate video stream
521  int vidStream = av_find_best_stream(m_context, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
522  if (vidStream >= 0)
523  m_dict = m_context->streams[vidStream]->metadata;
524 
525  if (!VideoMetaData::IsValid())
526  avformat_close_input(&m_context);
527 }
528 
529 
534 {
536  avformat_close_input(&m_context);
537 }
538 
539 
551 {
552  QStringList tags;
553  if (!IsValid())
554  return tags;
555 
556  // Only extract interesting fields:
557  // For list use: mythffprobe -show_format -show_streams <file>
558  QString cmd = GetAppBinDir() + MYTH_APPNAME_MYTHFFPROBE;
559  QStringList args;
560  args << "-loglevel quiet"
561  << "-print_format compact" // Returns "section|key=value|key=value..."
562  << "-pretty" // Add units etc
563  << "-show_entries "
564  "format=format_long_name,duration,bit_rate:format_tags:"
565  "stream=codec_long_name,codec_type,width,height,pix_fmt,color_space,avg_frame_rate"
566  ",codec_tag_string,sample_rate,channels,channel_layout,bit_rate:stream_tags"
567  << m_filePath;
568 
569  MythSystemLegacy ffprobe(cmd, args, kMSRunShell | kMSStdOut);
570 
571  ffprobe.Run(5s);
572 
573  if (ffprobe.Wait() != GENERIC_EXIT_OK)
574  {
575  LOG(VB_GENERAL, LOG_ERR, LOC +
576  QString("Timeout or Failed: %2 %3").arg(cmd, args.join(" ")));
577  return tags;
578  }
579 
580  QByteArray result = ffprobe.ReadAll();
581  QTextStream ostream(result);
582  int stream = 0;
583  while (!ostream.atEnd())
584  {
585  QStringList fields = ostream.readLine().split('|');
586 
587  if (fields.size() <= 1)
588  // Empty section
589  continue;
590 
591  // First fields should be "format" or "stream"
592  QString prefix = "";
593  QString group = fields.takeFirst();
594  if (group == "stream")
595  {
596  // Streams use index as group
597  prefix = QString::number(stream++) + ":";
598  group.append(prefix);
599  }
600 
601  for (const auto& field : std::as_const(fields))
602  {
603  // Expect label=value
604  QStringList parts = field.split('=');
605  if (parts.size() != 2)
606  continue;
607 
608  // Remove ffprobe "tag:" prefix
609  QString label = parts[0].remove("tag:");
610  QString value = parts[1];
611 
612  // Construct a pseudo-key for FFMPEG tags
613  QString key = QString("FFmpeg.%1.%2").arg(group, label);
614 
615  // Add stream id to labels
616  QString str = ToString(key, prefix + label, value);
617  tags << str;
618 
619 #ifdef DUMP_METADATA_TAGS
620  LOG(VB_FILE, LOG_DEBUG, LOC + str);
621 #endif
622  }
623  }
624  return tags;
625 }
626 
627 
634 QString VideoMetaData::GetTag(const QString &key, bool *exists)
635 {
636  if (m_dict)
637  {
638  AVDictionaryEntry *tag = nullptr;
639  while ((tag = av_dict_get(m_dict, "\0", tag, AV_DICT_IGNORE_SUFFIX)))
640  {
641  if (QString(tag->key) == key)
642  {
643  if (exists)
644  *exists = true;
645  return QString::fromUtf8(tag->value);
646  }
647  }
648  }
649  if (exists)
650  *exists = false;
651  return {};
652 }
653 
654 
661 {
662  QString angle = GetTag(FFMPEG_TAG_ORIENTATION, exists);
663  return Orientation::FromRotation(angle);
664 }
665 
666 
673 {
674  QString dt = GetTag(FFMPEG_TAG_DATETIME, exists);
675 
676  // Video time has no timezone
678 }
679 
680 
688 {
689  if (exists)
690  *exists = false;
691  return {};
692 }
693 
694 
700 ImageMetaData* ImageMetaData::FromPicture(const QString &filePath)
701 { return new PictureMetaData(filePath); }
702 
703 
709 ImageMetaData* ImageMetaData::FromVideo(const QString &filePath)
710 { return new VideoMetaData(filePath); }
711 
712 
713 const QString ImageMetaData::kSeparator = "|-|";
714 
715 
721 ImageMetaData::TagMap ImageMetaData::ToMap(const QStringList &tagStrings)
722 {
723  TagMap tags;
724  for (const auto& token : std::as_const(tagStrings))
725  {
726  QStringList parts = FromString(token);
727  // Expect Key, Label, Value.
728  if (parts.size() == 3)
729  {
730  // Map tags by Family.Group to keep them together
731  // Within each group they will preserve list ordering
732  QString group = parts[0].section('.', 0, 1);
733  tags.insert(group, parts);
734 
735 #ifdef DUMP_METADATA_TAGS
736  LOG(VB_FILE, LOG_DEBUG, LOC + QString("%1 = %2").arg(group, token));
737 #endif
738  }
739  }
740  return tags;
741 }
build_compdb.args
args
Definition: build_compdb.py:11
Orientation::Matrix
QHash< int, QHash< int, int > > Matrix
Definition: imagemetadata.h:83
FFMPEG_TAG_DATETIME
static constexpr const char * FFMPEG_TAG_DATETIME
Definition: imagemetadata.h:34
Orientation::m_current
int m_current
The orientation to use: the file orientation with user transformations applied.
Definition: imagemetadata.h:92
PictureMetaData::IsValid
bool IsValid() override
Definition: imagemetadata.cpp:264
VideoMetaData::IsValid
bool IsValid() override
Definition: imagemetadata.cpp:490
MythSystemLegacy
Definition: mythsystemlegacy.h:67
ImageMetaData
Abstract class for image metadata.
Definition: imagemetadata.h:99
EXIF_PRINT_IMAGE_MATCHING
static constexpr uint16_t EXIF_PRINT_IMAGE_MATCHING
Definition: imagemetadata.h:30
VideoMetaData::GetOrientation
int GetOrientation(bool *exists=nullptr) override
Read FFmpeg video orientation tag.
Definition: imagemetadata.cpp:660
xbmcvfs.exists
bool exists(str path)
Definition: xbmcvfs.py:51
LOC
#define LOC
Definition: imagemetadata.cpp:18
PictureMetaData::GetComment
QString GetComment(bool *exists=nullptr) override
Read Exif comments from metadata.
Definition: imagemetadata.cpp:446
EXIF_TAG_IMAGEDESCRIPTION
static constexpr const char * EXIF_TAG_IMAGEDESCRIPTION
Definition: imagemetadata.h:28
Orientation::FromRotation
static int FromRotation(const QString &degrees)
Convert degrees of rotation into Exif orientation code.
Definition: imagemetadata.cpp:210
EXIF_TAG_DATETIME
static constexpr const char * EXIF_TAG_DATETIME
Definition: imagemetadata.h:26
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythSystemLegacy::ReadAll
QByteArray & ReadAll()
Definition: mythsystemlegacy.cpp:402
MYTH_APPNAME_MYTHFFPROBE
static constexpr const char * MYTH_APPNAME_MYTHFFPROBE
Definition: mythcorecontext.h:36
vals
static float * vals
Definition: tentacle3d.cpp:19
FFMPEG_TAG_ORIENTATION
static constexpr const char * FFMPEG_TAG_ORIENTATION
Definition: imagemetadata.h:33
mythdirs.h
VideoMetaData::VideoMetaData
VideoMetaData(const QString &filePath)
Constructor. Opens best video stream from video.
Definition: imagemetadata.cpp:510
VideoMetaData::GetOriginalDateTime
QDateTime GetOriginalDateTime(bool *exists=nullptr) override
Read video datestamp.
Definition: imagemetadata.cpp:672
Orientation::m_file
int m_file
The orientation of the raw file image, as specified by the camera.
Definition: imagemetadata.h:94
ImageMetaData::FromVideo
static ImageMetaData * FromVideo(const QString &filePath)
Factory to retrieve metadata from videos.
Definition: imagemetadata.cpp:709
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
Orientation::GetCurrent
int GetCurrent(bool compensate)
Determines orientation required for an image.
Definition: imagemetadata.cpp:83
mythsystemlegacy.h
PictureMetaData::PictureMetaData
PictureMetaData(const QString &filePath)
Constructor. Reads metadata from image.
Definition: imagemetadata.cpp:285
Orientation::Transform
int Transform(int transform)
Adjust orientation to apply a transform to an image.
Definition: imagemetadata.cpp:26
PictureMetaData::m_exifData
Exiv2::ExifData m_exifData
Definition: imagemetadata.cpp:277
ImageMetaData::ToString
static QString ToString(const QString &name, const QString &label, const QString &value)
Encodes metadata into a string as <tag name><tag label><tag value>
Definition: imagemetadata.h:112
ImageMetaData::m_filePath
QString m_filePath
Image filepath.
Definition: imagemetadata.h:133
PictureMetaData::GetOrientation
int GetOrientation(bool *exists=nullptr) override
Read Exif orientation.
Definition: imagemetadata.cpp:418
PictureMetaData::GetOriginalDateTime
QDateTime GetOriginalDateTime(bool *exists=nullptr) override
Read Exif timestamp of image capture.
Definition: imagemetadata.cpp:430
kFlipVertical
@ kFlipVertical
Reflect about horizontal axis.
Definition: imagemetadata.h:51
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
VideoMetaData::m_context
AVFormatContext * m_context
Definition: imagemetadata.cpp:500
Orientation::Composite
int Composite() const
Encode original & current orientation to a single Db field.
Definition: imagemetadata.h:71
PictureMetaData::GetTag
std::string GetTag(const QString &key, bool *exists=nullptr)
Read a single Exif metadata tag.
Definition: imagemetadata.cpp:390
ImageMetaData::FromString
static QStringList FromString(const QString &str)
Decodes metadata name, label, value from a string.
Definition: imagemetadata.h:116
MythSystemLegacy::Wait
uint Wait(std::chrono::seconds timeout=0s)
Definition: mythsystemlegacy.cpp:243
EXIF_TAG_DATE_FORMAT
static constexpr const char * EXIF_TAG_DATE_FORMAT
Definition: imagemetadata.h:27
Orientation::Description
QString Description() const
Generate text description of orientation.
Definition: imagemetadata.cpp:226
VideoMetaData::~VideoMetaData
~VideoMetaData() override
Destructor. Closes file.
Definition: imagemetadata.cpp:533
PictureMetaData::m_image
Exiv2::Image::UniquePtr m_image
Definition: imagemetadata.cpp:276
PictureMetaData::GetAllTags
QStringList GetAllTags() override
Returns all metadata tags.
Definition: imagemetadata.cpp:317
ImageMetaData::ToMap
static TagMap ToMap(const QStringList &tags)
Creates a map of metadata tags as.
Definition: imagemetadata.cpp:721
ImageMetaData::FromPicture
static ImageMetaData * FromPicture(const QString &filePath)
Factory to retrieve metadata from pictures.
Definition: imagemetadata.cpp:700
PictureMetaData
Reads Exif metadata from a picture using libexiv2.
Definition: imagemetadata.cpp:258
kMSRunShell
@ kMSRunShell
run process through shell
Definition: mythsystem.h:43
ImageMetaData::TagMap
QMultiMap< QString, QStringList > TagMap
Definition: imagemetadata.h:119
PictureMetaData::DecodeComment
static QString DecodeComment(std::string rawValue)
Decodes charset of UserComment.
Definition: imagemetadata.cpp:469
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
VideoMetaData::GetTag
QString GetTag(const QString &key, bool *exists=nullptr)
Read a single video tag.
Definition: imagemetadata.cpp:634
VideoMetaData::GetAllTags
QStringList GetAllTags() override
Reads relevant video metadata by running mythffprobe.
Definition: imagemetadata.cpp:550
Orientation::Apply
int Apply(int transform) const
Adjust current orientation code to apply a transform to an image.
Definition: imagemetadata.cpp:112
Orientation::AsText
static QString AsText(int orientation)
Converts orientation code to text description for info display.
Definition: imagemetadata.cpp:240
mythcorecontext.h
Orientation::kQt541_orientation
static const Matrix kQt541_orientation
Orientation conversions for proper display on Qt 5.4.1.
Definition: imagemetadata.h:88
EXIF_TAG_USERCOMMENT
static constexpr const char * EXIF_TAG_USERCOMMENT
Definition: imagemetadata.h:29
ImageMetaData::kSeparator
static const QString kSeparator
Unique separator to delimit fields within a string.
Definition: imagemetadata.h:109
kFlipHorizontal
@ kFlipHorizontal
Reflect about vertical axis.
Definition: imagemetadata.h:50
imagemetadata.h
Handles Exif/FFMpeg metadata tags for images.
VideoMetaData::GetComment
QString GetComment(bool *exists=nullptr) override
Read Video comment from metadata.
Definition: imagemetadata.cpp:687
Orientation::InitOrientationMatrix
static Matrix InitOrientationMatrix()
Initialises conversion matrix for Qt 5.4.1.
Definition: imagemetadata.cpp:38
kResetToExif
@ kResetToExif
Reset to Exif value.
Definition: imagemetadata.h:47
GetAppBinDir
QString GetAppBinDir(void)
Definition: mythdirs.cpp:253
kRotateCCW
@ kRotateCCW
Rotate anti-clockwise.
Definition: imagemetadata.h:49
FFMPEG_TAG_DATE_FORMAT
static constexpr const char * FFMPEG_TAG_DATE_FORMAT
Definition: imagemetadata.h:35
VideoMetaData
Reads video metadata tags using FFmpeg Raw values for Orientation & Date are read quickly via FFmpeg ...
Definition: imagemetadata.cpp:484
PictureMetaData::~PictureMetaData
~PictureMetaData() override=default
EXIF_TAG_ORIENTATION
static constexpr const char * EXIF_TAG_ORIENTATION
Definition: imagemetadata.h:25
MythSystemLegacy::Run
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
Definition: mythsystemlegacy.cpp:213
kRotateCW
@ kRotateCW
Rotate clockwise.
Definition: imagemetadata.h:48
kMSStdOut
@ kMSStdOut
allow access to stdout
Definition: mythsystem.h:41
Orientation::krunningQt541
static const bool krunningQt541
True when using Qt 5.4.1 with its deviant orientation behaviour.
Definition: imagemetadata.h:86
VideoMetaData::m_dict
AVDictionary * m_dict
FFmpeg tag dictionary.
Definition: imagemetadata.cpp:502