使用媒体基础在 windows 上解码 android h264 编码流
decoding android h264 encoded stream on windows using media foundation
我正在尝试在 windows 电脑上解码从 android 设备流式传输的 h264 编码相机帧。
我正在使用 MediaFoundation H264 解码器解码从 android 设备发送的每一帧。但是我不断收到错误 'more input samples are required to process output error'.
MF H264解码器要求如下:
Media samples contain H.264 bitstream data with start codes and has interleaved SPS/PPS. Each sample contains one complete picture, either one field or one frame.
我想知道这是否与我从 android 设备发送的内容兼容。
我正在使用下面的代码将帧发送到 windows 设备:
private static class AvcEncoder {
private MediaCodec mediaCodec;
final static int FRAME_RATE = 15;
final static int MOTION_RANK = 2;
public AvcEncoder(int width, int height) {
mediaCodec = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, (int)(width*height*FRAME_RATE*MOTION_RANK*0.07));
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
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();
}
}
//frames are sent here
public void offerEncoder(byte[] input) {
try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
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);
// write frame length
byte frameLength[] = ByteBuffer.allocate(4).putInt(outData.length).array();
outputStream.write(frameLength, 0, 4);
// write the actual frame
outputStream.write(outData, 0, outData.length);
Log.i("AvcEncoder", outData.length + " bytes written");
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
如果需要,我也可以 post Windows 代码。
此外,当我将流式传输数据保存到文件时,我可以在 VLC 中播放它,因此 VLC 能够很好地理解和解码它。
好吧,修复非常简单。我不知道为什么,但 Media Foundation 要求您设置提供给解码器的每个样本的持续时间或时间戳。然而,输出似乎不受这两个参数的任何影响。
编辑:
请注意 IMFTransform
的 InputProcess
方法应该 return MF_E_NO_SAMPLE_DURATION
或 MF_E_NO_SAMPLE_TIMESTAMP
如果在传递的 IMFSample
对象中未设置样本持续时间或时间戳InputProcess
方法。但是,在我的例子中,它没有 return 任何这样的值。
我正在尝试在 windows 电脑上解码从 android 设备流式传输的 h264 编码相机帧。 我正在使用 MediaFoundation H264 解码器解码从 android 设备发送的每一帧。但是我不断收到错误 'more input samples are required to process output error'.
MF H264解码器要求如下:
Media samples contain H.264 bitstream data with start codes and has interleaved SPS/PPS. Each sample contains one complete picture, either one field or one frame.
我想知道这是否与我从 android 设备发送的内容兼容。
我正在使用下面的代码将帧发送到 windows 设备:
private static class AvcEncoder {
private MediaCodec mediaCodec;
final static int FRAME_RATE = 15;
final static int MOTION_RANK = 2;
public AvcEncoder(int width, int height) {
mediaCodec = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, (int)(width*height*FRAME_RATE*MOTION_RANK*0.07));
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
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();
}
}
//frames are sent here
public void offerEncoder(byte[] input) {
try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
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);
// write frame length
byte frameLength[] = ByteBuffer.allocate(4).putInt(outData.length).array();
outputStream.write(frameLength, 0, 4);
// write the actual frame
outputStream.write(outData, 0, outData.length);
Log.i("AvcEncoder", outData.length + " bytes written");
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
如果需要,我也可以 post Windows 代码。
此外,当我将流式传输数据保存到文件时,我可以在 VLC 中播放它,因此 VLC 能够很好地理解和解码它。
好吧,修复非常简单。我不知道为什么,但 Media Foundation 要求您设置提供给解码器的每个样本的持续时间或时间戳。然而,输出似乎不受这两个参数的任何影响。
编辑:
请注意 IMFTransform
的 InputProcess
方法应该 return MF_E_NO_SAMPLE_DURATION
或 MF_E_NO_SAMPLE_TIMESTAMP
如果在传递的 IMFSample
对象中未设置样本持续时间或时间戳InputProcess
方法。但是,在我的例子中,它没有 return 任何这样的值。