问题描述
这是我的第一个问题,所以请让我知道是否错过任何事情!
我必须解码h264流,并且在渲染后必须处理图像。我在https://developer.android.com/reference/android/media/MediaCodec的帮助下实现了解码器 作为“使用缓冲区的异步处理”。
我开始每40毫秒喂一次InputBuffer的过程。
//For the test I usea List<byte[]> with the encoded frames
byte[] p_encodedFrame = MyDataSource.GetData(m_frameIndex);
ByteBuffer inputBuf = codec.GetInputBuffer(index);
inputBuf.Clear();
//Load data to inputbuffer
inputBuf.Put(p_encodedFrame);
如果帧被解码,则由HW调用的 OnOutputBufferAvailable方法。我需要有关框架的一些信息,并使用MediaCodec.BufferInfo info
属性。 info.PresentationTimeUs
代表时间戳,是我将帧交给解码器的时间,但问题出在这里:
我得到了以下时间戳序列: 80000,40000,160000,120000 .... n + 1,n ....
渲染的图像顺序正确,但是交换了帧的时间戳。我在真实设备和模拟器的Android Api级别26、27、28、29上测试了此功能。我尝试使用“使用缓冲区进行同步处理”,但结果是相同的。
有人可以帮助我,为什么我要交换时间戳?
这是我的课程,用于解码h264帧。
public class OpenGLDecoderCallBackTest : MediaCodec.Callback
{
/// <summary>
/// Initialize the Surface,MediaCodec,MediaFormat
/// </summary>
public void Initialize()
{
//OpenGL surface
m_outputSurface = new CodecOutputSurface(OutputWidth,OutputHeight,MyCameraIndex);
//MMediaCodec for Decode
m_MediaCodec = Android.Media.MediaCodec.CreateDecoderByType("video/avc");
//Callback to renderfinished
m_MediaCodec.SetCallback(this);
//Format
m_format = MediaFormat.CreateVideoFormat("video/avc",2048,1536);
m_format.SetInteger(MediaFormat.KeyFrameRate,25);
m_format.SetInteger(MediaFormat.KeyMaxInputSize,300000);
m_MediaCodec.Configure(m_format,m_outputSurface.getSurface(),null,MediaCodecConfigFlags.None);
}
/// <summary>
/// Start decoding
/// </summary>
public void Start(int p_FrameNumber = 0)
{
…
//Start decoding
m_MediaCodec.Start();
}
/// <summary>
/// Stop decoding
/// </summary>
public void Stop()
{
m_MediaCodec.Stop();
EndOfStream = true;
if (EndOfStreamEvent != null)
{
EndOfStreamEvent();
}
//Destroy surface end codec
this.m_outputSurface.release();
this.m_outputSurface.dispose();
this.m_MediaCodec.Release();
this.m_MediaCodec.dispose();
}
public override void OnError(MediaCodec codec,MediaCodec.CodecException e)
{
Console.WriteLine($"!!!!!!!!!!!!!! CameraID : {MyCameraIndex} OnError : {e.Message}");
}
public override void OnInputBufferAvailable(MediaCodec codec,int index)
{
//Simulate 40 msec framerate
if (SimulateFPS && sw_Cycle_in.ElapsedMilliseconds < 40)
{
Thread.Sleep(40 - (int)sw_Cycle_in.ElapsedMilliseconds);
}
sw_Cycle_in.Restart();
if (MyDataSource.Length == m_frameIndex)
m_frameIndex = 0;
//Byte array to decode
byte[] p_encodedFrame = MyDataSource.GetData(m_frameIndex);
Frametocheck++;
m_frameIndex++;
//Get input free buffer
ByteBuffer inputBuf = codec.GetInputBuffer(index);
inputBuf.Clear();
//Load data to inputbuffer
inputBuf.Put(p_encodedFrame);
if (p_encodedFrame.Length < 0)
{
// End of stream -- send empty frame with EOS flag set.
codec.QueueInputBuffer(index,0L,MediaCodecBufferFlags.EndOfStream );
}
else
{
//Create timestamp for frame
m_presentationTimeUs = Frametocheck * 40000;
//KeyFrame or PartialFrame
MediaCodecBufferFlags flag = MediaCodecBufferFlags.KeyFrame;
if (p_encodedFrame.Length < 100000)
{
flag = MediaCodecBufferFlags.PartialFrame;
}
//Add frame to HW decoder and set the timestamp
codec.QueueInputBuffer(index,p_encodedFrame.Length,m_presentationTimeUs,flag);
}
}
public override void OnOutputBufferAvailable(MediaCodec codec,int index,MediaCodec.BufferInfo info)
{
//Decoder finished with the frame
int decoderStatus = index;
if (decoderStatus == (int)MediaCodecInfoState.TryAgainLater) …
else if (decoderStatus == (int)MediaCodecInfoState.OutputBuffersChanged) …
else if (decoderStatus == (int)MediaCodecInfoState.OutputFormatChanged) …
else if (decoderStatus < 0) …
else //The frame is completed to rendering
{
if (m_WriteConsole)
Console.WriteLine(" -------------- OUTPUT BUFFER : Cam ID : " + MyCameraIndex + " - Buffer : " + decoderStatus + " - Time : " + info.PresentationTimeUs + " )");
if (info.Flags == MediaCodecBufferFlags.EndOfStream)
{
if (m_WriteConsole)
{
Console.WriteLine("output EOS");
}
EndOfStream = true;
if (EndOfStreamEvent != null)
{
EndOfStreamEvent();
}
}
bool doRender = (info.Size != 0);
//Add frame to rendering
codec.ReleaSEOutputBuffer(decoderStatus,info.PresentationTimeUs);
if (doRender) …
}
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)