当前位置: 代码迷 >> 综合 >> 【音视频开发(一)】---MediaCodec NDK解码
  详细解决方案

【音视频开发(一)】---MediaCodec NDK解码

热度:67   发布时间:2024-01-13 04:59:53.0

初始化解码器:


void VideoDecoder::Init(int width, int height, int buffNumber)
{DM_NATIVE_PRINT("VideoDecoder::Init Start... %dx%d", width, height);imageW = width;imageH = height;//带解码图像队列个数mMaxBufferNumber = buffNumber;mInputDataList = new DmSyncQueue<InputData_t>(buffNumber);mOutputDataList = new DmSyncQueue<InputData_t>(buffNumber);//解码器为H264解码类型const char* mine = "video/avc";//创建解码器mMediaCodec =  AMediaCodec_createDecoderByType(mine);AMediaFormat* videoFormat = AMediaFormat_new();AMediaFormat_setString(videoFormat, "mime", mine);AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_WIDTH, width); // 视频宽度AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_HEIGHT, height); // 视频高度//设置PPS和SPSif (videoCsd0 != NULL) {AMediaFormat_setBuffer(videoFormat, "csd-0", videoCsd0, videoCsd0Size);DM_NATIVE_PRINT(" videoCsd0 = %d\n", videoCsd0Size);}if (videoCsd1 != NULL) {AMediaFormat_setBuffer(videoFormat, "csd-1", videoCsd1, videoCsd1Size);DM_NATIVE_PRINT(" videoCsd1 = %d\n", videoCsd1Size);}//不需要设置图像格式//AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, 21);//配置解码器media_status_t status = AMediaCodec_configure(mMediaCodec, videoFormat, NULL, NULL, 0);if (status != AMEDIA_OK){DM_NATIVE_ERR_PRINT("AMediaCodec_configure() failed with error %i for format %u", (int)status, 21);} else {//开始解码器状态机status = AMediaCodec_start(mMediaCodec);if (status != AMEDIA_OK){DM_NATIVE_ERR_PRINT("AMediaCodec_start: Could not start decoder.");}run = true;//创建解码线程mLoopThread = new std::thread(&VideoDecoder::Loop, this);}//释放解码格式AMediaFormat_delete(videoFormat);DM_NATIVE_PRINT("VideoDecoder::Init Done");
}

 解码器图像解码

解码线程:

void VideoDecoder::Loop()
{while(run) {Decode();}
}

解码过程:

void VideoDecoder::Decode()
{
#ifndef WIN32//获取带解码的数据InputData_t input;//static uint64_t m = 0;if (mMediaCodec == NULL){return;}if(mInputStreamDataList == NULL) {if(!mInputDataList->Take(input)) return;} else {if(!mInputStreamDataList->Take(input)) return;}ssize_t oBufidx = -1;size_t bufsize = 0;AMediaCodecBufferInfo info;uint8_t *buf = NULL;ssize_t iBufidx = -1;/*First put our H264 bitstream into the decoder*/do{//获取解码器空闲的输入队列索引iBufidx = AMediaCodec_dequeueInputBuffer(mMediaCodec, TIMEOUT_US);//DM_NATIVE_DEBUG_PRINT("decoder iBufidx %d %d", iBufidx, mInputDataList.size());if (iBufidx >= 0){//获取输入队列的缓冲区buf = AMediaCodec_getInputBuffer(mMediaCodec, iBufidx, &bufsize);if (buf){bufsize = input.size;//填充缓冲工区memcpy(buf, input.dataPtr, bufsize);//DM_NATIVE_DEBUG_PRINT("Decoder iBufidx %d size=%d %02X%02X%02X%02X%02X %p", iBufidx, bufsize, buf[0],buf[1],buf[2],buf[3],buf[4], buf);}// DM_NATIVE_DEBUG_PRINT("Decoder iBufidx %d size=%d %02X%02X%02X%02X%02X %p", iBufidx, bufsize, input.dataPtr[0],input.dataPtr[1],input.dataPtr[2],input.dataPtr[3],input.dataPtr[4], buf);//提交解码器解码AMediaCodec_queueInputBuffer(mMediaCodec, iBufidx, 0, bufsize, GetTimestampUs(), 0);//AMediaCodec_queueInputBuffer(mMediaCodec, iBufidx, 0, bufsize,m++, 0);//释放用户图像输入队列的内存CALLBACK_InputDataFinished(input);if (input.needRealeaseMemory) {SAFE_DELETE_ARRAY(input.dataPtr);}}else if (iBufidx == -1){break;}//继续查看用户队列是否还有待解码的数据if (!mInputDataList->IsEmpty()) {if(!mInputDataList->Take(input)) break;} else {break;}}while (true);//等待解码器结果输出/*secondly try to get decoded frames from the decoder, this is performed every tick*/oBufidx = AMediaCodec_dequeueOutputBuffer(mMediaCodec, &info, 500);//DM_NATIVE_DEBUG_PRINT("Decoder oBufidx %d", oBufidx);while (oBufidx >= 0){AMediaFormat *format;int color = 0;//获取解码器输出的队列缓冲区uint8_t *buf = AMediaCodec_getOutputBuffer(mMediaCodec, oBufidx, &bufsize);if (buf == NULL){DM_NATIVE_ERR_PRINT("MediaCodecH264Dec: AMediaCodec_getOutputBuffer() returned NULL");//continue;}else{int width = 0, height = 0;//获取解码器解码的格式format = AMediaCodec_getOutputFormat(mMediaCodec);if (format != NULL){AMediaFormat_getInt32(format, "width", &width);AMediaFormat_getInt32(format, "height", &height);AMediaFormat_getInt32(format, "color-format", &color);AMediaFormat_delete(format);//DM_NATIVE_DEBUG_PRINT("width=%d height=%d color=%d", width, height, color);} else {DM_NATIVE_ERR_PRINT("MediaCodecH264Dec: AMediaCodec_getOutputFormat() returned NULL");}if (width != 0 && height != 0){//if (color == 21)if (true){//DM_NATIVE_DEBUG_PRINT("12121212");
#if 1//将解码器的图像数据从缓冲区拷贝出来,并输送至下一个环节mYUVSize = width * height * 3 / 2;//NV12unsigned char* outNV12 = new unsigned char[mYUVSize];memcpy(outNV12, buf, mYUVSize);//mOutputNV12List.push_back(outNV12);InputData_t output;output.dataPtr = outNV12;output.size = mYUVSize;output.needRealeaseMemory = true;mOutputDataList->Put(output);
#endif}else{DM_NATIVE_DEBUG_PRINT("unknown format");}}else{DM_NATIVE_DEBUG_PRINT("MediaCodecH264Dec: width and height are not known !");}}//释放解码器的输出缓冲区AMediaCodec_releaseOutputBuffer(mMediaCodec, oBufidx, false);//继续查看是否有数据已经解码完成oBufidx = AMediaCodec_dequeueOutputBuffer(mMediaCodec, &info, 500);//DM_NATIVE_DEBUG_PRINT("Decoder oBufidx- %d", oBufidx);}if (oBufidx == AMEDIA_ERROR_UNKNOWN){DM_NATIVE_DEBUG_PRINT("MediaCodecH264Dec: AMediaCodec_dequeueOutputBuffer() had an exception");}
#endif // !WIN32
}

其他辅助函数:

获取时间戳:

static uint64_t GetTimestampUs() {static uint64_t start_uptime = 0;struct timeval tv;gettimeofday(&tv, NULL);uint64_t timestamp = (tv.tv_sec * 1000000ul + tv.tv_usec);if(start_uptime == 0) start_uptime = timestamp;timestamp-=start_uptime;//DM_NATIVE_PRINT("uptime:: %lld", timestamp);return timestamp;
}

解码图像数据入队,提交到解码器:

void VideoDecoder::PushData(const unsigned char *data, int size, int copy, int flag)
{InputData_t input;if (size <= 0 ) return;if (copy) {unsigned char *newdata = new unsigned char[size];memcpy(newdata, data, size);data = newdata;}input.dataPtr = (unsigned char *)data;input.size = size;input.needRealeaseMemory = copy;input.flag = flag;mInputDataList->Put(input);
}

去初始化:

void VideoEncoder::UnInit()
{run = false;if(mLoopThread) mLoopThread->join();if(mMediaCodec) { AMediaCodec_stop(mMediaCodec); AMediaCodec_delete(mMediaCodec); }SAFE_DELETE(mInputDataList);SAFE_DELETE(mOutputDataList);SAFE_DELETE(videoCfgData);
}

头文件:

#include "Flow.h"
#include <vector>
#include <thread>#include <media/NdkMediaCodec.h>#include "DmSyncQueue.h"
#include "InputData.h"
using namespace  std;class VideoDecoder : public Flow {
public:VideoDecoder();~VideoDecoder();void SetVideoCsdInfo(uint8_t *csd0, int csd0Size, uint8_t *csd1, int csd1Size){videoCsd0 = csd0;videoCsd0Size = csd0Size;videoCsd1 = csd1;videoCsd1Size = csd1Size;}void Init(int width, int height, int buffNumber=10);void UnInit();void PushData(const unsigned char *data, int size, int copy, int flag=0);//vector <unsigned char *> mOutputNV12List;
private:AMediaCodec *mMediaCodec;void Loop();void Decode();int mYUVSize;uint8_t *videoCsd0;int videoCsd0Size;uint8_t *videoCsd1;int videoCsd1Size;};