问题: 我有来自GoPro相机的视频流,格式为.m3u8。我需要在应用程序中显示流的内容,然后流式传输视频。 对于流媒体,我有与MediaCodec和ffmpeg一起使用的库。我应该能够流式传输MediaCodec的outputBuffer。
我可以在SurfaceView上使用MediaPlayer流式传输视频,没问题。 真正的困难在于使用MediaCodec。 我可以初始化MediaCodec,获取表面并将其添加到MediaPlayer - 蒸汽播放 - 我可以听到声音。
现在问题:
在SurfaceView上显示流 - 或MP和MC可以使用的任何其他视图。 从Surface到SurfaceView / TextureView显示数据的最佳方法是什么?
我无法从MediaCodec获取数据。 我只需要支持5.0+设备,所以我尝试使用MediaCodec.Callback。但我每次都会得到错误。我还没有找到错误的含义。 我可以做些什么来配合回拨工作?
有没有“简单”的方法,或者我必须像Google Grafika一样深入缓冲区和表面?
以下是我得到的错误:
E/ACodec﹕ [OMX.qcom.video.encoder.avc] storeMetaDataInBuffers (output) failed w/ err -2147483648
1877-1904/com.example.marek.goprorecorder E/ACodec﹕ [OMX.qcom.video.encoder.avc] ERROR(0x80001009)
07-15 15:54:47.411 1877-1904/com.example.marek.goprorecorder E/ACodec﹕ signalError(omxError 0x80001009, internalError -2147483648)
07-15 15:54:47.411 1877-1903/com.example.marek.goprorecorder E/MediaCodec﹕ Codec reported err 0x80001009, actionCode 0, while in state 6
Errror mess: android.media.MediaCodec$CodecException: Error 0x80001009
07-15 15:54:47.454 1877-1877/com.example.marek.goprorecorder D/MediaCodecCallback﹕ Errror diag: android.media.MediaCodec.error_neg_2147479543
07-15 15:54:47.454 1877-1877/com.example.marek.goprorecorder D/MediaCodecCallback﹕ Errror rec: false
07-15 15:54:47.454 1877-1877/com.example.marek.goprorecorder D/MediaCodecCallback﹕ Errror tra: false
这是我的活动:
public class MainActivity extends ActionBarActivity implements MediaPlayer.OnPreparedListener{
private final MediaPlayer mp = new MediaPlayer();
private Surface encoderSurface;
private static final String MIME_TYPE = "video/avc"; // H.264 Advanced Video Coding
private static final int FRAME_RATE = 30; // 30fps
private static final int IFRAME_INTERVAL = 0; // 5 seconds between I-frames
private static final File OUTPUT_DIR = Environment.getExternalStorageDirectory();
MediaCodec encoder = null;
MediaCodec.BufferInfo mBufferInfo;
TextureView surfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int width = 432;
int height = 240;
prepareEncoder(width, height, 600000);
}
private void prepareEncoder(int width, int height, int bitRate) {
mBufferInfo = new MediaCodec.BufferInfo();
MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, width, height);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
try {
encoder = MediaCodec.createEncoderByType(MIME_TYPE);
} catch (IOException e) {
e.printStackTrace();
}
CodecCallback callback = new CodecCallback();
encoder.setCallback(callback);
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
encoderSurface = encoder.createInputSurface();
preparePlayer(encoderSurface);
encoder.start();
}
void preparePlayer(Surface s) {
try {
//mp.setDataSource("http://10.5.5.9:8080/live/amba.m3u8");
mp.setDataSource("http://playertest.longtailvideo.com/adaptive/oceans_aes/oceans_aes.m3u8");
mp.setSurface(s);
mp.prepare();
mp.setOnPreparedListener(this);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
private class CodecCallback extends Callback {
@Override
public void onInputBufferAvailable(MediaCodec codec, int index) {
Log.d("MediaCodecCallback","InputBufferAvailable "+index);
}
@Override
public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) {
ByteBuffer outBuffer = codec.getOutputBuffer(index);
Log.d("MediaCodecCallback", "OutputBuffer Position: " + outBuffer.position());
Log.d("MediaCodecCallback", "OutputBuffer Limit: " + outBuffer.limit());
Log.d("MediaCodecCallback", "OutputBuffer Capacity: " + outBuffer.capacity());
Log.d("MediaCodecCallback","OutputBuffer: "+outBuffer.toString());
encoder.releaseOutputBuffer(index, false);
}
@Override
public void onError(MediaCodec codec, MediaCodec.CodecException e) {
Log.d("MediaCodecCallback","Errror mess: " + e);
Log.d("MediaCodecCallback","Errror diag: " + e.getDiagnosticInfo());
Log.d("MediaCodecCallback","Errror rec: " + e.isRecoverable());
Log.d("MediaCodecCallback","Errror tra: " + e.isTransient());
}
@Override
public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
Log.d("MediaCodecCallback","OutputFormatChanged: " + format.toString());
}
}
}
编辑1:
这是将输出添加到SurfaceTexture的正确方法吗?
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Surface s = new Surface(surface);
preparePlayer(s); //ads Surface to MediaPlayer and starts to play the stream
}
我可以使用fromSurfaceTextureUpdate获得的surfaceTexture吗?
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}