From 9e5babf9db52e64bdae60137be7696e56241fca6 Mon Sep 17 00:00:00 2001 From: xingzilong <xingzilong@454eff88-639b-444f-9e54-f578c98de674> Date: 星期五, 18 八月 2017 18:12:17 +0800 Subject: [PATCH] H264 NALU解析 并在RTSPServer判断 --- RtspFace/PL_H264Encoder.cpp | 197 ++++++++++++++++++++++++++++++------------------ 1 files changed, 123 insertions(+), 74 deletions(-) diff --git a/RtspFace/PL_H264Encoder.cpp b/RtspFace/PL_H264Encoder.cpp index 7068b79..68c502c 100644 --- a/RtspFace/PL_H264Encoder.cpp +++ b/RtspFace/PL_H264Encoder.cpp @@ -1,5 +1,6 @@ #include "PL_H264Encoder.h" #include "MaterialBuffer.h" +#include "logger.h" extern "C" { @@ -8,35 +9,46 @@ #include <libavutil/imgutils.h> #include <libavutil/opt.h> #include <libavformat/avformat.h> - - #include <libyuv.h> +} + +#include <libyuv.h> + +PL_H264Encoder_Config::PL_H264Encoder_Config() : + inBufferSize(2*1024*1024), // 2MByte + resetPTS(false), + bytesBufferImageWidth(0), bytesBufferImageHeight(0), + avc_bit_rate(1*1024*1024*8), //1Mbit + avc_fps(25), avc_gop(25), avc_max_b_frames(0), avc_profile(FF_PROFILE_H264_BASELINE), + av_opt_preset("superfast"), av_opt_tune(""), avc_profile_str("") +{ + // av_opt_tune: zerolatency } struct H264Encoder_Internal { - uint8_t buffer[1920*1080*3]; + uint8_t* buffer; size_t buffSize; - size_t buffSizeMax; bool payError; bool ffmpegInited; size_t frameCount; MB_Frame lastFrame; - + PL_H264Encoder_Config config; + AVCodecContext* pAVCodecContext; AVFrame* pAVFrame;//#todo delete - AVStream* pAVStream; AVFormatContext* pAVFormatContext; H264Encoder_Internal() : - buffSize(0), buffSizeMax(sizeof(buffer)), - payError(true), ffmpegInited(false), frameCount(0), - pAVCodecContext(nullptr), pAVFrame(nullptr), pAVStream(nullptr), pAVFormatContext(nullptr), - lastFrame() + buffer(nullptr), buffSize(0), + payError(true), ffmpegInited(false), frameCount(0), lastFrame(), config(), + pAVCodecContext(nullptr), pAVFrame(nullptr), pAVFormatContext(nullptr) { } ~H264Encoder_Internal() { + delete[] buffer; + buffer = nullptr; } void reset() @@ -49,10 +61,18 @@ MB_Frame _lastFrame; lastFrame = _lastFrame; + PL_H264Encoder_Config _config; + config = _config; + pAVCodecContext = nullptr; pAVFrame = nullptr; - pAVStream = nullptr; pAVFormatContext = nullptr; + + if (buffer != nullptr) + { + delete[] buffer; + buffer = nullptr; + } } }; @@ -76,6 +96,14 @@ H264Encoder_Internal* in = (H264Encoder_Internal*)internal; in->reset(); + if (args != nullptr) + { + PL_H264Encoder_Config* config = (PL_H264Encoder_Config*)args; + in->config = *config; + } + + in->buffer = new uint8_t[in->config.inBufferSize]; + return true; } @@ -94,24 +122,29 @@ if (!avCodec) { - printf("codec not found!\n"); + LOG_ERROR << "codec not found!" << std::endl; return false; } in->pAVCodecContext = avcodec_alloc_context3(avCodec); - in->pAVCodecContext->bit_rate = 1*1024*1024*8; // 3MB - in->pAVCodecContext->width = 800;//#todo test - in->pAVCodecContext->height = 600;//#todo from config - in->pAVCodecContext->time_base.num=1; - in->pAVCodecContext->time_base.den=25; - in->pAVCodecContext->gop_size = 25; - in->pAVCodecContext->max_b_frames = 0; - //in->pAVCodecContext->profile = FF_PROFILE_H264_MAIN; + in->pAVCodecContext->bit_rate = in->config.avc_bit_rate; + in->pAVCodecContext->width = in->config.bytesBufferImageWidth; + in->pAVCodecContext->height = in->config.bytesBufferImageHeight; + in->pAVCodecContext->time_base.num = 1; + in->pAVCodecContext->time_base.den = in->config.avc_fps; + in->pAVCodecContext->gop_size = in->config.avc_gop; + in->pAVCodecContext->max_b_frames = in->config.avc_max_b_frames; in->pAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P; - av_opt_set(in->pAVCodecContext->priv_data, "preset", "superfast", 0); - //av_opt_set(in->pAVCodecContext->priv_data, "tune", "zerolatency", 0); + if (!in->config.av_opt_preset.empty()) + av_opt_set(in->pAVCodecContext->priv_data, "preset", in->config.av_opt_preset.c_str(), 0); + if (!in->config.av_opt_tune.empty()) + av_opt_set(in->pAVCodecContext->priv_data, "tune", in->config.av_opt_tune.c_str(), 0); + if (!in->config.avc_profile_str.empty()) + av_opt_set(in->pAVCodecContext->priv_data, "profile", in->config.avc_profile_str.c_str(), 0); + else + in->pAVCodecContext->profile = in->config.avc_profile; if(avcodec_open2(in->pAVCodecContext, avCodec, NULL) >= 0) { @@ -121,59 +154,45 @@ in->pAVFrame->width = in->pAVCodecContext->width; in->pAVFrame->height = in->pAVCodecContext->height; - int ret = av_image_alloc(in->pAVFrame->data, in->pAVFrame->linesize, in->pAVCodecContext->width, in->pAVCodecContext->height, + int ret = av_image_alloc(in->pAVFrame->data, in->pAVFrame->linesize, + in->pAVCodecContext->width, in->pAVCodecContext->height, in->pAVCodecContext->pix_fmt, 16); if (ret < 0) { - printf("av_image_alloc error\n"); + LOG_ERROR << "av_image_alloc error" << std::endl; return false; } } else { - printf("avcodec_open2 error\n"); + LOG_ERROR << "avcodec_open2 error" << std::endl; return false; } - - //int ret = avformat_alloc_output_context2(&(in->pAVFormatContext), NULL, "avi", ""); - //if (ret < 0 || in->pAVFormatContext == nullptr) - //{ - // printf("avformat_alloc_output_context2 error\n"); - // return false; - //} - // - //in->pAVStream = avformat_new_stream(in->pAVFormatContext, avCodec); - //if (in->pAVStream == nullptr) - //{ - // printf("avformat_new_stream error\n"); - // return false; - //} - //in->pAVStream->id = in->pAVFormatContext->nb_streams-1; - + return true; } -#define SUBSAMPLE(v, a) ((((v) + (a) - 1)) / (a)) - void copyAVFrame(AVFrame* dest, AVFrame* src) { -int src_width = src->width; -int src_height = src->height; -int dst_width = dest->width; -int dst_height = dest->height; -printf("I420Scale sw=%d, sh=%d, dw=%d, dh=%d\n", src_width,src_height,dst_width, dst_height); - -libyuv::I420Scale(src->data[0], src_width, - src->data[1], SUBSAMPLE(src_width, 2), - src->data[2], SUBSAMPLE(src_width, 2), - src_width, src_height, - dest->data[0], dst_width, - dest->data[1], SUBSAMPLE(dst_width, 2), - dest->data[2], SUBSAMPLE(dst_width, 2), - dst_width, dst_height, - libyuv::kFilterNone ); +//#test +//#define SUBSAMPLE(v, a) ((((v) + (a) - 1)) / (a)) + //int src_width = src->width; + //int src_height = src->height; + //int dst_width = dest->width; + //int dst_height = dest->height; + //printf("I420Scale sw=%d, sh=%d, dw=%d, dh=%d\n", src_width,src_height,dst_width, dst_height); + // + //libyuv::I420Scale(src->data[0], src_width, + // src->data[1], SUBSAMPLE(src_width, 2), + // src->data[2], SUBSAMPLE(src_width, 2), + // src_width, src_height, + // dest->data[0], dst_width, + // dest->data[1], SUBSAMPLE(dst_width, 2), + // dest->data[2], SUBSAMPLE(dst_width, 2), + // dst_width, dst_height, + // libyuv::kFilterNone ); - //#test + //static size_t f=0; //char fname[50]; //sprintf(fname, "%u.yuv420", ++f); @@ -183,13 +202,12 @@ //fwrite (dest->data[2] , sizeof(char), dst_width * dst_height / 4, pFile); //fclose(pFile); - //dest->data[0] = src->data[0]; - //dest->data[1] = src->data[1]; - //dest->data[2] = src->data[2]; + dest->data[0] = src->data[0]; + dest->data[1] = src->data[1]; + dest->data[2] = src->data[2]; //int height = dest->height; //int width = dest->width; - // //memcpy(dest->data[0], src->data[0], height * width); // Y //memcpy(dest->data[1], src->data[1], height * width / 4); // U //memcpy(dest->data[2], src->data[2], height * width / 4); // V @@ -218,15 +236,15 @@ int ret = avcodec_encode_video2(in->pAVCodecContext, &pAVPacket, in->pAVFrame, &gotPacket); if (ret < 0) { - printf("avcodec_encode_video2 (1) error=%d\n", ret); + LOG_WARN << "avcodec_encode_video2 (1) error=" << ret << std::endl; return false; } if (gotPacket > 0) { in->frameCount++; - printf("Succeed to encode (1) frame=%d, size=%d\n", in->frameCount, pAVPacket.size); - memcpy(in->buffer, pAVPacket.data, pAVPacket.size); + LOGP(DEBUG, "Succeed to encode (1) frame=%d, size=%d", in->frameCount, pAVPacket.size); + memcpy(in->buffer, pAVPacket.data, pAVPacket.size);//#todo check inBufferSize in->buffSize = pAVPacket.size; av_free_packet(&pAVPacket); } @@ -265,12 +283,15 @@ bool encodeH264(H264Encoder_Internal* in, uint8_t* buffer, timeval pts) { + uint16_t width = in->config.bytesBufferImageWidth; + uint16_t height = in->config.bytesBufferImageHeight; + AVFrame avFrame; - avFrame.width = 1920;//#todo - avFrame.height = 1080; + avFrame.width = width; + avFrame.height = height; avFrame.data[0] = buffer; - avFrame.data[1] = buffer + 1920*1080; - avFrame.data[2] = buffer + 1920*1080 + 1920*1080/4; + avFrame.data[1] = buffer + width*height; + avFrame.data[2] = buffer + width*height + width*height/4; return encodeH264(in, &avFrame, pts); } @@ -282,10 +303,34 @@ if (!in->ffmpegInited) { + MB_Frame* frame = (MB_Frame*)pm.buffer; + if (frame != nullptr && frame->buffer != nullptr && + (in->config.bytesBufferImageWidth == 0 || in->config.bytesBufferImageHeight == 0)) + { + if (frame->type == MB_Frame::MBFT_PTR_AVFRAME) + { + AVFrame* pAVFrame = (AVFrame*)frame->buffer; + if (pAVFrame != nullptr) + { + in->config.bytesBufferImageWidth = pAVFrame->width; + in->config.bytesBufferImageHeight = pAVFrame->height; + LOGP(NOTICE, "Set codec size from AVFrame width=%d, height=%d", + in->config.bytesBufferImageWidth, in->config.bytesBufferImageHeight); + } + } + else if (frame->type == MB_Frame::MBFT_YUV420) + { + in->config.bytesBufferImageWidth = frame->width; + in->config.bytesBufferImageHeight = frame->height; + LOGP(NOTICE, "Set codec size from frame width=%d, height=%d", + in->config.bytesBufferImageWidth, in->config.bytesBufferImageHeight); + } + } + bool ret = initH264EncoderEnv(in); if (!ret) { - printf("initH264EncoderEnv error\n"); + LOG_ERROR << "initH264EncoderEnv error" << std::endl; return false; } else @@ -294,7 +339,7 @@ if (pm.type != PipeMaterial::PMT_FRAME) { - printf("PL_H264Encoder::pay only support PMT_FRAME\n"); + LOG_ERROR << "Only support PMT_FRAME" << std::endl; return false; } @@ -311,7 +356,7 @@ ret = encodeH264(in, (uint8_t*)(frame->buffer), frame->pts); else { - printf("PL_H264Encoder::pay only support MBFT_PTR_AVFRAME / MBFT_YUV420\n"); + LOG_ERROR << "Only support MBFT_PTR_AVFRAME / MBFT_YUV420" << std::endl; in->payError = true; return false; } @@ -325,7 +370,11 @@ in->lastFrame.buffSize = in->buffSize; in->lastFrame.width = frame->width; in->lastFrame.height = frame->height; - in->lastFrame.pts = frame->pts; + + if (in->config.resetPTS) + gettimeofday(&(in->lastFrame.pts),NULL); + else + in->lastFrame.pts = frame->pts; } return ret; -- Gitblit v1.8.0