summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Hochstein <tom.hochstein@nxp.com>2021-09-01 13:21:24 -0500
committerTom Hochstein <tom.hochstein@nxp.com>2021-09-01 13:21:24 -0500
commit7879b28eb0db6ea6c2493b11408d17aee8c6934d (patch)
tree32115992d239c4052f85b2212dd76600d6666f67
parent9c85c8770ff558bc391418a44ecfa71728e7a975 (diff)
downloadmeta-freescale-7879b28eb0db6ea6c2493b11408d17aee8c6934d.tar.gz
tinycompress: Add recipe
Add tinycompress, a library to handle compressed formats like MP3. Signed-off-by: Tom Hochstein <tom.hochstein@nxp.com>
-rwxr-xr-xrecipes-multimedia/tinycompress/tinycompress/0001-tinycompress-Add-id3-decoding.patch1001
-rwxr-xr-xrecipes-multimedia/tinycompress/tinycompress/0002-cplay-Support-wave-file.patch221
-rwxr-xr-xrecipes-multimedia/tinycompress/tinycompress/0003-cplay-Add-pause-feature.patch146
-rwxr-xr-xrecipes-multimedia/tinycompress/tinycompress/0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch40
-rwxr-xr-xrecipes-multimedia/tinycompress/tinycompress/0005-cplay-Support-aac-streams.patch251
-rw-r--r--recipes-multimedia/tinycompress/tinycompress_1.1.6.bb16
6 files changed, 1675 insertions, 0 deletions
diff --git a/recipes-multimedia/tinycompress/tinycompress/0001-tinycompress-Add-id3-decoding.patch b/recipes-multimedia/tinycompress/tinycompress/0001-tinycompress-Add-id3-decoding.patch
new file mode 100755
index 00000000..f578148a
--- /dev/null
+++ b/recipes-multimedia/tinycompress/tinycompress/0001-tinycompress-Add-id3-decoding.patch
@@ -0,0 +1,1001 @@
1From 16f6b7a5baec41f18fde75fd311fb988e3c31810 Mon Sep 17 00:00:00 2001
2From: Shengjiu Wang <shengjiu.wang@nxp.com>
3Date: Fri, 13 Jul 2018 18:13:24 +0800
4Subject: [PATCH] tinycompress: Add id3 decoding
5
6Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
7---
8 include/tinycompress/id3_tag_decode.h | 198 +++++++++++
9 src/utils/Makefile.am | 2 +-
10 src/utils/cplay.c | 88 +++++
11 src/utils/id3_tag_decode.c | 642 ++++++++++++++++++++++++++++++++++
12 4 files changed, 929 insertions(+), 1 deletion(-)
13 create mode 100644 include/tinycompress/id3_tag_decode.h
14 create mode 100644 src/utils/id3_tag_decode.c
15
16diff --git a/include/tinycompress/id3_tag_decode.h b/include/tinycompress/id3_tag_decode.h
17new file mode 100644
18index 0000000..1a911d7
19--- /dev/null
20+++ b/include/tinycompress/id3_tag_decode.h
21@@ -0,0 +1,198 @@
22+/*
23+ * Copyright (c) 2006-2017 Cadence Design Systems, Inc.
24+ * Copyright 2018 NXP
25+ *
26+ * Permission is hereby granted, free of charge, to any person obtaining
27+ * a copy of this software and associated documentation files (the
28+ * "Software"), to deal in the Software without restriction, including
29+ * without limitation the rights to use, copy, modify, merge, publish,
30+ * distribute, sublicense, and/or sell copies of the Software, and to
31+ * permit persons to whom the Software is furnished to do so, subject to
32+ * the following conditions:
33+ *
34+ * The above copyright notice and this permission notice shall be included
35+ * in all copies or substantial portions of the Software.
36+ *
37+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
38+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
41+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
42+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
43+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44+ */
45+
46+/******************************************************************
47+ * file name : id3_tag_decode.h
48+ *
49+ * description : stores typedefs of structures specific to MP3 tag
50+ *
51+ * revision history:
52+ * 29 04 2004 DK creation
53+ *****************************************************************/
54+
55+#ifndef ID3_TAG_DECODE_H
56+#define ID3_TAG_DECODE_H
57+
58+typedef signed char WORD8;
59+typedef signed char * pWORD8;
60+typedef unsigned char UWORD8;
61+typedef unsigned char * pUWORD8;
62+
63+typedef signed short WORD16;
64+typedef signed short * pWORD16;
65+typedef unsigned short UWORD16;
66+typedef unsigned short * pUWORD16;
67+
68+typedef signed int WORD24;
69+typedef signed int * pWORD24;
70+typedef unsigned int UWORD24;
71+typedef unsigned int * pUWORD24;
72+
73+typedef signed int WORD32;
74+typedef signed int * pWORD32;
75+typedef unsigned int UWORD32;
76+typedef unsigned int * pUWORD32;
77+
78+typedef void VOID;
79+typedef void * pVOID;
80+
81+typedef signed int BOOL;
82+typedef unsigned int UBOOL;
83+typedef signed int FLAG;
84+typedef unsigned int UFLAG;
85+typedef signed int LOOPIDX;
86+typedef unsigned int ULOOPIDX;
87+typedef signed int WORD;
88+typedef unsigned int UWORD;
89+
90+#define MAX_TAG_FRAME_SIZE 100
91+
92+#define ID3V1 (0x544147) /* 0x544147 is TAG in WORD8 */
93+
94+#define ID3V2 (0x494433) /* 0x494433 is ID3 in WORD8 */
95+
96+/*
97+ * structure corresponding to ID3 tag v1 header.
98+ * this structure has all the field corresponding to ID3 tag v1 header.
99+ */
100+
101+typedef struct {
102+ WORD32 tag; // 3 bytes
103+
104+ WORD16 version; // 2 bytes
105+
106+ WORD8 flag; //1 byte
107+
108+ WORD32 size; //4 bytes
109+
110+} id3_v2_header_struct;
111+
112+/* structure which will store the frame data and
113+ * also put a limit max data to be stored
114+ */
115+typedef struct {
116+ WORD8 frame_data[MAX_TAG_FRAME_SIZE];
117+
118+ WORD32 max_size; //4 bytes
119+
120+ WORD16 tag_present;
121+
122+ WORD16 exceeds_buffer_size;
123+
124+} id3_v2_frame_struct;
125+
126+/*
127+ * structure corresponding to ID3 tag v2.
128+ * this structure has some of the field corresponding to ID3 tag v2.
129+ * if user wants to read some more tag information from
130+ * the MP3 file, he can add that field in this structure and pass address
131+ * of that element to get_inf function in id3_tag_decode.c under the
132+ * corresponding field frame header. few fields which are needed are already
133+ * populated by reading from the TAG header.
134+ */
135+typedef struct {
136+ id3_v2_frame_struct album_movie_show_title;
137+
138+ id3_v2_frame_struct composer_name;
139+
140+ id3_v2_frame_struct content_type;
141+
142+ id3_v2_frame_struct encoded_by;
143+
144+ id3_v2_frame_struct lyricist_text_writer;
145+
146+ id3_v2_frame_struct content_group_description;
147+
148+ id3_v2_frame_struct title_songname_content_description;
149+
150+ id3_v2_frame_struct medxa_type;
151+
152+ id3_v2_frame_struct original_album_movie_show_title;
153+
154+ id3_v2_frame_struct original_filename;
155+
156+ id3_v2_frame_struct original_lyricist_text_writer;
157+
158+ id3_v2_frame_struct original_artist_performer;
159+
160+ id3_v2_frame_struct file_owner_licensee;
161+
162+ id3_v2_frame_struct lead_performer_soloist;
163+
164+ id3_v2_frame_struct publisher;
165+
166+ id3_v2_frame_struct private_frame;
167+
168+ id3_v2_frame_struct other_info;
169+
170+ id3_v2_header_struct id3_v2_header;
171+
172+ WORD32 header_end;
173+
174+ WORD32 bytes_consumed;
175+
176+} id3v2_struct;
177+
178+/*
179+ * structure corresponding to ID3 tag v1.
180+ * this structure has all the field corresponding to ID3 tag v1.
181+ */
182+typedef struct {
183+ WORD8 song_title[30]; //30 word8acters
184+
185+ WORD8 artist[30]; //30 word8acters
186+
187+ WORD8 album[30]; //30 word8acters
188+
189+ WORD8 year[4]; //4 word8acters
190+
191+ WORD8 comment[30]; //30 word8acters
192+
193+ WORD8 genre[1]; //1 byte
194+
195+} id3v1_struct;
196+
197+WORD32 get_info(const char *inp_buffer,
198+ unsigned int avail_inp,
199+ WORD32 tag_size,
200+ id3_v2_frame_struct *dest);
201+
202+WORD32 search_id3_v2(UWORD8 *buffer);
203+
204+WORD32 decode_id3_v2(const char *const buffer,
205+ id3v2_struct *id3v2,
206+ WORD32 continue_flag,
207+ WORD32 insize);
208+
209+WORD32 get_id3_v2_bytes(UWORD8 *buffer);
210+
211+WORD32 get_v1_info(UWORD8 *buffer, id3v1_struct *id3v1);
212+
213+WORD32 search_id3_v1(UWORD8 *buffer);
214+
215+WORD32 decode_id3_v1(UWORD8 *buffer, id3v1_struct *id3v1);
216+
217+void init_id3v2_field(id3v2_struct *id3v2);
218+
219+#endif
220diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
221index 1b996d4..e813689 100644
222--- a/src/utils/Makefile.am
223+++ b/src/utils/Makefile.am
224@@ -1,6 +1,6 @@
225 bin_PROGRAMS = cplay crecord
226
227-cplay_SOURCES = cplay.c
228+cplay_SOURCES = cplay.c id3_tag_decode.c
229 crecord_SOURCES = crecord.c
230
231 cplay_CFLAGS = -I$(top_srcdir)/include
232diff --git a/src/utils/cplay.c b/src/utils/cplay.c
233index 87863a3..2a52b52 100644
234--- a/src/utils/cplay.c
235+++ b/src/utils/cplay.c
236@@ -72,6 +72,7 @@
237 #include "sound/compress_params.h"
238 #include "tinycompress/tinycompress.h"
239 #include "tinycompress/tinymp3.h"
240+#include "tinycompress/id3_tag_decode.h"
241
242 static int verbose;
243 static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM;
244@@ -245,12 +246,97 @@ int main(int argc, char **argv)
245 exit(EXIT_SUCCESS);
246 }
247
248+void shift_buffer(char *buf, int buf_size, int bytes_consumed)
249+{
250+ int i;
251+
252+ if (bytes_consumed <= 0)
253+ return;
254+
255+ for (i = 0; i < buf_size - bytes_consumed; i++)
256+ buf[i] = buf[i + bytes_consumed];
257+}
258+
259+void parse_id3(FILE *file, int *offset) {
260+ /* ID3 tag specific declarations */
261+ unsigned char id3_buf[128];
262+ unsigned char id3v2_buf[4096];
263+ signed int id3_v1_found = 0, id3_v1_decoded = 0;
264+ signed int id3_v2_found = 0, id3_v2_complete = 0;
265+ signed int i_bytes_consumed = 0;
266+ signed int i_fread_bytes;
267+ id3v1_struct id3v1;
268+ id3v2_struct id3v2;
269+
270+ {
271+ fseek(file, -128, SEEK_END);
272+ fread(id3_buf, 1, 128, file);
273+
274+ /* search for ID3V1 */
275+ id3_v1_found = search_id3_v1(id3_buf + 0);
276+ if (id3_v1_found) {
277+ /* if ID3V1 is found, decode ID3V1 */
278+ decode_id3_v1(id3_buf + 3, &id3v1);
279+ id3_v1_decoded = 1;
280+ }
281+ fseek(file, 0, SEEK_SET);
282+ }
283+
284+ {
285+ signed int flag = 0;
286+ signed int continue_flag = 0;
287+
288+ i_fread_bytes = fread(id3v2_buf,
289+ sizeof(char), 0x1000, file);
290+
291+ /* search for ID3V2 */
292+ id3_v2_found =
293+ search_id3_v2(id3v2_buf);
294+
295+ if (id3_v2_found) {
296+ /* initialise the max fields */
297+ init_id3v2_field(&id3v2);
298+
299+ while (!id3_v2_complete && id3_v2_found) {
300+ /* if ID3V2 is found, decode ID3V2 */
301+ id3_v2_complete = decode_id3_v2((const char *const)id3v2_buf,
302+ &id3v2, continue_flag, i_fread_bytes);
303+
304+ if (!id3_v2_complete) {
305+ continue_flag = 1;
306+ i_bytes_consumed = id3v2.bytes_consumed;
307+
308+ fseek(file, i_bytes_consumed, SEEK_SET);
309+
310+ i_fread_bytes = fread(id3v2_buf,
311+ sizeof(unsigned char), 0x1000, file);
312+ if (i_fread_bytes <= 0) {
313+ return;
314+ }
315+ }
316+ }
317+
318+ if (id3_v2_complete) {
319+ i_bytes_consumed = id3v2.bytes_consumed;
320+ fseek(file, i_bytes_consumed, SEEK_SET);
321+ }
322+ }
323+ }
324+
325+ *offset = i_bytes_consumed;
326+}
327+
328 void get_codec_mp3(FILE *file, struct compr_config *config,
329 struct snd_codec *codec)
330 {
331 size_t read;
332 struct mp3_header header;
333 unsigned int channels, rate, bits;
334+ int offset = 0;
335+
336+ parse_id3(file, &offset);
337+
338+ fseek(file, offset, SEEK_SET);
339
340 read = fread(&header, 1, sizeof(header), file);
341 if (read != sizeof(header)) {
342@@ -279,6 +365,8 @@ void get_codec_mp3(FILE *file, struct compr_config *config,
343 codec->level = 0;
344 codec->ch_mode = 0;
345 codec->format = 0;
346+
347+ fseek(file, offset, SEEK_SET);
348 }
349
350 void get_codec_iec(FILE *file, struct compr_config *config,
351diff --git a/src/utils/id3_tag_decode.c b/src/utils/id3_tag_decode.c
352new file mode 100644
353index 0000000..393967a
354--- /dev/null
355+++ b/src/utils/id3_tag_decode.c
356@@ -0,0 +1,642 @@
357+/*
358+ * Copyright (c) 2006-2017 Cadence Design Systems, Inc.
359+ * Copyright 2018 NXP
360+ *
361+ * Permission is hereby granted, free of charge, to any person obtaining
362+ * a copy of this software and associated documentation files (the
363+ * "Software"), to deal in the Software without restriction, including
364+ * without limitation the rights to use, copy, modify, merge, publish,
365+ * distribute, sublicense, and/or sell copies of the Software, and to
366+ * permit persons to whom the Software is furnished to do so, subject to
367+ * the following conditions:
368+ *
369+ * The above copyright notice and this permission notice shall be included
370+ * in all copies or substantial portions of the Software.
371+ *
372+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
373+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
374+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
375+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
376+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
377+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
378+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
379+ */
380+#include <ctype.h>
381+#include "tinycompress/id3_tag_decode.h"
382+
383+#define CHAR4(c1, c2, c3, c4) \
384+ (int)(((unsigned char)(c1) << 24) | \
385+ ((unsigned char)(c2) << 16) | \
386+ ((unsigned char)(c3) << 8) | \
387+ ((unsigned char)c4))
388+
389+#ifndef MSVC_BUILD
390+unsigned int umin(unsigned int a, unsigned int b)
391+{
392+ return (a < b ? a : b);
393+}
394+
395+#else
396+unsigned int umin(unsigned int a, unsigned int b)
397+{
398+ return (a < b ? a : b);
399+}
400+#endif
401+
402+/***********************************************************
403+ * function name : display
404+ *
405+ * description : display ID3 tag contents.
406+ *
407+ * arguments : input parameters
408+ *
409+ * values returned : 0
410+ ***********************************************************/
411+
412+static void display2(const id3_v2_frame_struct * const src,
413+ int size,
414+ const char * const disp)
415+{
416+ int j;
417+
418+
419+ for (j = 0; j < size; j++) {
420+ int c = src->frame_data[j];
421+
422+ if (c) {
423+ if (!isprint(c))
424+ break;
425+ }
426+ }
427+}
428+
429+static VOID display1(WORD8 src[], WORD32 size, WORD8 disp[])
430+{
431+ WORD32 j;
432+
433+ for (j = 0; j < size ; j++) {
434+ int c = src[j];
435+
436+ if (c) {
437+ if (!isprint(c))
438+ break;
439+ }
440+ }
441+}
442+
443+/*****************************************************************
444+ * function name : init_id3_header
445+ *
446+ * description : initialise the max filed size of teh farem.
447+ *
448+ * arguments : input parameters
449+ *
450+ * values returned : 0
451+ ****************************************************************/
452+
453+VOID init_id3v2_field(id3v2_struct *id3v2)
454+{
455+ id3v2->album_movie_show_title.max_size = MAX_TAG_FRAME_SIZE;
456+ id3v2->composer_name.max_size = MAX_TAG_FRAME_SIZE;
457+ id3v2->content_type.max_size = MAX_TAG_FRAME_SIZE;
458+ id3v2->encoded_by.max_size = MAX_TAG_FRAME_SIZE;
459+ id3v2->lyricist_text_writer.max_size = MAX_TAG_FRAME_SIZE;
460+ id3v2->content_group_description.max_size = MAX_TAG_FRAME_SIZE;
461+ id3v2->title_songname_content_description.max_size = MAX_TAG_FRAME_SIZE;
462+ id3v2->medxa_type.max_size = MAX_TAG_FRAME_SIZE;
463+ id3v2->original_album_movie_show_title.max_size = MAX_TAG_FRAME_SIZE;
464+ id3v2->original_filename.max_size = MAX_TAG_FRAME_SIZE;
465+ id3v2->original_lyricist_text_writer.max_size = MAX_TAG_FRAME_SIZE;
466+ id3v2->original_artist_performer.max_size = MAX_TAG_FRAME_SIZE;
467+ id3v2->file_owner_licensee.max_size = MAX_TAG_FRAME_SIZE;
468+ id3v2->lead_performer_soloist.max_size = MAX_TAG_FRAME_SIZE;
469+ id3v2->publisher.max_size = MAX_TAG_FRAME_SIZE;
470+ id3v2->private_frame.max_size = MAX_TAG_FRAME_SIZE;
471+ id3v2->other_info.max_size = MAX_TAG_FRAME_SIZE;
472+
473+ /* resetting the flag to indicate presese of frame */
474+ id3v2->album_movie_show_title.tag_present = 0;
475+ id3v2->composer_name.tag_present = 0;
476+ id3v2->content_type.tag_present = 0;
477+ id3v2->encoded_by.tag_present = 0;
478+ id3v2->lyricist_text_writer.tag_present = 0;
479+ id3v2->content_group_description.tag_present = 0;
480+ id3v2->title_songname_content_description.tag_present = 0;
481+ id3v2->medxa_type.tag_present = 0;
482+ id3v2->original_album_movie_show_title.tag_present = 0;
483+ id3v2->original_filename.tag_present = 0;
484+ id3v2->original_lyricist_text_writer.tag_present = 0;
485+ id3v2->original_artist_performer.tag_present = 0;
486+ id3v2->file_owner_licensee.tag_present = 0;
487+ id3v2->lead_performer_soloist.tag_present = 0;
488+ id3v2->publisher.tag_present = 0;
489+ id3v2->private_frame.tag_present = 0;
490+ id3v2->other_info.tag_present = 0;
491+
492+ /* resetting the flag which indicates that size of the frame has
493+ * exceeded the max buffer size
494+ */
495+ id3v2->album_movie_show_title.exceeds_buffer_size = 0;
496+ id3v2->composer_name.exceeds_buffer_size = 0;
497+ id3v2->content_type.exceeds_buffer_size = 0;
498+ id3v2->encoded_by.exceeds_buffer_size = 0;
499+ id3v2->lyricist_text_writer.exceeds_buffer_size = 0;
500+ id3v2->content_group_description.exceeds_buffer_size = 0;
501+ id3v2->title_songname_content_description.exceeds_buffer_size = 0;
502+ id3v2->medxa_type.exceeds_buffer_size = 0;
503+ id3v2->original_album_movie_show_title.exceeds_buffer_size = 0;
504+ id3v2->original_filename.exceeds_buffer_size = 0;
505+ id3v2->original_lyricist_text_writer.exceeds_buffer_size = 0;
506+ id3v2->original_artist_performer.exceeds_buffer_size = 0;
507+ id3v2->file_owner_licensee.exceeds_buffer_size = 0;
508+ id3v2->lead_performer_soloist.exceeds_buffer_size = 0;
509+ id3v2->publisher.exceeds_buffer_size = 0;
510+ id3v2->private_frame.exceeds_buffer_size = 0;
511+ id3v2->other_info.exceeds_buffer_size = 0;
512+
513+ id3v2->bytes_consumed = 0;
514+ id3v2->header_end = 0;
515+}
516+
517+/***************************************************************
518+ * function name : search_id3_v2
519+ *
520+ * description : finds if ID3V2 starts at the start of given buffer.
521+ *
522+ * arguments : input parameters
523+ * buffer input buffer
524+ *
525+ * values returned : FLAG 1: ID3 found 0: ID3 not found
526+ ***************************************************************/
527+WORD32 search_id3_v2(UWORD8 *buffer)
528+{
529+ UWORD32 temp;
530+
531+ temp = buffer[0] << 16;
532+ temp |= buffer[1] << 8;
533+ temp |= buffer[2];
534+
535+ if (temp == ID3V2)
536+ return 1; /* ID3 found */
537+
538+ return 0; /* ID3 not found */
539+}
540+
541+/**************************************************************
542+ * function name : search_id3_v1
543+ *
544+ * description : finds if ID3V1 starts at the start of given buffer.
545+ *
546+ * arguments : input parameters
547+ * buffer input buffer
548+ *
549+ * values returned : FLAG 1: ID3 found 0: ID3 not found
550+ **************************************************************/
551+WORD32 search_id3_v1(UWORD8 *buffer)
552+{
553+ UWORD32 temp;
554+
555+ temp = buffer[0] << 16;
556+ temp |= buffer[1] << 8;
557+ temp |= buffer[2];
558+
559+ if (temp == ID3V1)
560+ return 1; /* ID3 found */
561+
562+ return 0; /* ID3 not found */
563+}
564+
565+/***************************************************************
566+ * function name : decode_id3_v1
567+ *
568+ * description : decodes ID3V1 tag.
569+ *
570+ * arguments : input parameters
571+ * buffer input buffer
572+ * id3v1 structure
573+ *
574+ * values returned : bytes consumed
575+ **************************************************************/
576+WORD32 decode_id3_v1(UWORD8 *buffer, id3v1_struct *id3v1)
577+{
578+ WORD32 bytes_consumed = 0;
579+ short tag_type;
580+
581+ /* setting the tag type */
582+ tag_type = 1;
583+
584+ bytes_consumed = get_v1_info(buffer, id3v1);
585+
586+ return bytes_consumed;
587+}
588+
589+/***********************************************************
590+ * function name : get_v1_info
591+ *
592+ * description : gets ID3V1 information fields.
593+ *
594+ * arguments : input parameters
595+ * buffer input buffer
596+ * id3v1 structure
597+ *
598+ * values returned : bytes consumed
599+ ***********************************************************/
600+WORD32 get_v1_info(UWORD8 *buffer, id3v1_struct *id3v1)
601+{
602+ WORD32 i;
603+ WORD32 bytes_consumed = 0;
604+
605+ /* get song_title */
606+ for (i = 0; i < 30; i++)
607+ id3v1->song_title[i] = buffer[i];
608+
609+ buffer += 30;
610+ bytes_consumed += 30;
611+ display1(id3v1->song_title, 30, (WORD8 *)"song_title : ");
612+
613+ /* get artist */
614+ for (i = 0; i < 30; i++)
615+ id3v1->artist[i] = buffer[i];
616+
617+ buffer += 30;
618+ bytes_consumed += 30;
619+ display1(id3v1->artist, 30, (WORD8 *)"artist : ");
620+
621+ /* get album */
622+ for (i = 0; i < 30; i++)
623+ id3v1->album[i] = buffer[i];
624+
625+ buffer += 30;
626+ bytes_consumed += 30;
627+ display1(id3v1->album, 30, (WORD8 *)"album : ");
628+
629+ /* get year */
630+ for (i = 0; i < 4; i++)
631+ id3v1->year[i] = buffer[i];
632+
633+ buffer += 4;
634+ bytes_consumed += 4;
635+ display1(id3v1->year, 4, (WORD8 *)"year : ");
636+
637+ /* get comment */
638+ for (i = 0; i < 30; i++)
639+ id3v1->comment[i] = buffer[i];
640+
641+ buffer += 30;
642+ bytes_consumed += 30;
643+ display1(id3v1->comment, 30, (WORD8 *)"comment : ");
644+
645+ /* get genre */
646+ for (i = 0; i < 1; i++)
647+ id3v1->genre[i] = buffer[i];
648+
649+ buffer += 1;
650+ bytes_consumed += 1;
651+
652+ return bytes_consumed;
653+}
654+
655+/*****************************************************
656+ * function name : decode_id3_v2
657+ *
658+ * description : decodes ID3V2 tag.
659+ *
660+ * arguments : input parameters
661+ * buffer input buffer
662+ * id3v2 structure
663+ * continue_flag FLAG to indicate whether
664+ * it is first call or not
665+ * insize input buffer size
666+ *
667+ * values returned : bytes consumed
668+ ******************************************************/
669+WORD32 decode_id3_v2(const char *const buffer,
670+ id3v2_struct *const id3v2,
671+ WORD32 continue_flag,
672+ WORD32 insize)
673+{
674+ UWORD32 size = 0, flag;
675+ WORD32 i, buf_update_val;
676+ UWORD8 buf[4], frame_header[10], id3_buffer[10];
677+ WORD8 *bitstream_ptr;
678+ short tag_type;
679+
680+ WORD32 bytes_consumed = 0;
681+
682+ if (id3v2->header_end == 1) {
683+ id3v2->bytes_consumed += insize;
684+ if (id3v2->bytes_consumed < id3v2->id3_v2_header.size)
685+ return 0;
686+
687+ id3v2->bytes_consumed = (id3v2->id3_v2_header.size + 10);
688+ return 1;
689+ }
690+
691+ bitstream_ptr = (WORD8 *)id3_buffer;
692+
693+ if (!continue_flag) {
694+ bytes_consumed += 3;
695+ /* setting the tag type */
696+ tag_type = 2;
697+ id3v2->id3_v2_header.version = buffer[bytes_consumed + 0] << 8;
698+ id3v2->id3_v2_header.version |= buffer[bytes_consumed + 1];
699+ id3v2->id3_v2_header.flag = buffer[bytes_consumed + 2];
700+
701+ /* making the msb of each byte zero */
702+ buf[0] = buffer[bytes_consumed + 6] & 0x7f;
703+ buf[1] = buffer[bytes_consumed + 5] & 0x7f;
704+ buf[2] = buffer[bytes_consumed + 4] & 0x7f;
705+ buf[3] = buffer[bytes_consumed + 3] & 0x7f;
706+
707+ bytes_consumed += 7;
708+
709+ /* concatenation the bytes after making
710+ * 7th bit zero to get 28 bits size
711+ */
712+ size = buf[0];
713+ size |= (buf[1] << 7);
714+ size |= (buf[2] << 14);
715+ size |= (buf[3] << 21);
716+ /* storing the size */
717+ id3v2->id3_v2_header.size = size;
718+
719+ /* check for extended header */
720+ if (id3v2->id3_v2_header.flag & 0x20) {
721+ for (i = 0; i < 10; i++)
722+ bitstream_ptr[i] = buffer[bytes_consumed + i];
723+
724+ i = 0;
725+ bytes_consumed += 10;
726+
727+ size = bitstream_ptr[i++] << 24;
728+ size |= bitstream_ptr[i++] << 16;
729+ size |= bitstream_ptr[i++] << 8;
730+ size |= bitstream_ptr[i++];
731+
732+ /* two bytes for flag */
733+ i += 2;
734+ {
735+ UWORD32 padding_size;
736+
737+ padding_size = bitstream_ptr[i++] << 24;
738+ padding_size |= bitstream_ptr[i++] << 16;
739+ padding_size |= bitstream_ptr[i++] << 8;
740+ padding_size |= bitstream_ptr[i++];
741+
742+ /* skipping the padding and frame size
743+ * number of bytes
744+ */
745+ bytes_consumed += (padding_size + size);
746+ }
747+ }
748+ }
749+
750+ while (id3v2->header_end != 1) {
751+ char *key;
752+ id3_v2_frame_struct *value;
753+ unsigned int avail_inp;
754+
755+ /* reading the 10 bytes to get the frame header */
756+
757+ for (i = 0; i < 10; i++)
758+ frame_header[i] = buffer[bytes_consumed + i];
759+ bytes_consumed += 10;
760+
761+ /* getting the size from the header */
762+ size = frame_header[4] << 24;
763+ size |= frame_header[5] << 16;
764+ size |= frame_header[6] << 8;
765+ size |= frame_header[7];
766+
767+ /* decoding the flag, currently not used */
768+ flag = frame_header[8] << 8;
769+ flag |= frame_header[9];
770+
771+ avail_inp = insize - bytes_consumed;
772+
773+ /* switching to the frame type */
774+ switch (CHAR4(frame_header[0],
775+ frame_header[1],
776+ frame_header[2],
777+ frame_header[3])) {
778+ case CHAR4('A', 'E', 'N', 'C'):
779+ case CHAR4('A', 'P', 'I', 'C'):
780+ case CHAR4('C', 'O', 'M', 'M'):
781+ case CHAR4('C', 'O', 'M', 'R'):
782+ case CHAR4('E', 'N', 'C', 'R'):
783+ case CHAR4('E', 'Q', 'U', 'A'):
784+ case CHAR4('E', 'T', 'C', 'O'):
785+ case CHAR4('G', 'E', 'O', 'B'):
786+ case CHAR4('G', 'R', 'I', 'D'):
787+ case CHAR4('I', 'P', 'L', 'S'):
788+ case CHAR4('L', 'I', 'N', 'K'):
789+ case CHAR4('M', 'C', 'D', 'I'):
790+ case CHAR4('M', 'L', 'L', 'T'):
791+ case CHAR4('O', 'W', 'N', 'E'):
792+ case CHAR4('P', 'C', 'N', 'T'):
793+ case CHAR4('P', 'O', 'P', 'M'):
794+ case CHAR4('P', 'O', 'S', 'S'):
795+ case CHAR4('R', 'B', 'U', 'F'):
796+ case CHAR4('R', 'V', 'A', 'D'):
797+ case CHAR4('R', 'V', 'R', 'B'):
798+ case CHAR4('S', 'Y', 'L', 'T'):
799+ case CHAR4('S', 'Y', 'T', 'C'):
800+ case CHAR4('T', 'B', 'P', 'M'):
801+ case CHAR4('T', 'C', 'O', 'P'):
802+ case CHAR4('T', 'D', 'A', 'T'):
803+ case CHAR4('T', 'D', 'L', 'Y'):
804+ case CHAR4('T', 'F', 'L', 'T'):
805+ case CHAR4('T', 'I', 'M', 'E'):
806+ case CHAR4('T', 'K', 'E', 'Y'):
807+ case CHAR4('T', 'L', 'A', 'N'):
808+ case CHAR4('T', 'L', 'E', 'N'):
809+ case CHAR4('T', 'M', 'E', 'D'):
810+ case CHAR4('T', 'O', 'F', 'N'):
811+ case CHAR4('T', 'O', 'L', 'Y'):
812+ case CHAR4('T', 'O', 'R', 'Y'):
813+ case CHAR4('T', 'P', 'E', '2'):
814+ case CHAR4('T', 'P', 'E', '3'):
815+ case CHAR4('T', 'P', 'E', '4'):
816+ case CHAR4('T', 'P', 'O', 'S'):
817+ case CHAR4('T', 'R', 'C', 'K'):
818+ case CHAR4('T', 'R', 'D', 'A'):
819+ case CHAR4('T', 'R', 'S', 'N'):
820+ case CHAR4('T', 'R', 'S', 'O'):
821+ case CHAR4('T', 'S', 'I', 'Z'):
822+ case CHAR4('T', 'S', 'R', 'C'):
823+ case CHAR4('T', 'S', 'S', 'E'):
824+ case CHAR4('T', 'Y', 'E', 'R'):
825+ case CHAR4('T', 'X', 'X', 'X'):
826+ case CHAR4('U', 'F', 'I', 'D'):
827+ case CHAR4('U', 'S', 'E', 'R'):
828+ case CHAR4('U', 'S', 'L', 'T'):
829+ case CHAR4('W', 'C', 'O', 'M'):
830+ case CHAR4('W', 'C', 'O', 'P'):
831+ case CHAR4('W', 'O', 'A', 'F'):
832+ case CHAR4('W', 'O', 'A', 'R'):
833+ case CHAR4('W', 'O', 'A', 'S'):
834+ case CHAR4('W', 'O', 'R', 'S'):
835+ case CHAR4('W', 'P', 'A', 'Y'):
836+ case CHAR4('W', 'P', 'U', 'B'):
837+ case CHAR4('W', 'X', 'X', 'X'):
838+ case CHAR4('T', 'I', 'T', '3'):
839+ key = "other_info : ";
840+ value = &id3v2->other_info;
841+ break;
842+ case CHAR4('P', 'R', 'I', 'V'):
843+ key = "private_frame : ";
844+ value = &id3v2->private_frame;
845+ break;
846+ case CHAR4('T', 'A', 'L', 'B'):
847+ key = "album_movie_show_title : ";
848+ value = &id3v2->album_movie_show_title;
849+ break;
850+ case CHAR4('T', 'C', 'O', 'M'):
851+ key = "composer_name : ";
852+ value = &id3v2->composer_name;
853+ break;
854+ case CHAR4('T', 'C', 'O', 'N'):
855+ key = "content_type : ";
856+ value = &id3v2->content_type;
857+ break;
858+ case CHAR4('T', 'E', 'N', 'C'):
859+ key = "encoded_by : ";
860+ value = &id3v2->encoded_by;
861+ break;
862+ case CHAR4('T', 'E', 'X', 'T'):
863+ key = "lyricist_text_writer : ";
864+ value = &id3v2->lyricist_text_writer;
865+ break;
866+ case CHAR4('T', 'I', 'T', '1'):
867+ key = "content_group_description : ";
868+ value = &id3v2->content_group_description;
869+ break;
870+ case CHAR4('T', 'I', 'T', '2'):
871+ key = "title_songname_content_description : ";
872+ value = &id3v2->title_songname_content_description;
873+ break;
874+ case CHAR4('T', 'O', 'A', 'L'):
875+ key = "original_album_movie_show_title : ";
876+ value = &id3v2->original_album_movie_show_title;
877+ break;
878+ case CHAR4('T', 'O', 'P', 'E'):
879+ key = "original_artist_performer : ";
880+ value = &id3v2->original_artist_performer;
881+ break;
882+ case CHAR4('T', 'O', 'W', 'N'):
883+ key = "file_owner_licensee : ";
884+ value = &id3v2->file_owner_licensee;
885+ break;
886+ case CHAR4('T', 'P', 'E', '1'):
887+ key = "lead_performer_soloist : ";
888+ value = &id3v2->lead_performer_soloist;
889+ break;
890+ case CHAR4('T', 'P', 'U', 'B'):
891+ key = "publisher : ";
892+ value = &id3v2->publisher;
893+ break;
894+ default:
895+ /* skipping the read 10 bytes */
896+ buf_update_val = -10;
897+ id3v2->header_end = 1;
898+ value = 0;
899+ key = 0;
900+ break;
901+ }
902+
903+ if (value != 0)
904+ buf_update_val = get_info(&buffer[bytes_consumed],
905+ avail_inp, size, value);
906+
907+ /* Negative value for buf_update_val means one of two things:
908+ * 1. The default case happened and we're done with ID3V2 tag
909+ * frames, or
910+ * 2. get_info() returned -1 to indicate that more input is
911+ * required to decode this frame of the tag.
912+ */
913+ if (buf_update_val >= 0)
914+ display2(value,
915+ umin(value->max_size, buf_update_val), key);
916+
917+ if (buf_update_val == -1) {
918+ id3v2->bytes_consumed += bytes_consumed;
919+ return 1;
920+ }
921+
922+ bytes_consumed += buf_update_val;
923+
924+ /* Is there enough input left (10 bytes) to begin
925+ * decoding another frame? If not, bag out temporarily
926+ * now. The caller will refill our input buffer and
927+ * call us again with continue_flag == 1.
928+ */
929+ if (insize - bytes_consumed < 10) {
930+ id3v2->bytes_consumed += bytes_consumed;
931+ return 0; /* not completely decoded */
932+ }
933+ }
934+
935+ id3v2->bytes_consumed += bytes_consumed;
936+ if ((id3v2->bytes_consumed + 10) < id3v2->id3_v2_header.size)
937+ return 0; /* not completely decoded */
938+
939+ return 1; /* completely decoded */
940+}
941+
942+/*******************************************************
943+ * function name : get_id3_v2_bytes
944+ *
945+ * description : tells the size of ID3V2 tag.
946+ *
947+ * arguments : input parameters
948+ * buffer input buffer
949+ *
950+ * values returned : bytes consumed
951+ ********************************************************/
952+WORD32 get_id3_v2_bytes(UWORD8 *buffer)
953+{
954+ WORD32 size;
955+
956+ /* making the msb of each byte zero */
957+ size = (buffer[9] & 0x7f);
958+ size |= ((buffer[8] & 0x7f) << 7);
959+ size |= ((buffer[7] & 0x7f) << 14);
960+ size |= ((buffer[6] & 0x7f) << 21);
961+
962+ return (size + 10);
963+}
964+
965+/****************************************************
966+ * function name : get_info
967+ *
968+ * description : read the frame information from the input buffer.
969+ *
970+ * arguments : input parameters
971+ *
972+ * values returned : update value for buffer
973+ ****************************************************/
974+WORD32 get_info(const char *inp_buffer,
975+ unsigned int avail_inp,
976+ WORD32 tag_size,
977+ id3_v2_frame_struct *dest)
978+{
979+ WORD32 j;
980+
981+ /* setting the tag to indicate the presence of frame */
982+ dest->tag_present = 1;
983+ /* If there isn't enough input available, we punt back to the top
984+ * level and ask for more.
985+ */
986+ if (avail_inp < umin(tag_size, dest->max_size))
987+ return -1;
988+
989+ if (dest->max_size >= tag_size) {
990+ for (j = 0; j < tag_size ; j++)
991+ dest->frame_data[j] = inp_buffer[j];
992+ } else {
993+ dest->exceeds_buffer_size = 1;
994+ for (j = 0; j < dest->max_size ; j++)
995+ dest->frame_data[j] = inp_buffer[j];
996+ }
997+ return tag_size;
998+}
999--
10002.7.4
1001
diff --git a/recipes-multimedia/tinycompress/tinycompress/0002-cplay-Support-wave-file.patch b/recipes-multimedia/tinycompress/tinycompress/0002-cplay-Support-wave-file.patch
new file mode 100755
index 00000000..9189bc0e
--- /dev/null
+++ b/recipes-multimedia/tinycompress/tinycompress/0002-cplay-Support-wave-file.patch
@@ -0,0 +1,221 @@
1From 4d4bc0a958fe254531920095fbabc241aad88113 Mon Sep 17 00:00:00 2001
2From: Shengjiu Wang <shengjiu.wang@nxp.com>
3Date: Tue, 28 Jul 2020 13:00:36 +0800
4Subject: [PATCH] cplay: Support wave file
5
6The supported format is mono/stereo, S16_LE/S32_LE, 8kHz-192kHz.
7Command is:
8cplay -c x -I PCM test.wav
9
10Upstream-Status: Inappropriate [i.MX specific]
11Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
12---
13 include/tinycompress/wave_formats.h | 51 +++++++++++++
14 src/utils/cplay.c | 107 ++++++++++++++++++++++++++++
15 2 files changed, 158 insertions(+)
16 create mode 100644 include/tinycompress/wave_formats.h
17
18diff --git a/include/tinycompress/wave_formats.h b/include/tinycompress/wave_formats.h
19new file mode 100644
20index 000000000000..4e2e009206cf
21--- /dev/null
22+++ b/include/tinycompress/wave_formats.h
23@@ -0,0 +1,51 @@
24+#ifndef WAVE_FORMATS_H
25+#define WAVE_FORMATS_H 1
26+
27+#define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
28+
29+#define WAV_RIFF COMPOSE_ID('R','I','F','F')
30+#define WAV_RIFX COMPOSE_ID('R','I','F','X')
31+#define WAV_WAVE COMPOSE_ID('W','A','V','E')
32+#define WAV_FMT COMPOSE_ID('f','m','t',' ')
33+#define WAV_DATA COMPOSE_ID('d','a','t','a')
34+
35+/* WAVE fmt block constants from Microsoft mmreg.h header */
36+#define WAV_FMT_PCM 0x0001
37+#define WAV_FMT_IEEE_FLOAT 0x0003
38+#define WAV_FMT_DOLBY_AC3_SPDIF 0x0092
39+#define WAV_FMT_EXTENSIBLE 0xfffe
40+
41+/* Used with WAV_FMT_EXTENSIBLE format */
42+#define WAV_GUID_TAG "\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71"
43+
44+typedef struct {
45+ u_int magic; /* 'RIFF' */
46+ u_int length; /* filelen */
47+ u_int type; /* 'WAVE' */
48+} WaveHeader;
49+
50+typedef struct {
51+ u_short format; /* see WAV_FMT_* */
52+ u_short channels;
53+ u_int sample_fq; /* frequence of sample */
54+ u_int byte_p_sec;
55+ u_short byte_p_spl; /* samplesize; 1 or 2 bytes */
56+ u_short bit_p_spl; /* 8, 12 or 16 bit */
57+} WaveFmtBody;
58+
59+typedef struct {
60+ WaveFmtBody format;
61+ u_short ext_size;
62+ u_short bit_p_spl;
63+ u_int channel_mask;
64+ u_short guid_format; /* WAV_FMT_* */
65+ u_char guid_tag[14]; /* WAV_GUID_TAG */
66+} WaveFmtExtensibleBody;
67+
68+typedef struct {
69+ u_int type; /* 'data' */
70+ u_int length; /* samplecount */
71+} WaveChunkHeader;
72+
73+
74+#endif /* FORMATS */
75diff --git a/src/utils/cplay.c b/src/utils/cplay.c
76index 5b749419e731..8882f4d9746d 100644
77--- a/src/utils/cplay.c
78+++ b/src/utils/cplay.c
79@@ -1,4 +1,6 @@
80 /*
81+ * Copyright 2020 NXP
82+ *
83 * This file is provided under a dual BSD/LGPLv2.1 license. When using or
84 * redistributing this file, you may do so under either license.
85 *
86@@ -73,6 +75,8 @@
87 #include "tinycompress/tinycompress.h"
88 #include "tinycompress/tinymp3.h"
89 #include "tinycompress/id3_tag_decode.h"
90+#include "tinycompress/wave_formats.h"
91+#include <alsa/asoundlib.h>
92
93 static int verbose;
94 static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM;
95@@ -166,6 +170,77 @@ static int parse_mp3_header(struct mp3_header *header, unsigned int *num_channel
96 return 0;
97 }
98
99+static int parse_wav_header(FILE *file, unsigned int *num_channels, unsigned int *sample_rate,
100+ unsigned int *format) {
101+ WaveHeader wave_header;
102+ WaveChunkHeader chunk_header;
103+ WaveFmtBody fmt_body;
104+ int more_chunks = 1;
105+
106+ fread(&wave_header, sizeof(WaveHeader), 1, file);
107+ if ((wave_header.magic != WAV_RIFF) ||
108+ (wave_header.type != WAV_WAVE)) {
109+ fprintf(stderr, "Error: it is not a riff/wave file\n");
110+ return -1;
111+ }
112+
113+ do {
114+ fread(&chunk_header, sizeof(WaveChunkHeader), 1, file);
115+ switch (chunk_header.type) {
116+ case WAV_FMT:
117+ fread(&fmt_body, sizeof(WaveFmtBody), 1, file);
118+ /* If the format header is larger, skip the rest */
119+ if (chunk_header.length > sizeof(WaveFmtBody))
120+ fseek(file, chunk_header.length - sizeof(WaveFmtBody), SEEK_CUR);
121+
122+ *num_channels = fmt_body.channels;
123+ *sample_rate = fmt_body.sample_fq;
124+
125+ switch (fmt_body.bit_p_spl) {
126+ case 8:
127+ *format = SND_PCM_FORMAT_U8;
128+ break;
129+ case 16:
130+ *format = SND_PCM_FORMAT_S16_LE;
131+ break;
132+ case 24:
133+ switch (fmt_body.byte_p_spl / fmt_body.channels) {
134+ case 3:
135+ *format = SND_PCM_FORMAT_S24_3LE;
136+ break;
137+ case 4:
138+ *format = SND_PCM_FORMAT_S24_LE;
139+ break;
140+ default:
141+ fprintf(stderr, "format error\n");
142+ return -1;
143+ }
144+ break;
145+ case 32:
146+ if (fmt_body.format == WAV_FMT_PCM) {
147+ *format = SND_PCM_FORMAT_S32_LE;
148+ } else if (fmt_body.format == WAV_FMT_IEEE_FLOAT) {
149+ *format = SND_PCM_FORMAT_FLOAT_LE;
150+ }
151+ break;
152+ default:
153+ fprintf(stderr, "format error\n");
154+ return -1;
155+ }
156+ break;
157+ case WAV_DATA:
158+ /* Stop looking for chunks */
159+ more_chunks = 0;
160+ break;
161+ default:
162+ /* Unknown chunk, skip bytes */
163+ fseek(file, chunk_header.length, SEEK_CUR);
164+ }
165+ } while (more_chunks);
166+
167+ return 0;
168+}
169+
170 static int print_time(struct compress *compress)
171 {
172 unsigned int avail;
173@@ -385,6 +460,35 @@ void get_codec_iec(FILE *file, struct compr_config *config,
174 codec->format = 0;
175 }
176
177+void get_codec_pcm(FILE *file, struct compr_config *config,
178+ struct snd_codec *codec)
179+{
180+ unsigned int channels, rate, format;
181+
182+ if (parse_wav_header(file, &channels, &rate, &format) == -1) {
183+ fclose(file);
184+ exit(EXIT_FAILURE);
185+ }
186+
187+ if (channels > 2 || (format != SND_PCM_FORMAT_S16_LE && format != SND_PCM_FORMAT_S32_LE) ||
188+ rate > 192000) {
189+ fprintf(stderr, "unsupported wave file\n");
190+ fclose(file);
191+ exit(EXIT_FAILURE);
192+ }
193+
194+ codec->id = SND_AUDIOCODEC_PCM;
195+ codec->ch_in = channels;
196+ codec->ch_out = channels;
197+ codec->sample_rate = rate;
198+ codec->bit_rate = 0;
199+ codec->rate_control = 0;
200+ codec->profile = SND_AUDIOPROFILE_PCM;
201+ codec->level = 0;
202+ codec->ch_mode = 0;
203+ codec->format = format;
204+}
205+
206 void play_samples(char *name, unsigned int card, unsigned int device,
207 unsigned long buffer_size, unsigned int frag,
208 unsigned long codec_id)
209@@ -411,6 +515,9 @@ void play_samples(char *name, unsigned int card, unsigned int device,
210 case SND_AUDIOCODEC_IEC61937:
211 get_codec_iec(file, &config, &codec);
212 break;
213+ case SND_AUDIOCODEC_PCM:
214+ get_codec_pcm(file, &config, &codec);
215+ break;
216 default:
217 fprintf(stderr, "codec ID %ld is not supported\n", codec_id);
218 exit(EXIT_FAILURE);
219--
2202.27.0
221
diff --git a/recipes-multimedia/tinycompress/tinycompress/0003-cplay-Add-pause-feature.patch b/recipes-multimedia/tinycompress/tinycompress/0003-cplay-Add-pause-feature.patch
new file mode 100755
index 00000000..7d8492b7
--- /dev/null
+++ b/recipes-multimedia/tinycompress/tinycompress/0003-cplay-Add-pause-feature.patch
@@ -0,0 +1,146 @@
1From 6f778c21ee357a662cdd758cff578a3e4b85eedf Mon Sep 17 00:00:00 2001
2From: Zhang Peng <peng.zhang_8@nxp.com>
3Date: Tue, 4 Aug 2020 15:29:29 +0800
4Subject: [PATCH] cplay: Add pause feature
5
6Add option: -p pause
7
8Upstream-Status: Inappropriate [i.MX specific]
9Signed-off-by: Zhang Peng <peng.zhang_8@nxp.com>
10---
11 src/utils/cplay.c | 56 +++++++++++++++++++++++++++++++++++++++++++----
12 1 file changed, 52 insertions(+), 4 deletions(-)
13
14diff --git a/src/utils/cplay.c b/src/utils/cplay.c
15index 8882f4d..8e3dcbb 100644
16--- a/src/utils/cplay.c
17+++ b/src/utils/cplay.c
18@@ -117,6 +117,9 @@ static void usage(void)
19 "-f\tfragments\n\n"
20 "-v\tverbose mode\n"
21 "-h\tPrints this help list\n\n"
22+ "-p\tpause\n"
23+ "-m\tpause blocks\n"
24+ "-n\tpause time duration\n"
25 "Example:\n"
26 "\tcplay -c 1 -d 2 test.mp3\n"
27 "\tcplay -f 5 test.mp3\n\n"
28@@ -133,7 +136,8 @@ static void usage(void)
29
30 void play_samples(char *name, unsigned int card, unsigned int device,
31 unsigned long buffer_size, unsigned int frag,
32- unsigned long codec_id);
33+ unsigned long codec_id, int pause_count, int pause_block,
34+ int pause_duration);
35
36 struct mp3_header {
37 uint16_t sync;
38@@ -262,12 +266,15 @@ int main(int argc, char **argv)
39 int c, i;
40 unsigned int card = 0, device = 0, frag = 0;
41 unsigned int codec_id = SND_AUDIOCODEC_MP3;
42+ int pause_count = 0;
43+ int pause_block = 6;
44+ int pause_duration = 10;
45
46 if (argc < 2)
47 usage();
48
49 verbose = 0;
50- while ((c = getopt(argc, argv, "hvb:f:c:d:I:")) != -1) {
51+ while ((c = getopt(argc, argv, "hvb:f:c:d:I:p:m:n:")) != -1) {
52 switch (c) {
53 case 'h':
54 usage();
55@@ -306,6 +313,23 @@ int main(int argc, char **argv)
56 case 'v':
57 verbose = 1;
58 break;
59+ case 'p':
60+ pause_count = strtol(optarg, NULL, 10);
61+ break;
62+ case 'm':
63+ pause_block = strtol(optarg, NULL, 10);
64+ if (pause_duration < 0) {
65+ printf("Set wrong paramter! Set duration default 6.\n");
66+ pause_duration = 6;
67+ }
68+ break;
69+ case 'n':
70+ pause_duration = strtol(optarg, NULL, 10);
71+ if (pause_duration < 0) {
72+ printf("Set wrong paramter! Set duration default 10.\n");
73+ pause_duration = 10;
74+ }
75+ break;
76 default:
77 exit(EXIT_FAILURE);
78 }
79@@ -315,7 +339,7 @@ int main(int argc, char **argv)
80
81 file = argv[optind];
82
83- play_samples(file, card, device, buffer_size, frag, codec_id);
84+ play_samples(file, card, device, buffer_size, frag, codec_id, pause_count, pause_block, pause_duration);
85
86 fprintf(stderr, "Finish Playing.... Close Normally\n");
87 exit(EXIT_SUCCESS);
88@@ -491,7 +515,8 @@ void get_codec_pcm(FILE *file, struct compr_config *config,
89
90 void play_samples(char *name, unsigned int card, unsigned int device,
91 unsigned long buffer_size, unsigned int frag,
92- unsigned long codec_id)
93+ unsigned long codec_id, int pause_count, int pause_block,
94+ int pause_duration)
95 {
96 struct compr_config config;
97 struct snd_codec codec;
98@@ -499,6 +524,7 @@ void play_samples(char *name, unsigned int card, unsigned int device,
99 FILE *file;
100 char *buffer;
101 int size, num_read, wrote;
102+ int write_count = 0;
103
104 if (verbose)
105 printf("%s: entry\n", __func__);
106@@ -574,6 +600,13 @@ void play_samples(char *name, unsigned int card, unsigned int device,
107 if (verbose)
108 printf("%s: You should hear audio NOW!!!\n", __func__);
109
110+ if (pause_count > 0) {
111+ printf("sleep...\n");
112+ compress_pause(compress);
113+ sleep(pause_duration);
114+ compress_resume(compress);
115+ }
116+
117 do {
118 num_read = fread(buffer, 1, size, file);
119 if (num_read > 0) {
120@@ -592,8 +625,23 @@ void play_samples(char *name, unsigned int card, unsigned int device,
121 printf("%s: wrote %d\n", __func__, wrote);
122 }
123 }
124+ write_count++;
125+ if ((pause_count > 0) && (write_count % pause_block == 0)) {
126+ printf("pause...\n");
127+ compress_pause(compress);
128+ sleep(pause_duration);
129+ printf("pause release...\n");
130+ compress_resume(compress);
131+ pause_count--;
132+ }
133 } while (num_read > 0);
134
135+ if (pause_count > 0) {
136+ compress_pause(compress);
137+ sleep(5);
138+ compress_resume(compress);
139+ }
140+
141 if (verbose)
142 printf("%s: exit success\n", __func__);
143 /* issue drain if it supports */
144--
1452.17.1
146
diff --git a/recipes-multimedia/tinycompress/tinycompress/0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch b/recipes-multimedia/tinycompress/tinycompress/0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch
new file mode 100755
index 00000000..dfedd186
--- /dev/null
+++ b/recipes-multimedia/tinycompress/tinycompress/0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch
@@ -0,0 +1,40 @@
1From a2892bf5db7520689fa9cb1d1589fa804bd9dc1a Mon Sep 17 00:00:00 2001
2From: Bing Song <bing.song@nxp.com>
3Date: Tue, 18 Aug 2020 15:26:51 +0800
4Subject: [PATCH] tinycompress: pass NULL buffer with 0 size to driver.
5
6The NULL buffer with 0 size to indecate driver drain input data with
7non-block mode. The defaul drain is block mode.
8
9Upstream-Status: Inappropriate [i.MX specific]
10Signed-off-by: Bing Song <bing.song@nxp.com>
11---
12 src/lib/compress.c | 5 +++--
13 1 file changed, 3 insertions(+), 2 deletions(-)
14
15diff --git a/src/lib/compress.c b/src/lib/compress.c
16index bba4fcf..d66df0b 100644
17--- a/src/lib/compress.c
18+++ b/src/lib/compress.c
19@@ -315,7 +315,8 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size
20 fds.events = POLLOUT;
21
22 /*TODO: treat auto start here first */
23- while (size) {
24+ /* NULL buffer with 0 size for non-block drain */
25+ do {
26 if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &avail))
27 return oops(compress, errno, "cannot get avail");
28
29@@ -357,7 +358,7 @@ int compress_write(struct compress *compress, const void *buf, unsigned int size
30 size -= written;
31 cbuf += written;
32 total += written;
33- }
34+ } while (size);
35 return total;
36 }
37
38--
392.17.1
40
diff --git a/recipes-multimedia/tinycompress/tinycompress/0005-cplay-Support-aac-streams.patch b/recipes-multimedia/tinycompress/tinycompress/0005-cplay-Support-aac-streams.patch
new file mode 100755
index 00000000..2f36551a
--- /dev/null
+++ b/recipes-multimedia/tinycompress/tinycompress/0005-cplay-Support-aac-streams.patch
@@ -0,0 +1,251 @@
1From 2912f8573cea25fbd38ac7a8b68af2ea6a05e599 Mon Sep 17 00:00:00 2001
2From: Zhang Peng <peng.zhang_8@nxp.com>
3Date: Wed, 28 Oct 2020 19:08:53 +0800
4Subject: [PATCH] cplay: Support aac streams
5
6Support run aac format streams for cplay.
7
8Upstream-Status: Inappropriate [i.MX specific]
9Signed-off-by: Zhang Peng <peng.zhang_8@nxp.com>
10---
11 src/utils/cplay.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++
12 1 file changed, 210 insertions(+)
13
14diff --git a/src/utils/cplay.c b/src/utils/cplay.c
15index 8e3dcbb..2a1464a 100644
16--- a/src/utils/cplay.c
17+++ b/src/utils/cplay.c
18@@ -245,6 +245,190 @@ static int parse_wav_header(FILE *file, unsigned int *num_channels, unsigned int
19 return 0;
20 }
21
22+int find_adts_header(FILE *file, unsigned int *num_channels, unsigned int *sample_rate, unsigned int *format)
23+{
24+ int ret;
25+ unsigned char buf[5];
26+
27+ ret = fread(buf, sizeof(buf), 1, file);
28+ if (ret < 0) {
29+ fprintf(stderr, "open file error: %d\n", ret);
30+ return 0;
31+ }
32+ fseek(file, 0, SEEK_SET);
33+
34+ if ((buf[0] != 0xff) || (buf[1] & 0xf0 != 0xf0))
35+ return 0;
36+ /* mpeg id */
37+ switch (buf[1]>>3 & 0x1) {
38+ case 0x0:
39+ *format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
40+ break;
41+ case 0x1:
42+ *format = SND_AUDIOSTREAMFORMAT_MP2ADTS;
43+ break;
44+ default:
45+ fprintf(stderr, "can't find stream format\n");
46+ break;
47+ }
48+ /* sample_rate */
49+ switch (buf[2]>>2 & 0xf) {
50+ case 0x0:
51+ *sample_rate = 96000;
52+ break;
53+ case 0x1:
54+ *sample_rate = 88200;
55+ break;
56+ case 0x2:
57+ *sample_rate = 64000;
58+ break;
59+ case 0x3:
60+ *sample_rate = 48000;
61+ break;
62+ case 0x4:
63+ *sample_rate = 44100;
64+ break;
65+ case 0x5:
66+ *sample_rate = 32000;
67+ break;
68+ case 0x6:
69+ *sample_rate = 24000;
70+ break;
71+ case 0x7:
72+ *sample_rate = 22050;
73+ break;
74+ case 0x8:
75+ *sample_rate = 16000;
76+ break;
77+ case 0x9:
78+ *sample_rate = 12000;
79+ break;
80+ case 0xa:
81+ *sample_rate = 11025;
82+ break;
83+ case 0xb:
84+ *sample_rate = 8000;
85+ break;
86+ case 0xc:
87+ *sample_rate = 7350;
88+ break;
89+ default:
90+ break;
91+ }
92+ /* channel */
93+ switch (((buf[2]&0x1) << 2) | (buf[3]>>6)) {
94+ case 1:
95+ *num_channels = 1;
96+ break;
97+ case 2:
98+ *num_channels = 2;
99+ break;
100+ case 3:
101+ *num_channels = 3;
102+ break;
103+ case 4:
104+ *num_channels = 4;
105+ break;
106+ case 5:
107+ *num_channels = 5;
108+ break;
109+ case 6:
110+ *num_channels = 6;
111+ break;
112+ case 7:
113+ *num_channels = 7;
114+ break;
115+ default:
116+ break;
117+ }
118+ return 1;
119+}
120+
121+static const int aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
122+ 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
123+};
124+
125+#define MAX_SR_NUM sizeof(aac_sample_rates)/sizeof(aac_sample_rates[0])
126+
127+static int get_sample_rate_from_index(int sr_index)
128+{
129+ if (sr_index >= 0 && sr_index < MAX_SR_NUM)
130+ return aac_sample_rates[sr_index];
131+
132+ return 0;
133+}
134+
135+int find_adif_header(FILE *file, unsigned int *num_channels, unsigned int *sample_rate, unsigned int *format)
136+{
137+ int ret;
138+ unsigned char adif_id[4];
139+ unsigned char adif_header[20];
140+ int bitstream_type;
141+ int bitrate;
142+ int object_type;
143+ int sr_index;
144+ int skip_size = 0;
145+
146+ ret = fread(adif_id, sizeof(unsigned char), 4, file);
147+ if (ret < 0) {
148+ fprintf(stderr, "read data from file err: %d\n", ret);
149+ return 0;
150+ }
151+ /* adif id */
152+ if ((adif_id[0] != 0x41) || (adif_id[1] != 0x44) ||
153+ (adif_id[2] != 0x49) || (adif_id[3] != 0x46))
154+ return 0;
155+
156+ fread(adif_header, sizeof(unsigned char), 20, file);
157+
158+ /* copyright string */
159+ if (adif_header[0] & 0x80)
160+ skip_size = 9;
161+
162+ bitstream_type = adif_header[0 + skip_size] & 0x10;
163+ bitrate =
164+ ((unsigned int) (adif_header[0 + skip_size] & 0x0f) << 19) |
165+ ((unsigned int) adif_header[1 + skip_size] << 11) |
166+ ((unsigned int) adif_header[2 + skip_size] << 3) |
167+ ((unsigned int) adif_header[3 + skip_size] & 0xe0);
168+
169+ if (bitstream_type == 0) {
170+ object_type = ((adif_header[6 + skip_size] & 0x01) << 1) |
171+ ((adif_header[7 + skip_size] & 0x80) >> 7);
172+ sr_index = (adif_header[7 + skip_size] & 0x78) >> 3;
173+ }
174+ /* VBR */
175+ else {
176+ object_type = (adif_header[4 + skip_size] & 0x18) >> 3;
177+ sr_index = ((adif_header[4 + skip_size] & 0x07) << 1) |
178+ ((adif_header[5 + skip_size] & 0x80) >> 7);
179+ }
180+
181+ /* sample rate */
182+ *sample_rate = get_sample_rate_from_index(sr_index);
183+
184+ /* FIXME: assume channels is 2 */
185+ *num_channels = 2;
186+
187+ *format = SND_AUDIOSTREAMFORMAT_ADIF;
188+ fseek(file, 0, SEEK_SET);
189+ return 1;
190+}
191+
192+static int parse_aac_header(FILE *file, unsigned int *num_channels, unsigned int *sample_rate, unsigned int *format)
193+{
194+ if (find_adts_header(file, num_channels, sample_rate, format))
195+ return 1;
196+ else if (find_adif_header(file, num_channels, sample_rate, format))
197+ return 1;
198+ else {
199+ fprintf(stderr, "can't find streams format\n");
200+ return 0;
201+ }
202+
203+ return 1;
204+}
205+
206 static int print_time(struct compress *compress)
207 {
208 unsigned int avail;
209@@ -513,6 +697,29 @@ void get_codec_pcm(FILE *file, struct compr_config *config,
210 codec->format = format;
211 }
212
213+void get_codec_aac(FILE *file, struct compr_config *config,
214+ struct snd_codec *codec)
215+{
216+ unsigned int channels, rate, format;
217+
218+ if (parse_aac_header(file, &channels, &rate, &format) == 0) {
219+ fclose(file);
220+ exit(EXIT_FAILURE);
221+ };
222+ fseek(file, 0, SEEK_SET);
223+
224+ codec->id = SND_AUDIOCODEC_AAC;
225+ codec->ch_in = channels;
226+ codec->ch_out = channels;
227+ codec->sample_rate = rate;
228+ codec->bit_rate = 0;
229+ codec->rate_control = 0;
230+ codec->profile = SND_AUDIOPROFILE_AAC;
231+ codec->level = 0;
232+ codec->ch_mode = 0;
233+ codec->format = format;
234+
235+}
236 void play_samples(char *name, unsigned int card, unsigned int device,
237 unsigned long buffer_size, unsigned int frag,
238 unsigned long codec_id, int pause_count, int pause_block,
239@@ -544,6 +751,9 @@ void play_samples(char *name, unsigned int card, unsigned int device,
240 case SND_AUDIOCODEC_PCM:
241 get_codec_pcm(file, &config, &codec);
242 break;
243+ case SND_AUDIOCODEC_AAC:
244+ get_codec_aac(file, &config, &codec);
245+ break;
246 default:
247 fprintf(stderr, "codec ID %ld is not supported\n", codec_id);
248 exit(EXIT_FAILURE);
249--
2502.17.1
251
diff --git a/recipes-multimedia/tinycompress/tinycompress_1.1.6.bb b/recipes-multimedia/tinycompress/tinycompress_1.1.6.bb
new file mode 100644
index 00000000..6c0fc72e
--- /dev/null
+++ b/recipes-multimedia/tinycompress/tinycompress_1.1.6.bb
@@ -0,0 +1,16 @@
1DESCRIPTION = "A library to handle compressed formats like MP3 etc."
2LICENSE = "LGPLv2.1 | BSD-3-Clause"
3LIC_FILES_CHKSUM = "file://COPYING;md5=cf9105c1a2d4405cbe04bbe3367373a0"
4DEPENDS = "alsa-lib"
5
6SRC_URI = "git://git.alsa-project.org/tinycompress.git;protocol=git;branch=master \
7 file://0001-tinycompress-Add-id3-decoding.patch \
8 file://0002-cplay-Support-wave-file.patch \
9 file://0003-cplay-Add-pause-feature.patch \
10 file://0004-tinycompress-pass-NULL-buffer-with-0-size-to-driver.patch \
11 file://0005-cplay-Support-aac-streams.patch \
12"
13SRCREV = "995f2ed91045dad8c20485ab1a64727d22cd92e5"
14S = "${WORKDIR}/git"
15
16inherit autotools pkgconfig