private boolean openSeekable() {
   final Info initialInfo = new Info();
   final Comment initialComment = new Comment();
   this.m_chunkSize = Math.min(8500, (int) length(this.m_vorbisStream));
   final Page page = new Page();
   final int[] testSerialno = {0};
   final int ret = this.fetchHeaders(initialInfo, initialComment, testSerialno, null);
   final int serialno = testSerialno[0];
   final int dataOffset = (int) this.m_offset;
   this.m_oggStreamState.clear();
   if (ret < 0) {
     return false;
   }
   seek(this.m_vorbisStream, 0L, 1);
   this.m_offset = tell(this.m_vorbisStream);
   final long end = this.getPreviousPage(page);
   if (page.serialno() != serialno) {
     if (this.bisectForwardSerialno(0L, 0L, end + 1L, serialno, 0) < 0) {
       return false;
     }
   } else if (this.bisectForwardSerialno(0L, end, end + 1L, serialno, 0) < 0) {
     return false;
   }
   this.prefetchAllHeaders(initialInfo, initialComment, dataOffset);
   this.rawSeek(this.m_dataOffsets[0]);
   return true;
 }
Beispiel #2
0
  private void pageOut() throws IOException {
    if (oggPage == null) {
      oggPage = new Page();
    }

    for (; ; ) {
      switch (oggSyncState.pageout(oggPage)) {
        case 0:
          return;
        case 1:
          if (oggStreamState == null) {
            oggStreamState = new StreamState();
            oggStreamState.init(oggPage.serialno());
            oggStreamState.reset();
          }
          if (oggStreamState.pagein(oggPage) < 0) {
            throw new IOException("error reading ogg page");
          } else {
            packetOut();
            if (oggPage.eos() != 0) {
              throw new EOFException();
            }
          }
          break;
        default:
          throw new IOException("ogg input format error");
      }
    }
  }
Beispiel #3
0
  /**
   * Last step of the OggVorbis_File initialization; get all the vorbis_info structs and PCM
   * positions. Only called by the seekable initialization (local stream storage is hacked slightly;
   * pay attention to how that's done)
   *
   * @param firstInfo first info
   * @param firstComment first comment
   * @param dataoffset data offset
   * @throws JOrbisException if an error occurs
   */
  void prefetchAllHeaders(Info firstInfo, Comment firstComment, int dataoffset)
      throws JOrbisException {
    Page og = new Page();
    int ret;

    vi = new Info[links];
    vc = new Comment[links];
    dataoffsets = new long[links];
    pcmlengths = new long[links];
    serialnos = new int[links];

    for (int i = 0; i < links; i++) {
      if (firstInfo != null && firstComment != null && i == 0) {
        // we already grabbed the initial header earlier. This just
        // saves the waste of grabbing it again
        vi[i] = firstInfo;
        vc[i] = firstComment;
        dataoffsets[i] = dataoffset;
      } else {
        // seek to the location of the initial header
        seekHelper(offsets[i]); // !!!
        vi[i] = new Info();
        vc[i] = new Comment();
        if (fetchHeaders(vi[i], vc[i], null, null) == -1) {
          dataoffsets[i] = -1;
        } else {
          dataoffsets[i] = offset;
          os.clear();
        }
      }

      // get the serial number and PCM length of this link. To do this,
      // get the last page of the stream
      long end = offsets[i + 1]; // !!!
      seekHelper(end);

      while (true) {
        ret = getPrevPage(og);
        if (ret == -1) {
          // this should not be possible
          vi[i].clear();
          vc[i].clear();
          break;
        }
        if (og.granulepos() != -1) {
          serialnos[i] = og.serialno();
          pcmlengths[i] = og.granulepos();
          break;
        }
      }
    }
  }
Beispiel #4
0
  /** @return negative value on error */
  private int seekDuration() {
    this.startOffset = getNextPageOffset();

    seek(getData().size());

    Page og = new Page();

    int endOffset = getPrevPage(og, serialno);
    if (endOffset < 0) {
      return -1;
    } else {
      numFrames = (int) og.granulepos();
      seek(startOffset);
      return 0;
    }
  }
Beispiel #5
0
  /**
   * Bisect forward serial number.
   *
   * @param begin beginning
   * @param searched searched
   * @param end end
   * @param currentno current number
   * @param m member
   * @return success flag OV_*
   */
  int bisectForwardSerialno(long begin, long searched, long end, int currentno, int m) {
    long endsearched = end;
    long next = end;
    Page page = new Page();
    int ret;

    while (searched < endsearched) {
      long bisect;
      if (endsearched - searched < CHUNKSIZE) {
        bisect = searched;
      } else {
        bisect = (searched + endsearched) / 2;
      }

      seekHelper(bisect);
      ret = getNextPage(page, -1);
      if (ret == OV_EREAD) {
        return OV_EREAD;
      }
      if (ret < 0 || page.serialno() != currentno) {
        endsearched = bisect;
        if (ret >= 0) {
          next = ret;
        }
      } else {
        searched = ret + page.headerLen + page.bodyLen;
      }
    }
    seekHelper(next);
    ret = getNextPage(page, -1);
    if (ret == OV_EREAD) {
      return OV_EREAD;
    }

    if (searched >= end || ret == -1) {
      links = m + 1;
      offsets = new long[m + 2];
      offsets[m + 1] = searched;
    } else {
      ret = bisectForwardSerialno(next, offset, end, page.serialno(), m + 1);
      if (ret == OV_EREAD) {
        return OV_EREAD;
      }
    }
    offsets[m] = begin;
    return 0;
  }
 public int fetchHeaders(final Info info, final Comment comment, final int[] serialno, Page page) {
   if (page == null) {
     page = new Page();
     final int retValue = this.getNextPage(page, this.m_chunkSize);
     if (retValue == -128) {
       return -128;
     }
     if (retValue < 0) {
       return -130;
     }
   }
   if (serialno != null) {
     serialno[0] = page.serialno();
   }
   this.m_oggStreamState.init(page.serialno());
   info.init();
   comment.init();
   final Packet packet = new Packet();
   int i = 0;
   while (i < 3) {
     this.m_oggStreamState.pagein(page);
     while (i < 3) {
       final int result = this.m_oggStreamState.packetout(packet);
       if (result == 0) {
         break;
       }
       if (result == -1) {
         info.clear();
         this.m_oggStreamState.clear();
         return -1;
       }
       if (info.synthesis_headerin(comment, packet) != 0) {
         info.clear();
         this.m_oggStreamState.clear();
         return -1;
       }
       ++i;
     }
     if (i < 3 && this.getNextPage(page, 1L) < 0) {
       info.clear();
       this.m_oggStreamState.clear();
       return -1;
     }
   }
   return 0;
 }
Beispiel #7
0
 /**
  * Open seekable.
  *
  * @return success value
  * @throws JOrbisException if an error occurs
  */
 int openSeekable() throws JOrbisException {
   Info initialInfo = new Info();
   Comment initialComment = new Comment();
   int serialno;
   long end;
   int ret;
   int dataoffset;
   Page og = new Page();
   // is this even vorbis...?
   int[] foo = new int[1];
   ret = fetchHeaders(initialInfo, initialComment, foo, null);
   serialno = foo[0];
   dataoffset = (int) offset; // !!
   os.clear();
   if (ret == -1) {
     return (-1);
   }
   if (ret < 0) {
     return (ret);
   }
   // we can seek, so set out learning all about this file
   seekable = true;
   fseek(datasource, 0, SEEK_END);
   offset = ftell(datasource);
   end = offset;
   // We get the offset for the last page of the physical bitstream.
   // Most OggVorbis files will contain a single logical bitstream
   end = getPrevPage(og);
   // moer than one logical bitstream?
   if (og.serialno() != serialno) {
     // Chained bitstream. Bisect-search each logical bitstream
     // section. Do so based on serial number only
     if (bisectForwardSerialno(0, 0, end + 1, serialno, 0) < 0) {
       clear();
       return OV_EREAD;
     }
   } else {
     // Only one logical bitstream
     if (bisectForwardSerialno(0, end, end + 1, serialno, 0) < 0) {
       clear();
       return OV_EREAD;
     }
   }
   prefetchAllHeaders(initialInfo, initialComment, dataoffset);
   return 0;
 }
 private int bisectForwardSerialno(
     final long begin, long searched, final long end, final int currentno, final int m) {
   long endsearched = end;
   long next = end;
   final Page page = new Page();
   while (searched < endsearched) {
     long bisect;
     if (endsearched - searched < this.m_chunkSize) {
       bisect = searched;
     } else {
       bisect = (searched + endsearched) / 2L;
     }
     this.seekHelper(bisect);
     final int ret = this.getNextPage(page, -1L);
     if (ret == -128) {
       return -128;
     }
     if (ret < 0 || page.serialno() != currentno) {
       endsearched = bisect;
       if (ret < 0) {
         continue;
       }
       next = ret;
     } else {
       searched = ret + page.header_len + page.body_len;
     }
   }
   this.seekHelper(next);
   int ret = this.getNextPage(page, -1L);
   if (ret == -128) {
     return -128;
   }
   if (searched >= end || ret == -1) {
     this.m_links = m + 1;
     (this.m_offsets = new long[m + 2])[m + 1] = searched;
   } else {
     ret = this.bisectForwardSerialno(next, this.m_offset, end, page.serialno(), m + 1);
     if (ret == -128) {
       return -128;
     }
   }
   this.m_offsets[m] = begin;
   return 0;
 }
 private void prefetchAllHeaders(
     final Info firstInfo, final Comment firstComment, final int dataoffset) {
   final Page page = new Page();
   this.m_info = new Info[this.m_links];
   this.m_comments = new Comment[this.m_links];
   this.m_dataOffsets = new long[this.m_links];
   this.m_pcmLengths = new long[this.m_links];
   this.m_serialnos = new int[this.m_links];
   for (int i = 0; i < this.m_links; ++i) {
     if (firstInfo != null && firstComment != null && i == 0) {
       this.m_info[i] = firstInfo;
       this.m_comments[i] = firstComment;
       this.m_dataOffsets[i] = dataoffset;
     } else {
       this.seekHelper(this.m_offsets[i]);
       this.m_info[i] = new Info();
       this.m_comments[i] = new Comment();
       if (this.fetchHeaders(this.m_info[i], this.m_comments[i], null, null) == -1) {
         this.m_dataOffsets[i] = -1L;
       } else {
         this.m_dataOffsets[i] = this.m_offset;
         this.m_oggStreamState.clear();
       }
     }
     final long end = this.m_offsets[i + 1];
     this.seekHelper(end);
     while (true) {
       final int ret = this.getPreviousPage(page);
       if (ret == -1) {
         this.m_info[i].clear();
         break;
       }
       if (page.granulepos() != -1L) {
         this.m_serialnos[i] = page.serialno();
         this.m_pcmLengths[i] = page.granulepos();
         break;
       }
     }
   }
 }
 @Override
 public int pcmSeek(final long pos) {
   if (!this.m_vorbisStream.isSeekable()) {
     return -1;
   }
   long total = this.pcmTotal(-1);
   if (pos < 0L || pos > total) {
     this.m_pcmOffset = -1L;
     this.decodeClear();
     return -1;
   }
   int link;
   for (link = this.m_links - 1; link >= 0; --link) {
     total -= this.m_pcmLengths[link];
     if (pos >= total) {
       break;
     }
   }
   final long target = pos - total;
   long end = this.m_offsets[link + 1];
   long begin = this.m_offsets[link];
   int best = (int) begin;
   final Page page = new Page();
   while (begin < end) {
     long bisect;
     if (end - begin < this.m_chunkSize) {
       bisect = begin;
     } else {
       bisect = (end + begin) / 2L;
     }
     this.seekHelper(bisect);
     final int ret = this.getNextPage(page, end - bisect);
     if (ret == -1) {
       end = bisect;
     } else {
       final long granulepos = page.granulepos();
       if (granulepos < target) {
         best = ret;
         begin = this.m_offset;
       } else {
         end = bisect;
       }
     }
   }
   if (this.rawSeek(best) != 0) {
     this.m_pcmOffset = -1L;
     this.decodeClear();
     return -1;
   }
   if (this.m_pcmOffset >= pos) {
     this.m_pcmOffset = -1L;
     this.decodeClear();
     return -1;
   }
   if (pos > this.pcmTotal(-1)) {
     this.m_pcmOffset = -1L;
     this.decodeClear();
     return -1;
   }
   while (this.m_pcmOffset < pos) {
     final int target2 = (int) (pos - this.m_pcmOffset);
     final int[] _index = new int[this.m_info[this.m_currentLink].channelsCount];
     int samples = this.m_dspState.synthesis_pcmout(this.m_pcmf_buffer, _index);
     if (samples > target2) {
       samples = target2;
     }
     this.m_dspState.synthesis_read(samples);
     this.m_pcmOffset += samples;
     if (samples < target2 && this.processPacket(true) == 0) {
       this.m_pcmOffset = this.pcmTotal(-1);
     }
   }
   return 0;
 }
Beispiel #11
0
  /**
   * @return a negative number if not enough data available, 0 for failure or a positive number for
   *     success.
   */
  private int getHeaders(Info tempInfo, Comment tempComment) {
    Page og = new Page();
    Packet op = new Packet();
    boolean done = false;
    int packets = 0;

    // Parse the headers
    // Only interested in Vorbis stream
    while (!done) {
      int ret = getDataChunk();
      if (ret <= 0) {
        return ret;
      }
      while (oy.pageout(og) > 0) {
        StreamState test = new StreamState();

        // is this a mandated initial header? If not, stop parsing
        if (og.bos() == 0) {
          if (os != null) {
            os.pagein(og);
          }
          done = true;
          break;
        }

        int testSerialNo = og.serialno();
        test.init(testSerialNo);
        test.pagein(og);
        test.packetout(op);

        if (packets == 0 && tempInfo.synthesis_headerin(tempComment, op) >= 0) {
          os = test;
          serialno = testSerialNo;
          packets = 1;
        } else {
          // Ignore unknown stream
          test.clear();
        }
      }
    }

    if (packets == 0) {
      return 0;
    }

    // we've now identified all the bitstreams. parse the secondary header packets.
    while (packets < 3) {
      int ret;

      // look for more vorbis header packets
      while (packets < 3 && ((ret = os.packetout(op)) != 0)) {
        if (ret < 0 || tempInfo.synthesis_headerin(tempComment, op) != 0) {
          return 0;
        }
        packets++;
      }

      // The header pages/packets will arrive before anything else we
      // care about, or the stream is not obeying spec
      if (oy.pageout(og) > 0) {
        os.pagein(og);
      } else {
        ret = getDataChunk();
        if (ret <= 0) {
          return ret;
        }
      }
    }

    vd.synthesis_init(tempInfo);
    return 1;
  }
Beispiel #12
0
  /*
   * Taken from the JOrbis Player
   */
  private void playStream(Thread me) throws InternalException {
    boolean chained = false;

    initJOrbis();

    while (true) {
      if (checkState()) {
        return;
      }

      int eos = 0;

      int index = oy.buffer(BUFSIZE);
      buffer = oy.data;
      try {
        bytes = bitStream.read(buffer, index, BUFSIZE);
      } catch (Exception e) {
        throw new InternalException(e);
      }
      oy.wrote(bytes);

      if (chained) {
        chained = false;
      } else {
        if (oy.pageout(og) != 1) {
          if (bytes < BUFSIZE) break;
          throw new InternalException("Input does not appear to be an Ogg bitstream.");
        }
      }
      os.init(og.serialno());
      os.reset();

      vi.init();
      vc.init();

      if (os.pagein(og) < 0) {
        // error; stream version mismatch perhaps
        throw new InternalException("Error reading first page of Ogg bitstream data.");
      }

      if (os.packetout(op) != 1) {
        // no page? must not be vorbis
        throw new InternalException("Error reading initial header packet.");
      }

      if (vi.synthesis_headerin(vc, op) < 0) {
        // error case; not a vorbis header
        throw new InternalException("This Ogg bitstream does not contain Vorbis audio data.");
      }

      int i = 0;

      while (i < 2) {
        while (i < 2) {
          if (checkState()) {
            return;
          }

          int result = oy.pageout(og);
          if (result == 0) break; // Need more data
          if (result == 1) {
            os.pagein(og);
            while (i < 2) {
              result = os.packetout(op);
              if (result == 0) break;
              if (result == -1) {
                throw new InternalException("Corrupt secondary header.  Exiting.");
              }
              vi.synthesis_headerin(vc, op);
              i++;
            }
          }
        }

        index = oy.buffer(BUFSIZE);
        buffer = oy.data;
        try {
          bytes = bitStream.read(buffer, index, BUFSIZE);
        } catch (Exception e) {
          throw new InternalException(e);
        }
        if (bytes == 0 && i < 2) {
          throw new InternalException("End of file before finding all Vorbis headers!");
        }
        oy.wrote(bytes);
      }

      convsize = BUFSIZE / vi.channels;

      vd.synthesis_init(vi);
      vb.init(vd);

      float[][][] _pcmf = new float[1][][];
      int[] _index = new int[vi.channels];

      getOutputLine(vi.channels, vi.rate);

      while (eos == 0) {
        while (eos == 0) {
          if (player != me) {
            return;
          }

          int result = oy.pageout(og);
          if (result == 0) break; // need more data
          if (result == -1) { // missing or corrupt data at this page
            // position
            // System.err.println("Corrupt or missing data in
            // bitstream;
            // continuing...");
          } else {
            os.pagein(og);

            if (og.granulepos() == 0) { //
              chained = true; //
              eos = 1; //
              break; //
            } //

            while (true) {
              if (checkState()) {
                return;
              }

              result = os.packetout(op);
              if (result == 0) break; // need more data
              if (result == -1) { // missing or corrupt data at
                // this page position
                // no reason to complain; already complained
                // above

                // System.err.println("no reason to complain;
                // already complained above");
              } else {
                // we have a packet. Decode it
                int samples;
                if (vb.synthesis(op) == 0) { // test for
                  // success!
                  vd.synthesis_blockin(vb);
                }
                while ((samples = vd.synthesis_pcmout(_pcmf, _index)) > 0) {
                  if (checkState()) {
                    return;
                  }

                  float[][] pcmf = _pcmf[0];
                  int bout = (samples < convsize ? samples : convsize);

                  // convert doubles to 16 bit signed ints
                  // (host order) and
                  // interleave
                  for (i = 0; i < vi.channels; i++) {
                    int ptr = i * 2;
                    // int ptr=i;
                    int mono = _index[i];
                    for (int j = 0; j < bout; j++) {
                      int val = (int) (pcmf[i][mono + j] * 32767.);
                      if (val > 32767) {
                        val = 32767;
                      }
                      if (val < -32768) {
                        val = -32768;
                      }
                      if (val < 0) val = val | 0x8000;
                      convbuffer[ptr] = (byte) (val);
                      convbuffer[ptr + 1] = (byte) (val >>> 8);
                      ptr += 2 * (vi.channels);
                    }
                  }
                  outputLine.write(convbuffer, 0, 2 * vi.channels * bout);
                  vd.synthesis_read(bout);
                }
              }
            }
            if (og.eos() != 0) eos = 1;
          }
        }

        if (eos == 0) {
          index = oy.buffer(BUFSIZE);
          buffer = oy.data;
          try {
            bytes = bitStream.read(buffer, index, BUFSIZE);
          } catch (Exception e) {
            throw new InternalException(e);
          }
          if (bytes == -1) {
            break;
          }
          oy.wrote(bytes);
          if (bytes == 0) eos = 1;
        }
      }

      os.clear();
      vb.clear();
      vd.clear();
      vi.clear();
    }

    oy.clear();
  }
 /** Reads headers and comments. */
 private void readHeaders(HashMap aff_properties, HashMap af_properties) throws IOException {
   if (TDebug.TraceAudioConverter) TDebug.out("readHeaders(");
   index = oggSyncState_.buffer(bufferSize_);
   buffer = oggSyncState_.data;
   bytes = readFromStream(buffer, index, bufferSize_);
   if (bytes == -1) {
     if (TDebug.TraceAudioConverter)
       TDebug.out("Cannot get any data from selected Ogg bitstream.");
     throw new IOException("Cannot get any data from selected Ogg bitstream.");
   }
   oggSyncState_.wrote(bytes);
   if (oggSyncState_.pageout(oggPage_) != 1) {
     if (bytes < bufferSize_) {
       throw new IOException("EOF");
     }
     if (TDebug.TraceAudioConverter) TDebug.out("Input does not appear to be an Ogg bitstream.");
     throw new IOException("Input does not appear to be an Ogg bitstream.");
   }
   oggStreamState_.init(oggPage_.serialno());
   vorbisInfo.init();
   vorbisComment.init();
   aff_properties.put("ogg.serial", new Integer(oggPage_.serialno()));
   if (oggStreamState_.pagein(oggPage_) < 0) {
     // error; stream version mismatch perhaps
     if (TDebug.TraceAudioConverter) TDebug.out("Error reading first page of Ogg bitstream data.");
     throw new IOException("Error reading first page of Ogg bitstream data.");
   }
   if (oggStreamState_.packetout(oggPacket_) != 1) {
     // no page? must not be vorbis
     if (TDebug.TraceAudioConverter) TDebug.out("Error reading initial header packet.");
     throw new IOException("Error reading initial header packet.");
   }
   if (vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_) < 0) {
     // error case; not a vorbis header
     if (TDebug.TraceAudioConverter)
       TDebug.out("This Ogg bitstream does not contain Vorbis audio data.");
     throw new IOException("This Ogg bitstream does not contain Vorbis audio data.");
   }
   int i = 0;
   while (i < 2) {
     while (i < 2) {
       int result = oggSyncState_.pageout(oggPage_);
       if (result == 0) {
         break;
       } // Need more data
       if (result == 1) {
         oggStreamState_.pagein(oggPage_);
         while (i < 2) {
           result = oggStreamState_.packetout(oggPacket_);
           if (result == 0) {
             break;
           }
           if (result == -1) {
             if (TDebug.TraceAudioConverter) TDebug.out("Corrupt secondary header.  Exiting.");
             throw new IOException("Corrupt secondary header.  Exiting.");
           }
           vorbisInfo.synthesis_headerin(vorbisComment, oggPacket_);
           i++;
         }
       }
     }
     index = oggSyncState_.buffer(bufferSize_);
     buffer = oggSyncState_.data;
     bytes = readFromStream(buffer, index, bufferSize_);
     if (bytes == -1) {
       break;
     }
     if (bytes == 0 && i < 2) {
       if (TDebug.TraceAudioConverter)
         TDebug.out("End of file before finding all Vorbis headers!");
       throw new IOException("End of file before finding all Vorbis  headers!");
     }
     oggSyncState_.wrote(bytes);
   }
   // Read Ogg Vorbis comments.
   byte[][] ptr = vorbisComment.user_comments;
   String currComment = "";
   int c = 0;
   for (int j = 0; j < ptr.length; j++) {
     if (ptr[j] == null) {
       break;
     }
     currComment = (new String(ptr[j], 0, ptr[j].length - 1, "UTF-8")).trim();
     if (TDebug.TraceAudioConverter) TDebug.out(currComment);
     if (currComment.toLowerCase().startsWith("artist")) {
       aff_properties.put("author", currComment.substring(7));
     } else if (currComment.toLowerCase().startsWith("title")) {
       aff_properties.put("title", currComment.substring(6));
     } else if (currComment.toLowerCase().startsWith("album")) {
       aff_properties.put("album", currComment.substring(6));
     } else if (currComment.toLowerCase().startsWith("date")) {
       aff_properties.put("date", currComment.substring(5));
     } else if (currComment.toLowerCase().startsWith("copyright")) {
       aff_properties.put("copyright", currComment.substring(10));
     } else if (currComment.toLowerCase().startsWith("comment")) {
       aff_properties.put("comment", currComment.substring(8));
     } else if (currComment.toLowerCase().startsWith("genre")) {
       aff_properties.put("ogg.comment.genre", currComment.substring(6));
     } else if (currComment.toLowerCase().startsWith("tracknumber")) {
       aff_properties.put("ogg.comment.track", currComment.substring(12));
     } else {
       c++;
       aff_properties.put("ogg.comment.ext." + c, currComment);
     }
     aff_properties.put(
         "ogg.comment.encodedby",
         new String(vorbisComment.vendor, 0, vorbisComment.vendor.length - 1));
   }
 }
Beispiel #14
0
  /**
   * Fetch and process a packet. Handles the case where we're at a bitstream boundary and dumps the
   * decoding machine. If the decoding machine is unloaded, it loads it. It also keeps pcm_offset up
   * to date (seek and read both use this. seek uses a special hack with readp).
   *
   * @param readp read pointer
   * @return -1) hole in the data (lost packet)<br>
   *     0) need more date (only if readp==0)/eof<br>
   *     1) got a packet
   */
  int processPacket(int readp) {
    Page og = new Page();

    // handle one packet. Try to fetch it from current stream state
    // extract packets from page
    while (true) {
      // process a packet if we can. If the machine isn't loaded,
      // neither is a page
      if (decodeReady) {
        Packet op = new Packet();
        int result = os.packetout(op);
        long granulepos;
        // if(result==-1)return(-1); // hole in the data. For now,
        // swallow
        // and go. We'll need to add a real
        // error code in a bit.
        if (result > 0) {
          // got a packet. process it
          granulepos = op.granulepos;
          if (vb.synthesis(op) == 0) { // lazy check for lazy
            // header handling. The
            // header packets aren't
            // audio, so if/when we
            // submit them,
            // vorbis_synthesis will
            // reject them
            // suck in the synthesis data and track bitrate
            int oldsamples = vd.synthesisPcmout(null, null);
            vd.synthesisBlockin(vb);
            samptrack += vd.synthesisPcmout(null, null) - oldsamples;
            bittrack += op.bytes * 8;

            // update the pcm offset.
            if (granulepos != -1 && op.endOfStream == 0) {
              int link = (seekable ? currentLink : 0);
              int samples;
              // this packet has a pcm_offset on it (the last
              // packet
              // completed on a page carries the offset) After
              // processing
              // (above), we know the pcm position of the *last*
              // sample
              // ready to be returned. Find the offset of the
              // *first*
              //
              // As an aside, this trick is inaccurate if we begin
              // reading anew right at the last page; the
              // end-of-stream
              // granulepos declares the last frame in the stream,
              // and the
              // last packet of the last page may be a partial
              // frame.
              // So, we need a previous granulepos from an
              // in-sequence page
              // to have a reference point. Thus the !op.e_o_s
              // clause above

              samples = vd.synthesisPcmout(null, null);
              granulepos -= samples;
              for (int i = 0; i < link; i++) {
                granulepos += pcmlengths[i];
              }
              pcmOffset = granulepos;
            }
            return (1);
          }
        }
      }

      if (readp == 0) {
        return (0);
      }
      if (getNextPage(og, -1) < 0) {
        return (0); // eof. leave unitialized
      }
      // bitrate tracking; add the header's bytes here, the body bytes
      // are done by packet above
      bittrack += og.headerLen * 8;

      // has our decoding just traversed a bitstream boundary?
      if (decodeReady) {
        if (currentSerialno != og.serialno()) {
          decodeClear();
        }
      }

      // Do we need to load a new machine before submitting the page?
      // This is different in the seekable and non-seekable cases.
      //
      // In the seekable case, we already have all the header
      // information loaded and cached; we just initialize the machine
      // with it and continue on our merry way.
      //
      // In the non-seekable (streaming) case, we'll only be at a
      // boundary if we just left the previous logical bitstream and
      // we're now nominally at the header of the next bitstream

      if (!decodeReady) {
        int i;
        if (seekable) {
          currentSerialno = og.serialno();

          // match the serialno to bitstream section. We use this
          // rather than
          // offset positions to avoid problems near logical bitstream
          // boundaries
          for (i = 0; i < links; i++) {
            if (serialnos[i] == currentSerialno) {
              break;
            }
          }
          if (i == links) {
            // sign of a bogus stream. error out,
            // leave machine uninitialized
            return (-1);
          }
          currentLink = i;

          os.init(currentSerialno);
          os.reset();

        } else {
          // we're streaming
          // fetch the three header packets, build the info struct
          int[] foo = new int[1];
          int ret = fetchHeaders(vi[0], vc[0], foo, og);
          currentSerialno = foo[0];
          if (ret != 0) {
            return ret;
          }
          currentLink++;
          i = 0;
        }
        makeDecodeReady();
      }
      os.pagein(og);
    }
  }
Beispiel #15
0
  /**
   * Uses the local ogg_stream storage in vf; this is important for non-streaming input sources.
   *
   * @param vi the info block
   * @param vc comment block
   * @param serialno serial numbers
   * @param ogPtr ogg pointer page
   * @return success codes OV_*
   */
  int fetchHeaders(Info vi, Comment vc, int[] serialno, Page ogPtr) {
    Page og = new Page();
    Packet op = new Packet();
    int ret;

    if (ogPtr == null) {
      ret = getNextPage(og, CHUNKSIZE);
      if (ret == OV_EREAD) {
        return OV_EREAD;
      }
      if (ret < 0) {
        return OV_ENOTVORBIS;
      }
      ogPtr = og;
    }

    if (serialno != null) {
      serialno[0] = ogPtr.serialno();
    }

    os.init(ogPtr.serialno());

    // extract the initial header from the first page and verify that the
    // Ogg bitstream is in fact Vorbis data

    vi.init();
    vc.init();

    int i = 0;
    while (i < 3) {
      os.pagein(ogPtr);
      while (i < 3) {
        int result = os.packetout(op);
        if (result == 0) {
          break;
        }
        if (result == -1) {
          vi.clear();
          vc.clear();
          os.clear();
          return -1;
        }
        if (vi.synthesisHeaderin(vc, op) != 0) {
          vi.clear();
          vc.clear();
          os.clear();
          return -1;
        }
        i++;
      }
      if (i < 3) {
        if (getNextPage(ogPtr, 1) < 0) {
          vi.clear();
          vc.clear();
          os.clear();
          return -1;
        }
      }
    }
    return 0;
  }
Beispiel #16
0
  /**
   * Seek to a sample offset relative to the decompressed pcm stream.
   *
   * @param pos position
   * @return zero on success, nonzero on failure
   */
  public int pcmSeek(long pos) {
    int link = -1;
    long total = pcmTotal(-1);

    if (!seekable) {
      return (-1); // don't dump machine if we can't seek
    }
    if (pos < 0 || pos > total) {
      // goto seek_error;
      pcmOffset = -1;
      decodeClear();
      return -1;
    }

    // which bitstream section does this pcm offset occur in?
    for (link = links - 1; link >= 0; link--) {
      total -= pcmlengths[link];
      if (pos >= total) {
        break;
      }
    }

    // search within the logical bitstream for the page with the highest
    // pcm_pos preceeding (or equal to) pos. There is a danger here;
    // missing pages or incorrect frame number information in the
    // bitstream could make our task impossible. Account for that (it
    // would be an error condition)
    long target = pos - total;
    long end = offsets[link + 1];
    long begin = offsets[link];
    int best = (int) begin;

    Page og = new Page();
    while (begin < end) {
      long bisect;
      int ret;

      if (end - begin < CHUNKSIZE) {
        bisect = begin;
      } else {
        bisect = (end + begin) / 2;
      }

      seekHelper(bisect);
      ret = getNextPage(og, end - bisect);

      if (ret == -1) {
        end = bisect;
      } else {
        long granulepos = og.granulepos();
        if (granulepos < target) {
          best = ret; // raw offset of packet with granulepos
          begin = offset; // raw offset of next packet
        } else {
          end = bisect;
        }
      }
    }
    // found our page. seek to it (call raw_seek).
    if (rawSeek(best) != 0) {
      // goto seek_error;
      pcmOffset = -1;
      decodeClear();
      return -1;
    }

    // verify result
    if (pcmOffset >= pos) {
      // goto seek_error;
      pcmOffset = -1;
      decodeClear();
      return -1;
    }
    if (pos > pcmTotal(-1)) {
      // goto seek_error;
      pcmOffset = -1;
      decodeClear();
      return -1;
    }

    // discard samples until we reach the desired position. Crossing a
    // logical bitstream boundary with abandon is OK.
    while (pcmOffset < pos) {
      int target2 = (int) (pos - pcmOffset);
      float[][][] lPcm = new float[1][][];
      int[] lIndex = new int[getInfo(-1).channels];
      int samples = vd.synthesisPcmout(lPcm, lIndex);

      if (samples > target2) {
        samples = target2;
      }
      vd.synthesisRead(samples);
      pcmOffset += samples;

      if (samples < target2) {
        if (processPacket(1) == 0) {
          pcmOffset = pcmTotal(-1); // eof
        }
      }
    }
    return 0;

    // seek_error:
    // dump machine so we're in a known state
    // pcm_offset=-1;
    // decode_clear();
    // return -1;
  }