1 /*
2 Copyright (c) 2012, Broadcom Europe Ltd
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above copyright
10       notice, this list of conditions and the following disclaimer in the
11       documentation and/or other materials provided with the distribution.
12     * Neither the name of the copyright holder nor the
13       names of its contributors may be used to endorse or promote products
14       derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #define CONTAINER_IS_LITTLE_ENDIAN
31 //#define ENABLE_CONTAINERS_LOG_FORMAT
32 //#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
33 #define CONTAINER_HELPER_LOG_INDENT(a) 0
34 #include "containers/core/containers_private.h"
35 #include "containers/core/containers_io_helpers.h"
36 #include "containers/core/containers_utils.h"
37 #include "containers/core/containers_logging.h"
38 #include "containers/core/containers_waveformat.h"
39 
40 /******************************************************************************
41 Defines.
42 ******************************************************************************/
43 #define WAV_EXTRADATA_MAX 16
44 #define BLOCK_SIZE (16*1024)
45 
46 /******************************************************************************
47 GUID list for the different codecs
48 ******************************************************************************/
49 static const GUID_T atracx_guid = {0xbfaa23e9, 0x58cb, 0x7144, {0xa1, 0x19, 0xff, 0xfa, 0x01, 0xe4, 0xce, 0x62}};
50 static const GUID_T pcm_guid = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
51 
52 /******************************************************************************
53 Type definitions
54 ******************************************************************************/
55 typedef struct VC_CONTAINER_MODULE_T
56 {
57    uint64_t data_offset; /**< Offset to the start of the data packets */
58    int64_t data_size;    /**< Size of the data contained in the data element */
59    uint32_t block_size;   /**< Size of a block of audio data */
60    int64_t position;
61    uint64_t frame_data_left;
62 
63    VC_CONTAINER_TRACK_T *track;
64    uint8_t extradata[WAV_EXTRADATA_MAX];
65 
66 } VC_CONTAINER_MODULE_T;
67 
68 /******************************************************************************
69 Function prototypes
70 ******************************************************************************/
71 VC_CONTAINER_STATUS_T wav_reader_open( VC_CONTAINER_T * );
72 
73 /******************************************************************************
74 Local Functions
75 ******************************************************************************/
76 
77 /*****************************************************************************
78 Functions exported as part of the Container Module API
79  *****************************************************************************/
80 
wav_reader_read(VC_CONTAINER_T * p_ctx,VC_CONTAINER_PACKET_T * p_packet,uint32_t flags)81 static VC_CONTAINER_STATUS_T wav_reader_read( VC_CONTAINER_T *p_ctx,
82                                               VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
83 {
84    VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
85    uint32_t packet_flags = 0, size, data_size;
86    int64_t pts;
87 
88    pts = module->position * 8000000 / p_ctx->tracks[0]->format->bitrate;
89    data_size = module->frame_data_left;
90    if(!data_size)
91    {
92       data_size = module->block_size;
93       packet_flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
94    }
95    module->frame_data_left = 0;
96 
97    if(module->position + data_size > module->data_size)
98       data_size = module->data_size - module->position;
99    if(data_size == 0) return VC_CONTAINER_ERROR_EOS;
100 
101    if((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO)) /* Skip packet */
102    {
103       size = SKIP_BYTES(p_ctx, data_size);
104       module->frame_data_left = data_size - size;
105       module->position += size;
106       return STREAM_STATUS(p_ctx);
107    }
108 
109    p_packet->flags = packet_flags;
110    p_packet->dts = p_packet->pts = pts;
111    p_packet->track = 0;
112 
113    if(flags & VC_CONTAINER_READ_FLAG_SKIP)
114    {
115       size = SKIP_BYTES(p_ctx, data_size);
116       module->frame_data_left = data_size - size;
117       if(!module->frame_data_left) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
118       module->position += size;
119       p_packet->size += size;
120       return STREAM_STATUS(p_ctx);
121    }
122 
123    if(flags & VC_CONTAINER_READ_FLAG_INFO)
124       return VC_CONTAINER_SUCCESS;
125 
126    size = MIN(data_size, p_packet->buffer_size - p_packet->size);
127    size = READ_BYTES(p_ctx, p_packet->data, size);
128    module->frame_data_left = data_size - size;
129    if(!module->frame_data_left) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
130    module->position += size;
131    p_packet->size += size;
132 
133    return STREAM_STATUS(p_ctx);
134 }
135 
136 /*****************************************************************************/
wav_reader_seek(VC_CONTAINER_T * p_ctx,int64_t * p_offset,VC_CONTAINER_SEEK_MODE_T mode,VC_CONTAINER_SEEK_FLAGS_T flags)137 static VC_CONTAINER_STATUS_T wav_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *p_offset,
138    VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
139 {
140    VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
141    int64_t position;
142    VC_CONTAINER_PARAM_UNUSED(mode);
143    VC_CONTAINER_PARAM_UNUSED(flags);
144 
145    position = *p_offset * p_ctx->tracks[0]->format->bitrate / 8000000;
146    if(p_ctx->tracks[0]->format->type->audio.block_align)
147       position = position / p_ctx->tracks[0]->format->type->audio.block_align *
148          p_ctx->tracks[0]->format->type->audio.block_align;
149    if(position > module->data_size) position = module->data_size;
150 
151    module->position = position;
152    module->frame_data_left = 0;
153 
154    if(position >= module->data_size) return VC_CONTAINER_ERROR_EOS;
155    return SEEK(p_ctx, module->data_offset + position);
156 }
157 
158 /*****************************************************************************/
wav_reader_close(VC_CONTAINER_T * p_ctx)159 static VC_CONTAINER_STATUS_T wav_reader_close( VC_CONTAINER_T *p_ctx )
160 {
161    VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
162    unsigned int i;
163 
164    for(i = 0; i < p_ctx->tracks_num; i++)
165       vc_container_free_track(p_ctx, p_ctx->tracks[i]);
166    free(module);
167    return VC_CONTAINER_SUCCESS;
168 }
169 
170 /*****************************************************************************/
wav_reader_open(VC_CONTAINER_T * p_ctx)171 VC_CONTAINER_STATUS_T wav_reader_open( VC_CONTAINER_T *p_ctx )
172 {
173    VC_CONTAINER_MODULE_T *module = 0;
174    VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
175    VC_CONTAINER_FOURCC_T codec;
176    int64_t chunk_size, chunk_pos;
177    uint32_t format, channels, samplerate, bitrate, block_align, bps, cbsize = 0;
178    uint8_t buffer[12];
179 
180    /* Check the RIFF chunk descriptor */
181    if( PEEK_BYTES(p_ctx, buffer, 12) != 12 )
182      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
183    if( VC_FOURCC(buffer[0], buffer[1], buffer[2], buffer[3]) !=
184        VC_FOURCC('R','I','F','F') )
185      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
186    if( VC_FOURCC(buffer[8], buffer[9], buffer[10], buffer[11]) !=
187        VC_FOURCC('W','A','V','E') )
188      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
189 
190    /*
191     *  We are dealing with a WAV file
192     */
193    SKIP_FOURCC(p_ctx, "Chunk ID");
194    SKIP_U32(p_ctx, "Chunk size");
195    SKIP_FOURCC(p_ctx, "WAVE ID");
196 
197    /* We're looking for the 'fmt' sub-chunk */
198    do {
199       chunk_pos = STREAM_POSITION(p_ctx) + 8;
200       if( READ_FOURCC(p_ctx, "Chunk ID") == VC_FOURCC('f','m','t',' ') ) break;
201 
202       /* Not interested in this chunk. Skip it. */
203       chunk_size = READ_U32(p_ctx, "Chunk size");
204       SKIP_BYTES(p_ctx, chunk_size);
205    } while(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS);
206 
207    if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS)
208       return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; /* 'fmt' not found */
209 
210    /* Parse the 'fmt' sub-chunk */
211    chunk_size  = READ_U32(p_ctx, "Chunk size");
212    format      = READ_U16(p_ctx, "wFormatTag");
213    channels    = READ_U16(p_ctx, "nChannels");
214    samplerate  = READ_U32(p_ctx, "nSamplesPerSec");
215    bitrate     = READ_U32(p_ctx, "nAvgBytesPerSec") * 8;
216    block_align = READ_U16(p_ctx, "nBlockAlign");
217    bps         = READ_U16(p_ctx, "wBitsPerSample");
218 
219    if(STREAM_POSITION(p_ctx) - chunk_pos <= chunk_size - 2)
220       cbsize = READ_U16(p_ctx, "cbSize");
221 
222    if(format == WAVE_FORMAT_EXTENSIBLE &&
223       chunk_size >= 18 + 22 && cbsize >= 22)
224    {
225       GUID_T guid;
226       codec = VC_CONTAINER_CODEC_UNKNOWN;
227 
228       SKIP_U16(p_ctx, "wValidBitsPerSample");
229       SKIP_U32(p_ctx, "dwChannelMask");
230       READ_GUID(p_ctx, &guid, "SubFormat");
231 
232       if(!memcmp(&guid, &pcm_guid, sizeof(guid)))
233          codec = VC_CONTAINER_CODEC_PCM_SIGNED_LE;
234       else if(!memcmp(&guid, &atracx_guid, sizeof(guid)))
235          codec = VC_CONTAINER_CODEC_ATRAC3;
236 
237       cbsize -= 22;
238 
239       /* TODO: deal with channel mapping */
240    }
241    else
242    {
243       codec = waveformat_to_codec(format);
244    }
245 
246    /* Bail out if we don't recognise the codec */
247    if(codec == VC_CONTAINER_CODEC_UNKNOWN)
248       return VC_CONTAINER_ERROR_FORMAT_FEATURE_NOT_SUPPORTED;
249 
250    /* Do some sanity checking on the info we got */
251    if(!channels || !samplerate || !block_align || !bitrate)
252       return VC_CONTAINER_ERROR_FORMAT_INVALID;
253    if(codec == VC_CONTAINER_CODEC_ATRAC3 && channels > 2)
254       return VC_CONTAINER_ERROR_FORMAT_INVALID;
255 
256    /* Allocate our context */
257    module = malloc(sizeof(*module));
258    if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
259    memset(module, 0, sizeof(*module));
260    p_ctx->priv->module = module;
261    p_ctx->tracks_num = 1;
262    p_ctx->tracks = &module->track;
263    p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
264    if(!p_ctx->tracks[0]) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
265 
266    p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
267    p_ctx->tracks[0]->format->codec = codec;
268    p_ctx->tracks[0]->format->type->audio.channels = channels;
269    p_ctx->tracks[0]->format->type->audio.sample_rate = samplerate;
270    p_ctx->tracks[0]->format->type->audio.block_align = block_align;
271    p_ctx->tracks[0]->format->type->audio.bits_per_sample = bps;
272    p_ctx->tracks[0]->format->bitrate = bitrate;
273    p_ctx->tracks[0]->is_enabled = true;
274    p_ctx->tracks[0]->format->extradata_size = 0;
275    p_ctx->tracks[0]->format->extradata = module->extradata;
276    module->block_size = block_align;
277 
278    /* Prepare the codec extradata */
279    if(codec == VC_CONTAINER_CODEC_ATRAC3)
280    {
281       uint16_t h, mode;
282 
283       SKIP_U16(p_ctx, "len");
284       SKIP_U16(p_ctx, "layer");
285       SKIP_U32(p_ctx, "bytes_per_frame");
286       mode = READ_U16(p_ctx, "mode");
287       SKIP_U16(p_ctx, "mode_ext");
288       SKIP_U16(p_ctx, "num_subframes");
289       SKIP_U16(p_ctx, "flags");
290 
291       h = (1 << 15);
292       if(channels == 2)
293       {
294          h |= (1 << 13);
295          if(mode == 1) h |= (1 << 14);
296       }
297       h |= block_align & 0x7ff;
298 
299       p_ctx->tracks[0]->format->extradata[0] = h >> 8;
300       p_ctx->tracks[0]->format->extradata[1] = h & 255;
301       p_ctx->tracks[0]->format->extradata_size = 2;
302    }
303    else if(codec == VC_CONTAINER_CODEC_ATRACX && cbsize >= 6)
304    {
305       SKIP_BYTES(p_ctx, 2);
306       p_ctx->tracks[0]->format->extradata_size =
307          READ_BYTES(p_ctx, p_ctx->tracks[0]->format->extradata, 6);
308    }
309    else if(codec == VC_CONTAINER_CODEC_PCM_SIGNED_LE)
310    {
311       /* Audioplus can no longer be given anything other than a multiple-of-16 number of samples */
312       block_align *= 16;
313       module->block_size = (BLOCK_SIZE / block_align) * block_align;
314    }
315 
316    /* Skip the rest of the 'fmt' sub-chunk */
317    SKIP_BYTES(p_ctx, chunk_pos + chunk_size - STREAM_POSITION(p_ctx));
318 
319    /* We also need the 'data' sub-chunk */
320    do {
321       chunk_pos = STREAM_POSITION(p_ctx) + 8;
322       if( READ_FOURCC(p_ctx, "Chunk ID") == VC_FOURCC('d','a','t','a') ) break;
323 
324       /* Not interested in this chunk. Skip it. */
325       chunk_size = READ_U32(p_ctx, "Chunk size");
326       SKIP_BYTES(p_ctx, chunk_size);
327    } while(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS);
328 
329    if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS)
330    {
331       status = VC_CONTAINER_ERROR_FORMAT_INVALID; /* 'data' not found */;
332       goto error;
333    }
334 
335    module->data_offset = chunk_pos;
336    module->data_size = READ_U32(p_ctx, "Chunk size");
337    p_ctx->duration = module->data_size * 8000000 / bitrate;
338    if(STREAM_SEEKABLE(p_ctx))
339       p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
340 
341    /*
342     *  We now have all the information we really need to start playing the stream
343     */
344 
345    p_ctx->priv->pf_close = wav_reader_close;
346    p_ctx->priv->pf_read = wav_reader_read;
347    p_ctx->priv->pf_seek = wav_reader_seek;
348 
349    /* Seek back to the start of the data */
350    status = SEEK(p_ctx, module->data_offset);
351    if(status != VC_CONTAINER_SUCCESS) goto error;
352    return VC_CONTAINER_SUCCESS;
353 
354  error:
355    LOG_DEBUG(p_ctx, "wav: error opening stream (%i)", status);
356    if(module) wav_reader_close(p_ctx);
357    return status;
358 }
359 
360 /********************************************************************************
361  Entrypoint function
362  ********************************************************************************/
363 
364 #if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
365 # pragma weak reader_open wav_reader_open
366 #endif
367