[英]Get H264 ip camera stream using mediacodec
我正在尝试获取网络上的摄像机产生的流。 主要问题是此相机产生的流是H264流。 我四处寻找找到管理这种流的最佳方法,并且我发现mediacodec是最合适的类。 不幸的是,该API的文档非常差,但是尽管如此,我还是找到了一些资源来获取此类的基本信息,并且编写了以下代码。
公共类DecodeActivity扩展Activity实现了SurfaceHolder.Callback {
private final String sampleStreamAddress = "http://192.168.0.240:80";
private PlayerThread mPlayer = null;
String mimeType = "video/avc";
MediaFormat format = MediaFormat.createVideoFormat(mimeType, 640, 360);
final byte[] header_sps = { 0, 0, 0, 1, 103, 100, 0, 40, -84, 52, -59, 1,
-32, 17, 31, 120, 11, 80, 16, 16, 31, 0, 0, 3, 3, -23, 0, 0, -22,
96, -108 };
final byte[] header_pps = { 0, 0, 0, 1, 104, -18, 60, -128 };
private static final String tag = DecodeActivity.class.getSimpleName();
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final SurfaceView sv = new SurfaceView(this);
sv.getHolder().addCallback(this);
setContentView(sv);
format.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));
format.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public void surfaceCreated(final SurfaceHolder holder) {
Log.i(tag, "surfaceCreated");
if (mPlayer == null) {
mPlayer = new PlayerThread(holder.getSurface());
mPlayer.start();
}
}
@Override
public void surfaceChanged(final SurfaceHolder holder, final int format,
final int width, final int height) {
Log.i(tag, "surfaceChanged");
if (mPlayer == null) {
mPlayer = new PlayerThread(holder.getSurface());
mPlayer.start();
}
}
@Override
public void surfaceDestroyed(final SurfaceHolder holder) {
Log.i(tag, "surfaceDestroyed");
if (mPlayer != null) {
mPlayer.interrupt();
}
}
private class PlayerThread extends Thread {
private MediaCodec decoder;
private final Surface surface;
public PlayerThread(final Surface surface) {
this.surface = surface;
}
@Override
public void run() {
try {
Log.i(tag, "running PlayerThrad");
decoder = MediaCodec.createDecoderByType(format.toString());
decoder.configure(format, surface, null, 0);
decoder.start();
final ByteBuffer[] inputBuffers = decoder.getInputBuffers();
ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
final BufferInfo info = new BufferInfo();
boolean isEOS = false;
final long startMs = System.currentTimeMillis();
//
HttpResponse res;
final DefaultHttpClient httpclient = new DefaultHttpClient();
while (!Thread.interrupted()) {
if (!isEOS) {
final int inIndex = decoder.dequeueInputBuffer(10000);
if (inIndex >= 0) {
final byte buffer2[] = new byte[18800 * 8 * 8 * 8];
final ByteBuffer buffer = inputBuffers[inIndex];
final HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(
httpParameters, 200);
httpclient.setParams(httpParameters);
Log.d(tag, " URL : " + sampleStreamAddress);
res = httpclient.execute(new HttpGet(URI
.create(sampleStreamAddress)));
final DataInputStream mjpegInputStream = new DataInputStream(
res.getEntity().getContent());
final int sampleSize = mjpegInputStream.read(
buffer2, 0, 18800 * 4);
buffer.clear();
buffer.put(buffer2, 0, sampleSize);
buffer.clear();
if (sampleSize < 0) {
// We shouldn't stop the playback at this point,
// just pass the EOS
// flag to decoder, we will get it again from
// the
// dequeueOutputBuffer
Log.d("DecodeActivity",
"InputBuffer BUFFER_FLAG_END_OF_STREAM");
decoder.queueInputBuffer(inIndex, 0, 0, 0,
MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
decoder.queueInputBuffer(inIndex, 0,
sampleSize, 0, 0);
// extractor.advance();
}
}
}
final int outIndex = decoder.dequeueOutputBuffer(info,
10000);
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED");
outputBuffers = decoder.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
Log.d("DecodeActivity",
"New format " + decoder.getOutputFormat());
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
Log.d("DecodeActivity",
"dequeueOutputBuffer timed out!");
break;
default:
final ByteBuffer buffer = outputBuffers[outIndex];
Log.v("DecodeActivity",
"We can't use this buffer but render it due to the API limit, "
+ buffer);
// We use a very simple clock to keep the video FPS, or
// the
// video
// playback will be too fast
while (info.presentationTimeUs / 1000 > System
.currentTimeMillis() - startMs) {
try {
sleep(10);
} catch (final InterruptedException e) {
e.printStackTrace();
break;
}
}
decoder.releaseOutputBuffer(outIndex, true);
break;
}
// All decoded frames have been rendered, we can stop
// playing
// now
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d("DecodeActivity",
"OutputBuffer BUFFER_FLAG_END_OF_STREAM");
break;
}
}
decoder.stop();
decoder.release();
} catch (final Exception e) {
e.printStackTrace();
}
}
}
}
问题是,当我尝试运行此活动时,出现以下错误:
(20736):无法实例化类型为'{csd-1 = java.nio.ReadWriteHeapByteBuffer'的解码器,状态:容量= 8位置= 0限制= 8,高度= 360,哑剧=视频/ avc,csd-0 = java .nio.ReadWriteHeapByteBuffer,状态:容量= 31位置= 0限制= 31,宽度= 640}'。
E / MediaCodec(20736):编解码器报告了一个错误。 (omx错误0x80001003,内部错误-2147483648)
F / libc(20736):致命信号11(SIGSEGV)位于0x00000008(代码= 1),线程20752(线程324)
有人能够指出我正确的方向吗? 因为我看不到我在做什么错。 提前致谢
可以肯定的是,MediaExtractor丢失了。 使用您的解决方案时,您会错过解析出解码器不感兴趣的标头信息的机会。
这个家伙走了正确的方向,但仍然没有解决方案。
Android从套接字使用MediaExtractor和MediaCodec(流mpeg)
接下来,您没有正确实例化解码器。 更换线
decoder = MediaCodec.createDecoderByType(format.toString());
同
decoder = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME));
如果我想出一个具体的解决方案,我将发布它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.