Add M4A to files pattern
[someplayer] / src / taglib / mp4 / mp4properties.cpp
1 /**************************************************************************
2     copyright            : (C) 2007 by Lukáš Lalinský
3     email                : lalinsky@gmail.com
4  **************************************************************************/
5
6 /***************************************************************************
7  *   This library is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU Lesser General Public License version   *
9  *   2.1 as published by the Free Software Foundation.                     *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful, but   *
12  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14  *   Lesser General Public License for more details.                       *
15  *                                                                         *
16  *   You should have received a copy of the GNU Lesser General Public      *
17  *   License along with this library; if not, write to the Free Software   *
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
19  *   USA                                                                   *
20  *                                                                         *
21  *   Alternatively, this file is available under the Mozilla Public        *
22  *   License Version 1.1.  You may obtain a copy of the License at         *
23  *   http://www.mozilla.org/MPL/                                           *
24  ***************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <tdebug.h>
31 #include <tstring.h>
32 #include "mp4file.h"
33 #include "mp4atom.h"
34 #include "mp4properties.h"
35
36 using namespace TagLib;
37
38 class MP4::Properties::PropertiesPrivate
39 {
40 public:
41   PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), bitsPerSample(0) {}
42
43   int length;
44   int bitrate;
45   int sampleRate;
46   int channels;
47   int bitsPerSample;
48 };
49
50 MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
51   : AudioProperties(style)
52 {
53   d = new PropertiesPrivate;
54
55   MP4::Atom *moov = atoms->find("moov");
56   if(!moov) {
57     debug("MP4: Atom 'moov' not found");
58     return;
59   }
60
61   MP4::Atom *trak = 0;
62   ByteVector data;
63
64   MP4::AtomList trakList = moov->findall("trak");
65   for (unsigned int i = 0; i < trakList.size(); i++) {
66     trak = trakList[i];
67     MP4::Atom *hdlr = trak->find("mdia", "hdlr");
68     if(!hdlr) {
69       debug("MP4: Atom 'trak.mdia.hdlr' not found");
70       return;
71     }
72     file->seek(hdlr->offset);
73     data = file->readBlock(hdlr->length);
74     if(data.mid(16, 4) == "soun") {
75       break;
76     }
77     trak = 0;
78   }
79   if (!trak) {
80     debug("MP4: No audio tracks");
81     return;
82   }
83
84   MP4::Atom *mdhd = trak->find("mdia", "mdhd");
85   if(!mdhd) {
86     debug("MP4: Atom 'trak.mdia.mdhd' not found");
87     return;
88   }
89
90   file->seek(mdhd->offset);
91   data = file->readBlock(mdhd->length);
92   if(data[8] == 0) {
93     unsigned int unit = data.mid(20, 4).toUInt();
94     unsigned int length = data.mid(24, 4).toUInt();
95     d->length = length / unit;
96   }
97   else {
98     long long unit = data.mid(28, 8).toLongLong();
99     long long length = data.mid(36, 8).toLongLong();
100     d->length = int(length / unit);
101   }
102
103   MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
104   if(!atom) {
105     return;
106   }
107
108   file->seek(atom->offset);
109   data = file->readBlock(atom->length);
110   if(data.mid(20, 4) == "mp4a") {
111     d->channels = data.mid(40, 2).toShort();
112     d->bitsPerSample = data.mid(42, 2).toShort();
113     d->sampleRate = data.mid(46, 4).toUInt();
114     if(data.mid(56, 4) == "esds" && data[64] == 0x03) {
115       long pos = 65;
116       if(data.mid(pos, 3) == "\x80\x80\x80") {
117         pos += 3;
118       }
119       pos += 4;
120       if(data[pos] == 0x04) {
121         pos += 1;
122         if(data.mid(pos, 3) == "\x80\x80\x80") {
123           pos += 3;
124         }
125         pos += 10;
126         d->bitrate = (data.mid(pos, 4).toUInt() + 500) / 1000;
127       }
128     }
129   }
130 }
131
132 MP4::Properties::~Properties()
133 {
134   delete d;
135 }
136
137 int
138 MP4::Properties::channels() const
139 {
140   return d->channels;
141 }
142
143 int
144 MP4::Properties::sampleRate() const
145 {
146   return d->sampleRate;
147 }
148
149 int
150 MP4::Properties::length() const
151 {
152   return d->length;
153 }
154
155 int
156 MP4::Properties::bitrate() const
157 {
158   return d->bitrate;
159 }
160
161 int
162 MP4::Properties::bitsPerSample() const
163 {
164   return d->bitsPerSample;
165 }
166