MythTV  master
metaiomp4.cpp
Go to the documentation of this file.
1 
2 // Libav*
3 extern "C" {
4 #include <libavformat/avformat.h>
5 #include <libavcodec/avcodec.h>
6 }
7 
8 // libmythmetadata
9 #include "metaiomp4.h"
10 #include "musicmetadata.h"
11 
12 // mythtv
13 #include "libmyth/mythcontext.h"
15 
19 bool MetaIOMP4::write(const QString &filename, MusicMetadata* mdata)
20 {
21  if (!mdata)
22  return false;
23 
24  if (filename.isEmpty())
25  return false;
26 
27 // Disabled because it doesn't actually work. Better implemented with Taglib
28 // when we formally move to 1.6
29 
30 // AVFormatContext* p_context = nullptr;
31 // AVFormatParameters* p_params = nullptr;
32 // AVInputFormat* p_inputformat = nullptr;
33 //
34 // QByteArray local8bit = filename.toLocal8Bit();
35 // if ((av_open_input_file(&p_context, local8bit.constData(),
36 // p_inputformat, 0, p_params) < 0))
37 // {
38 // return nullptr;
39 // }
40 //
41 // if (av_find_stream_info(p_context) < 0)
42 // return nullptr;
43 //
44 // QByteArray artist = mdata->Artist().toUtf8();
45 // QByteArray album = mdata->Album().toUtf8();
46 // QByteArray title = mdata->Title().toUtf8();
47 // QByteArray genre = mdata->Genre().toUtf8();
48 // QByteArray date = QString::number(mdata->Year()).toUtf8();
49 // QByteArray track = QString::number(mdata->Track()).toUtf8();
50 // QByteArray comp = QString(mdata->Compilation() ? "1" : "0").toUtf8();
51 //
52 // AVMetadata* avmetadata = p_context->metadata;
53 //
54 // av_metadata_set(&avmetadata, "author", artist.constData());
55 // av_metadata_set(&avmetadata, "album", album.constData());
56 // av_metadata_set(&avmetadata, "title", title.constData());
57 // av_metadata_set(&avmetadata, "genre", genre.constData());
58 // av_metadata_set(&avmetadata, "year", date.constData());
59 // av_metadata_set(&avmetadata, "track", track.constData());
60 // av_metadata_set(&avmetadata, "compilation", comp.constData());
61 //
62 // av_close_input_file(p_context);
63 
64  return true;
65 }
66 
71 {
72  QString title;
73  QString artist;
74  QString album;
75  QString genre;
76  int year = 0;
77  int tracknum = 0;
78  std::chrono::milliseconds length = 0ms;
79  bool compilation = false;
80 
81  AVFormatContext* p_context = nullptr;
82  AVInputFormat* p_inputformat = nullptr;
83 
84  QByteArray local8bit = filename.toLocal8Bit();
85  if ((avformat_open_input(&p_context, local8bit.constData(),
86  p_inputformat, nullptr) < 0))
87  {
88  return nullptr;
89  }
90 
91  if (avformat_find_stream_info(p_context, nullptr) < 0)
92  return nullptr;
93 
94 #if 0
95  //### Debugging, enable to dump a list of all field names/values found
96 
97  AVDictionaryEntry *tag = av_dict_get(p_context->metadata, "\0", nullptr,
98  AV_METADATA_IGNORE_SUFFIX);
99  while (tag != nullptr)
100  {
101  LOG(VB_GENERAL, LOG_DEBUG, QString("Tag: %1 Value: %2")
102  .arg(tag->key) .arg(QString::fromUtf8(tag->value)));
103  tag = av_dict_get(p_context->metadata, "\0", tag,
104  AV_METADATA_IGNORE_SUFFIX);
105  }
106  //####
107 #endif
108 
109  title = getFieldValue(p_context, "title");
110  if (title.isEmpty())
111  {
112  readFromFilename(filename, artist, album, title, genre, tracknum);
113  }
114  else
115  {
116  title = getFieldValue(p_context, "title");
117  artist = getFieldValue(p_context, "author");
118  // Author is the correct fieldname, but
119  // we've been saving to artist for years
120  if (artist.isEmpty())
121  artist = getFieldValue(p_context, "artist");
122  album = getFieldValue(p_context, "album");
123  year = getFieldValue(p_context, "year").toInt();
124  genre = getFieldValue(p_context, "genre");
125  tracknum = getFieldValue(p_context, "track").toInt();
126  compilation = (getFieldValue(p_context, "").toInt() != 0);
127  length = duration_cast<std::chrono::milliseconds>(av_duration(p_context->duration));
128  }
129 
130  metadataSanityCheck(&artist, &album, &title, &genre);
131 
132  auto *retdata = new MusicMetadata(filename, artist,
133  compilation ? artist : "",
134  album, title, genre, year,
135  tracknum, length);
136 
137  retdata->setCompilation(compilation);
138 
139  avformat_close_input(&p_context);
140 
141  return retdata;
142 }
143 
151 QString MetaIOMP4::getFieldValue(AVFormatContext* context, const char* tagname)
152 {
153  AVDictionaryEntry *tag = av_dict_get(context->metadata, tagname, nullptr, 0);
154 
155  QString value;
156 
157  if (tag)
158  value = QString::fromUtf8(tag->value);
159 
160  return value;
161 }
162 
169 std::chrono::milliseconds MetaIOMP4::getTrackLength(const QString &filename)
170 {
171  AVFormatContext* p_context = nullptr;
172  AVInputFormat* p_inputformat = nullptr;
173 
174  // Open the specified file and populate the metadata info
175  QByteArray local8bit = filename.toLocal8Bit();
176  if ((avformat_open_input(&p_context, local8bit.constData(),
177  p_inputformat, nullptr) < 0))
178  {
179  return 0ms;
180  }
181 
182  if (avformat_find_stream_info(p_context, nullptr) < 0)
183  return 0ms;
184 
185  std::chrono::milliseconds rv =
186  duration_cast<std::chrono::milliseconds>(av_duration(p_context->duration));
187 
188  avformat_close_input(&p_context);
189 
190  return rv;
191 }
192 
201 void MetaIOMP4::metadataSanityCheck(QString *artist, QString *album,
202  QString *title, QString *genre)
203 {
204  if (artist->isEmpty())
205  artist->append("Unknown Artist");
206 
207  if (album->isEmpty())
208  album->append("Unknown Album");
209 
210  if (title->isEmpty())
211  title->append("Unknown Title");
212 
213  if (genre->isEmpty())
214  genre->append("Unknown Genre");
215 }
MetaIOMP4::getTrackLength
std::chrono::milliseconds getTrackLength(const QString &filename) override
Find the length of the track (in milliseconds)
Definition: metaiomp4.cpp:169
MetaIOMP4::write
bool write(const QString &filename, MusicMetadata *mdata) override
Writes all metadata back to a file.
Definition: metaiomp4.cpp:19
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MetaIOMP4::getFieldValue
static QString getFieldValue(AVFormatContext *context, const char *tagname)
Retrieve the value of a named metadata field.
Definition: metaiomp4.cpp:151
MusicMetadata
Definition: musicmetadata.h:80
MetaIO::readFromFilename
void readFromFilename(const QString &filename, QString &artist, QString &album, QString &title, QString &genre, int &tracknum)
Reads MusicMetadata based on the folder/filename.
Definition: metaio.cpp:95
mythlogging.h
MetaIOMP4::metadataSanityCheck
static void metadataSanityCheck(QString *artist, QString *album, QString *title, QString *genre)
Replace any empty strings in extracted metadata with sane defaults.
Definition: metaiomp4.cpp:201
MetaIOMP4::read
MusicMetadata * read(const QString &filename) override
Reads MusicMetadata from a file.
Definition: metaiomp4.cpp:70
mythcontext.h
metaiomp4.h
build_compdb.filename
filename
Definition: build_compdb.py:21
musicmetadata.h