代码编织梦想

初始化解码器:


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;

};

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sdewenking/article/details/123031934

android自带硬解码解码类型说明mediacodec使用必看-爱代码爱编程

一、背景 随着Android系统手机性能的不断提升,现阶段大部分手机都自带GPU(承担图形显示的专门硬件),大幅度提高手机显示性能,在视频显示、游戏画面刷新,和高分辨图像显示方面必须使用GPU。GOOGLE在API 16 -4.1版本中增加MediaCodec类,专用于编解码多媒体数据, 二、MediaCodec使用方式      MediaCod

android mediacodec解析-爱代码爱编程

简介 MediaCodec类可以获取底层媒体编码/解码库,是Android底层多媒体支持库的一部分(一般和MediaExtractor、MediaSync、MediaMuxer、MediaCrypto、MediaDrm、Image、Surface、AudioTrack搭配使用)。 宽泛的说,codec(编解码器)通过异步的方式对输入的数据进行处

c++编程-2:使用android mediacodec 硬解码延时问题分析_椰果奶茶加冰的博客-爱代码爱编程

      最近做项目用到Android native层的MediaCodec的接口对H264进行解码,通过在解码前和解码后加打印日志,发现解码耗时200多ms,和IOS的解码耗时10ms相比实在是延时好大。后来研究了两周也没能解决延时问题,很悲惨……不过还是将这过程中分析的思路记录下来,说不定以后万一灵感来了就解决了呢。      起初在https:/

基于android o8.1的ffmpeg ndk 开发 - 1 - hello world!_yanbixing123的博客-爱代码爱编程

  很多做NDK开发的人(像我这样从底层转过来的 >_<!)对于Android app的开发不是很理解,而ffmpeg的NDK开发现在又离不开Andorid app。网上虽然教程虽多,但是很多过时或者与NDK开发需求的不契合,或者ffmpeg与Android Studio一直在更新,从而造成了很多困扰,故写此教程,希望用户可以直接从githu

Android音视频架构-学习路线规划-爱代码爱编程

接触Android音视频这一块已经有一段时间了,跟普通的应用层开发相比,的确更花费精力。期间为了学习音视频的录制,编码,处理也看过大大小小的几十个项目。总体感觉就是知识比较零散,对刚入门的朋友比较不友好。所以才萌生了写这个Android音视频系统文章的想法(时隔多年再次写起博客不容易啊),虽然给自己挖了一个深坑,但是相信坚持下来必定能很好的提升自己。另一方

视频教程-音视频高手课(致力于提高国内音视频开发水平)-Android-爱代码爱编程

音视频高手课(致力于提高国内音视频开发水平) 从事IT行业七年,有丰富的编程经验,曾担任阿里巴巴Android手淘架构师, 涂程 ¥2199.00

NDK中使用 MediaCodec 编解码视频-爱代码爱编程

背景 MediaCodec 作为Android自带的视频编解码工具,可以直接利用底层硬件编解码能力,现在已经逐渐成为主流了。API21已经支持NDK方法了,MediaCodec api设计得非常精妙,另一个方面也是很多人觉得不好懂。 内容 MediaCodec的两个Buffer和三板斧 MediaCodec内部包含InputBuffer和

NDK中使用mediacodec解码h264-爱代码爱编程

《Ndk中使用Mediacode解码》 《android mediacodec 编码demo(java)》 《NDK中使用mediacodec编码h264》 《Android native 层使用opengl渲染YUV420p和NV12》 《android 使用NativeWindow渲染RGB视频》 《opengl 叠加显示文字》 《android st

NDK中使用mediacodec编码h264-爱代码爱编程

《Ndk中使用Mediacode解码》 《android mediacodec 编码demo(java)》 《NDK中使用mediacodec编码h264》 《Android native 层使用opengl渲染YUV420p和NV12》 《android 使用NativeWindow渲染RGB视频》 《opengl 叠加显示文字》 《android st

android ndk r14b安装,[Cmake-Android音视频]NDK-r14b编译ffmpeg3.4支持neon,硬解码-爱代码爱编程

编译环境 Ubuntu16.04 x86_64 Ffmpeg3.4 ndk-r14b 编译前的准备 ubuntu16.04 64位linux 下载ndkubuntu 下载ffmpegbash 查看ubuntu的版本是32位仍是64位编辑器 uname -a android-ndk须要和ubuntu版本的位数保持一致ide 安装ma

Android音视频开发基础(六):学习MediaCodec API,完成视频H.264的解码-爱代码爱编程

前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》。本文是Android音视频任务列表的其中一个, 对应的要学习的内容是:学习MediaCodec API,完成视频H.264的解码。(本文是最基本的H264的解码,进阶内容以后会讲解) 音视频

【音视频开发(二)】---MediaCodec NDK编码-爱代码爱编程

初始化编码器: void VideoEncoder::Init(int width, int height, int buffNumber) { DM_NATIVE_PRINT("VideoEncoder::Init Start... %dx%d", width, height); imageW = width; imageH

android音视频开发之,全网疯传-爱代码爱编程

int audioFormat, int bufferSizeInBytes, int mode, int sess