2014-01-20 63 views
3

我正在創建由MediaCodec輸出的原始H.264流。問題是輸出文件在Android默認播放器(API 16)中無法播放。 Android如何導出無法在播放器中播放的文件,只能在PC上的VLC中導出。也許我的代碼有一些錯誤?我的視頻是384x288。由MediaCodec輸出的原始H.264流不可播放

public class AvcEncoder { 

private MediaCodec mediaCodec; 
private BufferedOutputStream outputStream; 
private File f; 

public AvcEncoder(int w, int h, String file_name) 
{ 
    f = new File(file_name + ".mp4"); 

    try { 
     outputStream = new BufferedOutputStream(new FileOutputStream(f)); 
    } catch (Exception e){ 
     e.printStackTrace(); 
    } 

    String key_mime = "video/avc"; //video/mp4v-es, video/3gpp, video/avc 
    mediaCodec = MediaCodec.createEncoderByType(key_mime); 
    MediaFormat mediaFormat = MediaFormat.createVideoFormat(key_mime, w, h); 

    mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, (w * h) << 3); 
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 25); 
    mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar); 
    mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5); 

    mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,MediaCodecInfo.CodecProfileLevel.MPEG4ProfileMain); 
    mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 
    mediaCodec.start(); 
} 

public void close() { 
    try { 
     mediaCodec.stop(); 
     mediaCodec.release(); 
     outputStream.flush(); 
     outputStream.close(); 
    } catch (Exception e){ 
     e.printStackTrace(); 
    } 
} 


public void offerEncoder(byte[] input) { 
    try { 
     ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); 
     ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers(); 
     int inputBufferIndex = mediaCodec.dequeueInputBuffer(0); 
     if (inputBufferIndex >= 0) { 
      ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; 
      inputBuffer.clear(); 
      inputBuffer.put(input); 
      mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, 0); 
     } 

     MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); 
     int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0); 
     while (outputBufferIndex >= 0) { 
      ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; 
      byte[] outData = new byte[bufferInfo.size]; 
      outputBuffer.get(outData); 
      outputStream.write(outData, 0, outData.length); 

      mediaCodec.releaseOutputBuffer(outputBufferIndex, false); 
      outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0); 
     } 
    } catch (Throwable t) { 

     } 
    } 
} 
+0

對於其他人遇到這個問題:能夠在VLC中播放它是完美的,並表明編碼正在工作。 h264曲目只是「沒有裝盒」,所以玩家無法知道如何播放它。順便說一句,在API 18之前,使用Mp4Parser/IsoParser java庫很容易將它複用。 AVC特別適合並優雅地取代MediaMuxer。 –

回答

1

Android MediaPlayer不處理原始的H.264流。

此類流的一個難點是H.264 NAL單元沒有時間戳信息,因此除非視頻幀處於已知的固定幀速率,否則播放器將不知道何時呈現它們。

您可以用MediaCodec(例如參見Grafika中的「播放視頻(TextureView)」)創建自己的播放器,或將原始流轉換爲.mp4文件。後者需要MediaMuxer,在API 18中可用,或者使用像ffmpeg這樣的第三方庫。

+0

什麼是已知的固定幀速率? – Dim

+2

如果播放器已知幀之間的時間間隔並且不改變,則該視頻具有已知的固定幀速率,例如,你碰巧知道這是30fps的視頻。如果您在Grafika中播放「gen-eight-rects」視頻,您可以看到動畫加速......但如果選擇「以60fps播放」複選框,則沒有變化。這是因爲演示時間戳用於控制播放速度,但是當您選中「60fps」時,它們將被忽略。 Android 4.4'screenrecord'工具使用這種方法來避免在屏幕上沒有任何內容變化時必須對幀進行編碼。 – fadden