Mediacodec 解码器在解码 H264 文件时总是超时

2023-12-14

我一直在努力decode编码的视频文件H264编码与安卓的媒体编解码器并尝试将解码器的输出放入surface,但是当我运行应用程序时,它显示黑色表面,并且在 DDMS logcat 中我看到解码器超时.

我已将文件解析为有效frames首先[首先读取 4 个字节,指示即将到来的帧的长度,然后读取指示帧的长度数量字节,然后再次读取 4 个字节以指示下一帧的长度,依此类推。] 然后将帧传递给解码器一个循环。配置解码器时,我通过sps和pps in the 媒体格式通过直接从编码文件中对值进行硬编码[我通过使用十六进制编辑打开该文件获得了这些值]。我做到了not设置任意演示时间美国并用 0 来表示。现在解码器的出队输出缓冲区()方法返回 >=0 值,但是出队输出缓冲区()只返回MediaCodec.INFO_TRY_AGAIN_LATER这最终意味着解码器超时。

请看一下我的代码并请帮助。

提前致谢。

这是文件网址 -https://drive.google.com/file/d/0B39qOyEnXlR8Z3FSb2lzTWlORUU/edit?usp=sharing

这是我的代码 -

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;

import android.app.Activity;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

public class MainActivity extends Activity implements SurfaceHolder.Callback 
{

    private static final String filePath = Environment.getExternalStorageDirectory()+ "/H264Data1.264"; // + "/video_encoded.263";//"/video_encoded.264";
    private PlayerThread mPlayer = null;
    Handler handler = null;
    public static byte[] SPS = null;
    public static byte[] PPS = null;
    public static ArrayList<Frame> frames = null;
    public static int frameID = 0;
    public static boolean incompleteLastFrame = false;
    File encodedFile = new File(filePath);
    InputStream is;

    private static class Frame
    {
        public int id;
        public byte[] frameData;

        public Frame(int id)
        {
            this.id = id;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        try 
        {
            is = new FileInputStream(encodedFile);
            byte[] data = new byte[(int)encodedFile.length()];

            System.out.println("Total file size : " + encodedFile.length());
            frameID = 0;
            frames = new ArrayList<Frame>();

            try {
                if ((is.read(data, 0, (int)encodedFile.length())) != -1) 
                {
                    getFramesFromData(data);
                    Toast.makeText(getApplicationContext(), "frames processing finished. number of frames : " + frames.size(), Toast.LENGTH_SHORT).show();

                    SurfaceView sv = new SurfaceView(this);
                    handler = new Handler();
                    sv.getHolder().addCallback(this);
                    setContentView(sv);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }


    }
    public static void getFramesFromData(byte[] data) 
    {
        int dataLength = data.length;
        int frameLength = 0;
        frameID = 0;

        if(data.length <= 0) return;

        // each iteration in this loop indicates generation of a new frame
        for(int i = 0; ; )
        {
            if(i+3 >= dataLength) return;

            frameLength = ((data[i] & 0xff) << 24)
                    + ((data[i + 1] & 0xff) << 16)
                    + ((data[i + 2] & 0xff) << 8)
                    + (data[i + 3] & 0xff);

            i += 4;

            if(frameLength > 0)
            {
                if(i+frameLength-1 >= dataLength) return;
                Frame frame = new Frame(frameID);
                frame.frameData = new byte[frameLength];
                System.arraycopy(data, i, frame.frameData, 0, frameLength);
                frames.add(frame);
                frameID++;
                i += frameLength;
            }

        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) 
    {
        Log.d("DecodeActivity", "in surfaceCreated");
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
    {
        Log.d("DecodeActivity", "in surfaceChanged");
        if (mPlayer == null) 
        {
            Toast.makeText(getApplicationContext(), "in surfaceChanged. creating playerthread", Toast.LENGTH_SHORT).show();
            mPlayer = new PlayerThread(holder.getSurface());
            mPlayer.start();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
    {
        if (mPlayer != null) 
        {
            mPlayer.interrupt();    
        }
    }

    private class PlayerThread extends Thread 
    {
        //private MediaExtractor extractor;
        private MediaCodec decoder;
        private Surface surface;

        public PlayerThread(Surface surface) 
        {
            this.surface = surface;
        }

        @Override
        public void run() 
        {
            handler.post(new Runnable()
            {

                @Override
                public void run() 
                {

                    decoder = MediaCodec.createDecoderByType("video/avc");
                    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 320, 240);

                    byte[] header_sps  = { 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, (byte)0x80, 0x0C, (byte)0xE4, 0x40, (byte)0xA0, (byte)0xFD, 0x00, (byte)0xDA, 0x14, 0x26, (byte)0xA0 };
                    byte[] header_pps = {0x00, 0x00, 0x00, 0x01, 0x68, (byte)0xCE, 0x38, (byte)0x80 };
                    mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));
                    mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));

                    decoder.configure(mediaFormat, surface /* surface */, null /* crypto */, 0 /* flags */);

                    if (decoder == null) 
                    {
                        Log.e("DecodeActivity", "Can't find video info!");
                        return;
                    }

                    decoder.start();
                    Log.d("DecodeActivity", "decoder.start() called");

                    ByteBuffer[] inputBuffers = decoder.getInputBuffers();
                    ByteBuffer[] outputBuffers = decoder.getOutputBuffers();


                    long startMs = System.currentTimeMillis();
                    int i = 0;
                    while(!Thread.interrupted())
                    {
                        if(i >= frames.size()) 
                            break;
                        byte[] data = new byte[frames.get(i).frameData.length];
                        System.arraycopy(frames.get(i).frameData, 0, data, 0, frames.get(i).frameData.length);
                        Log.d("DecodeActivity", "i = " + i + " dataLength = " + frames.get(i).frameData.length);

                        int inIndex = 0; 
                        while ((inIndex = decoder.dequeueInputBuffer(1)) < 0)
                            ;

                        if (inIndex >= 0) 
                        {
                            ByteBuffer buffer = inputBuffers[inIndex];
                            buffer.clear();
                            int sampleSize = data.length;
                            if (sampleSize < 0) 
                            {
                                Log.d("DecodeActivity", "InputBuffer BUFFER_FLAG_END_OF_STREAM");
                                decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                                break;
                            } 
                            else 
                            {
                                Log.d("DecodeActivity", "sample size: " + sampleSize);

                                buffer = ByteBuffer.allocate(data.length);
                                buffer.put(data);
                                decoder.queueInputBuffer(inIndex, 0, sampleSize, 0, 0);
                            }


                            BufferInfo info = new BufferInfo();
                            int outIndex = decoder.dequeueOutputBuffer(info, 100000);

                            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!");
                                try {
                                    sleep(100);
                                } catch (InterruptedException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                }
                                break;
                            default:
                                ByteBuffer outbuffer = outputBuffers[outIndex];

                                Log.d("DecodeActivity", "We can't use this buffer but render it due to the API limit, " + outbuffer);

                                /*while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) 
                                {
                                    try 
                                    {
                                        sleep(10);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                        break;
                                    }
                                }*/

                                decoder.releaseOutputBuffer(outIndex, true);
                                break;
                            }
                            i++;
                            // 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();
                }
            });         
        }
    }
}

这部分看起来是错误的:

ByteBuffer buffer = inputBuffers[inIndex];
[...]
buffer = ByteBuffer.allocate(data.length);
buffer.put(data);
decoder.queueInputBuffer(inIndex, 0, sampleSize, 0, 0);

您正在获取输入缓冲区,然后忽略它,转而使用您自己分配的缓冲区。更换ByteBuffer.allocate()打电话给buffer.clear().

你所做的与检查通过非常相似解码编辑编码测试,只不过后者只是将整个内容保存在内存中,而不是将其序列化到磁盘。看一眼checkVideoData().

您可能希望采用将块标志与数据序列化的测试方法。如果你这样做了,你就不需要专门处理 SPS/PPS 头——只需将它像任何其他块一样写入流(它恰好有CODEC_CONFIG标志设置)。序列化时间戳也是一个好主意,除非保证输入视频具有已知的、不变的帧速率。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mediacodec 解码器在解码 H264 文件时总是超时 的相关文章

随机推荐

  • 从 azure blob 存储文件生成 Zip 文件

    我的 Windows Azure Blob 存储中存储了一些文件 我想获取这些文件 创建一个 zip 文件并将它们存储在一个新文件夹中 然后返回 zip 文件的路径 设置 zip 文件位置的权限 以便我的用户可以通过单击链接将 zip 文件
  • WCF 数据服务 - 代理中间层服务

    我们正在进行的项目是一个经典的三层架构 第 1 层是数据库服务器 第 2 层是应用程序服务 第 3 层是表示层 网站 在应用程序服务层中 我有一个项目 其中包括实体框架模型和基于 WCF 数据服务的服务 该服务公开模型中的实体 例如 pub
  • 链接 LINQ 语句是否会导致多次迭代?

    链接 LINQ 语句是否会导致多次迭代 例如 假设我想使用 where 子句过滤数据 然后对匹配项进行求和 int total data Where item gt item Alpha 1 item Beta 2 Sum item gt
  • reachabilityWithAddress 在 Objective C 编程中不起作用

    我想通过 ip 检查服务器是否处于活动状态 例如 74 125 71 104 谷歌的IP 分配一个可达性对象 struct sockaddr in address address sin len sizeof address address
  • 如何使用分部类扩展 ADO.NET 实体框架对象?

    我创建了一个 Visual Basic WPF 应用程序项目 其中包含 Toy edmx 这是一个从名为 Toy 的数据库生成的 ADO NET 实体数据模型 Its Window1 xaml vb文件看起来像这样 1 Class Wind
  • 使用 PDFBox 2.x 在 PDF 上放置按钮

    我希望有人可以帮助我解决使用 PdfBox 2 x 创建的 PDF 上的按钮和文本字段问题 我尝试在我的页面上放置一个按钮 该按钮使用 Javascript 函数在文本字段中设置日期 效果很好 然后 我尝试将文本字段和按钮放在多页文档中 以
  • PHP调用其他类的方法

    在我的 php 项目中我创建了 4 个类 联系 class Mysqliconn public mysqli public function construct include dbconfig php this gt connect ho
  • 为什么我的 using 语句没有关闭连接? [复制]

    这个问题在这里已经有答案了 可能的重复 实体框架 4 未关闭 sql server 2005 profiler 中的连接 好吧 stackoverflow 上的许多开发人员都说我不应该担心关闭连接 我的 using 语句将为我关闭连接 he
  • PrintServerException - “...名称无效”,即使我可以从 Windows 访问路径

    类似于以下的行引发了上述异常 PrintServer ps new PrintServer prntsrv 当我在 Windows 上使用 运行 时 上面的地址确实有效 并将我带到打印作业列表 那么为什么该行代码不起作用 显然 地址 prn
  • 类型错误:[API] 在内容脚本中未定义或为什么我不能在内容脚本中执行此操作?

    我试图在 Firefox 中编写一个简单的扩展 其中我修改了X Frame Allow header 我简单地查看了文档 发现它们支持webRequest onHeadersReceived addListener 但是 当收到标头时 我无
  • 带 Alpha 通道的颜色的十六进制表示?

    对于如何以十六进制格式表示颜色 包括 Alpha 通道 是否有 W3 或任何其他值得注意的标准 是 RGBA 还是 ARGB 在 CSS 3 中 引用规范 RGBA 值没有十六进制表示法 请参阅CSS Level 3 规范 相反 您可以使用
  • 是否可以在 Flash 或 Flex 中存储 cookie 的值?

    在PHP中有一个setcookie基于函数来存储它 在Flash中可以吗 如果可以的话怎么办 我想储存价值 首先 PHP 运行在服务器上 因此可以发送必要的 HTTP 标头来设置 cookie Flash 运行在客户端浏览器中 因此不能执行
  • 如何在主应用程序中合并 Rails Engine ApplicationController 方法?

    如何将 Rails 引擎 ApplicationController 它的方法 合并到主应用程序中 我需要访问这些引擎控制器方法 并且我想在不使用主应用程序的 ApplicationController 中的 包含 的情况下执行此操作 mo
  • 如何使用 AngularJS 限制输入值?

    我正在寻找将输入内的值限制为 4 并将 4 位数字值处理到我的控制器的方法
  • 捕获 FileSystemWatcher 侦听器线程抛出的异常

    我正在尝试找出一种方法来捕获抛出的异常FileSystemWatcher正如我从软件的崩溃报告日志中注意到的那样 这些似乎是随机发生的 崩溃并不频繁 因为上个月只发生了两次 但很烦人 我很想修复它 有问题的异常似乎与路径中包含无效字符的文件
  • C# 代码无法“查看”我的 C++ dll 中的方法

    我有一段用 C 编写的代码 不是我写的 并且想在 C 中使用它 所以我决定制作一个 dll 并从那里使用这个类 我对 C 的了解很少 并且在我的 C 项目中引用此类的方法时遇到问题 C 代码是这样的 ifndef BeamAn class
  • 使用 jQuery 更改 URL 和重定向

    我有一些这样的代码
  • PCA 中第一个分量覆盖的 99% 方差的显着性

    当第一个分量覆盖 PCA 分析中总方差的 99 以上时 这意味着什么 我有一个大小为 500X1000 的特征向量 我在其中使用了 Matlab 的 pca 函数 该函数返回 coeff score latent tsquared expl
  • Android OpenGL ES 透明背景

    我正在构建一个利用 OpenGL 的 Android 应用程序 就目前而言 本次活动的背景GLSurfaceView由我的代码动态生成并作为纹理加载并用glDrawTexfOES 这是 好的 但我可以简单地将图像更平滑地显示到其自己的表面
  • Mediacodec 解码器在解码 H264 文件时总是超时

    我一直在努力decode编码的视频文件H264编码与安卓的媒体编解码器并尝试将解码器的输出放入surface 但是当我运行应用程序时 它显示黑色表面 并且在 DDMS logcat 中我看到解码器超时 我已将文件解析为有效frames首先