#include "PL_H264Decoder.h" #include "MaterialBuffer.h" #include "MediaHelper.h" #include "logger.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 MB_Frame lastFrame; PL_H264Decoder_Config config; H264Decoder_Internal() : //buffSize(0), buffSizeMax(sizeof(buffer)), fmtp_set_to_context(false), payError(true), pAVCodecContext(nullptr), pAVFrame(nullptr), lastFrame(), config() { } ~H264Decoder_Internal() { } void reset() { //buffSize = 0; fmtp_set_to_context = false; payError = true; pAVCodecContext = nullptr; pAVFrame = nullptr; MB_Frame _lastFrame; lastFrame = _lastFrame; PL_H264Decoder_Config _config; config = _config; } }; 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(); if (args) { PL_H264Decoder_Config* config = (PL_H264Decoder_Config*)args; in->config = *config; } return true; } void PL_H264Decoder::finit() { H264Decoder_Internal* in = (H264Decoder_Internal*)internal; } 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) { LOG_WARN << "codec not found!" << std::endl; return false; } in->pAVCodecContext = avcodec_alloc_context3(avCodec); in->pAVCodecContext->codec_type = AVMEDIA_TYPE_VIDEO; // this is only reference for codec //in->pAVCodecContext->frame_number = 1; //in->pAVCodecContext->bit_rate = 0; //in->pAVCodecContext->time_base.num = 1; //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, timeval pts) { AVPacket packet = {0}; int gotPicture = buffSize; // frameFinished if (av_packet_from_data(&packet, buffer, buffSize) != 0) { LOG_WARN << "av_packet_from_data error" << std::endl; return false; } packet.pts = packet.dts = (pts.tv_sec * 1000 * 1000 + pts.tv_usec) / 90000; // decode avcodec_decode_video2(in->pAVCodecContext, in->pAVFrame, &gotPicture, &packet); if(gotPicture) { // decode ok return true; } else { //#todo sps sps changing LOG_WARN << "incomplete frame" << std::endl; 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_param(PLGP_RTSP_FMTP)); if (fmtp.empty()) return false; int 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]; bool ret = initH264DecoderEnv(in, sps.sPropBytes, sps.sPropLength, pps.sPropBytes, pps.sPropLength); if (!ret) { LOG_ERROR << "initH264DecoderEnv error" << std::endl; return false; } else in->fmtp_set_to_context = true; } if (pm.buffer == nullptr) return false; bool ret = false; if (pm.type == PipeMaterial::PMT_BYTES) { if (pm.buffSize <= 0) return false; timeval pts = {0}; ret = decodeH264(in, (uint8_t*)pm.buffer, pm.buffSize, pts); } else if (pm.type == PipeMaterial::PMT_FRAME) { MB_Frame* frame = (MB_Frame*)pm.buffer; if (frame->buffSize <= 0) return false; ret = decodeH264(in, (uint8_t*)frame->buffer, frame->buffSize, frame->pts); if (ret) { in->lastFrame.type = MB_Frame::MBFT_PTR_AVFRAME; in->lastFrame.buffer = (uint8_t*)(in->pAVFrame); in->lastFrame.buffSize = sizeof(in->pAVFrame); in->lastFrame.width = in->pAVFrame->width; in->lastFrame.height = in->pAVFrame->height; if (in->config.resetPTS) gettimeofday(&(in->lastFrame.pts),NULL); else in->lastFrame.pts = frame->pts; } } in->payError = !ret; return ret; } bool PL_H264Decoder::gain(PipeMaterial& pm) { H264Decoder_Internal* in = (H264Decoder_Internal*)internal; if (!in->payError) { pm.type = PipeMaterial::PMT_FRAME; pm.buffer = &(in->lastFrame); pm.buffSize = 0; } pm.former = this; return !in->payError; }