NdkMediaCodec: couldn't get output / input buffers

限于喜欢 提交于 2019-12-11 15:28:42

问题


I am using native codec to read .mp4 file...

My application flow:

I have 2 buttons when I click on first button I am starting to read one .mp4 file, when I click second button I am starting to read another .mp4 file

So, problems came when I am clicking on the buttons 1 and 2 in one second delay between them in order to check app behaviour when I am switching the video from one to another...

And sometimes I get crash with such log

/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/NdkMediaCodec: sf error code: -38
/ E/ACodec: failed to set min buffer size to 6291456 (is still 3145728)
/ E/native: hit_test.cc:376 generic::internal: No point hit.
/ E/ACodec: failed to set min buffer size to 6291456 (is still 3145728)
/ E/native: hit_test.cc:376 generic::internal: No point hit.
/ E/ACodec: failed to set min buffer size to 6291456 (is still 3145728)
/ E/native: hit_test.cc:376 generic::internal: No point hit.
/ E/ACodec: failed to set min buffer size to 6291456 (is still 3145728)
/ E/native: hit_test.cc:376 generic::internal: No point hit.
/ E/ACodec: failed to set min buffer size to 6291456 (is still 3145728)
/ E/native: hit_test.cc:376 generic::internal: No point hit.
/ E/native: camera_image_stream.cc:229 Failed to extract the native metadata, status=generic::deadline_exceeded: Timed out waiting for metadata.
/ E/native: camera_image_stream.cc:229 Failed to extract the native metadata, status=CameraStatusErrorSpaceClass::ACAMERA_ERROR_METADATA_NOT_FOUND: 
/ E/native: camera_image_stream.cc:180 Camera Image Stream failed to dequeue Image from ImageReader. status=ImageReaderStatusErrorSpaceClass::AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE: AImageReader_acquireLatestImage acquired_image_count=10
/ E/native: camera_image_stream.cc:180 Camera Image Stream failed to dequeue Image from ImageReader. status=ImageReaderStatusErrorSpaceClass::AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE: AImageReader_acquireLatestImage acquired_image_count=10
/ E/ACodec: failed to set min buffer size to 6291456 (is still 3145728)
/ A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 20950 (), pid 20870 ()

Here is my NativeCodec class implementaion .H file

#include <jni.h>
#include <memory>

#include <opencv2/opencv.hpp>

#include "media/NdkMediaCodec.h"
#include "media/NdkMediaExtractor.h"

#ifndef NATIVE_CODEC_NATIVECODECC_H
#define NATIVE_CODEC_NATIVECODECC_H

//Originally took from here https://github.com/googlesamples/android-ndk/tree/master/native-codec
//Convert took from here https://github.com/kueblert/AndroidMediaCodec/blob/master/nativecodecvideo.cpp

class NativeCodec
{
public:
    NativeCodec() = default;

    ~NativeCodec() = default;

    void DecodeDone();

    void Pause();

    void Resume();

    bool createStreamingMediaPlayer(const std::string &filename);

    void setPlayingStreamingMediaPlayer(bool isPlaying);

    void shutdown();

    void rewindStreamingMediaPlayer();

    int getFrameWidth() const
    {
        return m_frameWidth;
    }

    int getFrameHeight() const
    {
        return m_frameHeight;
    }

    bool getNextFrame(std::vector<unsigned char> &imageData);

private:
    struct Workerdata
    {
        AMediaExtractor *ex;
        AMediaCodec *codec;
        bool sawInputEOS;
        bool sawOutputEOS;
        bool isPlaying;
        bool renderonce;
    };

    void Seek();

    ssize_t m_bufidx = -1;
    int m_frameWidth = -1;
    int m_frameHeight = -1;
    cv::Size m_frameSize;

    Workerdata m_data = {nullptr, nullptr, false, false, false, false};
};

#endif //NATIVE_CODEC_NATIVECODECC_H

.CC file

#include "native_codec.h"

#include <cassert>
#include "native_codec.h"
#include <jni.h>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cerrno>
#include <climits>
#include "utils/util.h"
#include <android/log.h>
#include <string>
#include <chrono>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>

#include <android/log.h>
#include <string>
#include <chrono>

// for native window JNI
#include <android/native_window_jni.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>

using namespace std;
using namespace std::chrono;

bool NativeCodec::createStreamingMediaPlayer(const std::string &filename)
{
    AMediaExtractor *ex = AMediaExtractor_new();
    media_status_t err = AMediaExtractor_setDataSource(ex, filename.c_str());;

    if (err != AMEDIA_OK)
    {
        return false;
    }

    size_t numtracks = AMediaExtractor_getTrackCount(ex);

    AMediaCodec *codec = nullptr;

    for (int i = 0; i < numtracks; i++)
    {
        AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);

        int format_color;

        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, &format_color);
        bool ok = AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &m_frameWidth);
        ok = ok && AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &m_frameHeight);

        if (ok)
        {
            m_frameSize = cv::Size(m_frameWidth, m_frameHeight);
        } else
        {
            //Asking format for frame width / height failed.
        }

        const char *mime;

        if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime))
        {
            return false;
        } else if (!strncmp(mime, "video/", 6))
        {
            // Omitting most error handling for clarity.
            // Production code should check for errors.
            AMediaExtractor_selectTrack(ex, i);
            codec = AMediaCodec_createDecoderByType(mime);
            AMediaCodec_configure(codec, format, nullptr, nullptr, 0);
            m_data.ex = ex;
            m_data.codec = codec;
            m_data.sawInputEOS = false;
            m_data.sawOutputEOS = false;
            m_data.isPlaying = false;
            m_data.renderonce = true;
            AMediaCodec_start(codec);
        }

        AMediaFormat_delete(format);
    }

    return true;
}

bool NativeCodec::getNextFrame(std::vector<unsigned char> &imageData)
{
    if (!m_data.isPlaying)
        return false;

    if (!m_data.sawInputEOS)
    {
        m_bufidx = AMediaCodec_dequeueInputBuffer(m_data.codec, 2000);

        if (m_bufidx >= 0)
        {
            size_t bufsize;
            auto buf = AMediaCodec_getInputBuffer(m_data.codec, m_bufidx, &bufsize);
            auto sampleSize = AMediaExtractor_readSampleData(m_data.ex, buf, bufsize);

            if (sampleSize < 0)
            {
                sampleSize = 0;
                m_data.sawInputEOS = true;
            }

            auto presentationTimeUs = AMediaExtractor_getSampleTime(m_data.ex);

            AMediaCodec_queueInputBuffer(m_data.codec, m_bufidx, 0, sampleSize, presentationTimeUs,
                                         m_data.sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);

            AMediaExtractor_advance(m_data.ex);
        }
    }

    if (!m_data.sawOutputEOS)
    {
        AMediaCodecBufferInfo info;
        auto status = AMediaCodec_dequeueOutputBuffer(m_data.codec, &info, 0);

        if (status >= 0)
        {
            if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM)
            {
                __android_log_print(ANDROID_LOG_ERROR, "AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM", "AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM :: %s", //
                                    "output EOS");

                m_data.sawOutputEOS = true;
            }

            if (info.size > 0)
            {
                size_t bufsize = 0;

//                uint8_t *buf = AMediaCodec_getOutputBuffer(m_data.codec, static_cast<size_t>(status), /*bufsize*/nullptr);
                uint8_t *buf = AMediaCodec_getOutputBuffer(m_data.codec, static_cast<size_t>(status), &bufsize);

                cv::Mat YUVframe(cv::Size(m_frameSize.width, static_cast<int>(m_frameSize.height * 1.5)), CV_8UC1, buf);

                cv::Mat colImg(m_frameSize, CV_8UC3);
                cv::cvtColor(YUVframe, colImg, CV_YUV420sp2BGR, 3);
                auto dataSize = colImg.rows * colImg.cols * colImg.channels();
                imageData.assign(colImg.data, colImg.data + dataSize);
            }

            AMediaCodec_releaseOutputBuffer(m_data.codec, static_cast<size_t>(status), info.size != 0);

            if (m_data.renderonce)
            {
                m_data.renderonce = false;
                return false;
            }
        } else if (status < 0)
        {
            getNextFrame(imageData);
        } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
        {
            __android_log_print(ANDROID_LOG_ERROR, "AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED", "AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED :: %s", //
                                "output buffers changed");
        } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
        {
            auto format = AMediaCodec_getOutputFormat(m_data.codec);

            __android_log_print(ANDROID_LOG_ERROR, "AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED", "AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED :: %s", //
                                AMediaFormat_toString(format));

            AMediaFormat_delete(format);
        } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
        {
            __android_log_print(ANDROID_LOG_ERROR, "AMEDIACODEC_INFO_TRY_AGAIN_LATER", "AMEDIACODEC_INFO_TRY_AGAIN_LATER :: %s", //
                                "no output buffer right now");
        } else
        {
            __android_log_print(ANDROID_LOG_ERROR, "UNEXPECTED INFO CODE", "UNEXPECTED INFO CODE :: %zd", //
                                status);
        }
    }

    return true;
}

void NativeCodec::DecodeDone()
{
    if (m_data.codec != nullptr)
    {
        AMediaCodec_stop(m_data.codec);
        AMediaCodec_delete(m_data.codec);
        AMediaExtractor_delete(m_data.ex);
        m_data.sawInputEOS = true;
        m_data.sawOutputEOS = true;
    }
}

void NativeCodec::Seek()
{
    AMediaExtractor_seekTo(m_data.ex, 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
    AMediaCodec_flush(m_data.codec);
    m_data.sawInputEOS = false;
    m_data.sawOutputEOS = false;

    if (!m_data.isPlaying)
    {
        m_data.renderonce = true;
    }
}

void NativeCodec::Pause()
{
    if (m_data.isPlaying)
    {
        // flush all outstanding codecbuffer messages with a no-op message
        m_data.isPlaying = false;
    }
}

void NativeCodec::Resume()
{
    if (!m_data.isPlaying)
    {
        m_data.isPlaying = true;
    }
}

void NativeCodec::setPlayingStreamingMediaPlayer(bool isPlaying)
{
    if (isPlaying)
    {
        Resume();
    } else
    {
        Pause();
    }
}

void NativeCodec::shutdown()
{
    m_bufidx = -1;
    DecodeDone();
}

void NativeCodec::rewindStreamingMediaPlayer()
{
    Seek();
}

Sometimes I get the error in this line m_bufidx = AMediaCodec_dequeueInputBuffer(m_data.codec, 2000); and sometimes in this cv::Mat YUVframe(cv::Size(m_frameSize.width, static_cast<int>(m_frameSize.height * 1.5)), CV_8UC1, buf);

What is the possible problem here?

Feel free to ask

来源:https://stackoverflow.com/questions/57182857/ndkmediacodec-couldnt-get-output-input-buffers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!