NdkMediaCodec需要安卓5.0以上系统才能运行,在Android.mk里加入
1 | LOCAL_LDLIBS += -lmediandk |
如果是在安卓5.0以下系统中跑,程序会直接崩掉,主函数都不会进,所以要在旧手机中运行,要根据系统版本来判断是不是5.0以上系统,如果是则动态加载libmediandk.so,而不要写死在编译脚本里。
还有,要看手机上有没有解mjpeg的硬解码器,通过以下java代码来查看
1 2 3 4 5 6 7 8 9 10 11 12 | int n = MediaCodecList.getCodecCount(); for (int i = 0; i < n; ++i) { MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); String[] supportedTypes = info.getSupportedTypes(); boolean mime_support = false; if(info.isEncoder()){ continue; } for (int j = 0; j < supportedTypes.length; ++j) { Log.v("euhat", "codec info:" + info.getName()+" supportedTypes:" + supportedTypes[j]); } } |
以下是jni硬解码代码,因为没找到支持mjpeg硬解的手机,所以还没实际跑起来过。
但实际测试过程中,新的手机上软解1920x1080的mjpeg输出yuv都很流畅了。
DecodeOp.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #pragma once class AMediaCodec; class DecodeOp { int mWidth; int mHeight; int mOriFrameSize; int mFrameSize; public: int init(int width, int height); int fini(); int decode(char *bufData, int bufSize, char *outBuf); AMediaCodec *mMediaCodec; }; |
DecodeOp.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | #include "DecodeOp.h" #include <media/NdkMediaCodec.h> #include "CommonOp.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a)) int DecodeOp::init(int width, int height) { const char *mine = "video/mjpeg"; mMediaCodec = AMediaCodec_createDecoderByType(mine); //注意这里,如果系统不存在对应的mine,mMediaCodec也会返回对象, //不过之后涉及到mMediaCodec的任何函数都会直接导致程序崩掉。 if (NULL == mMediaCodec) { return 0; } AMediaFormat *videoFormat = AMediaFormat_new(); AMediaFormat_setString(videoFormat, "mime", "video/mjpeg"); AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_WIDTH, width); AMediaFormat_setInt32(videoFormat, AMEDIAFORMAT_KEY_HEIGHT, height); media_status_t status = AMediaCodec_configure(mMediaCodec, videoFormat, NULL, NULL, 0); if (status != AMEDIA_OK) { AMediaCodec_delete(mMediaCodec); mMediaCodec = NULL; return 0; } mWidth = width; mHeight = height; mOriFrameSize = width * height * 3 / 2; mFrameSize = mOriFrameSize; status = AMediaCodec_start(mMediaCodec); if (status != AMEDIA_OK) { AMediaCodec_delete(mMediaCodec); mMediaCodec = NULL; return 0; } return 1; } int DecodeOp::fini() { AMediaCodec_stop(mMediaCodec); AMediaCodec_delete(mMediaCodec); mMediaCodec = NULL; return 1; } int DecodeOp::decode(char *bufData, int bufSize, char *outBuf) { if (NULL == mMediaCodec) return 0; ssize_t bufidx = AMediaCodec_dequeueInputBuffer(mMediaCodec, 2000); if (bufidx >= 0) { // 获取buffer的索引 size_t outsize; uint8_t* inputBuf = AMediaCodec_getInputBuffer(mMediaCodec, bufidx, &outsize); if (inputBuf != nullptr && bufSize <= outsize) { // 将待解码的数据copy到硬件中 memcpy(inputBuf, bufData, bufSize); media_status_t status = AMediaCodec_queueInputBuffer(mMediaCodec, bufidx, 0, bufSize, 2000 /* pts */, 0); } } AMediaCodecBufferInfo info; ssize_t outbufidx = AMediaCodec_dequeueOutputBuffer(mMediaCodec, &info, 2000); if (outbufidx >= 0) { size_t outsize; uint8_t* outputBuf = AMediaCodec_getOutputBuffer(mMediaCodec, outbufidx, &outsize); if (outputBuf != nullptr) { //pts = info.presentationTimeUs; //int32_t pts32 = (int32_t) pts; uint8_t *dst = (uint8_t *)outBuf; memcpy(dst, outputBuf, MIN(mOriFrameSize, mFrameSize)); uint8_t *uvBuf = outputBuf + mFrameSize; uint32_t uvSize = MIN(mOriFrameSize >> 1, mFrameSize >> 1); uint8_t *uBuf = dst + mOriFrameSize; uint8_t *vBuf = uBuf + (mOriFrameSize >> 2); memcpy(uBuf, uvBuf, uvSize); AMediaCodec_releaseOutputBuffer(mMediaCodec, outbufidx, info.size != 0); return 1; } } else { switch (outbufidx) { case AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED: // 解码输出的格式发生变化 { auto format = AMediaCodec_getOutputFormat(mMediaCodec); AMediaFormat_getInt32(format, "width", &mWidth); AMediaFormat_getInt32(format, "height", &mHeight); int32_t localColorFMT; AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, &localColorFMT); /* mColorFormat = getTTFormatFromMC(localColorFMT); int32_t stride = 0; AMediaFormat_getInt32(format, "stride", &stride); if(stride == 0) { stride = mWidth; } mLineSize[0] = stride; mFrameSize = stride * mHeight; mOriFrameSize = stride * mOriHeight; */ return 0; } case AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED: break; default: break; } } return 1; |