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

初始化解码器:


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和SPS
    if (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;
                    //NV12
                    unsigned 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;

};

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值