#include "PL_H264Decoder.h" #include // for SPropRecord #include extern "C" { #include #include #include } struct H264Decoder_Internal { //uint8_t buffer[1920*1080*3]; //size_t buffSize; //size_t buffSizeMax; bool fmtp_set_to_context; bool payError; AVCodecContext* pAVCodecContext; AVFrame* pAVFrame;//#todo delete H264Decoder_Internal() : //buffSize(0), buffSizeMax(sizeof(buffer)), fmtp_set_to_context(false), payError(true), pAVCodecContext(nullptr), pAVFrame(nullptr) { } ~H264Decoder_Internal() { } void reset() { //buffSize = 0; fmtp_set_to_context = false; payError = true; } }; PipeLineElem* create_PL_H264Decoder() { return new PL_H264Decoder; } PL_H264Decoder::PL_H264Decoder() : internal(new H264Decoder_Internal) { } PL_H264Decoder::~PL_H264Decoder() { delete (H264Decoder_Internal*)internal; internal= nullptr; } bool PL_H264Decoder::init(void* args) { H264Decoder_Internal* in = (H264Decoder_Internal*)internal; in->reset(); return true; } void PL_H264Decoder::finit() { H264Decoder_Internal* in = (H264Decoder_Internal*)internal; } SPropRecord* parseSPropParameterSets(char const* sPropParameterSetsStr, size_t& numSPropRecords) { // Make a copy of the input string, so we can replace the commas with '\0's: char* inStr = strDup(sPropParameterSetsStr); if (inStr == NULL) { numSPropRecords = 0; return NULL; } // Count the number of commas (and thus the number of parameter sets): numSPropRecords = 1; char* s; for (s = inStr; *s != '\0'; ++s) { if (*s == ',') { ++numSPropRecords; *s = '\0'; } } // Allocate and fill in the result array: SPropRecord* resultArray = new SPropRecord[numSPropRecords]; s = inStr; for (unsigned i = 0; i < numSPropRecords; ++i) { resultArray[i].sPropBytes = new uint8_t[256]; size_t sPropLength = 0; base64_decode(s, strlen(s), (char*)resultArray[i].sPropBytes, &sPropLength, 0); resultArray[i].sPropLength = sPropLength; s += strlen(s) + 1; } delete[] inStr; return resultArray; } bool initH264DecoderEnv(H264Decoder_Internal* in, uint8_t* sps, size_t spsSize, uint8_t* pps, size_t ppsSize) { av_register_all(); // find the video encoder AVCodec* avCodec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!avCodec) { printf("codec not found!\n"); return false; } in->pAVCodecContext = avcodec_alloc_context3(avCodec); in->pAVCodecContext->time_base.num = 1; in->pAVCodecContext->frame_number = 1; in->pAVCodecContext->codec_type = AVMEDIA_TYPE_VIDEO; in->pAVCodecContext->bit_rate = 0; in->pAVCodecContext->time_base.den = 25; in->pAVCodecContext->width = 1920; in->pAVCodecContext->height = 1080; if (in->pAVCodecContext->extradata == NULL) { int totalsize = 0; unsigned char* tmp = NULL; unsigned char nalu_header[4] = { 0, 0, 0, 1 }; totalsize = 8 + spsSize + ppsSize; tmp = new unsigned char[totalsize]; memcpy(tmp, nalu_header, 4); memcpy(tmp + 4, sps, spsSize); memcpy(tmp + 4 + spsSize, nalu_header, 4); memcpy(tmp + 4 + spsSize + 4, pps, ppsSize); in->pAVCodecContext->extradata_size = totalsize; in->pAVCodecContext->extradata = tmp; } if(avcodec_open2(in->pAVCodecContext, avCodec, NULL) >= 0) in->pAVFrame = av_frame_alloc();// Allocate video frame else return false; return true; } bool decodeH264(H264Decoder_Internal* in, uint8_t* buffer, size_t buffSize) { AVPacket packet = {0}; int frameFinished = buffSize; if (av_packet_from_data(&packet, buffer, buffSize) != 0) { printf("av_packet_from_data error\n"); return false; } // decode avcodec_decode_video2(in->pAVCodecContext, in->pAVFrame, &frameFinished, &packet); if(frameFinished) { // decode ok return true; } else { printf("incomplete frame\n"); return false; } } bool PL_H264Decoder::pay(const PipeMaterial& pm) { H264Decoder_Internal* in = (H264Decoder_Internal*)internal; in->payError = true; if (!in->fmtp_set_to_context) { if (manager == NULL) return false; std::string fmtp(manager->get_global_param(PLGP_RTSP_FMTP)); if (fmtp.empty()) return false; size_t numSPropRecords = 0; SPropRecord *p_record = parseSPropParameterSets(fmtp.c_str(), numSPropRecords); if (numSPropRecords < 2) return false;//#todo log SPropRecord &sps = p_record[0]; SPropRecord &pps = p_record[1]; bool ret = initH264DecoderEnv(in, sps.sPropBytes, sps.sPropLength, pps.sPropBytes, pps.sPropLength); if (!ret) return false; // #todo log else in->fmtp_set_to_context = true; } bool ret = decodeH264(in, pm.buffer, pm.buffSize); in->payError = !ret; return ret; } bool PL_H264Decoder::gain(PipeMaterial& pm) { H264Decoder_Internal* in = (H264Decoder_Internal*)internal; if (!in->payError) { pm.buffer = (uint8_t*)in->pAVFrame;//in->buffer; pm.buffSize = sizeof(uint8_t*);//in->buffSize; } pm.former = this; return !in->payError; }