/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* JOrbis * Copyright (C) 2000 ymnk, JCraft,Inc. * * Written by: 2000 ymnk<ymnk@jcraft.com> * * Many thanks to * Monty <monty@xiph.org> and * The XIPHOPHORUS Company http://www.xiph.org/ . * JOrbis has been based on their awesome works, Vorbis codec. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library 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 Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package com.jcraft.jorbis; import com.jcraft.jogg.Buffer; import com.jcraft.jogg.Packet; public class Info { private static final int OV_EBADPACKET = -136; private static final int OV_ENOTAUDIO = -135; private static byte[] _vorbis = "vorbis".getBytes(); private static final int VI_TIMEB = 1; // private static final int VI_FLOORB=1; private static final int VI_FLOORB = 2; // private static final int VI_RESB=1; private static final int VI_RESB = 3; private static final int VI_MAPB = 1; private static final int VI_WINDOWB = 1; public int version; public int channels; public int rate; // The below bitrate declarations are *hints*. // Combinations of the three values carry the following implications: // // all three set to the same value: // implies a fixed rate bitstream // only nominal set: // implies a VBR stream that averages the nominal bitrate. No hard // upper/lower limit // upper and or lower set: // implies a VBR bitstream that obeys the bitrate limits. nominal // may also be set to give a nominal rate. // none set: // the coder does not care to speculate. int bitrate_upper; int bitrate_nominal; int bitrate_lower; // Vorbis supports only short and long blocks, but allows the // encoder to choose the sizes int[] blocksizes = new int[2]; // modes are the primary means of supporting on-the-fly different // blocksizes, different channel mappings (LR or mid-side), // different residue backends, etc. Each mode consists of a // blocksize flag and a mapping (along with the mapping setup int modes; int maps; int times; int floors; int residues; int books; int psys; // encode only InfoMode[] mode_param = null; int[] map_type = null; Object[] map_param = null; int[] time_type = null; Object[] time_param = null; int[] floor_type = null; Object[] floor_param = null; int[] residue_type = null; Object[] residue_param = null; StaticCodeBook[] book_param = null; PsyInfo[] psy_param = new PsyInfo[64]; // encode only // for block long/sort tuning; encode only int envelopesa; float preecho_thresh; float preecho_clamp; // used by synthesis, which has a full, alloced vi public void init() { rate = 0; } public void clear() { for (int i = 0; i < modes; i++) { mode_param[i] = null; } mode_param = null; for (int i = 0; i < maps; i++) { // unpack does the range checking FuncMapping.mapping_P[map_type[i]].free_info(map_param[i]); } map_param = null; for (int i = 0; i < times; i++) { // unpack does the range checking FuncTime.time_P[time_type[i]].free_info(time_param[i]); } time_param = null; for (int i = 0; i < floors; i++) { // unpack does the range checking FuncFloor.floor_P[floor_type[i]].free_info(floor_param[i]); } floor_param = null; for (int i = 0; i < residues; i++) { // unpack does the range checking FuncResidue.residue_P[residue_type[i]].free_info(residue_param[i]); } residue_param = null; // the static codebooks *are* freed if you call info_clear, because // decode side does alloc a 'static' codebook. Calling clear on the // full codebook does not clear the static codebook (that's our // responsibility) for (int i = 0; i < books; i++) { // just in case the decoder pre-cleared to save space if (book_param[i] != null) { book_param[i].clear(); book_param[i] = null; } } //if(vi->book_param)free(vi->book_param); book_param = null; for (int i = 0; i < psys; i++) { psy_param[i].free(); } } // Header packing/unpacking int unpack_info(Buffer opb) { version = opb.read(32); if (version != 0) return (-1); channels = opb.read(8); rate = opb.read(32); bitrate_upper = opb.read(32); bitrate_nominal = opb.read(32); bitrate_lower = opb.read(32); blocksizes[0] = 1 << opb.read(4); blocksizes[1] = 1 << opb.read(4); if ((rate < 1) || (channels < 1) || (blocksizes[0] < 8) || (blocksizes[1] < blocksizes[0]) || (opb.read(1) != 1)) { clear(); return (-1); } return (0); } // all of the real encoding details are here. The modes, books, // everything int unpack_books(Buffer opb) { books = opb.read(8) + 1; if (book_param == null || book_param.length != books) book_param = new StaticCodeBook[books]; for (int i = 0; i < books; i++) { book_param[i] = new StaticCodeBook(); if (book_param[i].unpack(opb) != 0) { clear(); return (-1); } } // time backend settings times = opb.read(6) + 1; if (time_type == null || time_type.length != times) time_type = new int[times]; if (time_param == null || time_param.length != times) time_param = new Object[times]; for (int i = 0; i < times; i++) { time_type[i] = opb.read(16); if (time_type[i] < 0 || time_type[i] >= VI_TIMEB) { clear(); return (-1); } time_param[i] = FuncTime.time_P[time_type[i]].unpack(this, opb); if (time_param[i] == null) { clear(); return (-1); } } // floor backend settings floors = opb.read(6) + 1; if (floor_type == null || floor_type.length != floors) floor_type = new int[floors]; if (floor_param == null || floor_param.length != floors) floor_param = new Object[floors]; for (int i = 0; i < floors; i++) { floor_type[i] = opb.read(16); if (floor_type[i] < 0 || floor_type[i] >= VI_FLOORB) { clear(); return (-1); } floor_param[i] = FuncFloor.floor_P[floor_type[i]].unpack(this, opb); if (floor_param[i] == null) { clear(); return (-1); } } // residue backend settings residues = opb.read(6) + 1; if (residue_type == null || residue_type.length != residues) residue_type = new int[residues]; if (residue_param == null || residue_param.length != residues) residue_param = new Object[residues]; for (int i = 0; i < residues; i++) { residue_type[i] = opb.read(16); if (residue_type[i] < 0 || residue_type[i] >= VI_RESB) { clear(); return (-1); } residue_param[i] = FuncResidue.residue_P[residue_type[i]].unpack(this, opb); if (residue_param[i] == null) { clear(); return (-1); } } // map backend settings maps = opb.read(6) + 1; if (map_type == null || map_type.length != maps) map_type = new int[maps]; if (map_param == null || map_param.length != maps) map_param = new Object[maps]; for (int i = 0; i < maps; i++) { map_type[i] = opb.read(16); if (map_type[i] < 0 || map_type[i] >= VI_MAPB) { clear(); return (-1); } map_param[i] = FuncMapping.mapping_P[map_type[i]].unpack(this, opb); if (map_param[i] == null) { clear(); return (-1); } } // mode settings modes = opb.read(6) + 1; if (mode_param == null || mode_param.length != modes) mode_param = new InfoMode[modes]; for (int i = 0; i < modes; i++) { mode_param[i] = new InfoMode(); mode_param[i].blockflag = opb.read(1); mode_param[i].windowtype = opb.read(16); mode_param[i].transformtype = opb.read(16); mode_param[i].mapping = opb.read(8); if ((mode_param[i].windowtype >= VI_WINDOWB) || (mode_param[i].transformtype >= VI_WINDOWB) || (mode_param[i].mapping >= maps)) { clear(); return (-1); } } if (opb.read(1) != 1) { clear(); return (-1); } return (0); } // The Vorbis header is in three packets; the initial small packet in // the first page that identifies basic parameters, a second packet // with bitstream comments and a third packet that holds the // codebook. public int synthesis_headerin(Comment vc, Packet op) { Buffer opb = new Buffer(); if (op != null) { opb.readinit(op.packet_base, op.packet, op.bytes); // Which of the three types of header is this? // Also verify header-ness, vorbis { byte[] buffer = new byte[6]; int packtype = opb.read(8); opb.read(buffer, 6); if (buffer[0] != 'v' || buffer[1] != 'o' || buffer[2] != 'r' || buffer[3] != 'b' || buffer[4] != 'i' || buffer[5] != 's') { // not a vorbis header return (-1); } switch (packtype) { case 0x01: // least significant *bit* is read first if (op.b_o_s == 0) { // Not the initial packet return (-1); } if (rate != 0) { // previously initialized info header return (-1); } return (unpack_info(opb)); case 0x03: // least significant *bit* is read first if (rate == 0) { // um... we didn't get the initial header return (-1); } return (vc.unpack(opb)); case 0x05: // least significant *bit* is read first if (rate == 0 || vc.vendor == null) { // um... we didn;t get the initial header or comments yet return (-1); } return (unpack_books(opb)); default: // Not a valid vorbis header type //return(-1); break; } } } return (-1); } // pack side int pack_info(Buffer opb) { // preamble opb.write(0x01, 8); opb.write(_vorbis); // basic information about the stream opb.write(0x00, 32); opb.write(channels, 8); opb.write(rate, 32); opb.write(bitrate_upper, 32); opb.write(bitrate_nominal, 32); opb.write(bitrate_lower, 32); opb.write(Util.ilog2(blocksizes[0]), 4); opb.write(Util.ilog2(blocksizes[1]), 4); opb.write(1, 1); return (0); } int pack_books(Buffer opb) { opb.write(0x05, 8); opb.write(_vorbis); // books opb.write(books - 1, 8); for (int i = 0; i < books; i++) { if (book_param[i].pack(opb) != 0) { //goto err_out; return (-1); } } // times opb.write(times - 1, 6); for (int i = 0; i < times; i++) { opb.write(time_type[i], 16); FuncTime.time_P[time_type[i]].pack(this.time_param[i], opb); } // floors opb.write(floors - 1, 6); for (int i = 0; i < floors; i++) { opb.write(floor_type[i], 16); FuncFloor.floor_P[floor_type[i]].pack(floor_param[i], opb); } // residues opb.write(residues - 1, 6); for (int i = 0; i < residues; i++) { opb.write(residue_type[i], 16); FuncResidue.residue_P[residue_type[i]].pack(residue_param[i], opb); } // maps opb.write(maps - 1, 6); for (int i = 0; i < maps; i++) { opb.write(map_type[i], 16); FuncMapping.mapping_P[map_type[i]].pack(this, map_param[i], opb); } // modes opb.write(modes - 1, 6); for (int i = 0; i < modes; i++) { opb.write(mode_param[i].blockflag, 1); opb.write(mode_param[i].windowtype, 16); opb.write(mode_param[i].transformtype, 16); opb.write(mode_param[i].mapping, 8); } opb.write(1, 1); return (0); } public int blocksize(Packet op) { //codec_setup_info Buffer opb = new Buffer(); int mode; opb.readinit(op.packet_base, op.packet, op.bytes); /* Check the packet type */ if (opb.read(1) != 0) { /* Oops. This is not an audio data packet */ return (OV_ENOTAUDIO); } { int modebits = 0; int v = modes; while (v > 1) { modebits++; v >>>= 1; } /* read our mode and pre/post windowsize */ mode = opb.read(modebits); } if (mode == -1) return (OV_EBADPACKET); return (blocksizes[mode_param[mode].blockflag]); } public String toString() { return "version:" + new Integer(version) + ", channels:" + new Integer(channels) + ", rate:" + new Integer(rate) + ", bitrate:" + new Integer(bitrate_upper) + "," + new Integer(bitrate_nominal) + "," + new Integer(bitrate_lower); } }