MediaCodec PresentationTimeUs错误还是交换?

问题描述

这是我的第一个问题,所以请让我知道是否错过任何事情!

我必须解码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 (将#修改为@)