MythTV  master
imagemetadata.cpp
Go to the documentation of this file.
1 #include "imagemetadata.h"
2 
3 #include "mythlogging.h"
4 #include "mythcorecontext.h" // for avcodeclock
5 #include "mythdirs.h" // for ffprobe
6 #include "mythsystemlegacy.h" // for ffprobe
7 #include "exitcodes.h" // for ffprobe
8 
9 // libexiv2 for Exif metadata
10 #include <exiv2/exiv2.hpp>
11 
12 // To read FFMPEG Metadata
13 extern "C" {
14 #include "libavformat/avformat.h"
15 }
16 
17 // Uncomment this to log raw metadata from exif/ffmpeg
18 //#define DUMP_METADATA_TAGS yes
19 
20 #define LOC QString("ImageMetaData: ")
21 
22 
28 int Orientation::Transform(int transform)
29 {
30  m_current = Apply(transform);
31  return Composite();
32 }
33 
34 
41 {
42  Orientation::Matrix matrix;
43 
44  if (krunningQt541)
45  {
46  // Each row/string defines codes for a single file orientation
47  // Each col/value defines applicable code for corresponding current orientation
48  // As current orientation is applicable to raw camera image, these codes
49  // define the current orientation relative to 1/Normal (as Qt 5.4.1 has already
50  // applied the file orientation)
51  QStringList vals = QStringList()
52  << "0 1 2 3 4 5 6 7 8"
53  << "0 1 2 3 4 5 6 7 8"
54  << "0 2 1 4 3 8 7 6 5"
55  << "0 3 4 1 2 7 8 5 6"
56  << "0 4 3 2 1 6 5 8 7"
57  << "0 5 6 7 8 1 2 3 4"
58  << "0 8 7 6 5 2 1 4 3"
59  << "0 7 8 5 6 3 4 1 2"
60  << "0 6 5 8 7 4 3 2 1";
61 
62  for (int row = 0; row < vals.size(); ++row)
63  {
64  QStringList rowVals = vals.at(row).split(' ');
65  for (int col = 0; col < rowVals.size(); ++col)
66  matrix[row][col] = rowVals.at(col).toInt();
67  }
68  }
69  return matrix;
70 }
71 
72 const bool Orientation::krunningQt541 = (strcmp(qVersion(), "5.4.1") == 0);
75 
76 
85 int Orientation::GetCurrent(bool compensate)
86 {
87  // Qt 5.4.1 automatically applies the file orientation when loading images
88  // Ref: https://codereview.qt-project.org/#/c/111398/
89  // Ref: https://codereview.qt-project.org/#/c/110685/
90  // https://bugreports.qt.io/browse/QTBUG-37946
91  if (compensate && krunningQt541)
92  {
93  // Deduce orientation relative to 1/Normal from file & current orientations
94  int old = m_current;
96 
97  LOG(VB_FILE, LOG_DEBUG, LOC +
98  QString("Adjusted orientation %1 to %2 for Qt 5.4.1")
99  .arg(old).arg(m_current));
100  }
101  return m_current;
102 }
103 
104 
114 int Orientation::Apply(int transform) const
115 {
116  if (transform == kResetToExif)
117  return m_file;
118 
119  // https://github.com/recurser/exif-orientation-examples is a useful resource.
120  switch (m_current)
121  {
122  case 0: // The image has no orientation info
123  case 1: // The image is in its original state
124  switch (transform)
125  {
126  case kRotateCW: return 6;
127  case kRotateCCW: return 8;
128  case kFlipHorizontal: return 2;
129  case kFlipVertical: return 4;
130  }
131  break;
132 
133  case 2: // The image is horizontally flipped
134  switch (transform)
135  {
136  case kRotateCW: return 7;
137  case kRotateCCW: return 5;
138  case kFlipHorizontal: return 1;
139  case kFlipVertical: return 3;
140  }
141  break;
142 
143  case 3: // The image is rotated 180°
144  switch (transform)
145  {
146  case kRotateCW: return 8;
147  case kRotateCCW: return 6;
148  case kFlipHorizontal: return 4;
149  case kFlipVertical: return 2;
150  }
151  break;
152 
153  case 4: // The image is vertically flipped
154  switch (transform)
155  {
156  case kRotateCW: return 5;
157  case kRotateCCW: return 7;
158  case kFlipHorizontal: return 3;
159  case kFlipVertical: return 1;
160  }
161  break;
162 
163  case 5: // The image is rotated 90° CW and flipped horizontally
164  switch (transform)
165  {
166  case kRotateCW: return 2;
167  case kRotateCCW: return 4;
168  case kFlipHorizontal: return 6;
169  case kFlipVertical: return 8;
170  }
171  break;
172 
173  case 6: // The image is rotated 90° CCW
174  switch (transform)
175  {
176  case kRotateCW: return 3;
177  case kRotateCCW: return 1;
178  case kFlipHorizontal: return 5;
179  case kFlipVertical: return 7;
180  }
181  break;
182 
183  case 7: // The image is rotated 90° CW and flipped vertically
184  switch (transform)
185  {
186  case kRotateCW: return 4;
187  case kRotateCCW: return 2;
188  case kFlipHorizontal: return 8;
189  case kFlipVertical: return 6;
190  }
191  break;
192 
193  case 8: // The image is rotated 90° CW
194  switch (transform)
195  {
196  case kRotateCW: return 1;
197  case kRotateCCW: return 3;
198  case kFlipHorizontal: return 7;
199  case kFlipVertical: return 5;
200  }
201  break;
202  }
203  return m_current;
204 }
205 
206 
212 int Orientation::FromRotation(const QString &degrees)
213 {
214  if (degrees == "0") return 1;
215  if (degrees == "90") return 6;
216  if (degrees == "180") return 3;
217  if (degrees == "270") return 8;
218  return 0;
219 }
220 
221 
229 {
230  return (m_file == m_current)
231  ? AsText(m_file)
232  : tr("File: %1, Db: %2").arg(AsText(m_file),
233  AsText(m_current));
234 }
235 
236 
242 QString Orientation::AsText(int orientation)
243 {
244  switch (orientation)
245  {
246  case 1: return tr("1 (Normal)");
247  case 2: return tr("2 (H Mirror)");
248  case 3: return tr("3 (Rotate 180°)");
249  case 4: return tr("4 (V Mirror)");
250  case 5: return tr("5 (H Mirror, Rot 270°)");
251  case 6: return tr("6 (Rotate 90°)");
252  case 7: return tr("7 (H Mirror, Rot 90°)");
253  case 8: return tr("8 (Rotate 270°)");
254  default: return tr("%1 (Undefined)").arg(orientation);
255  }
256 }
257 
258 
261 {
262 public:
263  explicit PictureMetaData(const QString &filePath);
264  ~PictureMetaData() override = default; // libexiv2 closes file, cleans up via autoptrs
265 
266  bool IsValid() override // ImageMetaData
267  { return m_image.get(); }
268  QStringList GetAllTags() override; // ImageMetaData
269  int GetOrientation(bool *exists = nullptr) override; // ImageMetaData
270  QDateTime GetOriginalDateTime(bool *exists = nullptr) override; // ImageMetaData
271  QString GetComment(bool *exists = nullptr) override; // ImageMetaData
272 
273 protected:
274  static QString DecodeComment(std::string rawValue);
275 
276  std::string GetTag(const QString &key, bool *exists = nullptr);
277 
278  Exiv2::Image::UniquePtr m_image;
279  Exiv2::ExifData m_exifData;
280 };
281 
282 
287 PictureMetaData::PictureMetaData(const QString &filePath)
288  : ImageMetaData(filePath), m_image(nullptr)
289 {
290  try
291  {
292  m_image = Exiv2::ImageFactory::open(filePath.toStdString());
293 
295  {
296  m_image->readMetadata();
297  m_exifData = m_image->exifData();
298  }
299  else
300  LOG(VB_GENERAL, LOG_ERR, LOC +
301  QString("Exiv2 error: Could not open file %1").arg(filePath));
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 
446 QString PictureMetaData::GetComment(bool *exists)
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;
502  AVDictionary *m_dict;
503 };
504 
505 
510 VideoMetaData::VideoMetaData(const QString &filePath)
511  : ImageMetaData(filePath), m_context(nullptr), m_dict(nullptr)
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(5);
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 : qAsConst(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 QString();
652 }
653 
654 
661 {
662  QString angle = GetTag(FFMPEG_TAG_ORIENTATION, exists);
663  return Orientation::FromRotation(angle);
664 }
665 
666 
672 QDateTime VideoMetaData::GetOriginalDateTime(bool *exists)
673 {
674  QString dt = GetTag(FFMPEG_TAG_DATETIME, exists);
675 
676  // Video time has no timezone
678 }
679 
680 
687 QString VideoMetaData::GetComment(bool *exists)
688 {
689  if (exists)
690  *exists = false;
691  return QString();
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 : qAsConst(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 }
FFMPEG_TAG_DATETIME
#define FFMPEG_TAG_DATETIME
Definition: imagemetadata.h:34
build_compdb.args
args
Definition: build_compdb.py:11
Orientation::Matrix
QHash< int, QHash< int, int > > Matrix
Definition: imagemetadata.h:83
e
QDomElement e
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1420
GENERIC_EXIT_OK
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
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:266
VideoMetaData::IsValid
bool IsValid() override
Definition: imagemetadata.cpp:490
MythSystemLegacy
Definition: mythsystemlegacy.h:68
EXIF_PRINT_IMAGE_MATCHING
#define EXIF_PRINT_IMAGE_MATCHING
Definition: imagemetadata.h:30
ImageMetaData
Abstract class for image metadata.
Definition: imagemetadata.h:100
VideoMetaData::GetOrientation
int GetOrientation(bool *exists=nullptr) override
Read FFmpeg video orientation tag.
Definition: imagemetadata.cpp:660
LOC
#define LOC
Definition: imagemetadata.cpp:20
arg
arg(title).arg(filename).arg(doDelete))
PictureMetaData::GetComment
QString GetComment(bool *exists=nullptr) override
Read Exif comments from metadata.
Definition: imagemetadata.cpp:446
Orientation::FromRotation
static int FromRotation(const QString &degrees)
Convert degrees of rotation into Exif orientation code.
Definition: imagemetadata.cpp:212
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythSystemLegacy::ReadAll
QByteArray & ReadAll()
Definition: mythsystemlegacy.cpp:397
vals
static float * vals
Definition: tentacle3d.cpp:18
MythSystemLegacy::Run
void Run(time_t timeout=0)
Runs a command inside the /bin/sh shell. Returns immediately.
Definition: mythsystemlegacy.cpp:212
mythdirs.h
VideoMetaData::VideoMetaData
VideoMetaData(const QString &filePath)
Constructor. Opens best video stream from video.
Definition: imagemetadata.cpp:510
EXIF_TAG_ORIENTATION
#define EXIF_TAG_ORIENTATION
Definition: imagemetadata.h:25
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:85
mythsystemlegacy.h
PictureMetaData::PictureMetaData
PictureMetaData(const QString &filePath)
Constructor. Reads metadata from image.
Definition: imagemetadata.cpp:287
EXIF_TAG_USERCOMMENT
#define EXIF_TAG_USERCOMMENT
Definition: imagemetadata.h:29
Orientation::Transform
int Transform(int transform)
Adjust orientation to apply a transform to an image.
Definition: imagemetadata.cpp:28
PictureMetaData::m_exifData
Exiv2::ExifData m_exifData
Definition: imagemetadata.cpp:279
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
mythlogging.h
PictureMetaData::GetOriginalDateTime
QDateTime GetOriginalDateTime(bool *exists=nullptr) override
Read Exif timestamp of image capture.
Definition: imagemetadata.cpp:430
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
EXIF_TAG_IMAGEDESCRIPTION
#define EXIF_TAG_IMAGEDESCRIPTION
Definition: imagemetadata.h:28
Orientation::Description
QString Description() const
Generate text description of orientation.
Definition: imagemetadata.cpp:228
VideoMetaData::~VideoMetaData
~VideoMetaData() override
Destructor. Closes file.
Definition: imagemetadata.cpp:533
PictureMetaData::m_image
Exiv2::Image::UniquePtr m_image
Definition: imagemetadata.cpp:278
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
token
return token
Definition: musicutils.cpp:74
PictureMetaData
Reads Exif metadata from a picture using libexiv2.
Definition: imagemetadata.cpp:261
kMSRunShell
@ kMSRunShell
run process through shell
Definition: mythsystem.h:41
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:30
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
MYTH_APPNAME_MYTHFFPROBE
#define MYTH_APPNAME_MYTHFFPROBE
Definition: mythcorecontext.h:35
Orientation::Apply
int Apply(int transform) const
Adjust current orientation code to apply a transform to an image.
Definition: imagemetadata.cpp:114
Orientation::AsText
static QString AsText(int orientation)
Converts orientation code to text description for info display.
Definition: imagemetadata.cpp:242
kFlipVertical
@ kFlipVertical
Reflect about horizontal axis.
Definition: imagemetadata.h:51
EXIF_TAG_DATE_FORMAT
#define EXIF_TAG_DATE_FORMAT
Definition: imagemetadata.h:27
mythcorecontext.h
Orientation::kQt541_orientation
static const Matrix kQt541_orientation
Orientation conversions for proper display on Qt 5.4.1.
Definition: imagemetadata.h:88
FFMPEG_TAG_ORIENTATION
#define FFMPEG_TAG_ORIENTATION
Definition: imagemetadata.h:33
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:687
Orientation::InitOrientationMatrix
static Matrix InitOrientationMatrix()
Initialises conversion matrix for Qt 5.4.1.
Definition: imagemetadata.cpp:40
GetAppBinDir
QString GetAppBinDir(void)
Definition: mythdirs.cpp:221
FFMPEG_TAG_DATE_FORMAT
#define 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:485
PictureMetaData::~PictureMetaData
~PictureMetaData() override=default
kFlipHorizontal
@ kFlipHorizontal
Reflect about vertical axis.
Definition: imagemetadata.h:50
exitcodes.h
kMSStdOut
@ kMSStdOut
allow access to stdout
Definition: mythsystem.h:39
EXIF_TAG_DATETIME
#define EXIF_TAG_DATETIME
Definition: imagemetadata.h:26
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
MythSystemLegacy::Wait
uint Wait(time_t timeout=0)
Definition: mythsystemlegacy.cpp:242
kRotateCCW
@ kRotateCCW
Rotate anti-clockwise.
Definition: imagemetadata.h:49
VideoMetaData::m_dict
AVDictionary * m_dict
FFmpeg tag dictionary.
Definition: imagemetadata.cpp:502