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