File indexing completed on 2024-05-19 04:56:30

0001 /**
0002  * \file m4afile.h
0003  * Handling of MPEG-4 audio files.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 25 Oct 2007
0008  *
0009  * Copyright (C) 2007-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #pragma once
0028 
0029 #include "taggedfile.h"
0030 #include <QMap>
0031 
0032 /** MPEG-4 audio file */
0033 class M4aFile : public TaggedFile {
0034 public:
0035   /**
0036    * Constructor.
0037    *
0038    * @param idx index in tagged file system model
0039    */
0040   explicit M4aFile(const QPersistentModelIndex& idx);
0041 
0042   /**
0043    * Destructor.
0044    */
0045   ~M4aFile() override = default;
0046 
0047   /**
0048    * Get key of tagged file format.
0049    * @return "Mp4v2Metadata".
0050    */
0051   QString taggedFileKey() const override;
0052 
0053   /**
0054    * Read tags from file.
0055    *
0056    * @param force true to force reading even if tags were already read.
0057    */
0058   void readTags(bool force) override;
0059 
0060   /**
0061    * Write tags to file and rename it if necessary.
0062    *
0063    * @param force   true to force writing even if file was not changed.
0064    * @param renamed will be set to true if the file was renamed,
0065    *                i.e. the file name is no longer valid, else *renamed
0066    *                is left unchanged
0067    * @param preserve true to preserve file time stamps
0068    *
0069    * @return true if ok, false if the file could not be written or renamed.
0070    */
0071   bool writeTags(bool force, bool* renamed, bool preserve) override;
0072 
0073   /**
0074    * Free resources allocated when calling readTags().
0075    *
0076    * @param force true to force clearing even if the tags are modified
0077    */
0078   void clearTags(bool force) override;
0079 
0080   /**
0081    * Remove frames.
0082    *
0083    * @param tagNr tag number
0084    * @param flt filter specifying which frames to remove
0085    */
0086   void deleteFrames(Frame::TagNumber tagNr, const FrameFilter& flt) override;
0087 
0088   /**
0089    * Check if tag information has already been read.
0090    *
0091    * @return true if information is available,
0092    *         false if the tags have not been read yet, in which case
0093    *         hasTag() does not return meaningful information.
0094    */
0095   bool isTagInformationRead() const override;
0096 
0097   /**
0098    * Check if file has a tag.
0099    *
0100    * @param tagNr tag number
0101    * @return true if a V2 tag is available.
0102    * @see isTagInformationRead()
0103    */
0104   bool hasTag(Frame::TagNumber tagNr) const override;
0105 
0106   /**
0107    * Get technical detail information.
0108    *
0109    * @param info the detail information is returned here
0110    */
0111   void getDetailInfo(DetailInfo& info) const override;
0112 
0113   /**
0114    * Get duration of file.
0115    *
0116    * @return duration in seconds,
0117    *         0 if unknown.
0118    */
0119   unsigned getDuration() const override;
0120 
0121   /**
0122    * Get file extension including the dot.
0123    *
0124    * @return file extension ".m4a".
0125    */
0126   QString getFileExtension() const override;
0127 
0128   /**
0129    * Get the format of tag.
0130    *
0131    * @param tagNr tag number
0132    * @return "Vorbis".
0133    */
0134   QString getTagFormat(Frame::TagNumber tagNr) const override;
0135 
0136   /**
0137    * Get a specific frame from the tags.
0138    *
0139    * @param tagNr tag number
0140    * @param type  frame type
0141    * @param frame the frame is returned here
0142    *
0143    * @return true if ok.
0144    */
0145   bool getFrame(Frame::TagNumber tagNr, Frame::Type type, Frame& frame) const override;
0146 
0147   /**
0148    * Set a frame in the tags.
0149    *
0150    * @param tagNr tag number
0151    * @param frame frame to set
0152    *
0153    * @return true if ok.
0154    */
0155   bool setFrame(Frame::TagNumber tagNr, const Frame& frame) override;
0156 
0157   /**
0158    * Add a frame in the tags.
0159    *
0160    * @param tagNr tag number
0161    * @param frame frame to add
0162    *
0163    * @return true if ok.
0164    */
0165   bool addFrame(Frame::TagNumber tagNr, Frame& frame) override;
0166 
0167   /**
0168    * Delete a frame from the tags.
0169    *
0170    * @param tagNr tag number
0171    * @param frame frame to delete.
0172    *
0173    * @return true if ok.
0174    */
0175   bool deleteFrame(Frame::TagNumber tagNr, const Frame& frame) override;
0176 
0177   /**
0178    * Get all frames in tag.
0179    *
0180    * @param tagNr tag number
0181    * @param frames frame collection to set.
0182    */
0183   void getAllFrames(Frame::TagNumber tagNr, FrameCollection& frames) override;
0184 
0185   /**
0186    * Get a list of frame IDs which can be added.
0187    * @param tagNr tag number
0188    * @return list with frame IDs.
0189    */
0190   QStringList getFrameIds(Frame::TagNumber tagNr) const override;
0191 
0192 private:
0193   M4aFile(const M4aFile&);
0194   M4aFile& operator=(const M4aFile&);
0195 
0196   /**
0197    * Get metadata field as string.
0198    *
0199    * @param name field name
0200    *
0201    * @return value as string, "" if not found,
0202    *         QString::null if the tags have not been read yet.
0203    */
0204   QString getTextField(const QString& name) const;
0205 
0206   /**
0207    * Set text field.
0208    * If value is null if the tags have not been read yet, nothing is changed.
0209    * If value is different from the current value, tag 2 is marked as changed.
0210    *
0211    * @param name name
0212    * @param value value, "" to remove, QString::null to do nothing
0213    * @param type frame type
0214    */
0215   void setTextField(const QString& name, const QString& value,
0216                     const Frame::ExtendedType& type);
0217 
0218   /** true if file has been read. */
0219   bool m_fileRead;
0220 
0221   /** Information about MPEG-4 file. */
0222   struct FileInfo {
0223     /**
0224      * Constructor.
0225      */
0226     FileInfo() : valid(false), channels(0), sampleRate(0), bitrate(0),
0227                  duration(0) {}
0228 
0229     /**
0230      * Read information about an MPEG-4 file.
0231      * @param handle MP4 handle
0232      * @return true if ok.
0233      */
0234     bool read(void* handle);
0235 
0236     bool valid;      /**< true if read() was successful */
0237     int channels;    /**< number of channels */
0238     long sampleRate; /**< sample rate in Hz */
0239     long bitrate;    /**< bitrate in bits/s */
0240     long duration;   /**< duration in seconds */
0241   };
0242 
0243   /** Info about file. */
0244   FileInfo m_fileInfo;
0245 
0246   /** Map with metadata. */
0247   typedef QMap<QString, QByteArray> MetadataMap;
0248 
0249   /** Metadata. */
0250   MetadataMap m_metadata;
0251   QList<Frame> m_extraFrames;
0252 };