Logo Search packages:      
Sourcecode: libsbc version File versions

sbcinfo.c

/*
 *
 *  Bluetooth low-complexity, subband codec (SBC) analyzer
 *
 *  Copyright (C) 2004-2006  Marcel Holtmann <marcel@holtmann.org>
 *
 *
 *  This program 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <libgen.h>

struct sbc_frame_hdr {
      uint8_t syncword:8;           /* Sync word */
      uint8_t subbands:1;           /* Subbands */
      uint8_t allocation_method:1;  /* Allocation method */
      uint8_t channel_mode:2;       /* Channel mode */
      uint8_t blocks:2;       /* Blocks */
      uint8_t sampling_frequency:2; /* Sampling frequency */
      uint8_t bitpool:8;            /* Bitpool */
      uint8_t crc_check:8;          /* CRC check */
} __attribute__ ((packed));

static int calc_frame_len(struct sbc_frame_hdr *hdr)
{
      int tmp, nrof_subbands, nrof_blocks;

      nrof_subbands = (hdr->subbands + 1) * 4;
      nrof_blocks = (hdr->blocks + 1) * 4;

      switch (hdr->channel_mode) {
      case 0x00:
            nrof_subbands /= 2;
            tmp = nrof_blocks * hdr->bitpool;
            break;
      case 0x01:
            tmp = nrof_blocks * hdr->bitpool * 2;
            break;
      case 0x02:
            tmp = nrof_blocks * hdr->bitpool;
            break;
      case 0x03:
            tmp = nrof_blocks * hdr->bitpool + nrof_subbands;
            break;
      default:
            return 0;
      }

      return (nrof_subbands + ((tmp + 7) / 8));
}

static double calc_bit_rate(struct sbc_frame_hdr *hdr)
{
      int nrof_subbands, nrof_blocks;
      double f;

      nrof_subbands = (hdr->subbands + 1) * 4;
      nrof_blocks = (hdr->blocks + 1) * 4;

      switch (hdr->sampling_frequency) {
      case 0:
            f = 16;
            break;
      case 1:
            f = 32;
            break;
      case 2:
            f = 44.1;
            break;
      case 3:
            f = 48;
            break;
      default:
            return 0;
      }

      return ((8 * (calc_frame_len(hdr) + 4) * f) / (nrof_subbands * nrof_blocks));
}

static char *freq2str(uint8_t freq)
{
      switch (freq) {
      case 0:
            return "16 kHz";
      case 1:
            return "32 kHz";
      case 2:
            return "44.1 kHz";
      case 3:
            return "48 kHz";
      default:
            return "Unknown";
      }
}

static char *mode2str(uint8_t mode)
{
      switch (mode) {
      case 0:
            return "Mono";
      case 1:
            return "Dual Channel";
      case 2:
            return "Stereo";
      case 3:
            return "Joint Stereo";
      default:
            return "Unknown";
      }
}

static ssize_t __read(int fd, void *buf, size_t count)
{
      ssize_t len, pos = 0;

      while (count > 0) {
            len = read(fd, buf + pos, count);
            if (len <= 0)
                  return len;

            count -= len;
            pos   += len;
      }

      return pos;
}

#define SIZE 32

static int analyze_file(char *filename)
{
      struct sbc_frame_hdr hdr;
      unsigned char buf[64];
      double rate;
      int bitpool[SIZE], frame_len[SIZE];
      int subbands, blocks, freq, mode, method;
      int n, p1, p2, fd, len, size, count, num;

      if (strcmp(filename, "-")) {
            printf("Filename\t\t%s\n", basename(filename));

            fd = open(filename, O_RDONLY);
            if (fd < 0) {
                  perror("Can't open file");
                  return -1;
            }
      } else
            fd = fileno(stdin);

      len = __read(fd, &hdr, sizeof(hdr));
      if (len != sizeof(hdr) || hdr.syncword != 0x9c) {
            fprintf(stderr, "Not a SBC audio file\n");
            return -1;
      }

      subbands = (hdr.subbands + 1) * 4;
      blocks = (hdr.blocks + 1) * 4;
      freq = hdr.sampling_frequency;
      mode = hdr.channel_mode;
      method = hdr.allocation_method;

      count = calc_frame_len(&hdr);

      bitpool[0] = hdr.bitpool;
      frame_len[0] = count + 4;

      for (n = 1; n < SIZE; n++) {
            bitpool[n] = 0;
            frame_len[n] = 0;
      }

      if (lseek(fd, 0, SEEK_SET) < 0) {
            num = 1;
            rate = calc_bit_rate(&hdr);
            while (count) {
                  size = count > sizeof(buf) ? sizeof(buf) : count;
                  len = __read(fd, buf, size);
                  if (len < 0)
                        break;
                  count -= len;
            }
      } else {
            num = 0;
            rate = 0;
      }

      while (1) {
            len = __read(fd, &hdr, sizeof(hdr));
            if (len < 0) {
                  fprintf(stderr, "Unable to read frame header (error %d)\n", errno);
                  break;
            }

            if (len == 0)
                  break;

            if (len < sizeof(hdr) || hdr.syncword != 0x9c) {
                  fprintf(stderr, "Corrupted SBC stream (len %d syncword 0x%02x)\n",
                                                len, hdr.syncword);
                  break;
            }

            count = calc_frame_len(&hdr);
            len = count + 4;

            p1 = -1;
            p2 = -1;
            for (n = 0; n < SIZE; n++) {
                  if (p1 < 0 && (bitpool[n] == 0 || bitpool[n] == hdr.bitpool))
                        p1 = n;
                  if (p2 < 0 && (frame_len[n] == 0 || frame_len[n] == len))
                        p2 = n;
            }
            if (p1 >= 0)
                  bitpool[p1] = hdr.bitpool;
            if (p2 >= 0)
                  frame_len[p2] = len;

            while (count) {
                  size = count > sizeof(buf) ? sizeof(buf) : count;

                  len = __read(fd, buf, size);
                  if (len != size) {
                        fprintf(stderr, "Unable to read frame data (error %d)\n", errno);
                        break;
                  }

                  count -= len;
            }

            rate += calc_bit_rate(&hdr);
            num++;
      }

      printf("Subbands\t\t%d\n", subbands);
      printf("Block length\t\t%d\n", blocks);
      printf("Sampling frequency\t%s\n", freq2str(freq));
      printf("Channel mode\t\t%s\n", mode2str(hdr.channel_mode));
      printf("Allocation method\t%s\n", method ? "SNR" : "Loudness");
      printf("Bitpool\t\t\t%d", bitpool[0]);
      for (n = 1; n < SIZE; n++)
            if (bitpool[n] > 0)
                  printf(", %d", bitpool[n]);
      printf("\n");
      printf("Number of frames\t%d\n", num);
      printf("Frame length\t\t%d", frame_len[0]);
      for (n = 1; n < SIZE; n++)
            if (frame_len[n] > 0)
                  printf(", %d", frame_len[n]);
      printf(" Bytes\n");
      if (num > 0)
            printf("Bit rate\t\t%.3f kbps\n", rate / num);

      if (fd > fileno(stderr))
            close(fd);

      printf("\n");

      return 0;
}

int main(int argc, char *argv[])
{
      int i;

      if (argc < 2) {
            fprintf(stderr, "Usage: sbcinfo <file>\n");
            exit(1);
      }

      for (i = 0; i < argc - 1; i++)
            if (analyze_file(argv[i + 1]) < 0)
                  exit(1);

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index