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  LOG(VB_GENERAL, LOG_ERR, LOC +
299  QString("Exiv2 error: Could not open file %1").arg(filePath));
300  }
301  catch (Exiv2::Error &e)
302  {
303  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Exiv2 exception %1").arg(e.what()));
304  }
305 }
306 
307 
316 {
317  QStringList tags;
318  if (!IsValid())
319  return tags;
320 
321  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Found %1 tag(s) for file %2")
322  .arg(m_exifData.count()).arg(m_filePath));
323 
324  Exiv2::ExifData::const_iterator i;
325  for (i = m_exifData.begin(); i != m_exifData.end(); ++i)
326  {
327  QString label = QString::fromStdString(i->tagLabel());
328 
329  // Ignore empty labels
330  if (label.isEmpty())
331  continue;
332 
333  QString key = QString::fromStdString(i->key());
334 
335  // Ignore large values (binary/private tags)
336  if (i->size() >= 256)
337  {
338  LOG(VB_FILE, LOG_DEBUG, LOC +
339  QString("Ignoring %1 (%2, %3) : Too big")
340  .arg(key, i->typeName()).arg(i->size()));
341  }
342  // Ignore 'Print Image Matching'
343  else if (i->tag() == EXIF_PRINT_IMAGE_MATCHING)
344  {
345  LOG(VB_FILE, LOG_DEBUG, LOC +
346  QString("Ignoring %1 (%2, %3) : Undecodable")
347  .arg(key, i->typeName()).arg(i->size()));
348  }
349  else
350  {
351  // Use interpreted values
352  std::string val = i->print(&m_exifData);
353 
354  // Comment needs charset decoding
355  QString value = (key == EXIF_TAG_USERCOMMENT)
356  ? DecodeComment(val) : QString::fromStdString(val);
357 
358  // Nulls can arise from corrupt metadata (MakerNote)
359  // Remove them as they disrupt socket comms between BE & remote FE's
360  if (value.contains(QChar::Null))
361  {
362  LOG(VB_GENERAL, LOG_NOTICE, LOC +
363  QString("Corrupted Exif detected in %1").arg(m_filePath));
364  value = "????";
365  }
366 
367  // Encode tag
368  QString str = ToString(key, label, value);
369  tags << str;
370 
371 #ifdef DUMP_METADATA_TAGS
372  LOG(VB_FILE, LOG_DEBUG, LOC + QString("%1 (%2, %3)")
373  .arg(str, i->typeName()).arg(i->size()));
374 #endif
375  }
376  }
377  return tags;
378 }
379 
380 
388 std::string PictureMetaData::GetTag(const QString &key, bool *exists)
389 {
390  std::string value;
391  if (exists)
392  *exists = false;
393 
394  if (!IsValid())
395  return value;
396 
397  Exiv2::ExifKey exifKey = Exiv2::ExifKey(key.toStdString());
398  auto exifIt = m_exifData.findKey(exifKey);
399 
400  if (exifIt == m_exifData.end())
401  return value;
402 
403  if (exists)
404  *exists = true;
405 
406  // Use raw value
407  return exifIt->value().toString();
408 }
409 
410 
417 {
418  std::string value = GetTag(EXIF_TAG_ORIENTATION, exists);
419  return QString::fromStdString(value).toInt();
420 }
421 
422 
429 {
430  std::string value = GetTag(EXIF_TAG_DATETIME, exists);
431  QString dt = QString::fromStdString(value);
432 
433  // Exif time has no timezone
435 }
436 
437 
444 QString PictureMetaData::GetComment(bool *exists)
445 {
446  // Use User Comment or else Image Description
447  bool comExists = false;
448  bool desExists = false;
449 
450  std::string comment = GetTag(EXIF_TAG_USERCOMMENT, &comExists);
451 
452  if (comment.empty())
453  comment = GetTag(EXIF_TAG_IMAGEDESCRIPTION, &desExists);
454 
455  if (exists)
456  *exists = comExists || desExists;
457 
458  return DecodeComment(comment);
459 }
460 
461 
467 QString PictureMetaData::DecodeComment(std::string rawValue)
468 {
469  // Decode charset
470  Exiv2::CommentValue comVal = Exiv2::CommentValue(rawValue);
471  if (comVal.charsetId() != Exiv2::CommentValue::undefined)
472  rawValue = comVal.comment();
473  return QString::fromStdString(rawValue);
474 }
475 
476 
483 {
484 public:
485  explicit VideoMetaData(const QString &filePath);
486  ~VideoMetaData() override;
487 
488  bool IsValid() override // ImageMetaData
489  { return m_dict; }
490  QStringList GetAllTags() override; // ImageMetaData
491  int GetOrientation(bool *exists = nullptr) override; // ImageMetaData
492  QDateTime GetOriginalDateTime(bool *exists = nullptr) override; // ImageMetaData
493  QString GetComment(bool *exists = nullptr) override; // ImageMetaData
494 
495 protected:
496  QString GetTag(const QString &key, bool *exists = nullptr);
497 
498  AVFormatContext *m_context { nullptr };
500  AVDictionary *m_dict { nullptr };
501 };
502 
503 
508 VideoMetaData::VideoMetaData(const QString &filePath)
509  : ImageMetaData(filePath)
510 {
511  AVInputFormat* p_inputformat = nullptr;
512 
513  // Open file
514  if (avformat_open_input(&m_context, filePath.toLatin1().constData(),
515  p_inputformat, nullptr) < 0)
516  return;
517 
518  // Locate video stream
519  int vidStream = av_find_best_stream(m_context, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
520  if (vidStream >= 0)
521  m_dict = m_context->streams[vidStream]->metadata;
522 
523  if (!VideoMetaData::IsValid())
524  avformat_close_input(&m_context);
525 }
526 
527 
532 {
534  avformat_close_input(&m_context);
535 }
536 
537 
549 {
550  QStringList tags;
551  if (!IsValid())
552  return tags;
553 
554  // Only extract interesting fields:
555  // For list use: mythffprobe -show_format -show_streams <file>
556  QString cmd = GetAppBinDir() + MYTH_APPNAME_MYTHFFPROBE;
557  QStringList args;
558  args << "-loglevel quiet"
559  << "-print_format compact" // Returns "section|key=value|key=value..."
560  << "-pretty" // Add units etc
561  << "-show_entries "
562  "format=format_long_name,duration,bit_rate:format_tags:"
563  "stream=codec_long_name,codec_type,width,height,pix_fmt,color_space,avg_frame_rate"
564  ",codec_tag_string,sample_rate,channels,channel_layout,bit_rate:stream_tags"
565  << m_filePath;
566 
567  MythSystemLegacy ffprobe(cmd, args, kMSRunShell | kMSStdOut);
568 
569  ffprobe.Run(5s);
570 
571  if (ffprobe.Wait() != GENERIC_EXIT_OK)
572  {
573  LOG(VB_GENERAL, LOG_ERR, LOC +
574  QString("Timeout or Failed: %2 %3").arg(cmd, args.join(" ")));
575  return tags;
576  }
577 
578  QByteArray result = ffprobe.ReadAll();
579  QTextStream ostream(result);
580  int stream = 0;
581  while (!ostream.atEnd())
582  {
583  QStringList fields = ostream.readLine().split('|');
584 
585  if (fields.size() <= 1)
586  // Empty section
587  continue;
588 
589  // First fields should be "format" or "stream"
590  QString prefix = "";
591  QString group = fields.takeFirst();
592  if (group == "stream")
593  {
594  // Streams use index as group
595  prefix = QString::number(stream++) + ":";
596  group.append(prefix);
597  }
598 
599  for (const auto& field : qAsConst(fields))
600  {
601  // Expect label=value
602  QStringList parts = field.split('=');
603  if (parts.size() != 2)
604  continue;
605 
606  // Remove ffprobe "tag:" prefix
607  QString label = parts[0].remove("tag:");
608  QString value = parts[1];
609 
610  // Construct a pseudo-key for FFMPEG tags
611  QString key = QString("FFmpeg.%1.%2").arg(group, label);
612 
613  // Add stream id to labels
614  QString str = ToString(key, prefix + label, value);
615  tags << str;
616 
617 #ifdef DUMP_METADATA_TAGS
618  LOG(VB_FILE, LOG_DEBUG, LOC + str);
619 #endif
620  }
621  }
622  return tags;
623 }
624 
625 
632 QString VideoMetaData::GetTag(const QString &key, bool *exists)
633 {
634  if (m_dict)
635  {
636  AVDictionaryEntry *tag = nullptr;
637  while ((tag = av_dict_get(m_dict, "\0", tag, AV_DICT_IGNORE_SUFFIX)))
638  {
639  if (QString(tag->key) == key)
640  {
641  if (exists)
642  *exists = true;
643  return QString::fromUtf8(tag->value);
644  }
645  }
646  }
647  if (exists)
648  *exists = false;
649  return {};
650 }
651 
652 
659 {
660  QString angle = GetTag(FFMPEG_TAG_ORIENTATION, exists);
661  return Orientation::FromRotation(angle);
662 }
663 
664 
670 QDateTime VideoMetaData::GetOriginalDateTime(bool *exists)
671 {
672  QString dt = GetTag(FFMPEG_TAG_DATETIME, exists);
673 
674  // Video time has no timezone
676 }
677 
678 
685 QString VideoMetaData::GetComment(bool *exists)
686 {
687  if (exists)
688  *exists = false;
689  return {};
690 }
691 
692 
698 ImageMetaData* ImageMetaData::FromPicture(const QString &filePath)
699 { return new PictureMetaData(filePath); }
700 
701 
707 ImageMetaData* ImageMetaData::FromVideo(const QString &filePath)
708 { return new VideoMetaData(filePath); }
709 
710 
711 const QString ImageMetaData::kSeparator = "|-|";
712 
713 
719 ImageMetaData::TagMap ImageMetaData::ToMap(const QStringList &tagStrings)
720 {
721  TagMap tags;
722  for (const auto& token : qAsConst(tagStrings))
723  {
724  QStringList parts = FromString(token);
725  // Expect Key, Label, Value.
726  if (parts.size() == 3)
727  {
728  // Map tags by Family.Group to keep them together
729  // Within each group they will preserve list ordering
730  QString group = parts[0].section('.', 0, 1);
731  tags.insert(group, parts);
732 
733 #ifdef DUMP_METADATA_TAGS
734  LOG(VB_FILE, LOG_DEBUG, LOC + QString("%1 = %2").arg(group, token));
735 #endif
736  }
737  }
738  return tags;
739 }
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:488
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:658
LOC
#define LOC
Definition: imagemetadata.cpp:18
PictureMetaData::GetComment
QString GetComment(bool *exists=nullptr) override
Read Exif comments from metadata.
Definition: imagemetadata.cpp:444
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:37
vals
static float * vals
Definition: tentacle3d.cpp:18
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:508
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:11
VideoMetaData::GetOriginalDateTime
QDateTime GetOriginalDateTime(bool *exists=nullptr) override
Read video datestamp.
Definition: imagemetadata.cpp:670
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:707
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:416
PictureMetaData::GetOriginalDateTime
QDateTime GetOriginalDateTime(bool *exists=nullptr) override
Read Exif timestamp of image capture.
Definition: imagemetadata.cpp:428
VideoMetaData::m_context
AVFormatContext * m_context
Definition: imagemetadata.cpp:498
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:388
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:531
PictureMetaData::m_image
Exiv2::Image::UniquePtr m_image
Definition: imagemetadata.cpp:276
PictureMetaData::GetAllTags
QStringList GetAllTags() override
Returns all metadata tags.
Definition: imagemetadata.cpp:315
ImageMetaData::ToMap
static TagMap ToMap(const QStringList &tags)
Creates a map of metadata tags as.
Definition: imagemetadata.cpp:719
ImageMetaData::FromPicture
static ImageMetaData * FromPicture(const QString &filePath)
Factory to retrieve metadata from pictures.
Definition: imagemetadata.cpp:698
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:467
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:34
VideoMetaData::GetTag
QString GetTag(const QString &key, bool *exists=nullptr)
Read a single video tag.
Definition: imagemetadata.cpp:632
VideoMetaData::GetAllTags
QStringList GetAllTags() override
Reads relevant video metadata by running mythffprobe.
Definition: imagemetadata.cpp:548
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
kFlipVertical
@ kFlipVertical
Reflect about horizontal axis.
Definition: imagemetadata.h:51
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
kRotateCW
@ kRotateCW
Rotate clockwise.
Definition: imagemetadata.h:48
ImageMetaData::kSeparator
static const QString kSeparator
Unique separator to delimit fields within a string.
Definition: imagemetadata.h:109
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:685
Orientation::InitOrientationMatrix
static Matrix InitOrientationMatrix()
Initialises conversion matrix for Qt 5.4.1.
Definition: imagemetadata.cpp:38
GetAppBinDir
QString GetAppBinDir(void)
Definition: mythdirs.cpp:253
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:482
PictureMetaData::~PictureMetaData
~PictureMetaData() override=default
kFlipHorizontal
@ kFlipHorizontal
Reflect about vertical axis.
Definition: imagemetadata.h:50
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
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
kResetToExif
@ kResetToExif
Reset to Exif value.
Definition: imagemetadata.h:47
kRotateCCW
@ kRotateCCW
Rotate anti-clockwise.
Definition: imagemetadata.h:49
VideoMetaData::m_dict
AVDictionary * m_dict
FFmpeg tag dictionary.
Definition: imagemetadata.cpp:500