Merge lp:~neale/mixxx/m4a into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Neale Pickett
Status: Needs review
Proposed branch: lp:~neale/mixxx/m4a
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 1832 lines (+338/-1341)
9 files modified
mixxx/build/features.py (+5/-10)
mixxx/plugins/soundsourcem4a/SConscript (+1/-8)
mixxx/plugins/soundsourcem4a/m4a/comment.h (+0/-30)
mixxx/plugins/soundsourcem4a/m4a/ip.h (+0/-99)
mixxx/plugins/soundsourcem4a/m4a/mp4-mixxx.cpp (+0/-587)
mixxx/plugins/soundsourcem4a/m4a/mp4.c (+0/-407)
mixxx/plugins/soundsourcem4a/m4a/sf.h (+0/-61)
mixxx/plugins/soundsourcem4a/soundsourcem4a.cpp (+316/-129)
mixxx/plugins/soundsourcem4a/soundsourcem4a.h (+16/-10)
To merge this branch: bzr merge lp:~neale/mixxx/m4a
Reviewer Review Type Date Requested Status
Stefan Nürnberger (community) Needs Information
RJ Skerry-Ryan Pending
Review via email: mp+121310@code.launchpad.net

Description of the change

Rewritten M4A plugin, uses libmp4ff instead of libmp4v2. Works with all my M4A files, and I will maintain the code if people can send me examples of problem files.

To post a comment you must log in.
Revision history for this message
Stefan Nürnberger (kabelfrickler) wrote :

As the faad2 developers mention, mp4ff is not meant as a library for external programs like Mixxx. They do not ship the library by default anymore, resulting in quite some bug reports about broken dependencies. See e.g. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=550679#57

Quote:
"again, libmp4ff was never meant to be used outside of faad2 and its
use is explicitely discouraged upstream and we deeply regret having
shipped it at all. Please get your application fixed to use mp4v2
instead (if it is MPL-compatible) or ffmpeg (prefered)."

I therefore propose to keep the old implementation using mp4v2. What is/was the reason for using mp4ff instead, anyway?

review: Needs Information
Revision history for this message
Neale Pickett (neale) wrote :

> I therefore propose to keep the old implementation using mp4v2. What is/was
> the reason for using mp4ff instead, anyway?

Yeah, it should use mp4v2.

The reason I moved to mp4ff is because I couldn't find example code for mp4v2. The original motivation for this branch was that I have a whole lot of m4a files with frames larger than the current implementation can handle.

I'll port this branch to mp4v2 and submit another merge request when that work is done. The main thing this patch does is make mixxx work with all m4a files I can find, the container parsing library isn't significant.

Unmerged revisions

3293. By Neale Pickett

Rewritten M4A plugin

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mixxx/build/features.py'
2--- mixxx/build/features.py 2012-07-08 07:30:32 +0000
3+++ mixxx/build/features.py 2012-08-25 14:26:19 +0000
4@@ -465,21 +465,16 @@
5 if not self.enabled(build):
6 return
7
8- have_mp4v2_h = conf.CheckHeader('mp4v2/mp4v2.h')
9- have_mp4v2 = conf.CheckLib(['mp4v2','libmp4v2'], autoadd=False)
10- have_mp4 = conf.CheckLib('mp4', autoadd=False)
11-
12- # Either mp4 or mp4v2 works
13- have_mp4 = (have_mp4v2_h and have_mp4v2) or have_mp4
14-
15- if not have_mp4:
16- raise Exception('Could not find libmp4, libmp4v2 or the libmp4v2 development headers.')
17-
18 have_faad = conf.CheckLib(['faad','libfaad'], autoadd=False)
19
20 if not have_faad:
21 raise Exception('Could not find libfaad or the libfaad development headers.')
22
23+ have_mp4ff = conf.CheckLib(['mp4ff', 'libmp4ff'], autoadd=False)
24+
25+ if not have_mp4ff:
26+ raise Exception('Could not find libmp4ff or the libmp4ff development headers.')
27+
28
29 class WavPack(Feature):
30 def description(self):
31
32=== modified file 'mixxx/plugins/soundsourcem4a/SConscript'
33--- mixxx/plugins/soundsourcem4a/SConscript 2011-03-07 22:25:20 +0000
34+++ mixxx/plugins/soundsourcem4a/SConscript 2012-08-25 14:26:19 +0000
35@@ -23,9 +23,7 @@
36
37 conf = Configure(env)
38
39- have_mp4v2_h = conf.CheckHeader('mp4v2/mp4v2.h')
40- have_mp4 = (have_mp4v2_h and conf.CheckLib(['mp4v2', 'libmp4v2'])) or \
41- conf.CheckLib('mp4')
42+ have_mp4ff = conf.CheckLib(['mp4ff', 'libmp4ff'])
43
44 have_faad = conf.CheckLib(['faad', 'libfaad'])
45 have_faad_26 = False
46@@ -47,8 +45,6 @@
47 if have_faad_26:
48 env.Append(CPPDEFINES = '__M4AHACK__')
49 print "libfaad 2.6 compatibility mode... enabled"
50- if have_mp4v2_h:
51- env.Append(CPPDEFINES = '__MP4V2__')
52
53 env = conf.Finish()
54 SHLIBPREFIX='lib' #Makes the filename "libsoundsourcem4a" consistently across platforms to make our lives easier.
55@@ -63,6 +59,3 @@
56 Return("ssm4a_bin")
57 else:
58 Return("")
59-
60-
61-
62
63=== removed directory 'mixxx/plugins/soundsourcem4a/m4a'
64=== removed file 'mixxx/plugins/soundsourcem4a/m4a/comment.h'
65--- mixxx/plugins/soundsourcem4a/m4a/comment.h 2008-12-14 09:12:07 +0000
66+++ mixxx/plugins/soundsourcem4a/m4a/comment.h 1970-01-01 00:00:00 +0000
67@@ -1,30 +0,0 @@
68-#ifndef _COMMENT_H
69-#define _COMMENT_H
70-
71-struct keyval {
72- char *key;
73- char *val;
74-};
75-
76-struct growing_keyvals {
77- struct keyval *comments;
78- int alloc;
79- int count;
80-};
81-
82-#define GROWING_KEYVALS(name) struct growing_keyvals name = { NULL, 0, 0 }
83-
84-struct keyval *comments_dup(const struct keyval *comments);
85-void comments_free(struct keyval *comments);
86-
87-/* case insensitive key */
88-const char *comments_get_val(const struct keyval *comments, const char *key);
89-const char *comments_get_albumartist(const struct keyval *comments);
90-int comments_get_int(const struct keyval *comments, const char *key);
91-int comments_get_date(const struct keyval *comments, const char *key);
92-
93-int comments_add(struct growing_keyvals *c, const char *key, char *val);
94-int comments_add_const(struct growing_keyvals *c, const char *key, const char *val);
95-void comments_terminate(struct growing_keyvals *c);
96-
97-#endif
98
99=== removed file 'mixxx/plugins/soundsourcem4a/m4a/ip.h'
100--- mixxx/plugins/soundsourcem4a/m4a/ip.h 2008-12-14 09:12:07 +0000
101+++ mixxx/plugins/soundsourcem4a/m4a/ip.h 1970-01-01 00:00:00 +0000
102@@ -1,99 +0,0 @@
103-/*
104- * Copyright 2004-2005 Timo Hirvonen
105- *
106- * This program is free software; you can redistribute it and/or
107- * modify it under the terms of the GNU General Public License as
108- * published by the Free Software Foundation; either version 2 of the
109- * License, or (at your option) any later version.
110- *
111- * This program is distributed in the hope that it will be useful, but
112- * WITHOUT ANY WARRANTY; without even the implied warranty of
113- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
114- * General Public License for more details.
115- *
116- * You should have received a copy of the GNU General Public License
117- * along with this program; if not, write to the Free Software
118- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
119- * 02111-1307, USA.
120- */
121-
122-#ifndef _IP_H
123-#define _IP_H
124-
125-#include "comment.h"
126-#include "sf.h"
127-
128-enum {
129- /* no error */
130- IP_ERROR_SUCCESS,
131- /* system error (error code in errno) */
132- IP_ERROR_ERRNO,
133- /* file type not supported */
134- IP_ERROR_UNRECOGNIZED_FILE_TYPE,
135- /* function not supported (usually seek) */
136- IP_ERROR_FUNCTION_NOT_SUPPORTED,
137- /* input plugin detected corrupted file */
138- IP_ERROR_FILE_FORMAT,
139- /* malformed uri */
140- IP_ERROR_INVALID_URI,
141- /* sample format not supported */
142- IP_ERROR_SAMPLE_FORMAT,
143- /* error parsing response line / headers */
144- IP_ERROR_HTTP_RESPONSE,
145- /* usually 404 */
146- IP_ERROR_HTTP_STATUS,
147- /* */
148- IP_ERROR_INTERNAL
149-};
150-
151-/*
152-struct input_plugin_data {
153- // filled by ip-layer
154- char *filename;
155- int fd;
156-
157- unsigned int remote : 1;
158- unsigned int metadata_changed : 1;
159-
160- // shoutcast
161- int counter;
162- int metaint;
163- char *metadata;
164-
165- // filled by plugin
166- sample_format_t sf;
167- void * private_ipd;
168-};
169-*/
170-
171-struct input_plugin_data {
172- // filled by ip-layer
173-// QString filename;
174- char *filename;
175- int fd;
176-
177- unsigned int remote : 1;
178- unsigned int metadata_changed : 1;
179-
180- // shoutcast
181- int counter;
182- int metaint;
183- char *metadata;
184-
185- // filled by plugin
186- sample_format_t sf;
187- void * private_ipd;
188-};
189-
190-
191-struct input_plugin_ops {
192- int (*open)(struct input_plugin_data *ip_data);
193- int (*close)(struct input_plugin_data *ip_data);
194- int (*read)(struct input_plugin_data *ip_data, char *buffer, int count);
195- int (*seek)(struct input_plugin_data *ip_data, double offset);
196- int (*read_comments)(struct input_plugin_data *ip_data,
197- struct keyval **comments);
198- int (*duration)(struct input_plugin_data *ip_data);
199-};
200-
201-#endif
202
203=== removed file 'mixxx/plugins/soundsourcem4a/m4a/mp4-mixxx.cpp'
204--- mixxx/plugins/soundsourcem4a/m4a/mp4-mixxx.cpp 2012-05-04 03:44:44 +0000
205+++ mixxx/plugins/soundsourcem4a/m4a/mp4-mixxx.cpp 1970-01-01 00:00:00 +0000
206@@ -1,587 +0,0 @@
207-// mp4-mixxx.cpp
208-// This file is a hopefully shortlived fork + convertsion to C++ of the M4A audio playback plugin from the C* Music Player (cmus) project.
209-// The original file mp4.c is also in this directory.
210-//
211-// This forked and converted by Garth and Albert in Summer 2008 to support M4A playback in Mixxx
212-//
213-// g++ $(pkg-config --cflags QtCore) $(pkg-config --libs-only-l QtCore) -lmp4v2 -lfaad -o mp4-mixxx mp4-mixxx.cpp
214-//
215-#include <QtCore>
216-#include <stdlib.h>
217-
218-#include "mathstuff.h"
219-
220-/*
221- * Copyright 2006 dnk <dnk@bjum.net>
222- *
223- * This program is free software; you can redistribute it and/or
224- * modify it under the terms of the GNU General Public License as
225- * published by the Free Software Foundation; either version 2 of the
226- * License, or (at your option) any later version.
227- *
228- * This program is distributed in the hope that it will be useful, but
229- * WITHOUT ANY WARRANTY; without even the implied warranty of
230- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
231- * General Public License for more details.
232- *
233- * You should have received a copy of the GNU General Public License
234- * along with this program; if not, write to the Free Software
235- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
236- * 02111-1307, USA.
237- */
238-
239-#include "ip.h"
240-// #include "xmalloc.h"
241-// #include "debug.h"
242-// #include "file.h"
243-
244-#ifdef __MP4V2__
245- #include <mp4v2/mp4v2.h>
246-#else
247- #include <mp4.h>
248-#endif
249-
250-#include <neaacdec.h>
251-
252-#include <errno.h>
253-#include <string.h>
254-#include <sys/types.h>
255-#ifndef _MSC_VER
256- #include <unistd.h>
257-#endif
258-
259-#ifdef _MSC_VER
260- #define S_ISDIR(mode) (mode & _S_IFDIR)
261- #define strcasecmp stricmp
262- #define strncasecmp strnicmp
263-#endif
264-
265-#ifdef __M4AHACK__
266- typedef uint32_t SAMPLERATE_TYPE;
267-#else
268- typedef unsigned long SAMPLERATE_TYPE;
269-#endif
270-
271-struct mp4_private {
272- char *overflow_buf;
273- int overflow_buf_len;
274-
275- unsigned char *aac_data;
276- unsigned int aac_data_len;
277-
278- char *sample_buf;
279- unsigned int sample_buf_frame;
280- unsigned int sample_buf_len;
281-
282- unsigned char channels;
283- unsigned long sample_rate;
284-
285- faacDecHandle decoder; /* typedef void * */
286-
287- struct {
288- MP4FileHandle handle; /* typedef void * */
289-
290- MP4TrackId track;
291- MP4SampleId sample;
292- MP4SampleId num_samples;
293- } mp4;
294-};
295-
296-
297-static MP4TrackId mp4_get_track(MP4FileHandle *handle)
298-{
299- MP4TrackId num_tracks;
300- const char *track_type;
301- uint8_t obj_type;
302- MP4TrackId i;
303-
304- num_tracks = MP4GetNumberOfTracks(handle, NULL, 0);
305-
306- for (i = 1; i <= num_tracks; i++) {
307- track_type = MP4GetTrackType(handle, i);
308- if (!track_type)
309- continue;
310-
311- if (!MP4_IS_AUDIO_TRACK_TYPE(track_type))
312- continue;
313-
314- /* MP4GetTrackAudioType */
315- obj_type = MP4GetTrackEsdsObjectTypeId(handle, i);
316- if (obj_type == MP4_INVALID_AUDIO_TYPE)
317- continue;
318-
319- if (obj_type == MP4_MPEG4_AUDIO_TYPE) {
320- obj_type = MP4GetTrackAudioMpeg4Type(handle, i);
321-
322- if (MP4_IS_MPEG4_AAC_AUDIO_TYPE(obj_type))
323- return i;
324- } else {
325- if (MP4_IS_AAC_AUDIO_TYPE(obj_type))
326- return i;
327- }
328- }
329-
330- return MP4_INVALID_TRACK_ID;
331-}
332-
333-static int mp4_open(struct input_plugin_data *ip_data)
334-{
335- struct mp4_private *priv;
336- faacDecConfigurationPtr neaac_cfg;
337- unsigned char *buf;
338- unsigned int buf_size;
339-
340- /* http://sourceforge.net/forum/message.php?msg_id=3578887 */
341- if (ip_data->remote)
342- return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
343-
344- /* init private_ipd struct */
345- // priv = xnew0(struct mp4_private, 1);
346- priv = new mp4_private();
347- //priv = (mp4_private*) calloc(1, sizeof(mp4_private));
348- // FIXME: there was some alloc error checking in the orgininal ver
349- memset(priv, 0, sizeof(*priv));
350-
351- priv->overflow_buf_len = 0;
352- priv->overflow_buf = NULL;
353-
354- priv->sample_buf_len = 4096;
355- priv->sample_buf = new char[priv->sample_buf_len];
356- priv->sample_buf_frame = -1;
357-
358- ip_data->private_ipd = priv;
359-
360- priv->decoder = faacDecOpen();
361- /* set decoder config */
362- neaac_cfg = faacDecGetCurrentConfiguration(priv->decoder);
363- neaac_cfg->outputFormat = FAAD_FMT_16BIT; /* force 16 bit audio */
364- neaac_cfg->downMatrix = 1; /* 5.1 -> stereo */
365- neaac_cfg->defObjectType = LC;
366- //qDebug() << "Decoder Config" << neaac_cfg->defObjectType
367- // << neaac_cfg->defSampleRate
368- // << neaac_cfg->useOldADTSFormat
369- // << neaac_cfg->dontUpSampleImplicitSBR;
370- faacDecSetConfiguration(priv->decoder, neaac_cfg);
371-
372- /* open mpeg-4 file, check for >= ver 1.9.1 */
373-#if MP4V2_PROJECT_version_hex <= 0x00010901
374- priv->mp4.handle = MP4Read(ip_data->filename, 0);
375-#else
376- priv->mp4.handle = MP4Read(ip_data->filename);
377-#endif
378- if (!priv->mp4.handle) {
379- qDebug() << "MP4Read failed";
380- goto out;
381- }
382-
383- /* find aac audio track */
384- priv->mp4.track = mp4_get_track((MP4FileHandle*)priv->mp4.handle);
385- if (priv->mp4.track == MP4_INVALID_TRACK_ID) {
386- qDebug() << "MP4FindTrackId failed";
387- goto out;
388- }
389-
390- // Allocate AAC read buffer
391- priv->aac_data_len = MP4GetTrackMaxSampleSize(priv->mp4.handle, priv->mp4.track);
392- priv->aac_data = new unsigned char[priv->aac_data_len];
393-
394- priv->mp4.num_samples = MP4GetTrackNumberOfSamples(priv->mp4.handle, priv->mp4.track);
395- // MP4 frames are 1-indexed
396- priv->mp4.sample = 1;
397-
398- buf = NULL;
399- buf_size = 0;
400- if (!MP4GetTrackESConfiguration(priv->mp4.handle, priv->mp4.track, &buf, &buf_size)) {
401- /* failed to get mpeg-4 audio config... this is ok.
402- * faacDecInit2() will simply use default values instead.
403- */
404- qDebug() << "Didn't get MP4 Audio Config (not a bad thing)";
405- buf = NULL;
406- buf_size = 0;
407- }
408-
409- /* init decoder according to mpeg-4 audio config */
410- if (faacDecInit2(priv->decoder, buf, buf_size,
411- (SAMPLERATE_TYPE*)&priv->sample_rate, &priv->channels) < 0) {
412- free(buf);
413- goto out;
414- }
415- free(buf);
416-
417- // qDebug() << "sample rate "<< priv->sample_rate <<"hz, channels" << priv->channels;
418-
419- ip_data->sf = sf_rate(priv->sample_rate) | sf_channels(priv->channels) | sf_bits(16) | sf_signed(1);
420-#if defined(WORDS_BIGENDIAN)
421- ip_data->sf |= sf_bigendian(1);
422-#endif
423-
424- return 0;
425-out:
426- if (priv->mp4.handle)
427- MP4Close(priv->mp4.handle);
428- if (priv->decoder)
429- faacDecClose(priv->decoder);
430- delete [] priv->sample_buf;
431- delete [] priv->aac_data;
432- delete priv;
433- return -IP_ERROR_FILE_FORMAT;
434-}
435-
436-static int mp4_close(struct input_plugin_data *ip_data)
437-{
438- struct mp4_private *priv;
439-
440- priv = (mp4_private*) ip_data->private_ipd;
441-
442- if (priv->mp4.handle)
443- MP4Close(priv->mp4.handle);
444-
445- if (priv->decoder)
446- faacDecClose(priv->decoder);
447-
448- if (priv->sample_buf) {
449- delete [] priv->sample_buf;
450- }
451-
452- if (priv->aac_data) {
453- delete [] priv->aac_data;
454- }
455-
456- delete priv;
457- ip_data->private_ipd = NULL;
458-
459- return 0;
460-}
461-
462-/* returns -1 on fatal errors
463- * returns -2 on non-fatal errors
464- * 0 on eof
465- * number of bytes put in 'buffer' on success */
466-static int decode_one_frame(struct input_plugin_data *ip_data, void *buffer, int count)
467-{
468- struct mp4_private *priv = (mp4_private*) ip_data->private_ipd;
469- faacDecFrameInfo frame_info;
470- int bytes;
471-
472- //BUG_ON(priv->overflow_buf_len);
473-
474- if (priv->mp4.sample > priv->mp4.num_samples)
475- return 0; /* EOF */
476-
477- unsigned char *aac_data = priv->aac_data;
478- unsigned int aac_data_len = priv->aac_data_len;
479-
480- // If you do this, then MP4ReadSample allocates the buffer for you. We don't
481- // want this because it's slow.
482- // unsigned char *aac_data = NULL;
483- // unsigned int aac_data_len = 0;
484-
485- int this_frame = priv->mp4.sample;
486- if (MP4ReadSample(priv->mp4.handle, priv->mp4.track, this_frame,
487- &aac_data, &aac_data_len,
488- NULL, NULL, NULL, NULL) == 0) {
489- qWarning() << "m4a: error reading mp4 sample" << priv->mp4.sample;
490- errno = EINVAL;
491- return -1;
492- }
493-
494- if (!aac_data) {
495- qWarning() << "m4a: aac_data == NULL";
496- errno = EINVAL;
497- return -1;
498- }
499-
500- char* sample_buf = priv->sample_buf;
501- int sample_buf_len = priv->sample_buf_len;
502-
503- NeAACDecDecode2(priv->decoder,
504- &frame_info,
505- aac_data, aac_data_len,
506- (void**)&sample_buf, sample_buf_len);
507-
508- // qDebug() << "Sample frame" << priv->mp4.sample
509- // << "has" << frame_info.samples << "samples"
510- // << frame_info.bytesconsumed << "bytes"
511- // << frame_info.channels << "channels"
512- // << frame_info.error << "error"
513- // << frame_info.samplerate << "samplerate";
514-
515- if (!sample_buf || frame_info.bytesconsumed <= 0) {
516- qWarning() << "m4a fatal error:" << faacDecGetErrorMessage(frame_info.error);
517- errno = EINVAL;
518- return -1;
519- }
520-
521- if (frame_info.error != 0) {
522- qDebug() << "frame error:" << faacDecGetErrorMessage(frame_info.error);
523- return -2;
524- }
525-
526- if (frame_info.samples <= 0) {
527- return -2;
528- }
529-
530- if (frame_info.channels != priv->channels ||
531- frame_info.samplerate != priv->sample_rate) {
532- qDebug() << "invalid channel or sample_rate count\n";
533- return -2;
534- }
535-
536- // The frame read was successful
537- priv->sample_buf_frame = this_frame;
538- priv->mp4.sample++;
539-
540- /* 16-bit samples */
541- bytes = frame_info.samples * 2;
542-
543- if (bytes > count) {
544- /* decoded too much; keep overflow. */
545- //memcpy(priv->overflow_buf_base, sample_buf + count, bytes - count);
546- //priv->overflow_buf = priv->overflow_buf_base;
547-
548- priv->overflow_buf = sample_buf + count;
549- priv->overflow_buf_len = bytes - count;
550- memcpy(buffer, sample_buf, count);
551- return count;
552- }
553-
554- memcpy(buffer, sample_buf, bytes);
555- return bytes;
556-}
557-
558-static int mp4_read(struct input_plugin_data *ip_data, char *buffer, int count)
559-{
560- struct mp4_private *priv = (mp4_private*) ip_data->private_ipd;
561- int rc;
562-
563- /* use overflow from previous call (if any) */
564- if (priv->overflow_buf_len > 0) {
565- int len = priv->overflow_buf_len;
566-
567- if (len > count)
568- len = count;
569-
570- memcpy(buffer, priv->overflow_buf, len);
571- priv->overflow_buf += len;
572- priv->overflow_buf_len -= len;
573-
574- //qDebug() << "Reading" << len << "from overflow."
575- // << priv->overflow_buf_len << "overflow remains";
576-
577- return len;
578- }
579-
580- do {
581- rc = decode_one_frame(ip_data, buffer, count);
582- } while (rc == -2);
583-
584- return rc;
585-}
586-
587-static int mp4_total_samples(struct input_plugin_data *ip_data) {
588- struct mp4_private *priv = (struct mp4_private*)ip_data->private_ipd;
589- return priv->channels * priv->mp4.num_samples * 1024;
590-}
591-
592-static int mp4_current_sample(struct input_plugin_data *ip_data) {
593- struct mp4_private *priv = (struct mp4_private*)ip_data->private_ipd;
594- int frame_length = priv->channels * 1024;
595- if (priv->overflow_buf_len == 0) {
596- return priv->mp4.sample * frame_length - priv->overflow_buf_len;
597- }
598- // rryan 9/2009 This is equivalent to the current sample. The full expression
599- // is (priv->mp4.sample - 1) * frame_length + (frame_length -
600- // priv->overflow_buf_len); but the frame_length lone terms drop out.
601-
602- // -1 because if overflow buf is filled then mp4.sample is incremented, and
603- // the samples in the overflow buf are for sample - 1
604- return (priv->mp4.sample - 1) * frame_length - priv->overflow_buf_len;
605-}
606-
607-static int mp4_seek_sample(struct input_plugin_data *ip_data, int sample)
608-{
609- struct mp4_private *priv;
610- priv = (mp4_private*) ip_data->private_ipd;
611-
612- Q_ASSERT(sample >= 0);
613- // The first frame is samples 0 through 2047. The first sample of the second
614- // frame is 2048. 2048 / 2048 = 1, so frame_for_sample will be 2 on the
615- // 2048'th sample. The frame_offset_samples is how many samples into the frame
616- // the sample'th sample is. For x in (0,2047), the frame offset is x. For x in
617- // (2048,4095) the offset is x-2048 and so on. sample % 2048 is therefore
618- // suitable for calculating the offset.
619- unsigned int frame_for_sample = 1 + (sample / (2 * 1024));
620- unsigned int frame_offset_samples = sample % (2 * 1024);
621- unsigned int frame_offset_bytes = frame_offset_samples * 2;
622-
623- //qDebug() << "Seeking to" << frame_for_sample << ":" << frame_offset;
624-
625- // Invalid sample requested -- return the current position.
626- if (frame_for_sample < 1 || frame_for_sample > priv->mp4.num_samples)
627- return mp4_current_sample(ip_data);
628-
629- // We don't have the current frame decoded -- decode it.
630- if (priv->sample_buf_frame != frame_for_sample) {
631-
632- // We might have to 'prime the pump' if this isn't the first frame. The
633- // decoder has internal state that it builds as it plays, and just seeking
634- // to the frame we want will result in poor audio quality (clicks and
635- // pops). This is akin to seeking in a video and seeing MPEG
636- // artifacts. Figure out how many frames we need to go backward -- 1 seems
637- // to work.
638- const int how_many_backwards = 1;
639- int start_frame = math_max(frame_for_sample - how_many_backwards, 1);
640- priv->mp4.sample = start_frame;
641-
642- // rryan 9/2009 -- the documentation is sketchy on this, but I think that
643- // it tells the decoder that you are seeking so it should flush its state
644- faacDecPostSeekReset(priv->decoder, priv->mp4.sample);
645-
646- // Loop until the current frame is past the frame we intended to read
647- // (i.e. we have decoded how_many_backwards + 1 frames). The desidered
648- // decoded frame will be stored in the overflow buffer, since we're asking
649- // to read 0 bytes.
650- int result;
651- do {
652- result = decode_one_frame(ip_data, 0, 0);
653- if (result < 0) qDebug() << "SEEK_ERROR";
654- } while (result == -2 || priv->mp4.sample <= frame_for_sample);
655-
656- if (result == -1 || result == 0) {
657- return mp4_current_sample(ip_data);
658- }
659- } else {
660- qDebug() << "Seek within frame";
661- }
662-
663- // Now the overflow buffer contains the sample we want to seek to. Fix the
664- // overflow buffer so that the next call to read() will read starting with the
665- // requested sample.
666- priv->overflow_buf = priv->sample_buf;
667- priv->overflow_buf += frame_offset_bytes;
668- priv->overflow_buf_len -= frame_offset_bytes;
669-
670- return mp4_current_sample(ip_data);
671-}
672-
673-static int mp4_seek(struct input_plugin_data *ip_data, double offset)
674-{
675- struct mp4_private *priv;
676- MP4SampleId sample;
677- uint32_t scale;
678-
679- priv = (mp4_private*) ip_data->private_ipd;
680-
681- scale = MP4GetTrackTimeScale(priv->mp4.handle, priv->mp4.track);
682- if (scale == 0)
683- return -IP_ERROR_INTERNAL;
684-
685- sample = MP4GetSampleIdFromTime(priv->mp4.handle, priv->mp4.track,
686- (MP4Timestamp)(offset * (double)scale), 0);
687- if (sample == MP4_INVALID_SAMPLE_ID)
688- return -IP_ERROR_INTERNAL;
689-
690- qDebug() << "seeking from sample" << priv->mp4.sample << "to sample" << sample;
691- priv->mp4.sample = sample;
692- priv->overflow_buf_len = 0;
693-
694- return priv->mp4.sample;
695-}
696-
697-/* commented because we use TagLib now ??? -- bkgood
698-static int mp4_read_comments(struct input_plugin_data *ip_data,
699- struct keyval **comments)
700-{
701- struct mp4_private *priv;
702- uint16_t meta_num, meta_total;
703- uint8_t val;
704- uint8_t *ustr;
705- uint32_t size;
706- char *str;
707- GROWING_KEYVALS(c);
708-
709- priv = ip_data->private;
710-
711- MP4GetMetadata* provides malloced pointers, and the data
712- * is in UTF-8 (or at least it should be).
713- if (MP4GetMetadataArtist(priv->mp4.handle, &str))
714- comments_add(&c, "artist", str);
715- if (MP4GetMetadataAlbum(priv->mp4.handle, &str))
716- comments_add(&c, "album", str);
717- if (MP4GetMetadataName(priv->mp4.handle, &str))
718- comments_add(&c, "title", str);
719- if (MP4GetMetadataGenre(priv->mp4.handle, &str))
720- comments_add(&c, "genre", str);
721- if (MP4GetMetadataYear(priv->mp4.handle, &str))
722- comments_add(&c, "date", str);
723-
724- if (MP4GetMetadataCompilation(priv->mp4.handle, &val))
725- comments_add_const(&c, "compilation", val ? "yes" : "no");
726-#if 0
727- if (MP4GetBytesProperty(priv->mp4.handle, "moov.udta.meta.ilst.aART.data", &ustr, &size)) {
728- char *xstr;
729-
730- What's this?
731- * This is the result from lack of documentation.
732- * It's supposed to return just a string, but it
733- * returns an additional 16 bytes of junk at the
734- * beginning. Could be a bug. Could be intentional.
735- * Hopefully this works around it:
736-
737- if (ustr[0] == 0 && size > 16) {
738- ustr += 16;
739- size -= 16;
740- }
741- xstr = xmalloc(size + 1);
742- memcpy(xstr, ustr, size);
743- xstr[size] = 0;
744- comments_add(&c, "albumartist", xstr);
745- free(xstr);
746- }
747-#endif
748- if (MP4GetMetadataTrack(priv->mp4.handle, &meta_num, &meta_total)) {
749- char buf[6];
750- snprintf(buf, 6, "%u", meta_num);
751- comments_add_const(&c, "tracknumber", buf);
752- }
753- if (MP4GetMetadataDisk(priv->mp4.handle, &meta_num, &meta_total)) {
754- char buf[6];
755- snprintf(buf, 6, "%u", meta_num);
756- comments_add_const(&c, "discnumber", buf);
757- }
758-
759- comments_terminate(&c);
760- *comments = c.comments;
761- return 0;
762-}
763-*/
764-
765-static int mp4_duration(struct input_plugin_data *ip_data)
766-{
767- struct mp4_private *priv;
768- uint32_t scale;
769- uint64_t duration;
770-
771- priv = (mp4_private*) ip_data->private_ipd;
772-
773- scale = MP4GetTrackTimeScale(priv->mp4.handle, priv->mp4.track);
774- if (scale == 0)
775- return 0;
776-
777- duration = MP4GetTrackDuration(priv->mp4.handle, priv->mp4.track);
778-
779- return duration / scale;
780-}
781-/*
782-const struct input_plugin_ops ip_ops = {
783- .open = mp4_open,
784- .close = mp4_close,
785- .read = mp4_read,
786- .seek = mp4_seek,
787- .read_comments = mp4_read_comments,
788- .duration = mp4_duration
789-};
790-
791-const char * const ip_extensions[] = { "mp4", "m4a", "m4b", NULL };
792-const char * const ip_mime_types[] = { "audio/mp4", "audio/mp4a-latm", NULL };
793-*/
794
795=== removed file 'mixxx/plugins/soundsourcem4a/m4a/mp4.c'
796--- mixxx/plugins/soundsourcem4a/m4a/mp4.c 2010-01-19 21:49:19 +0000
797+++ mixxx/plugins/soundsourcem4a/m4a/mp4.c 1970-01-01 00:00:00 +0000
798@@ -1,407 +0,0 @@
799-/*
800- * Copyright 2006 dnk <dnk@bjum.net>
801- *
802- * This program is free software; you can redistribute it and/or
803- * modify it under the terms of the GNU General Public License as
804- * published by the Free Software Foundation; either version 2 of the
805- * License, or (at your option) any later version.
806- *
807- * This program is distributed in the hope that it will be useful, but
808- * WITHOUT ANY WARRANTY; without even the implied warranty of
809- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
810- * General Public License for more details.
811- *
812- * You should have received a copy of the GNU General Public License
813- * along with this program; if not, write to the Free Software
814- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
815- * 02111-1307, USA.
816- */
817-
818-#include "ip.h"
819-#include "xmalloc.h"
820-#include "debug.h"
821-#include "file.h"
822-
823-#ifdef __MP4V2__
824- #include <mp4v2/mp4v2.h>
825-#else
826- #include <mp4.h>
827-#endif
828-#include <faad.h>
829-
830-#include <errno.h>
831-#include <string.h>
832-#include <sys/types.h>
833-#include <unistd.h>
834-
835-struct mp4_private {
836- char *overflow_buf;
837- int overflow_buf_len;
838-
839- unsigned char channels;
840- unsigned long sample_rate;
841-
842- faacDecHandle decoder; /* typedef void * */
843-
844- struct {
845- MP4FileHandle handle; /* typedef void * */
846-
847- MP4TrackId track;
848- MP4SampleId sample;
849- MP4SampleId num_samples;
850- } mp4;
851-};
852-
853-
854-static MP4TrackId mp4_get_track(MP4FileHandle *handle)
855-{
856- MP4TrackId num_tracks;
857- const char *track_type;
858- uint8_t obj_type;
859- MP4TrackId i;
860-
861- num_tracks = MP4GetNumberOfTracks(handle, NULL, 0);
862-
863- for (i = 1; i <= num_tracks; i++) {
864- track_type = MP4GetTrackType(handle, i);
865- if (!track_type)
866- continue;
867-
868- if (!MP4_IS_AUDIO_TRACK_TYPE(track_type))
869- continue;
870-
871- /* MP4GetTrackAudioType */
872- obj_type = MP4GetTrackEsdsObjectTypeId(handle, i);
873- if (obj_type == MP4_INVALID_AUDIO_TYPE)
874- continue;
875-
876- if (obj_type == MP4_MPEG4_AUDIO_TYPE) {
877- obj_type = MP4GetTrackAudioMpeg4Type(handle, i);
878-
879- if (MP4_IS_MPEG4_AAC_AUDIO_TYPE(obj_type))
880- return i;
881- } else {
882- if (MP4_IS_AAC_AUDIO_TYPE(obj_type))
883- return i;
884- }
885- }
886-
887- return MP4_INVALID_TRACK_ID;
888-}
889-
890-static int mp4_open(struct input_plugin_data *ip_data)
891-{
892- struct mp4_private *priv;
893- faacDecConfigurationPtr neaac_cfg;
894- unsigned char *buf;
895- unsigned int buf_size;
896-
897-
898- /* http://sourceforge.net/forum/message.php?msg_id=3578887 */
899- if (ip_data->remote)
900- return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
901-
902- /* init private struct */
903- priv = xnew0(struct mp4_private, 1);
904- ip_data->private = priv;
905-
906- priv->decoder = faacDecOpen();
907-
908- /* set decoder config */
909- neaac_cfg = faacDecGetCurrentConfiguration(priv->decoder);
910- neaac_cfg->outputFormat = FAAD_FMT_16BIT; /* force 16 bit audio */
911- neaac_cfg->downMatrix = 1; /* 5.1 -> stereo */
912- faacDecSetConfiguration(priv->decoder, neaac_cfg);
913-
914- /* open mpeg-4 file */
915- priv->mp4.handle = MP4Read(ip_data->filename, 0);
916- if (!priv->mp4.handle) {
917- d_print("MP4Read failed\n");
918- goto out;
919- }
920-
921- /* find aac audio track */
922- priv->mp4.track = mp4_get_track(priv->mp4.handle);
923- if (priv->mp4.track == MP4_INVALID_TRACK_ID) {
924- d_print("MP4FindTrackId failed\n");
925- goto out;
926- }
927-
928- priv->mp4.num_samples = MP4GetTrackNumberOfSamples(priv->mp4.handle, priv->mp4.track);
929-
930- priv->mp4.sample = 1;
931-
932- buf = NULL;
933- buf_size = 0;
934- if (!MP4GetTrackESConfiguration(priv->mp4.handle, priv->mp4.track, &buf, &buf_size)) {
935- /* failed to get mpeg-4 audio config... this is ok.
936- * faacDecInit2() will simply use default values instead.
937- */
938- buf = NULL;
939- buf_size = 0;
940- }
941-
942- /* init decoder according to mpeg-4 audio config */
943- if (faacDecInit2(priv->decoder, buf, buf_size, &priv->sample_rate, &priv->channels) < 0) {
944- free(buf);
945- goto out;
946- }
947-
948- free(buf);
949-
950- d_print("sample rate %luhz, channels %u\n", priv->sample_rate, priv->channels);
951-
952- ip_data->sf = sf_rate(priv->sample_rate) | sf_channels(priv->channels) | sf_bits(16) | sf_signed(1);
953-#if defined(WORDS_BIGENDIAN)
954- ip_data->sf |= sf_bigendian(1);
955-#endif
956-
957- return 0;
958-
959-out:
960- if (priv->mp4.handle)
961- MP4Close(priv->mp4.handle);
962- if (priv->decoder)
963- faacDecClose(priv->decoder);
964- free(priv);
965- return -IP_ERROR_FILE_FORMAT;
966-}
967-
968-static int mp4_close(struct input_plugin_data *ip_data)
969-{
970- struct mp4_private *priv;
971-
972- priv = ip_data->private;
973-
974- if (priv->mp4.handle)
975- MP4Close(priv->mp4.handle);
976-
977- if (priv->decoder)
978- faacDecClose(priv->decoder);
979-
980- free(priv);
981- ip_data->private = NULL;
982-
983- return 0;
984-}
985-
986-/* returns -1 on fatal errors
987- * returns -2 on non-fatal errors
988- * 0 on eof
989- * number of bytes put in 'buffer' on success */
990-static int decode_one_frame(struct input_plugin_data *ip_data, void *buffer, int count)
991-{
992- struct mp4_private *priv;
993- unsigned char *aac_data = NULL;
994- unsigned int aac_data_len = 0;
995- faacDecFrameInfo frame_info;
996- char *sample_buf;
997- int bytes;
998-
999- priv = ip_data->private;
1000-
1001- BUG_ON(priv->overflow_buf_len);
1002-
1003- if (priv->mp4.sample > priv->mp4.num_samples)
1004- return 0; /* EOF */
1005-
1006- if (MP4ReadSample(priv->mp4.handle, priv->mp4.track, priv->mp4.sample,
1007- &aac_data, &aac_data_len, NULL, NULL, NULL, NULL) == 0) {
1008- d_print("error reading mp4 sample %d\n", priv->mp4.sample);
1009- errno = EINVAL;
1010- return -1;
1011- }
1012-
1013- priv->mp4.sample++;
1014-
1015- if (!aac_data) {
1016- d_print("aac_data == NULL\n");
1017- errno = EINVAL;
1018- return -1;
1019- }
1020-
1021- sample_buf = faacDecDecode(priv->decoder, &frame_info, aac_data, aac_data_len);
1022-
1023- free(aac_data);
1024-
1025- if (!sample_buf || frame_info.bytesconsumed <= 0) {
1026- d_print("fatal error: %s\n", faacDecGetErrorMessage(frame_info.error));
1027- errno = EINVAL;
1028- return -1;
1029- }
1030-
1031- if (frame_info.error != 0) {
1032- d_print("frame error: %s\n", faacDecGetErrorMessage(frame_info.error));
1033- return -2;
1034- }
1035-
1036- if (frame_info.samples <= 0)
1037- return -2;
1038-
1039- if (frame_info.channels != priv->channels || frame_info.samplerate != priv->sample_rate) {
1040- d_print("invalid channel or sample_rate count\n");
1041- return -2;
1042- }
1043-
1044- /* 16-bit samples */
1045- bytes = frame_info.samples * 2;
1046-
1047- if (bytes > count) {
1048- /* decoded too much; keep overflow. */
1049- priv->overflow_buf = sample_buf + count;
1050- priv->overflow_buf_len = bytes - count;
1051- memcpy(buffer, sample_buf, count);
1052- return count;
1053- } else {
1054- memcpy(buffer, sample_buf, bytes);
1055- }
1056-
1057- return bytes;
1058-}
1059-
1060-static int mp4_read(struct input_plugin_data *ip_data, char *buffer, int count)
1061-{
1062- struct mp4_private *priv;
1063- int rc;
1064-
1065- priv = ip_data->private;
1066-
1067- /* use overflow from previous call (if any) */
1068- if (priv->overflow_buf_len > 0) {
1069- int len = priv->overflow_buf_len;
1070-
1071- if (len > count)
1072- len = count;
1073-
1074- memcpy(buffer, priv->overflow_buf, len);
1075- priv->overflow_buf += len;
1076- priv->overflow_buf_len -= len;
1077-
1078- return len;
1079- }
1080-
1081- do {
1082- rc = decode_one_frame(ip_data, buffer, count);
1083- } while (rc == -2);
1084-
1085- return rc;
1086-}
1087-
1088-static int mp4_seek(struct input_plugin_data *ip_data, double offset)
1089-{
1090- struct mp4_private *priv;
1091- MP4SampleId sample;
1092- uint32_t scale;
1093-
1094- priv = ip_data->private;
1095-
1096- scale = MP4GetTrackTimeScale(priv->mp4.handle, priv->mp4.track);
1097- if (scale == 0)
1098- return -IP_ERROR_INTERNAL;
1099-
1100- sample = MP4GetSampleIdFromTime(priv->mp4.handle, priv->mp4.track,
1101- (MP4Timestamp)(offset * (double)scale), 0);
1102- if (sample == MP4_INVALID_SAMPLE_ID)
1103- return -IP_ERROR_INTERNAL;
1104-
1105- priv->mp4.sample = sample;
1106-
1107- d_print("seeking to sample %d\n", sample);
1108-
1109- return 0;
1110-}
1111-
1112-static int mp4_read_comments(struct input_plugin_data *ip_data,
1113- struct keyval **comments)
1114-{
1115- struct mp4_private *priv;
1116- uint16_t meta_num, meta_total;
1117- uint8_t val;
1118- /*uint8_t *ustr;
1119- uint32_t size;*/
1120- char *str;
1121- GROWING_KEYVALS(c);
1122-
1123- priv = ip_data->private;
1124-
1125- /* MP4GetMetadata* provides malloced pointers, and the data
1126- * is in UTF-8 (or at least it should be). */
1127- if (MP4GetMetadataArtist(priv->mp4.handle, &str))
1128- comments_add(&c, "artist", str);
1129- if (MP4GetMetadataAlbum(priv->mp4.handle, &str))
1130- comments_add(&c, "album", str);
1131- if (MP4GetMetadataName(priv->mp4.handle, &str))
1132- comments_add(&c, "title", str);
1133- if (MP4GetMetadataGenre(priv->mp4.handle, &str))
1134- comments_add(&c, "genre", str);
1135- if (MP4GetMetadataYear(priv->mp4.handle, &str))
1136- comments_add(&c, "date", str);
1137-
1138- if (MP4GetMetadataCompilation(priv->mp4.handle, &val))
1139- comments_add_const(&c, "compilation", val ? "yes" : "no");
1140-#if 0
1141- if (MP4GetBytesProperty(priv->mp4.handle, "moov.udta.meta.ilst.aART.data", &ustr, &size)) {
1142- char *xstr;
1143-
1144- /* What's this?
1145- * This is the result from lack of documentation.
1146- * It's supposed to return just a string, but it
1147- * returns an additional 16 bytes of junk at the
1148- * beginning. Could be a bug. Could be intentional.
1149- * Hopefully this works around it:
1150- */
1151- if (ustr[0] == 0 && size > 16) {
1152- ustr += 16;
1153- size -= 16;
1154- }
1155- xstr = xmalloc(size + 1);
1156- memcpy(xstr, ustr, size);
1157- xstr[size] = 0;
1158- comments_add(&c, "albumartist", xstr);
1159- free(xstr);
1160- }
1161-#endif
1162- if (MP4GetMetadataTrack(priv->mp4.handle, &meta_num, &meta_total)) {
1163- char buf[6];
1164- snprintf(buf, 6, "%u", meta_num);
1165- comments_add_const(&c, "tracknumber", buf);
1166- }
1167- if (MP4GetMetadataDisk(priv->mp4.handle, &meta_num, &meta_total)) {
1168- char buf[6];
1169- snprintf(buf, 6, "%u", meta_num);
1170- comments_add_const(&c, "discnumber", buf);
1171- }
1172-
1173- comments_terminate(&c);
1174- *comments = c.comments;
1175- return 0;
1176-}
1177-
1178-static int mp4_duration(struct input_plugin_data *ip_data)
1179-{
1180- struct mp4_private *priv;
1181- uint32_t scale;
1182- uint64_t duration;
1183-
1184- priv = ip_data->private;
1185-
1186- scale = MP4GetTrackTimeScale(priv->mp4.handle, priv->mp4.track);
1187- if (scale == 0)
1188- return 0;
1189-
1190- duration = MP4GetTrackDuration(priv->mp4.handle, priv->mp4.track);
1191-
1192- return duration / scale;
1193-}
1194-
1195-const struct input_plugin_ops ip_ops = {
1196- .open = mp4_open,
1197- .close = mp4_close,
1198- .read = mp4_read,
1199- .seek = mp4_seek,
1200- .read_comments = mp4_read_comments,
1201- .duration = mp4_duration
1202-};
1203-
1204-const char * const ip_extensions[] = { "mp4", "m4a", "m4b", NULL };
1205-const char * const ip_mime_types[] = { /*"audio/mp4", "audio/mp4a-latm",*/ NULL };
1206
1207=== removed file 'mixxx/plugins/soundsourcem4a/m4a/sf.h'
1208--- mixxx/plugins/soundsourcem4a/m4a/sf.h 2008-12-14 09:12:07 +0000
1209+++ mixxx/plugins/soundsourcem4a/m4a/sf.h 1970-01-01 00:00:00 +0000
1210@@ -1,61 +0,0 @@
1211-/*
1212- * Copyright 2004 Timo Hirvonen
1213- *
1214- * This program is free software; you can redistribute it and/or
1215- * modify it under the terms of the GNU General Public License as
1216- * published by the Free Software Foundation; either version 2 of the
1217- * License, or (at your option) any later version.
1218- *
1219- * This program is distributed in the hope that it will be useful, but
1220- * WITHOUT ANY WARRANTY; without even the implied warranty of
1221- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1222- * General Public License for more details.
1223- *
1224- * You should have received a copy of the GNU General Public License
1225- * along with this program; if not, write to the Free Software
1226- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1227- * 02111-1307, USA.
1228- */
1229-
1230-#ifndef _SF_H
1231-#define _SF_H
1232-
1233-/*
1234- * 0 1 big_endian 0-1
1235- * 1 1 is_signed 0-1
1236- * 2 1 unused 0
1237- * 3-5 3 bits >> 3 0-7 (* 8 = 0-56)
1238- * 6-23 18 rate 0-262143
1239- * 24-31 8 channels 0-255
1240- */
1241-typedef unsigned int sample_format_t;
1242-
1243-#define SF_BIGENDIAN_MASK 0x00000001
1244-#define SF_SIGNED_MASK 0x00000002
1245-#define SF_BITS_MASK 0x00000038
1246-#define SF_RATE_MASK 0x00ffffc0
1247-#define SF_CHANNELS_MASK 0xff000000
1248-
1249-#define SF_BIGENDIAN_SHIFT 0
1250-#define SF_SIGNED_SHIFT 1
1251-#define SF_BITS_SHIFT 0
1252-#define SF_RATE_SHIFT 6
1253-#define SF_CHANNELS_SHIFT 24
1254-
1255-#define sf_get_bigendian(sf) (((sf) & SF_BIGENDIAN_MASK) >> SF_BIGENDIAN_SHIFT)
1256-#define sf_get_signed(sf) (((sf) & SF_SIGNED_MASK ) >> SF_SIGNED_SHIFT)
1257-#define sf_get_bits(sf) (((sf) & SF_BITS_MASK ) >> SF_BITS_SHIFT)
1258-#define sf_get_rate(sf) (((sf) & SF_RATE_MASK ) >> SF_RATE_SHIFT)
1259-#define sf_get_channels(sf) (((sf) & SF_CHANNELS_MASK ) >> SF_CHANNELS_SHIFT)
1260-
1261-#define sf_bigendian(val) (((val) << SF_BIGENDIAN_SHIFT) & SF_BIGENDIAN_MASK)
1262-#define sf_signed(val) (((val) << SF_SIGNED_SHIFT ) & SF_SIGNED_MASK)
1263-#define sf_bits(val) (((val) << SF_BITS_SHIFT ) & SF_BITS_MASK)
1264-#define sf_rate(val) (((val) << SF_RATE_SHIFT ) & SF_RATE_MASK)
1265-#define sf_channels(val) (((val) << SF_CHANNELS_SHIFT ) & SF_CHANNELS_MASK)
1266-
1267-#define sf_get_sample_size(sf) (sf_get_bits((sf)) >> 3)
1268-#define sf_get_frame_size(sf) (sf_get_sample_size((sf)) * sf_get_channels((sf)))
1269-#define sf_get_second_size(sf) (sf_get_rate((sf)) * sf_get_frame_size((sf)))
1270-
1271-#endif
1272
1273=== modified file 'mixxx/plugins/soundsourcem4a/soundsourcem4a.cpp'
1274--- mixxx/plugins/soundsourcem4a/soundsourcem4a.cpp 2011-03-31 16:07:22 +0000
1275+++ mixxx/plugins/soundsourcem4a/soundsourcem4a.cpp 2012-08-25 14:26:19 +0000
1276@@ -1,9 +1,14 @@
1277-/***************************************************************************
1278- soundsourcem4a.cpp - mp4/m4a decoder
1279- -------------------
1280- copyright : (C) 2008 by Garth Dahlstrom
1281- email : ironstorm@users.sf.net
1282- ***************************************************************************/
1283+/* soundsourcem4a.cpp - mp4/m4a decoder
1284+ *
1285+ * Author: Neale Pickett <neale@woozle.org>
1286+ *
1287+ * Based on:
1288+ * soundsourcem4a.cpp (C) 2008 Garth Dahlstrom <ironstorm@users.sf.net>
1289+ * faad 2.7 (C) Ahead Software
1290+ *
1291+ *
1292+ * Both GPLv2.
1293+ */
1294
1295 /***************************************************************************
1296 * *
1297@@ -14,14 +19,11 @@
1298 * *
1299 ***************************************************************************/
1300
1301+#include <stdio.h>
1302+
1303 #include <taglib/mp4file.h>
1304 #include <neaacdec.h>
1305-
1306-#ifdef __MP4V2__
1307- #include <mp4v2/mp4v2.h>
1308-#else
1309- #include <mp4.h>
1310-#endif
1311+#include <mp4ff.h>
1312
1313 #ifdef __WINDOWS__
1314 #include <io.h>
1315@@ -30,7 +32,90 @@
1316
1317 #include <QtDebug>
1318 #include "soundsourcem4a.h"
1319-#include "m4a/mp4-mixxx.cpp"
1320+
1321+
1322+/* Some things I use for debugging */
1323+#ifdef NODUMP
1324+# define DUMPf(fmt, args...)
1325+#else
1326+# define DUMPf(fmt, args...) fprintf(stderr, "%s:%s:%d " fmt "\n", __FILE__, __FUNCTION__, __LINE__, ##args)
1327+#endif
1328+#define DUMP() DUMPf("")
1329+#define DUMP_d(v) DUMPf("%s = %d", #v, v)
1330+#define DUMP_x(v) DUMPf("%s = 0x%x", #v, v)
1331+#define DUMP_s(v) DUMPf("%s = %s", #v, v)
1332+#define DUMP_c(v) DUMPf("%s = '%c' (0x%02x)", #v, v, v)
1333+#define DUMP_p(v) DUMPf("%s = %p", #v, v)
1334+
1335+static uint32_t
1336+read_callback(void *user_data, void *buffer, uint32_t length)
1337+{
1338+ return fread(buffer, 1, length, (FILE*)user_data);
1339+}
1340+
1341+static uint32_t
1342+seek_callback(void *user_data, uint64_t position)
1343+{
1344+ return fseek((FILE*)user_data, position, SEEK_SET);
1345+}
1346+
1347+static int
1348+GetAACTrack(mp4ff_t *infile)
1349+{
1350+ /* find AAC track */
1351+ int i, rc;
1352+ int numTracks = mp4ff_total_tracks(infile);
1353+
1354+ for (i = 0; i < numTracks; i++)
1355+ {
1356+ mp4AudioSpecificConfig mp4ASC;
1357+ unsigned char *buff = NULL;
1358+ unsigned int buff_size = 0;
1359+
1360+ mp4ff_get_decoder_config(infile, i, &buff, &buff_size);
1361+
1362+ if (buff)
1363+ {
1364+ rc = NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC);
1365+ free(buff);
1366+
1367+ if (rc < 0)
1368+ continue;
1369+ return i;
1370+ }
1371+ }
1372+
1373+ /* can't decode this */
1374+ return -1;
1375+}
1376+
1377+static long
1378+read_decode_frame(NeAACDecHandle hDecoder,
1379+ mp4ff_t *infile,
1380+ unsigned long track,
1381+ unsigned long frameno,
1382+ char *buf,
1383+ size_t buflen)
1384+{
1385+ NeAACDecFrameInfo frameInfo;
1386+ unsigned char frame[8192];
1387+ size_t framelen;
1388+
1389+ /* Read a frame (mp4ff calls it a "sample") of encoded data */
1390+ framelen = mp4ff_read_sample_v2(infile, track, frameno, frame);
1391+ if (framelen == 0) {
1392+ qWarning() << "SoundSourceM4A::read failed!";
1393+ return -1;
1394+ }
1395+
1396+ /* Decode that into the buffer */
1397+ NeAACDecDecode2(hDecoder, &frameInfo, frame, framelen, (void **)&buf, buflen);
1398+ if (frameInfo.bytesconsumed <= 0) {
1399+ qWarning() << "m4a fatal error:" << faacDecGetErrorMessage(frameInfo.error);
1400+ return -1;
1401+ }
1402+ return frameInfo.samples;
1403+}
1404
1405 namespace Mixxx {
1406
1407@@ -38,146 +123,247 @@
1408 : SoundSource(qFileName) {
1409
1410 // Initialize variables to invalid values in case loading fails.
1411- mp4file = MP4_INVALID_FILE_HANDLE;
1412- filelength = 0;
1413- memset(&ipd, 0, sizeof(ipd));
1414+ stream = NULL;
1415+ infile = NULL;
1416+ hDecoder = NULL;
1417+ frame = NULL;
1418 }
1419
1420 SoundSourceM4A::~SoundSourceM4A() {
1421- if (ipd.filename) {
1422- delete [] ipd.filename;
1423- ipd.filename = NULL;
1424- }
1425-
1426- if (mp4file != MP4_INVALID_FILE_HANDLE) {
1427- mp4_close(&ipd);
1428- mp4file = MP4_INVALID_FILE_HANDLE;
1429- }
1430+ close();
1431+}
1432+
1433+void
1434+SoundSourceM4A::close() {
1435+ if (infile) {
1436+ mp4ff_close(infile);
1437+ infile = NULL;
1438+ }
1439+ if (stream) {
1440+ fclose(stream);
1441+ stream = NULL;
1442+ }
1443+ if (hDecoder) {
1444+ NeAACDecClose(hDecoder);
1445+ hDecoder = NULL;
1446+ }
1447+
1448+ if (frame) {
1449+ free(frame);
1450+ frame = NULL;
1451+ }
1452+
1453+}
1454+
1455+int SoundSourceM4A::decoder_init()
1456+{
1457+ int passed = 0;
1458+ unsigned char *buffer = NULL;
1459+
1460+ do {
1461+ unsigned int buffer_size = 0;
1462+ unsigned long samplerate;
1463+ unsigned char channels;
1464+ NeAACDecConfigurationPtr config;
1465+
1466+ if (hDecoder) {
1467+ NeAACDecClose(hDecoder);
1468+ }
1469+ hDecoder = NeAACDecOpen();
1470+
1471+ config = NeAACDecGetCurrentConfiguration(hDecoder);
1472+ config->outputFormat = FAAD_FMT_16BIT;
1473+ config->downMatrix = 1; /* 5.1 -> stereo */
1474+ config->defObjectType = LC;
1475+ NeAACDecSetConfiguration(hDecoder, config);
1476+
1477+ mp4ff_get_decoder_config(infile, track, &buffer, &buffer_size);
1478+
1479+ if (NeAACDecInit2(hDecoder, buffer, buffer_size, &samplerate, &channels) < 0) break;
1480+
1481+ // Apparently this prevents dropping the first frame.
1482+ // http://ac3filter.net/repo/valib/file/37171946becf/valib/parsers/aac/aac_parser.cpp
1483+
1484+ m_iSampleRate = samplerate;
1485+ m_iChannels = channels;
1486+
1487+ passed = 1;
1488+ } while (0);
1489+
1490+ if (buffer) {
1491+ free(buffer);
1492+ }
1493+
1494+ if (passed) {
1495+ return 0;
1496+ }
1497+
1498+ return -1;
1499 }
1500
1501 int SoundSourceM4A::open()
1502 {
1503- //Initialize the FAAD2 decoder...
1504- initializeDecoder();
1505-
1506- //qDebug() << "SSM4A: channels:" << m_iChannels
1507- // << "filelength:" << filelength
1508- // << "Sample Rate:" << m_iSampleRate;
1509- return OK;
1510-}
1511-
1512-int SoundSourceM4A::initializeDecoder()
1513-{
1514- // Copy QString to char[] buffer for mp4_open to read from later
1515- QByteArray qbaFileName;
1516+ int passed = 0;
1517+ char filename[PATH_MAX];
1518+
1519+ {
1520+ QByteArray qbaFileName;
1521+ size_t fnlen;
1522+
1523 #ifdef Q_OS_WIN32
1524- // fopen() doesn't do utf8 on windows
1525- qbaFileName = m_qFilename.toLocal8Bit();
1526+ qbaFileName = m_qFilename.toLocal8Bit(); // fopen() doesn't do utf8 on windows
1527 #else
1528- qbaFileName = m_qFilename.toUtf8();
1529+ qbaFileName = m_qFilename.toUtf8();
1530 #endif
1531- int bytes = qbaFileName.length() + 1;
1532- ipd.filename = new char[bytes];
1533- strncpy(ipd.filename, qbaFileName.constData(), bytes);
1534- ipd.filename[bytes-1] = '\0';
1535- ipd.remote = false; // File is not an stream
1536- // The file was loading and failing erratically because
1537- // ipd.remote was an in an uninitialized state, it needed to be
1538- // set to false.
1539-
1540- int mp4_open_status = mp4_open(&ipd);
1541- if (mp4_open_status != 0) {
1542- qWarning() << "SSM4A::initializeDecoder failed"
1543- << m_qFilename << " with status:" << mp4_open_status;
1544+ fnlen = qbaFileName.length() + 1;
1545+
1546+ if (fnlen >= sizeof filename) {
1547+ fnlen = sizeof filename;
1548+ }
1549+
1550+ strncpy(filename, qbaFileName.constData(), fnlen);
1551+ filename[fnlen-1] = '\0';
1552+ }
1553+
1554+ do {
1555+
1556+ stream = fopen(filename, "r");
1557+ if (! stream) break;
1558+
1559+ mp4cb.read = read_callback;
1560+ mp4cb.seek = seek_callback;
1561+ mp4cb.user_data = stream;
1562+
1563+ infile = mp4ff_open_read(&mp4cb);
1564+ if (! infile) break;
1565+
1566+ if ((track = GetAACTrack(infile)) < 0) break;
1567+
1568+ if (-1 == decoder_init()) break;
1569+
1570+ nframes = mp4ff_num_samples(infile, track);
1571+
1572+ passed = 1;
1573+ } while (0);
1574+
1575+ // It's okay to pass through mp4ff's approximation of track duration.
1576+ // This is the only place in this plugin where mixxx can handle an inexact value.
1577+ audiolen = mp4ff_get_track_duration(infile, track) * 2;
1578+
1579+ // I have seen no frame larger than 700 bytes. Hopefully this is big enough.
1580+ frame = (unsigned char *)malloc(4096);
1581+
1582+ mixxx_pos = 0;
1583+
1584+ if (! passed) {
1585+ close();
1586+
1587+ qWarning() << "SoundSourceM4A::open failed";
1588 return ERR;
1589 }
1590
1591- // mp4_open succeeded -> populate variables
1592- mp4_private* mp = (struct mp4_private*)ipd.private_ipd;
1593- Q_ASSERT(mp);
1594- mp4file = mp->mp4.handle;
1595- filelength = mp4_total_samples(&ipd);
1596- m_iSampleRate = mp->sample_rate;
1597- m_iChannels = mp->channels;
1598-
1599 return OK;
1600 }
1601
1602-long SoundSourceM4A::seek(long filepos){
1603+
1604+long SoundSourceM4A::seek(long filepos) {
1605 // Abort if file did not load.
1606- if (filelength == 0)
1607+ if (! infile) {
1608 return 0;
1609-
1610- //qDebug() << "SSM4A::seek()" << filepos;
1611-
1612- // qDebug() << "MP4SEEK: seek time:" << filepos / (m_iChannels * m_iSampleRate) ;
1613-
1614- int position = mp4_seek_sample(&ipd, filepos);
1615- //int position = mp4_seek(&ipd, filepos / (m_iChannels * m_iSampleRate));
1616- return position;
1617+ }
1618+
1619+ if (mixxx_pos == filepos) {
1620+ // Don't reset decoder state
1621+ return mixxx_pos;
1622+ }
1623+
1624+ if (filepos < 0) {
1625+ mixxx_pos = 0;
1626+ } else if (filepos > audiolen) {
1627+ mixxx_pos = audiolen;
1628+ } else {
1629+ mixxx_pos = filepos;
1630+ }
1631+
1632+ decoder_init();
1633+ {
1634+ // In my tests, faad needs about 2 frames to establish enough
1635+ // state that there are no abrupt pops. So we'll do 4.
1636+ long f = mp4ff_find_sample(infile, track, mixxx_pos/2, NULL);
1637+ long g = f - 4;
1638+
1639+ if (f == 0) g = 0;
1640+ NeAACDecPostSeekReset(hDecoder, g);
1641+
1642+ for (; g < f; g += 1) {
1643+ char buf[8192];
1644+
1645+ read_decode_frame(hDecoder, infile, track, g, buf, sizeof buf);
1646+ }
1647+ }
1648+
1649+ return mixxx_pos;
1650 }
1651
1652-unsigned SoundSourceM4A::read(volatile unsigned long size, const SAMPLE* destination) {
1653+
1654+unsigned SoundSourceM4A::read(unsigned long samples_wanted, const SAMPLE *destination) {
1655+ SAMPLE *dbuf = (SAMPLE *)destination;
1656+ unsigned int samples_decoded = 0;
1657+ int32_t toskip;
1658+ long f; // Current frame number
1659+
1660 // Abort if file did not load.
1661- if (filelength == 0)
1662- return 0;
1663-
1664- //qDebug() << "SSM4A::read()" << size;
1665-
1666- // We want to read a total of "size" samples, and the mp4_read()
1667- // function wants to know how many bytes we want to decode. One
1668- // sample is 16-bits = 2 bytes here, so we multiply size by channels to
1669- // get the number of bytes we want to decode.
1670-
1671- int total_bytes_to_decode = size * m_iChannels;
1672- int total_bytes_decoded = 0;
1673- int num_bytes_req = 4096;
1674- char* buffer = (char*)destination;
1675- SAMPLE * as_buffer = (SAMPLE*) destination; //pointer for mono->stereo filling.
1676- do {
1677- if (total_bytes_decoded + num_bytes_req > total_bytes_to_decode)
1678- num_bytes_req = total_bytes_to_decode - total_bytes_decoded;
1679-
1680- // (char *)&destination[total_bytes_decoded/2],
1681- int numRead = mp4_read(&ipd,
1682- buffer,
1683- num_bytes_req);
1684- if(numRead <= 0) {
1685- //qDebug() << "SSM4A::read: EOF";
1686- break;
1687- }
1688- buffer += numRead;
1689- total_bytes_decoded += numRead;
1690- } while (total_bytes_decoded < total_bytes_to_decode);
1691-
1692- // At this point *destination should be filled. If mono : double all samples
1693- // (L => R)
1694- if (m_iChannels == 1) {
1695- for (int i = total_bytes_decoded/2-1; i >= 0; --i) {
1696- // as_buffer[i] is an audio sample (s16)
1697- //scroll through , copying L->R & expanding buffer
1698- as_buffer[i*2+1] = as_buffer[i];
1699- as_buffer[i*2] = as_buffer[i];
1700- }
1701- }
1702-
1703- // Tell us about it only if we end up decoding a different value
1704- // then what we expect.
1705-
1706- if (total_bytes_decoded % (size * 2)) {
1707- qDebug() << "SSM4A::read : total_bytes_decoded:"
1708- << total_bytes_decoded
1709- << "size:"
1710- << size;
1711- }
1712-
1713- //There are two bytes in a 16-bit sample, so divide by 2.
1714- return total_bytes_decoded / 2;
1715+ if (! infile) {
1716+ return 0;
1717+ }
1718+
1719+ // Figure out which frame to start reading
1720+ f = mp4ff_find_sample(infile, track, mixxx_pos/2, &toskip);
1721+ if (-1 == f) {
1722+ // Can't find that sample, probably because mp4ff_get_track_duration
1723+ // overestimated earlier
1724+ return 0;
1725+ }
1726+
1727+ // In theory, we could see a tiny speedup by caching the output of
1728+ // the last-read frame's decode, in case f here is the same as it
1729+ // was at the end of the last call to this function.
1730+ //
1731+ // In practice, this situation never seems to arise. The complexity
1732+ // caching introduces into the code isn't worth the diminutive
1733+ // theoretical performance gain.
1734+
1735+ while ((f < nframes) && (samples_decoded < samples_wanted)) {
1736+ long samples;
1737+
1738+ samples = read_decode_frame(hDecoder, infile, track, f, (char *)dbuf, (samples_wanted - samples_decoded)*2);
1739+
1740+ /* If we were supposed to skip some samples, shuffle */
1741+ if (toskip > 0) {
1742+ // XXX: I have no idea what the unit of toskip is. I've never seen it non-zero.
1743+ qDebug() << "Warning: toskip=" << toskip << ", this may sound glitchy!";
1744+ memmove(dbuf, (char *)dbuf + toskip, (samples - toskip) * 2);
1745+ toskip = 0;
1746+ }
1747+
1748+ /* Next! */
1749+ f += 1;
1750+
1751+ dbuf += samples;
1752+ samples_decoded += samples;
1753+ }
1754+
1755+ // Advance where mixxx thinks we are in the file
1756+ mixxx_pos += samples_decoded;
1757+
1758+ return samples_decoded;
1759 }
1760
1761 inline long unsigned SoundSourceM4A::length(){
1762- return filelength;
1763- //return m_iChannels * mp4_duration(&ipd) * m_iSampleRate;
1764+ if (! infile) {
1765+ return 0;
1766+ }
1767+ return audiolen;
1768 }
1769
1770 int SoundSourceM4A::parseHeader(){
1771@@ -210,4 +396,5 @@
1772 return list;
1773 }
1774
1775+
1776 }
1777
1778=== modified file 'mixxx/plugins/soundsourcem4a/soundsourcem4a.h'
1779--- mixxx/plugins/soundsourcem4a/soundsourcem4a.h 2011-10-09 19:05:15 +0000
1780+++ mixxx/plugins/soundsourcem4a/soundsourcem4a.h 2012-08-25 14:26:19 +0000
1781@@ -17,17 +17,13 @@
1782 #ifndef SOUNDSOURCEM4A_H
1783 #define SOUNDSOURCEM4A_H
1784
1785-#ifdef __MP4V2__
1786- #include <mp4v2/mp4v2.h>
1787-#else
1788- #include <mp4.h>
1789-#endif
1790+#include <stdio.h>
1791
1792 #include <neaacdec.h>
1793+#include <mp4ff.h>
1794 #include <QString>
1795 #include "soundsource.h"
1796 #include "defs_version.h"
1797-#include "m4a/ip.h"
1798
1799 //As per QLibrary docs: http://doc.trolltech.com/4.6/qlibrary.html#resolve
1800 #ifdef Q_WS_WIN
1801@@ -43,6 +39,7 @@
1802 SoundSourceM4A(QString qFileName);
1803 ~SoundSourceM4A();
1804 int open();
1805+ void close();
1806 long seek(long);
1807 int initializeDecoder();
1808 unsigned read(unsigned long size, const SAMPLE*);
1809@@ -50,10 +47,19 @@
1810 int parseHeader();
1811 static QList<QString> supportedFileExtensions();
1812 private:
1813- int trackId;
1814- unsigned long filelength;
1815- MP4FileHandle mp4file;
1816- input_plugin_data ipd;
1817+ int decoder_init();
1818+
1819+ FILE *stream; // Input stream
1820+ mp4ff_t *infile; // Container context object
1821+ mp4ff_callback_t mp4cb;
1822+
1823+ NeAACDecHandle hDecoder; // AAC context object
1824+ long nframes; // Number of frames in container
1825+ long audiolen; // Length of track (in samples)
1826+ long mixxx_pos; // Where mixxx thinks we are (in samples)
1827+ int track;
1828+
1829+ unsigned char *frame; // A little buffer space for reading container frames
1830 };
1831
1832 extern "C" MY_EXPORT const char* getMixxxVersion()