New file |
| | |
| | | #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;
|
| | | }
|