我已经使用Android的MediaCodec
API编写了H264流编码器。我在大约十种使用不同处理器的不同设备上对其进行了测试,并且可以在所有这些设备上正常工作,除了在使用Snapdragon
800的设备(Google Nexus 5和Sony Xperia
Z1)上。在这些设备上,我得到了SPS和PPS以及第一个关键帧,但是在那之后,mEncoder.dequeueOutputBuffer(mBufferInfo,0)仅返回MediaCodec.INFO_TRY_AGAIN_LATER。我已经尝试了不同的超时,比特率,分辨率和其他配置选项,但无济于事。结果始终是相同的。
我使用以下代码初始化编码器:
mBufferInfo = new MediaCodec.BufferInfo();
encoder = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 640, 480);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 768000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, mEncoderColorFormat);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
encoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
所选颜色格式为:
MediaCodecInfo.CodecCapabilities capabilities = mCodecInfo.getCapabilitiesForType(MIME_TYPE);
for (int i = 0; i < capabilities.colorFormats.length && selectedColorFormat == 0; i++)
{
int format = capabilities.colorFormats[i];
switch (format) {
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar:
selectedColorFormat = format;
break;
default:
LogHandler.e(LOG_TAG, "Unsupported color format " + format);
break;
}
}
我通过做得到数据
ByteBuffer[] inputBuffers = mEncoder.getInputBuffers();
ByteBuffer[] outputBuffers = mEncoder.getOutputBuffers();
int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0)
{
// fill inputBuffers[inputBufferIndex] with valid data
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(rawFrame);
mEncoder.queueInputBuffer(inputBufferIndex, 0, rawFrame.length, 0, 0);
LogHandler.e(LOG_TAG, "Queue Buffer in " + inputBufferIndex);
}
while(true)
{
int outputBufferIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, 0);
if (outputBufferIndex >= 0)
{
Log.d(LOG_TAG, "Queue Buffer out " + outputBufferIndex);
ByteBuffer buffer = outputBuffers[outputBufferIndex];
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0)
{
// Config Bytes means SPS and PPS
Log.d(LOG_TAG, "Got config bytes");
}
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0)
{
// Marks a Keyframe
Log.d(LOG_TAG, "Got Sync Frame");
}
if (mBufferInfo.size != 0)
{
// adjust the ByteBuffer values to match BufferInfo (not needed?)
buffer.position(mBufferInfo.offset);
buffer.limit(mBufferInfo.offset + mBufferInfo.size);
int nalUnitLength = 0;
while((nalUnitLength = parseNextNalUnit(buffer)) != 0)
{
switch(mVideoData[0] & 0x0f)
{
// SPS
case 0x07:
{
Log.d(LOG_TAG, "Got SPS");
break;
}
// PPS
case 0x08:
{
Log.d(LOG_TAG, "Got PPS");
break;
}
// Key Frame
case 0x05:
{
Log.d(LOG_TAG, "Got Keyframe");
}
//$FALL-THROUGH$
default:
{
// Process Data
break;
}
}
}
}
mEncoder.releaseOutputBuffer(outputBufferIndex, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
{
// Stream is marked as done,
// break out of while
Log.d(LOG_TAG, "Marked EOS");
break;
}
}
else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{
outputBuffers = mEncoder.getOutputBuffers();
Log.d(LOG_TAG, "Output Buffer changed " + outputBuffers);
}
else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
MediaFormat newFormat = mEncoder.getOutputFormat();
Log.d(LOG_TAG, "Media Format Changed " + newFormat);
}
else if(outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER)
{
// No Data, break out
break;
}
else
{
// Unexpected State, ignore it
Log.d(LOG_TAG, "Unexpected State " + outputBufferIndex);
}
}
谢谢你的帮助!
您需要在对queueInputBuffer的调用中设置presentationTimeUs参数。大多数编码器都忽略了这一点,您可以对流进行编码而不会出现问题。Snapdragon
800设备使用的编码器没有。
此参数表示帧的录制时间,因此需要增加您要编码的帧与上一个帧之间的距离。
如果参数集与上一帧的值相同,则编码器将其丢弃。如果参数设置的值太小(例如,在30 FPS记录下为100000),则编码帧的质量会下降。
我正在Android系统上使用简单数据格式。我试图将时间从美国语言环境转换为瑞典语。它在模拟器中工作正常,但当我在真实设备上测试时,它不起作用。 提前谢谢。
我无法在iOS设备上进行测试
我不太清楚为什么会发生这种情况。我一直在做一些研究,但情况太模糊了,我甚至很难找到解决办法。 我使用Android Studio创建了一个应用程序,并一直在一个虚拟仿真器上运行,其中< code>Toast功能使用这两行简单的代码运行良好 但当我在手机上运行这个应用程序时,它一直死机。我有Galaxy Grand Prime,甚至不确定它是否重要。
我试图使用新的Google-service-libs在我的应用中设置AdMob广告。在Genymotion模拟器广告中一切看起来都很好。但他们没有像我的Galaxy Ace GT5830i和Android 2.3.6这样的真实设备。我不知道是什么问题。 下面是一些代码: XML: 我的Ad_Unit_Id以字符串形式保存。res/文件夹中的xml文件。 java语言: 如果您需要更多代码,请告诉我
我在GitHub中使用这个项目:https://github.com/gankit0701/Face-Mask-Detection-In-android-App 这个使用TensorFlow Lite for mobile(Android)。它检测一个人是否戴面具。它在面部顶部绘制一个框(红色/绿色)。 我奇怪的问题是,如果我直接在设备上安装演示APK,面罩检测工作正常。但是当我在Android