2014-01-20 3 views
3

Я создаю поток исходных потоков H.264 от MediaCodec. Проблема заключается в том, что выходной файл не воспроизводится в проигрывателе Android по умолчанию (API 16). Как может быть, что Android может экспортировать файл, который не воспроизводится в проигрывателе, только в VLC на ПК. Может быть, что-то не так с моим кодом? Мое видео - 384х288.Вывод Raw H.264 с помощью MediaCodec not playble

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 очень легко использовать его с помощью java-библиотеки Mp4Parser/IsoParser. Это особенно хорошо с AVC и изящно заменяет MediaMuxer. –

ответ

1

Андроида MediaPlayer не обрабатывает исходные потоки H.264.

Одна из трудностей с такими потоками заключается в том, что блоки NAL H.264 не имеют информации о временной отметке, поэтому, если видеокадры не имеют фиксированной частоты кадров, игрок не будет знать, когда их представлять.

Вы можете создать свой собственный плеер с помощью MediaCodec (см., Например, «Воспроизвести видео (TextureView)» в Grafika) или преобразовать необработанный поток в файл .mp4. Последний требует MediaMuxer, доступный в API 18, или использование сторонней библиотеки, такой как ffmpeg.

+0

Известна фиксированная частота кадров? – Dim

+2

Видео имеет известную фиксированную частоту кадров, если время между кадрами известно игроку и не изменяется, например. вы знаете, что это 30fps видео. Если вы играете видео «gen-eight-rects» в Grafika, вы можете увидеть ускорение анимации ... но если вы выберете флажок «play at 60fps», изменений нет. Это связано с тем, что метки времени представления используются для управления скоростью воспроизведения, но когда вы проверяете поле «60 кадров в секунду», они игнорируются. Инструмент «screenrecord» для Android 4.4 использует этот подход, чтобы избежать необходимости кодировать кадры, когда на экране ничего не меняется. – fadden

Смежные вопросы