代码之家  ›  专栏  ›  技术社区  ›  GOXR3PLUS

Java AudioInputStream如何支持字节数为负数的跳过

  •  1
  • GOXR3PLUS  · 技术社区  · 7 年前

    我试图用 AudioInputStream skip(long bytes) 方法

    问题是试图(比如说少量字节…):

    int skipped = audioInputStream.skip(-bytes);
    

    始终按此答案中的说明返回0 Java AudioInputStream skip with negative number of bytes always returns 0

    我需要创建一个实现,它还支持负字节数或类似于倒排的东西。


    Here is the full code github上的图书馆。

    我所做的是在用户每次跳过音频时重新创建该行 当我可以做得更好的时候,这是非常缓慢的。。。通过后退或前进。现在它只支持向前。。。

    /**                                                                                                                   
     * Skip bytes in the File input stream. It will skip N frames matching to bytes, so it will never skip given bytes len
     *                                                                                                                    
     * @param bytes                                                                                                       
     *            the bytes                                                                                               
     * @return value bigger than 0 for File and value = 0 for URL and InputStream                                         
     * @throws StreamPlayerException                                                                                      
     *             the stream player exception                                                                            
     */                                                                                                                   
    public long seek(long bytes) throws StreamPlayerException {                                                           
        long totalSkipped = 0;                                                                                            
    
        //If it is File                                                                                                   
        if (dataSource instanceof File) {                                                                                 
    
            //Check if the requested bytes are more than totalBytes of Audio                                              
            long bytesLength = getTotalBytes();                                                                           
            System.out.println("Bytes: " + bytes + " BytesLength: " + bytesLength);                                       
            if ( ( bytesLength <= 0 ) || ( bytes >= bytesLength )) {                                                      
                generateEvent(Status.EOM, getEncodedStreamPosition(), null);                                              
                return totalSkipped;                                                                                      
            }                                                                                                             
    
            logger.info(() -> "Bytes to skip : " + bytes);                                                                
            Status previousStatus = status;                                                                               
            status = Status.SEEKING;                                                                                      
    
            try {                                                                                                         
                synchronized (audioLock) {                                                                                
                    generateEvent(Status.SEEKING, AudioSystem.NOT_SPECIFIED, null);                                       
                    initAudioInputStream();                                                                               
                    if (audioInputStream != null) {                                                                       
    
                        long skipped;                                                                                     
                        // Loop until bytes are really skipped.                                                           
                        while (totalSkipped < ( bytes )) { //totalSkipped < (bytes-SKIP_INACCURACY_SIZE)))                
                            //System.out.println("Running");                                                              
                            skipped = audioInputStream.skip(bytes - totalSkipped);                                        
                            if (skipped == 0)                                                                             
                                break;                                                                                    
                            totalSkipped += skipped;                                                                      
                            logger.info("Skipped : " + totalSkipped + "/" + bytes);                                       
                            if (totalSkipped == -1)                                                                       
                                throw new StreamPlayerException(StreamPlayerException.PlayerException.SKIP_NOT_SUPPORTED);
    
                            logger.info("Skeeping:" + totalSkipped);                                                      
                        }                                                                                                 
                    }                                                                                                     
                }                                                                                                         
                generateEvent(Status.SEEKED, getEncodedStreamPosition(), null);                                           
                status = Status.OPENED;                                                                                   
                if (previousStatus == Status.PLAYING)                                                                     
                    play();                                                                                               
                else if (previousStatus == Status.PAUSED) {                                                               
                    play();                                                                                               
                    pause();                                                                                              
                }                                                                                                         
    
            } catch (IOException ex) {                                                                                    
                logger.log(Level.WARNING, ex.getMessage(), ex);                                                           
            }                                                                                                             
        }                                                                                                                 
        return totalSkipped;                                                                                              
    }                                                                                                                     
    
    2 回复  |  直到 7 年前
        1
  •  2
  •   gpasch    7 年前

    你可以创建自己的缓冲区,可以是ByteArrayOutputStream,但这是一个臃肿的东西——总是在几分钟后让我内存不足——或者拥有自己的向量或其他数组列表。

    我试了10分钟。wav文件,它运行良好——播放并将字节添加到缓冲区。

    例如

    Vector v=new Vector();
    byte[] data=new byte[basicU];
    while(true) {
      k=audioInputStream.read(data, 0, data.length);
      v.add(data);
      if(k<0) break;
      tot+=k;
    }
    

    --

    以下是我使用seek播放文件的方法。我有一条生成寻道信号的线索。当我们进行多次搜索时,问题就复杂了。我使用变量K来检查是否需要向缓冲区添加数据。我不使用skip,而是使用普通阅读;只是不要在台词中使用它。

    public void play() {
      boolean seekingBack=false;
      int i, j, k=0, seekPos=0, basicU=1024;
      AudioFormat targetFormat=null;
      int tot=0;
            new Thread() {
              public void run() {
                while(true) {
                  numBytes=(Math.random()>0.5?1:-1)*500000;
                  try { Thread.sleep(5000); } catch (Exception e) {} 
                  seekSignal=true;
                }
              }}.start();
          try {
          File fileIn=new File("........");
            AudioInputStream audioInputStream=AudioSystem.getAudioInputStream(fileIn);
            targetFormat=audioInputStream.getFormat();
            DataLine.Info dinfo=new DataLine.Info(SourceDataLine.class, targetFormat);
            SourceDataLine line=null;
            line=(SourceDataLine)AudioSystem.getLine(dinfo);
            if(line==null) return;
            line.open(targetFormat);
            line.start();
            Vector v=new Vector();
            byte[] data=new byte[basicU];
            int K=0;
            while(true) {
              if(seekingBack) { // seeking backwards
                K=seekPos;
                k=data.length;
                for(j=0; j<data.length; j++)
                  if(seekPos+j<v.size()) data[j]=((Byte)v.get(seekPos+j)).byteValue();
                  else { k=j; break; }
                line.write(data, 0, k);
                seekPos+=k;
                K+=k;
                if(seekPos>v.size()-1) seekingBack=false;
              }
              else { // normal playing
                k=audioInputStream.read(data, 0, data.length);
                if(k<0) break;
                line.write(data, 0, k);
                if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
                K+=k;
              }
              if(seekSignal) { // received a seek signal
                if(seekingBack) { // we are on a previous back seek - reading from the buffer
                if(numBytes<0) {
                  seekPos+=numBytes;
                  if(seekPos<0) seekPos=0;
                }
                else { // depending on where the seek will go (in the buffer or actual audio stream)
                  if(numBytes+seekPos<v.size())
                    seekPos+=numBytes;
                  else { // actual stream
                    int rem=numBytes-(v.size()-seekPos);
                    K=v.size();
                    while(rem>0) {
                      k=audioInputStream.read(data, 0, data.length);
                      if(k<0) break;
                      if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
                      rem-=k;
                      K+=k;
                    }
                  }
                }
                }
                else { // we are not processing a previous back seek
                if(numBytes>=0) { // forward
                    while(numBytes>0) {
                      k=audioInputStream.read(data, 0, data.length);
                      if(k<0) break;
                      if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
                      numBytes-=k;
                      K+=k;
                    }
                }
                else { // backward
                  seekingBack=true; seekPos=v.size()+numBytes; if(seekPos<0) seekPos=0; }
                }
                seekSignal=false;
              }
            }
            line.stop();
            line.close();
          }
          catch(Exception ex) { ex.printStackTrace(); System.out.println("audio problem "+ex); }
    }
    
        2
  •  0
  •   Martijn Courteaux    7 年前

    使用你自己的缓冲区,它保存着一个滚动的历史窗口。我将通过分配一个 List<byte[]> 以块的形式管理历史,例如8192字节。然后,您需要一些简单的溢出机制来抛出最旧的块,并结合一些指针操作来跟踪您在流中的实际位置。祝你好运

    推荐文章