From b022b91c0c6fa807424b6c12cc92ac5946838083 Mon Sep 17 00:00:00 2001
From: houxiao <houxiao@454eff88-639b-444f-9e54-f578c98de674>
Date: 星期四, 13 七月 2017 16:34:39 +0800
Subject: [PATCH] update pipeline

---
 RtspFace/PL_AndroidMediaCodecDecoder.cpp |  322 ++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 242 insertions(+), 80 deletions(-)

diff --git a/RtspFace/PL_AndroidMediaCodecDecoder.cpp b/RtspFace/PL_AndroidMediaCodecDecoder.cpp
index 23ed474..65f6b35 100644
--- a/RtspFace/PL_AndroidMediaCodecDecoder.cpp
+++ b/RtspFace/PL_AndroidMediaCodecDecoder.cpp
@@ -1,23 +1,38 @@
 #include "PL_AndroidMediaCodecDecoder.h"
 #include "MaterialBuffer.h"
 #include "logger.h"
+#include "MediaHelper.h"
+
+#include <media/NdkMediaCodec.h>
+#include <media/NdkMediaFormat.h>
+
+#include <android/bitmap.h>
+
+#include <stdlib.h>
+#include <liveMedia/liveMedia.hh>
 
 struct PL_AMCD_Internal
 {
-	uint8_t buffer[1920*1080*4];//#todo from config
+	uint8_t buffer[1920*1080*3];//#todo new from config
 	size_t buffSize;
-	size_t buffSizeMax;
-	MB_Frame lastFrame;
+	const size_t buffSizeMax;
+	
+	size_t inputFrameCount;
+	int lastOutputBuffIdx; // -1 is invalid for android omx
+	
+	MB_Frame lastMbfBuffIdx; // pm for bufidx
+	MB_Frame lastMbfBuffer; // frame for buffer (decoded data)
+	MB_Frame* lastMbfList[2];
+	
 	PL_AndroidMediaCodecDecoder_Config config;
 
-	bool payError;
-	
 	AMediaCodec* codec;
-	
+
 	PL_AMCD_Internal() : 
-		buffSize(0), buffSizeMax(sizeof(buffer)), lastFrame(), 
+		buffSize(0), buffSizeMax(sizeof(buffer)), 
+		inputFrameCount(0), lastOutputBuffIdx(-1), 
+		lastMbfBuffIdx(), lastMbfBuffer(),
 		config(), 
-		payError(true),
 		codec(nullptr)
 	{
 	}
@@ -29,10 +44,14 @@
 	void reset()
 	{
 		buffSize = 0;
-		payError = true;
 		
-		MB_Frame _lastFrame;
-		lastFrame = _lastFrame;
+		inputFrameCount = 0;
+		lastOutputBuffIdx = 0;
+		
+		lastMbfBuffIdx.reset();
+		lastMbfBuffer.reset();
+		lastMbfList[0] = &lastMbfBuffIdx;
+		lastMbfList[1] = &lastMbfBuffer;
 		
 		PL_AndroidMediaCodecDecoder_Config _config;
 		config = _config;
@@ -66,23 +85,73 @@
 
     AMediaFormat* format = AMediaFormat_new();
 
-    AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, config.ak_mime.c_str());
-    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, config.ak_height);
-    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, config.ak_width);
+    AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, config->ak_mime.c_str());
+    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, config->ak_height);
+    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, config->ak_width);
+
+// see: https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities.html#COLOR_FormatYUV420Flexible
+#define AMEDIA_COLOR_FormatYUV420Flexible 0x7f420888
+    //AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, AMEDIA_COLOR_FormatYUV420Flexible);
+    //AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_STRIDE, config->ak_width*2);
+	
+	// #19 COLOR_FormatYUV420Planar (I420)
+	// #20 COLOR_FormatYUV420PackedPlanar (also I420)
+	// #21 COLOR_FormatYUV420SemiPlanar (NV12)
+	// #39 COLOR_FormatYUV420PackedSemiPlanar (also NV12)
+	// #0x7f000100 COLOR_TI_FormatYUV420PackedSemiPlanar (also also NV12)
+	
+	//tegra: I420
+	//qcom: NV12
+
+    /*
+        std::string fmtp(manager->get_param(PLGP_RTSP_FMTP));
+        if (fmtp.empty())
+            return false;
+
+        uint32_t numSPropRecords = 0;
+        SPropRecord *p_record = parseSPropParameterSets(fmtp.c_str(), numSPropRecords);
+        if (numSPropRecords < 2)
+        {
+            LOG_WARN << "numSPropRecords < 2" << std::endl;
+            return false;
+        }
+
+        SPropRecord &sps = p_record[0];
+        SPropRecord &pps = p_record[1];
+
+        AMediaFormat_setBuffer(format, "csd-0", sps.sPropBytes, sps.sPropLength); // sps
+        AMediaFormat_setBuffer(format, "csd-1", pps.sPropBytes, pps.sPropLength); // pps
+
+        //uint8_t sps[] = {0x0,0x0,0x0,0x1, 0x67, 0x42, 0x00, 0x2A, 0x95, 0xA8, 0x1E, 0x00, 0x89, 0xF9, 0x61, 0x00, 0x00, 0x07, 0x08, 0x00, 0x01, 0x5F, 0x90, 0x04};
+        //uint8_t pps[] = {0x0,0x0,0x0,0x1, 0x68, 0xCE, 0x3C, 0x80};
+        //AMediaFormat_setBuffer(format, "csd-0", sps, sizeof(sps)); // sps
+        //AMediaFormat_setBuffer(format, "csd-1", pps, sizeof(pps)); // pps
+    */
 
     // should like:
     // mime: string(video/avc), durationUs: int64(10000000), width: int32(480), height: int32(360), max-input-size: int32(55067), csd-0: data, csd-1: data}
     LOG_INFO << "AMediaFormat_toString: " << AMediaFormat_toString(format) << LOG_ENDL;
 
-    in->codec = AMediaCodec_createDecoderByType(config.ak_mime.c_str());
-    if (AMediaCodec_configure(in->codec, format, data.window, NULL, 0) != AMEDIA_OK)
+    in->codec = AMediaCodec_createDecoderByType(config->ak_mime.c_str());
+
+    // if no sureface android use software decoder
+    // see: http://stackoverflow.com/questions/15500290/access-violation-in-native-code-with-hardware-accelerated-android-mediacodec-dec
+    ANativeWindow* window = (config->renderFromOutputBuffIdx ? (ANativeWindow*)config->windowSurface : nullptr);
+    if (AMediaCodec_configure(in->codec, format, window, NULL, 0) != AMEDIA_OK)
+	{
+		AMediaFormat_delete(format);
         LOG_ERROR << "AMediaCodec_configure error" << LOG_ENDL;
+		return false;
+	}
 
     if (AMediaCodec_start(in->codec) != AMEDIA_OK)
+	{
+		AMediaFormat_delete(format);
         LOG_ERROR << "AMediaCodec_start error" << LOG_ENDL;
+		return false;
+	}
 
     AMediaFormat_delete(format);
-
 	return true;
 }
 
@@ -90,6 +159,7 @@
 {
 	PL_AMCD_Internal* in = (PL_AMCD_Internal*)internal;
 	//todo release codec
+	// call AMediaCodec_stop
 }
 
 bool PL_AndroidMediaCodecDecoder::pay(const PipeMaterial& pm)
@@ -111,73 +181,44 @@
 		LOG_ERROR << "Only support MBFT_H264_NALU" << std::endl;
 		return false;
 	}
-	
-	
-	
-	
+
     ssize_t bufidx = AMediaCodec_dequeueInputBuffer(in->codec, 2000);
-    static int framecount = 0;
-    LOGP(DEBUG, "input buffer bufidx=%zd, framecount=%d", bufidx, framecount++);
+    LOGP(DEBUG, "input buffer bufidx=%zd, inputFrameCount=%d", bufidx, in->inputFrameCount++);
 
     if (bufidx >= 0)
 	{
         size_t bufsize;
-        uint8_t* buf = AMediaCodec_getInputBuffer(in->codec, bufidx, &bufsize);
+        uint8_t* inputBuff = AMediaCodec_getInputBuffer(in->codec, bufidx, &bufsize);
         size_t sampleSize = std::min(bufsize, frame->buffSize);
-        memcpy(buf, buffer, sampleSize);
-        //auto sampleSize = AMediaExtractor_readSampleData(d->ex, buf, bufsize);
-        //if (sampleSize < 0) {
-        //    sampleSize = 0;
-        //    d->sawInputEOS = true;
-        //    LOGV("EOS");
-        //}
-        //auto presentationTimeUs = AMediaExtractor_getSampleTime(d->ex);
-        uint64_t presentationTimeUs = presentationTime.tv_sec * 1000 * 1000 + presentationTime.tv_usec; //microseconds
+        memcpy(inputBuff, frame->buffer, sampleSize); // fill buffer
 
-        media_status_t ms = AMediaCodec_queueInputBuffer(data.codec, bufidx, 0, sampleSize, presentationTimeUs, 0);
-        //LOGV("media_status_t=%d", ms);
-        //AMediaExtractor_advance(d->ex);
+        uint64_t presentationTimeUs = timeval_to_microseconds(frame->pts); //microseconds
+
+        media_status_t ms = AMediaCodec_queueInputBuffer(in->codec, bufidx, 0, sampleSize, presentationTimeUs, 0);
+        LOGP(DEBUG, "media_status_t=%d", ms);
     }
+	else
+	{
+		LOG_WARN << "bufidx=" << bufidx << LOG_ENDL;
+		return false; // return true for gain
+	}
 	
-	
-//
-//	AVFrame* pAVFrame = (AVFrame*)frame->buffer;
-//	if (pAVFrame == nullptr)
-//		return false;
-//
-//	const int height = pAVFrame->height;
-//	const int width = pAVFrame->width;
-//
-////int I420ToBGRA(const uint8* src_y, int src_stride_y,
-////               const uint8* src_u, int src_stride_u,
-////               const uint8* src_v, int src_stride_v,
-////               uint8* dst_argb, int dst_stride_argb,
-////			   int width, int height);
-//
-//	libyuv::I420ToBGRA(pAVFrame->data[0], width, 
-//						pAVFrame->data[1], SUBSAMPLE(width, 2), 
-//						pAVFrame->data[2], SUBSAMPLE(width, 2), 
-//						in->buffer, 4 * width, 
-//						width, height);
-//
-//	in->buffSize = in->buffSizeMax;
-//	//in->buffer readly
-//	
-//	in->lastFrame.type = MB_Frame::MBFT_BGRA;
-//	in->lastFrame.buffer = in->buffer;
-//	in->lastFrame.buffSize = in->buffSize;
-//	in->lastFrame.width = width;
-//	in->lastFrame.height = height;
-//	in->lastFrame.pts = frame->pts;
-//
-//	//#test
-//	//static size_t f=0;
-//	//char fname[50];
-//	//sprintf(fname, "%u.bgra", ++f);
-//	//FILE * pFile = fopen (fname,"wb");
-//	//fwrite (in->buffer , sizeof(char), in->buffSize, pFile);
-//	//fclose(pFile);
-//
+	if (in->config.releaseOutputBuffIdxInPay)
+	{
+		AMediaCodecBufferInfo info;
+		in->lastOutputBuffIdx = AMediaCodec_dequeueOutputBuffer(in->codec, &info, 0);
+		LOG_WARN << "releaseOutputBuffIdxInPay bufidx=" << in->lastOutputBuffIdx << ", flags=" << info.flags << LOG_ENDL;
+		
+		if (in->lastOutputBuffIdx >= 0)
+		{
+			if (in->config.releaseOutputBuffIdx)
+			{
+				AMediaCodec_releaseOutputBuffer(in->codec, in->lastOutputBuffIdx, info.size != 0);
+				in->lastOutputBuffIdx = -1;
+			}
+		}
+	}
+
 	return true;
 }
 
@@ -185,9 +226,130 @@
 {
 	PL_AMCD_Internal* in = (PL_AMCD_Internal*)internal;
 
-	pm.type = PipeMaterial::PMT_FRAME;
-	pm.buffer = &(in->lastFrame);
-	pm.buffSize = 0;
-	pm.former = this;
-	return true;
+	AMediaCodecBufferInfo info;
+	in->lastOutputBuffIdx = AMediaCodec_dequeueOutputBuffer(in->codec, &info, 0);
+	if (in->lastOutputBuffIdx >= 0)
+	{
+		if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM)
+		{
+			LOGP(WARNING, "output EOS");
+		}
+		//int64_t presentationNano = info.presentationTimeUs * 1000;
+		//if (d->renderstart < 0) {
+		//	d->renderstart = systemnanotime() - presentationNano;
+		//}
+		//int64_t delay = (d->renderstart + presentationNano) - systemnanotime();
+		//if (delay > 0) {
+		//	usleep(delay / 1000);
+		//}
+
+        AMediaFormat* format = AMediaCodec_getOutputFormat(in->codec);
+        if (format != NULL)
+        {
+            int32_t width, height, color;
+            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
+            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
+            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, &color);
+            AMediaFormat_delete(format);
+            format = nullptr;
+
+            LOGP(DEBUG, "output media format, w=%d, h=%d, c=%d", width, height, color);
+        }
+
+		in->lastMbfBuffIdx.reset();
+		if (! in->config.releaseOutputBuffIdx)
+		{
+			in->lastMbfBuffIdx.type = MB_Frame::MBFT_INDEX;
+			in->lastMbfBuffIdx.buffer = (void*)(in->lastOutputBuffIdx);
+			in->lastMbfBuffIdx.buffSize = sizeof(in->lastOutputBuffIdx);
+			in->lastMbfBuffIdx.width = in->config.ak_width;
+			in->lastMbfBuffIdx.height = in->config.ak_height;
+			microseconds_to_timeval(info.presentationTimeUs, in->lastMbfBuffIdx.pts);
+		}
+		
+		in->lastMbfBuffer.reset();
+		if ((in->config.generateDecodedDataPerFrame != 0) && (in->inputFrameCount % in->config.generateDecodedDataPerFrame == 0))
+		{
+            size_t outSize = in->buffSizeMax;
+            uint8_t* outputBuff = AMediaCodec_getOutputBuffer(in->codec, in->lastOutputBuffIdx, &outSize);
+            if (outputBuff != nullptr)
+            {
+                in->buffSize = std::min((size_t) info.size, in->buffSizeMax);
+                memcpy(in->buffer, outputBuff + info.offset, in->buffSize);
+
+                if (in->config.renderFromOutputBuff)
+				{
+                    ANativeWindow* window = (ANativeWindow*)(in->config.windowSurface);
+					ANativeWindow_Buffer wbuffer;
+					if (ANativeWindow_lock(window, &wbuffer, NULL) == 0)
+                    {
+                        size_t bitsSize = 0;
+                        if (wbuffer.format == WINDOW_FORMAT_RGBA_8888 || wbuffer.format == WINDOW_FORMAT_RGBX_8888)
+                            bitsSize = wbuffer.height*wbuffer.width*4;
+                        else if (wbuffer.format == WINDOW_FORMAT_RGB_565)
+                            bitsSize = wbuffer.height*wbuffer.width*2;
+                        else
+                            bitsSize = wbuffer.height*wbuffer.width;
+
+                        memcpy(wbuffer.bits, in->buffer,  bitsSize);
+                        //memcpy(in->buffer, wbuffer.bits,  bitsSize);//#test copy opposite
+						ANativeWindow_unlockAndPost(window);
+					}
+				}
+
+                in->lastMbfBuffer.type = MB_Frame::MBFT_YUV420;
+                in->lastMbfBuffer.buffer = in->buffer;
+                in->lastMbfBuffer.buffSize = in->buffSize;
+                in->lastMbfBuffer.width = in->config.ak_width;
+                in->lastMbfBuffer.height = in->config.ak_height;
+                microseconds_to_timeval(info.presentationTimeUs, in->lastMbfBuffer.pts);
+				
+				//if (in->lastMbfBuffer.buffSize > 10)
+				//{
+				//	static size_t f = 0;
+				//	char fname[50];
+				//	sprintf(fname, "/sdcard/face-%u.yuv", ++f);
+				//	FILE *pFile = fopen(fname, "wb");
+				//	fwrite(in->lastMbfBuffer.buffer, sizeof(char), in->lastMbfBuffer.buffSize, pFile);
+				//	printf("write face file %s\n", fname);
+				//	fclose(pFile);
+				//	if (f > 50) exit(0);
+				//}
+            }
+		}
+
+		pm.type = PipeMaterial::PMT_FRAME_LIST;
+		pm.buffer = *(in->lastMbfList); // in->lastMbfList is typeof MB_Frame**
+		pm.buffSize = sizeof(in->lastMbfList) / sizeof(MB_Frame*); // 2
+		pm.deleter = nullptr;
+		pm.former = this;
+
+		if (in->config.releaseOutputBuffIdx)
+		{
+			AMediaCodec_releaseOutputBuffer(in->codec, in->lastOutputBuffIdx, in->config.renderFromOutputBuffIdx);//info.size != 0
+			in->lastOutputBuffIdx = -1;
+		}
+		
+		return true;
+	}
+	else if (in->lastOutputBuffIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
+	{
+		LOGP(DEBUG, "output buffers changed");
+	}
+	else if (in->lastOutputBuffIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
+	{
+		auto format = AMediaCodec_getOutputFormat(in->codec);
+		LOGP(INFO, "format changed to: %s", AMediaFormat_toString(format));
+		AMediaFormat_delete(format);
+	}
+	else if (in->lastOutputBuffIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
+	{
+		LOGP(DEBUG, "no output buffer right now");
+	}
+	else
+	{
+		LOGP(WARNING, "unexpected info code: %zd", in->lastOutputBuffIdx);
+	}
+	
+	return false;
 }

--
Gitblit v1.8.0