From 5ce6085328a841e270c7ce1ddfdd36efabf0b095 Mon Sep 17 00:00:00 2001 From: xingzilong <xingzilong@454eff88-639b-444f-9e54-f578c98de674> Date: 星期四, 17 八月 2017 11:46:03 +0800 Subject: [PATCH] h264裸数据读取 --- RtspFace/PL_AndroidMediaCodecFileFrame.cpp | 378 ++++++++++++++++++++++++++++++++++++++++++ RtspFace/PL_AndroidMediaCodecFileFrame.h | 47 +++++ RtspFace/my_timer.hpp | 65 +++++++ 3 files changed, 490 insertions(+), 0 deletions(-) diff --git a/RtspFace/PL_AndroidMediaCodecFileFrame.cpp b/RtspFace/PL_AndroidMediaCodecFileFrame.cpp new file mode 100644 index 0000000..ed09a1f --- /dev/null +++ b/RtspFace/PL_AndroidMediaCodecFileFrame.cpp @@ -0,0 +1,378 @@ +#include "PL_AndroidMediaCodecFileFrame.h" +#include "MaterialBuffer.h" +#include "logger.h" +#include "MediaHelper.h" + +#include <media/NdkMediaCodec.h> +#include <media/NdkMediaFormat.h> + +#include <android/bitmap.h> + +#include "my_timer.hpp" +#include <stdlib.h> +#include <fstream> +using namespace std; +#include <liveMedia/liveMedia.hh> + +#define H264_HEAD "01" + +struct PL_AMCE_Internal +{ + uint8_t buffer[1920*1080*3];//#todo new from config + size_t buffSize; + const size_t buffSizeMax; + + size_t inputFrameCount; + + PL_AndroidMediaCodecFileFrame_Config config; + + AMediaCodec* codec; + + bool payOK; + + MB_Frame tempFrame; // frame for gain + + PL_AMCE_Internal() : + buffSize(0), buffSizeMax(sizeof(buffer)), + inputFrameCount(0), + config(), + codec(nullptr), + payOK(false), + tempFrame() + { + } + + ~PL_AMCE_Internal() + { + } + + void reset() + { + buffSize = 0; + + inputFrameCount = 0; + + PL_AndroidMediaCodecFileFrame_Config _config; + config = _config; + + codec = nullptr;//#todo destory + + payOK = false; + + MB_Frame _tempFrame; + tempFrame = _tempFrame; + } +}; + +PipeLineElem* create_PL_AndroidMediaCodecFileFrame() +{ + return new PL_AndroidMediaCodecFileFrame; +} + +PL_AndroidMediaCodecFileFrame::PL_AndroidMediaCodecFileFrame() : internal(new PL_AMCE_Internal) +,m_b_loop_play(false),m_begin(-1),m_current_time(0) +{ +} + +PL_AndroidMediaCodecFileFrame::~PL_AndroidMediaCodecFileFrame() +{ + delete (PL_AMCE_Internal*)internal; + internal= nullptr; +} + +bool PL_AndroidMediaCodecFileFrame::init(void* args) +{ + PL_AMCE_Internal* in = (PL_AMCE_Internal*)internal; + in->reset(); + + PL_AndroidMediaCodecFileFrame_Config* config = (PL_AndroidMediaCodecFileFrame_Config*)args; + + int ret = read_file(config->sz_path); + if(1!=ret) + { + LOG_ERROR << "read_file error return length:" <<ret<< LOG_ENDL; + return false; + } + m_b_loop_play = config->b_loop_play; + +// 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_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, config->ak_bit_rate); +// AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, config->ak_frame_rate); +// AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, config->ak_i_frame_interval); +// //AMediaFormat_setInt32(format, "profile", 0x00000100); +// +//// 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, config->ak_color_format); +// //AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_STRIDE, config->ak_width * 2); +// +// //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_createEncoderByType(config->ak_mime.c_str()); +// +// if (AMediaCodec_configure(in->codec, format, nullptr, nullptr, AMEDIACODEC_CONFIGURE_FLAG_ENCODE) != 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; +} + +void PL_AndroidMediaCodecFileFrame::finit() +{ + PL_AMCE_Internal* in = (PL_AMCE_Internal*)internal; + //todo release codec + // call AMediaCodec_stop +} + +bool amce_pay_file_frame_breaker(const PipeMaterial* pm, void* args) +{ + PL_AMCE_Internal* in = (PL_AMCE_Internal*)args; + MB_Frame* frame = (MB_Frame*)pm->buffer; + +// ssize_t bufidx = AMediaCodec_dequeueInputBuffer(in->codec, 2000); +// LOGP(DEBUG, "input buffer bufidx=%zd, inputFrameCount=%d", bufidx, in->inputFrameCount++); +// +// if (bufidx >= 0) +// { +// size_t bufsize; +// uint8_t* inputBuff = AMediaCodec_getInputBuffer(in->codec, bufidx, &bufsize); +// size_t sampleSize = std::min(bufsize, frame->buffSize); +// memcpy(inputBuff, frame->buffer, sampleSize); // fill buffer +// +// uint64_t presentationTimeUs = timeval_to_microseconds(frame->pts); //microseconds +// +// media_status_t ms = AMediaCodec_queueInputBuffer(in->codec, bufidx, 0, sampleSize, presentationTimeUs, 0); +// +// in->payOK = true; +// LOGP(DEBUG, "media_status_t=%d", ms); +// } +// else +// { +// LOG_WARN << "bufidx=" << bufidx << LOG_ENDL; +// in->payOK = false; +// return false; +// } + + return false; +} + +bool PL_AndroidMediaCodecFileFrame::pay(const PipeMaterial& pm) +{ + PL_AMCE_Internal* in = (PL_AMCE_Internal*)internal; + + in->payOK = false; + if (!in->payOK) + pm.breake(PipeMaterial::PMT_FRAME, MB_Frame::MBFT_NV12, amce_pay_file_frame_breaker, in); + + return in->payOK; +} + +bool PL_AndroidMediaCodecFileFrame::gain(PipeMaterial& pm) +{ + PL_AMCE_Internal* in = (PL_AMCE_Internal*)internal; + +// if (!in->payOK) +// { +// LOG_WARN << "not in->payOK" << LOG_ENDL; +// return false; +// } + + pm.deleter = nullptr; + pm.former = this; + +// AMediaCodecBufferInfo info; +// ssize_t outputBuffIdx = AMediaCodec_dequeueOutputBuffer(in->codec, &info, 0); + //if (outputBuffIdx >= 0) + { + string str_buf; +// LOG_WARN << "hello" << LOG_ENDL; +// LOGP(WARNING,"hello %s",m_str_context.c_str()); +// LOG_WARN << "world" << LOG_ENDL; + std::string data({0,0,0,1}); + m_begin = m_str_context.find(data,m_begin+1); + static int _count = 0; + char sz_path[256]={0}; + if((m_begin!=string::npos)&&(m_begin!=0)&&(m_begin!=-1)) + { + my_module_space::Timer _timer; + long long tmp = _timer.tell_ms()-m_current_time; + if(tmp<40) + { + long long _value = (40-tmp)*1000; + //usleep(_value); + } + m_current_time = _timer.tell_ms(); + str_buf = m_str_context.substr(0, m_begin); + LOGP(WARNING,"still running..."); +// memset(sz_path,0,256); +// sprintf(sz_path,"/data/stream_content/%d",_count); +// write_file(sz_path,str_buf.c_str(),str_buf.length()); +// _count++; + m_str_context = m_str_context.substr(m_begin, m_str_context.length() - m_begin); + in->buffSize = std::min(str_buf.length(), in->buffSizeMax); + memcpy(in->buffer, &str_buf[0], in->buffSize); + + in->tempFrame.type = MB_Frame::MBFT_H264_NALU_AUX; + in->tempFrame.buffer = in->buffer; + in->tempFrame.buffSize = in->buffSize; + // microseconds_to_timeval(info.presentationTimeUs, in->tempFrame.pts); + pm.type = PipeMaterial::PMT_FRAME; + pm.buffer = &(in->tempFrame); + pm.buffSize = 0; + return true; + } + else if((m_begin==string::npos)&&m_b_loop_play) + { + m_str_context = m_str_old_context; + } + } + +// ssize_t outputBuffIdx = AMediaCodec_dequeueOutputBuffer(in->codec, &info, 0); +// if (outputBuffIdx >= 0) +// { +// if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) +// { +// LOGP(WARNING, "output EOS"); +// } +// +// //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->tempFrame.reset(); +// +// size_t outSize = in->buffSizeMax; +// uint8_t* outputBuff = AMediaCodec_getOutputBuffer(in->codec, outputBuffIdx, &outSize); +// if (outputBuff != nullptr) +// { +// in->buffSize = std::min((size_t) info.size, in->buffSizeMax); +// memcpy(in->buffer, outputBuff + info.offset, in->buffSize); +// +// in->tempFrame.type = MB_Frame::MBFT_H264_NALU_AUX; +// in->tempFrame.buffer = in->buffer; +// in->tempFrame.buffSize = in->buffSize; +// in->tempFrame.width = in->config.ak_width; +// in->tempFrame.height = in->config.ak_height; +// microseconds_to_timeval(info.presentationTimeUs, in->tempFrame.pts); +// +// pm.type = PipeMaterial::PMT_FRAME; +// pm.buffer = &(in->tempFrame); +// pm.buffSize = 0; +// +// //static size_t f = 0; +// //static FILE *pFile = fopen("/data/aa.264", "wb"); +// //fwrite(in->buffer, sizeof(char), in->buffSize, pFile); +// //if (++f > 400){ +// // fclose(pFile); +// // exit(0); +// //} +// } +// +// AMediaCodec_releaseOutputBuffer(in->codec, outputBuffIdx, false); +// +// return true; +// } +// else if (outputBuffIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) +// { +// LOGP(DEBUG, "output buffers changed"); +// } +// else if (outputBuffIdx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) +// { +// auto format = AMediaCodec_getOutputFormat(in->codec); +// LOGP(INFO, "format changed to: %s", AMediaFormat_toString(format)); +// +// uint8_t* sps = nullptr; +// size_t spsSize = 0; +// uint8_t* pps = nullptr; +// size_t ppsSize = 0; +// +// AMediaFormat_getBuffer(format, "csd-0", (void**)&sps, &spsSize); // sps +// AMediaFormat_getBuffer(format, "csd-1", (void**)&pps, &ppsSize); // pps +// +// if (spsSize != 0) +// { +// std::string spsStr = base64_encode(((const char*)sps) + 4, spsSize - 4);//#todo aux +// std::string ppsStr = base64_encode(((const char*)pps) + 4, ppsSize - 4); +// +// this->manager->set_param(PLGP_ENC_SPS_B64, spsStr); +// this->manager->set_param(PLGP_ENC_PPS_B64, ppsStr); +// } +// +// AMediaFormat_delete(format); +// } +// else if (outputBuffIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER) +// { +// LOGP(DEBUG, "no output buffer right now"); +// } +// else +// { +// LOGP(WARNING, "unexpected info code: %zd", outputBuffIdx); +// } + + return false; +} +int PL_AndroidMediaCodecFileFrame::write_file(const char* p_path,const char* p_content,int nlength) +{ + std::fstream outfile(p_path, std::ios_base::out | std::ios_base::binary); + outfile.write(p_content, nlength); + outfile.close(); +} +int PL_AndroidMediaCodecFileFrame::read_file(const char* p_path) +{ + std::fstream infile(p_path, std::ios_base::in | std::ios_base::binary | ios::ate); + size_t nSize = infile.tellg(); + infile.seekg(0, ios::beg); + if (nSize <= 0) + { + infile.close(); + return nSize; + } + m_str_context.resize(nSize); + infile.read(&(m_str_context[0]), nSize); + m_str_old_context = m_str_context; + infile.close(); + + return 1; +} + +int PL_AndroidMediaCodecFileFrame::analyse_context() +{ + int _count = 0; + int _begin = -1; + while((_begin=m_str_context.find(H264_HEAD,_begin+1))!=string::npos) + { + _count++; + } + return 1; +} diff --git a/RtspFace/PL_AndroidMediaCodecFileFrame.h b/RtspFace/PL_AndroidMediaCodecFileFrame.h new file mode 100644 index 0000000..c73f78a --- /dev/null +++ b/RtspFace/PL_AndroidMediaCodecFileFrame.h @@ -0,0 +1,47 @@ +#ifndef _PL_ANDROIDMEDIACODECFILEFRAME_H_ +#define _PL_ANDROIDMEDIACODECFILEFRAME_H_ + +#include "PipeLine.h" + +struct PL_AndroidMediaCodecFileFrame_Config +{ + char sz_path[256]; + bool b_loop_play; + + PL_AndroidMediaCodecFileFrame_Config() : + b_loop_play(false) + { + memset(sz_path,0,256); + } +}; + +class PL_AndroidMediaCodecFileFrame : public PipeLineElem +{ +public: + PL_AndroidMediaCodecFileFrame(); + virtual ~PL_AndroidMediaCodecFileFrame(); + + virtual bool init(void* args); + virtual void finit(); + + virtual bool pay(const PipeMaterial& pm); + virtual bool gain(PipeMaterial& pm); + +private: + void* internal; + bool m_b_loop_play; + std::string m_str_context; + std::string m_str_old_context; + std::string m_str_buf; + int m_begin; + long long m_current_time; + +private: + int write_file(const char*,const char*,int); + int read_file(const char*); + int analyse_context(); +}; + +PipeLineElem* create_PL_AndroidMediaCodecFileFrame(); + +#endif diff --git a/RtspFace/my_timer.hpp b/RtspFace/my_timer.hpp new file mode 100644 index 0000000..3241e7d --- /dev/null +++ b/RtspFace/my_timer.hpp @@ -0,0 +1,65 @@ +/*********************************************************** +* Date: 2016-06-30 +* +* Author: 鐗熼煹 +* +* Email: mouyun1115@163.com +* +* Module: 璁℃椂鍣� +* +* Brief: +* +* Note: +* +* CodePage: Pure UTF-8 +************************************************************/ +#ifndef __MY_TIMER_HPP_BY_MOUYUN_2014_09_28__ +#define __MY_TIMER_HPP_BY_MOUYUN_2014_09_28__ + +#include <chrono> + +namespace my_module_space +{ + class Timer + { + public: + Timer() : m_begin(std::chrono::high_resolution_clock::now()) {} + ~Timer() {} + + private: + Timer(const Timer&) = delete; + Timer(Timer&&) = delete; + Timer operator=(const Timer&) = delete; + + public: + void reset() + { + m_begin = std::chrono::high_resolution_clock::now(); + } + + double tell_s() const + { + return std::chrono::duration_cast<std::chrono::duration<double> >(std::chrono::high_resolution_clock::now() - m_begin).count(); + } + + long long tell_ms() const + { + return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_begin).count(); + } + + long long tell_us() const + { + return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_begin).count(); + } + + long long tell_ns() const + { + return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - m_begin).count(); + } + + private: + std::chrono::time_point<std::chrono::high_resolution_clock> m_begin; + }; +} + +#endif -- Gitblit v1.8.0