Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lp1445885: Fix handling of files with wrong suffix #4615

Merged
merged 26 commits into from
Jan 25, 2022

Conversation

daschuer
Copy link
Member

This continues the closed #4608 from @uklotzde

I have implemented now the solution with a s_fileTypeByMimeType QHash.

We have now a strong 1 to n relationship where one FileType is a replacement for n MimeTypes.

Unfortunately this did not work for opus files, because they are detected as audio/ogg I have added a spacial case for opus files.

I have also removed the space is the getTypeFromMissingFile test, because QT does not detect such files. I consider this case as to exotic to not use the QMemeTypeDatabase for this.

Existing files with spaces are working.

const QString fileSuffix = fileInfo.suffix().toLower().trimmed();

if (fileSuffix == "opus") {
// opus has mime type "audio/ogg" which will be decoded with the SoundSourceOggVobis()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is because "ogg" is a container and "vorbis" is the compression algorithm.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the OGG container can include Speex, Vorbis, Opus, FLAC, OggPCM.
The Ogg magic numbers are:
OggS...........v.....v......vorbis is Vorbis
OggS.............l..........Opus is Opus

fLaC..."is the magic number for native FLAC. I think we do not support Ogg FLAC which will probably also start with OggS

Copy link
Member

@ywwg ywwg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is an improvement so I'm approving it. But I think much like the old code assumed "file extension == codec", this code assumes "mimetype == codec", which is not the case, which is why there is the hacks needed with vorbis vs opus. I would prefer a cleaner solution that first detects the mimetype, and then supports multiple compression algorithms for the ogg mimetype.

if (fileType == "opus") {
// opus has mime type "audio/ogg" which will be decoded with the SoundSourceOggVobis()
// but we want SoundSourceOpus()
return {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems a little hacky, is there a way we can detect files as audio/ogg and then later decide if they are vorbis or opus? It's not a bug that opus shows up as an ogg mimetype, it's just that mimetype is not sufficient to determine the codec, much like .avi can contain many codecs. (https://datatracker.ietf.org/doc/html/rfc7845)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may create a joint sound source for opus and vorbis files. Here we just work around the limitation of QMimeDatabase() because we currently need both, the mime type + the extension to select the soundsource.

@daschuer
Copy link
Member Author

Currently we rely on the correct file extension in case of "audio/ogg" files. I can imagine to open the file ourselves and check the stream content. Is this the type of cleaner solution you have in mind?

While it would be correct to have a file type vorbis and a file type opus, I think this may confuse users, because ogg vorbis files are called "ogg" files.

What do you think?

@ywwg
Copy link
Member

ywwg commented Jan 16, 2022

Yeah I see. My preference would be to avoid the hack where we say that the opus filetype has no mimetype (in mimeTypesForFileType). This means that the function is broken by design, and code elsewhere needs to understand what to do because of that hack. I'd prefer mimeTypesForFileType return the correct values and the correction be done elsewhere (in registerProviders for instance)

@daschuer
Copy link
Member Author

mimeTypesForFileType returns now "audio/x-opus+ogg" even though the lookup is bypassed. This would be a prerequisite if we decide to implement our own magic number lookup.
Such a lookup would help to detect opus files with a wrong suffix.

@JoergAtGithub
Copy link
Member

How is this done for other container formats like .wav ?
I'm guess that Mixxx doesn't support all codecs supported by .wav:
https://de.wikipedia.org/wiki/RIFF_WAVE#Datenformate_(Format-Tag)

@daschuer
Copy link
Member Author

RIFF....WAVEfmt is the normal magic number for *.wav files. Files without a known magic number are detected by their extension. As long they have a *.wav extension, they are passed to SoundSourceSndFile() and are played.

This is for example the case for RF46 wav files which are not in the magic number database RF64....WAVEds64 but can be still played with the recommended *.wav extension.

Copy link
Member

@ywwg ywwg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for the fix

@Holzhaus
Copy link
Member

There are conflicts now

@daschuer
Copy link
Member Author

Conflicts resolved.

Copy link
Contributor

@uklotzde uklotzde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Could be merged as is, only some minor remarks.

I just noticed that we could use QLatin1String instead of QStringLiteral at many places, especially for comparisons. Qt's string handling with their internal UTF-16 encoding adopted from Java is super inconvenient and confusing. It causes a lot of boilerplate code with the risk for inconsistencies due to the implicit overloads.

const QMimeType mimeType = QMimeDatabase().mimeTypeForFile(
const QString fileSuffix = fileInfo.suffix().toLower().trimmed();

if (fileSuffix == "opus") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit-pick: QLatin1String("opus")?

QString provides many QLatin1String overloads as I only recently noticed.

}
static const QStringList& getSupportedFileNamePatterns() {
return s_supportedFileNamePatterns;
}
static const QRegularExpression& getSupportedFileNamesRegex() {
return s_supportedFileNamesRegex;
}
static QString getFileTypeByMimeType(const QMimeType& mimeType) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming of the function and member variable is slightly inconsistent with getFileSuffixesForFileType(). It shouldn't matter that one returns a single item while the other returns multiple items.

if (supportedFileExtension.startsWith(QStringLiteral("aif")) ||
supportedFileExtension == QLatin1String("wav")) {
const QString& supportedFileType) const {
if (supportedFileType.startsWith(QStringLiteral("aif")) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already inconsistent in existing code: We should use either QStringLiteral or QLatin1String. Preferably the latter if it suffices.

@daschuer
Copy link
Member Author

Done!

Copy link
Contributor

@uklotzde uklotzde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Waiting for CI checks to succeed.

@uklotzde uklotzde merged commit b0a7c9e into mixxxdj:main Jan 25, 2022
@daschuer daschuer deleted the soundsource-file-type branch April 14, 2022 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants