问题
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