2014-02-18 5 views
0

Приведенный ниже код отлично работает на эмуляторе, но не на устройстве. Я нашел следующие строки, которые выглядели подозрительно ко мне:Android MediaCodec API - Музыкальные эффекты на эмуляторе, а не на устройстве

V/MediaExtractor (5030): автоопределение медиа-контента, как «аудио/MPEG» с уверенностью 0,20 V/ChromiumHTTPDataSource (5030): mContentSize неопределен или сеть может быть отключен V/ChromiumHTTPDataSource (5030): mContentSize неопределен или сеть может быть отключена D/com.example.mediacodectest (5030): MIME-тип: аудио/MPEG

Я ищу советы/предложения. Спасибо заранее ...

private class PlayerThread extends Thread { 

    @Override 
    public void run() { 
     MediaExtractor extractor; 
     MediaCodec codec; 
     ByteBuffer[] codecInputBuffers; 
     ByteBuffer[] codecOutputBuffers; 

     AudioTrack mAudioTrack; 

     mAudioTrack = new AudioTrack(
       AudioManager.STREAM_MUSIC, 
       44100, 
       AudioFormat.CHANNEL_OUT_STEREO, 
       AudioFormat.ENCODING_PCM_16BIT, 
       8192 * 2, 
       AudioTrack.MODE_STREAM); 

     extractor = new MediaExtractor(); 
     try 
     { 
      extractor.setDataSource("http://anmp3streamingsource.com/stream"); 
      MediaFormat format = extractor.getTrackFormat(0); 
      String mime = format.getString(MediaFormat.KEY_MIME); 
      Log.d(TAG, String.format("MIME TYPE: %s", mime)); 

      codec = MediaCodec.createDecoderByType(mime); 
      codec.configure(
        format, 
        null /* surface */, 
        null /* crypto */, 
        0 /* flags */); 
      codec.start(); 
      codecInputBuffers = codec.getInputBuffers(); 
      codecOutputBuffers = codec.getOutputBuffers(); 

      extractor.selectTrack(0); // <= You must select a track. You will read samples from the media from this track! 

      boolean sawInputEOS = false; 
      boolean sawOutputEOS = false;    

      for (;;) { 
       int inputBufIndex = codec.dequeueInputBuffer(-1); 
       if (inputBufIndex >= 0) { 
        ByteBuffer dstBuf = codecInputBuffers[inputBufIndex]; 

        int sampleSize = extractor.readSampleData(dstBuf, 0); 
        long presentationTimeUs = 0; 
        if (sampleSize < 0) { 
         sawInputEOS = true; 
         sampleSize = 0; 
        } else { 
         presentationTimeUs = extractor.getSampleTime(); 
        } 

        codec.queueInputBuffer(inputBufIndex, 
              0, //offset 
              sampleSize, 
              presentationTimeUs, 
              sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); 
        if (!sawInputEOS) { 
         extractor.advance(); 
        } 

        MediaCodec.BufferInfo info = new BufferInfo(); 
        final int res = codec.dequeueOutputBuffer(info, -1); 
        if (res >= 0) { 
         int outputBufIndex = res; 
         ByteBuffer buf = codecOutputBuffers[outputBufIndex]; 

         final byte[] chunk = new byte[info.size]; 
         buf.get(chunk); // Read the buffer all at once 
         buf.clear(); // ** MUST DO!!! OTHERWISE THE NEXT TIME YOU GET THIS SAME BUFFER BAD THINGS WILL HAPPEN 

         mAudioTrack.play(); 

         if (chunk.length > 0) { 
          mAudioTrack.write(chunk, 0, chunk.length); 
         } 
         codec.releaseOutputBuffer(outputBufIndex, false /* render */); 

         if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 
          sawOutputEOS = true; 
         } 
        } 
        else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) 
        { 
         codecOutputBuffers = codec.getOutputBuffers(); 
        } 
        else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) 
        { 
         final MediaFormat oformat = codec.getOutputFormat(); 
         Log.d(TAG, "Output format has changed to " + oformat); 
         mAudioTrack.setPlaybackRate(oformat.getInteger(MediaFormat.KEY_SAMPLE_RATE)); 
        } 
       } 
      } 

     }     
     catch (IOException e) 
     { 
      Log.e(TAG, e.getMessage()); 
     } 
    } 
} 
+0

Ваша обработка вывода не совсем правильная; Я добавил FAQ пункт № 11 по адресу http://bigflake.com/mediacodec/#q11. Строки журнала, которые вы показываете, не выглядят слишком подозрительными. Можете ли вы более четко определить, как код не работает на устройстве? – fadden

+0

Спасибо за ответ. Код отлично работает на эмуляторе уровня 17, но не на самом устройстве с уровнем API 18. Я мог бы отлаживать до строки: final int res = codec.dequeueOutputBuffer (info, -1); , но не далее ... – burakk

ответ

1

Я не работал с аудио, но я думаю, что вижу проблему. Вы висете в dequeueOutputBuffer(), потому что кодек ждет большего ввода.

Некоторые видеокодеки хотят ~ 4 буфера ввода, прежде чем они даже закончат инициализацию (for example). Я ожидаю, что некоторые аудиокодеки могут вести себя одинаково. Реализации кодеков варьируются от устройства к устройству, поэтому неудивительно, что то, что работает на эмуляторе, ведет себя по-разному.

Изменить таймауты от -1 (ждать вечно) на что-то скромное (скажем, 1000 микросекунд).

+0

Спасибо, что сработало. Когда вы установили таймаут -1, то? – burakk

+0

Я бы не использовал его как постоянное значение. Если вы ожидаете самого первого входного буфера, или вы отправили входной EOS и просто ожидаете, что выход будет истощен, нет точки вокруг цикла. Таким образом, вы можете установить переменную в -1, выполнить первое ожидание ввода, затем установить переменную до 1000 и использовать ее до тех пор, пока не закончите вход, и в этот момент вы установите ее на -1. (Я имел в виду делать что-то подобное в Grafika с тех пор, как возник вопрос о задержке запуска, но пока у меня еще нет.) – fadden