/* This file is part of libextractor. Copyright (C) 2004, 2009, 2012 Vidyut Samanta and Christian Grothoff libextractor is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. libextractor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with libextractor; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. This code was based on bitcollider 0.6.0 (PD) 2004 The Bitzi Corporation http://bitzi.com/ (PD) 2001 The Bitzi Corporation Please see file COPYING or http://bitzi.com/publicdomain for more info. */ /** * @file plugins/wav_extractor.c * @brief plugin to support WAV files * @author Christian Grothoff */ #include "platform.h" #include "extractor.h" #if BIG_ENDIAN_HOST static uint16_t little_endian_to_host16 (uint16_t in) { unsigned char *ptr = (unsigned char *) ∈ return ((ptr[1] & 0xFF) << 8) | (ptr[0] & 0xFF); } static uint32_t little_endian_to_host32 (uint32_t in) { unsigned char *ptr = (unsigned char *) ∈ return ((ptr[3] & 0xFF) << 24) | ((ptr[2] & 0xFF) << 16) | ((ptr[1] & 0xFF) << 8) | (ptr[0] & 0xFF); } #endif /** * Extract information from WAV files. * * @param ec extraction context * * @detail * A WAV header looks as follows: * * Offset Value meaning * 16 4 bytes 0x00000010 // Length of the fmt data (16 bytes) * 20 2 bytes 0x0001 // Format tag: 1 = PCM * 22 2 bytes // Channels: 1 = mono, 2 = stereo * 24 4 bytes // Samples per second: e.g., 44100 */ void EXTRACTOR_wav_extract_method (struct EXTRACTOR_ExtractContext *ec) { void *data; const unsigned char *buf; uint16_t channels; uint16_t sample_size; uint32_t sample_rate; uint32_t data_len; uint32_t samples; char scratch[256]; if (44 > ec->read (ec->cls, &data, 44)) return; buf = data; if ((buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' || buf[8] != 'W' || buf[9] != 'A' || buf[10] != 'V' || buf[11] != 'E' || buf[12] != 'f' || buf[13] != 'm' || buf[14] != 't' || buf[15] != ' ')) return; /* not a WAV file */ channels = *((uint16_t *) &buf[22]); sample_rate = *((uint32_t *) &buf[24]); sample_size = *((uint16_t *) &buf[34]); data_len = *((uint32_t *) &buf[40]); #if BIG_ENDIAN_HOST channels = little_endian_to_host16 (channels); sample_size = little_endian_to_host16 (sample_size); sample_rate = little_endian_to_host32 (sample_rate); data_len = little_endian_to_host32 (data_len); #endif if ( (8 != sample_size) && (16 != sample_size) ) return; /* invalid sample size found in wav file */ if (0 == channels) return; /* invalid channels value -- avoid division by 0! */ if (0 == sample_rate) return; /* invalid sample_rate */ samples = data_len / (channels * (sample_size >> 3)); snprintf (scratch, sizeof (scratch), "%u ms, %d Hz, %s", (samples < sample_rate) ? (samples * 1000 / sample_rate) : (samples / sample_rate) * 1000, sample_rate, (1 == channels) ? _("mono") : _("stereo")); if (0 != ec->proc (ec->cls, "wav", EXTRACTOR_METATYPE_RESOURCE_TYPE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", scratch, strlen (scratch) + 1)) return; if (0 != ec->proc (ec->cls, "wav", EXTRACTOR_METATYPE_MIMETYPE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "audio/x-wav", strlen ("audio/x-wav") +1 )) return; } /* end of wav_extractor.c */