From 1abced42eb3997ef9ef675bfe990f7913ea73f2f Mon Sep 17 00:00:00 2001 From: houxiao <houxiao@454eff88-639b-444f-9e54-f578c98de674> Date: 星期五, 23 十二月 2016 18:34:10 +0800 Subject: [PATCH] add h264 encoder and rtsp server --- RtspFace/PL_H264Encoder.cpp | 196 ++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 169 insertions(+), 27 deletions(-) diff --git a/RtspFace/PL_H264Encoder.cpp b/RtspFace/PL_H264Encoder.cpp index ebdfb7f..9fc0a0b 100644 --- a/RtspFace/PL_H264Encoder.cpp +++ b/RtspFace/PL_H264Encoder.cpp @@ -2,24 +2,33 @@ extern "C" { - #include <libyuv.h> + #include <libavcodec/avcodec.h> + #include <libavutil/frame.h> + #include <libavformat/avformat.h> + #include "libavutil/imgutils.h" } -struct PL_H264Encoder_Internal +struct H264Encoder_Internal { - uint8_t buffer[1920*1080*4]; + uint8_t buffer[1920*1080*3]; size_t buffSize; size_t buffSizeMax; - bool payError; + bool ffmpegInited; + size_t frameCount; + + AVCodecContext* pAVCodecContext; + AVFrame* pAVFrame;//#todo delete - PL_H264Encoder_Internal() : + H264Encoder_Internal() : buffSize(0), buffSizeMax(sizeof(buffer)), - payError(true) + payError(true), ffmpegInited(false), frameCount(0), + pAVCodecContext(nullptr), pAVFrame(nullptr) + { } - ~PL_H264Encoder_Internal() + ~H264Encoder_Internal() { } @@ -27,6 +36,11 @@ { buffSize = 0; payError = true; + ffmpegInited = false; + frameCount = 0; + + pAVCodecContext = nullptr; + pAVFrame = nullptr; } }; @@ -35,52 +49,180 @@ return new PL_H264Encoder; } -PL_H264Encoder::PL_H264Encoder() : internal(new PL_H264Encoder_Internal) +PL_H264Encoder::PL_H264Encoder() : internal(new H264Encoder_Internal) { } PL_H264Encoder::~PL_H264Encoder() { - delete (PL_H264Encoder_Internal*)internal; + delete (H264Encoder_Internal*)internal; internal= nullptr; } bool PL_H264Encoder::init(void* args) { - PL_H264Encoder_Internal* in = (PL_H264Encoder_Internal*)internal; + H264Encoder_Internal* in = (H264Encoder_Internal*)internal; in->reset(); - + return true; } void PL_H264Encoder::finit() { - PL_H264Encoder_Internal* in = (PL_H264Encoder_Internal*)internal; + H264Encoder_Internal* in = (H264Encoder_Internal*)internal; +} + +bool initH264EncoderEnv(H264Encoder_Internal* in) +{ + av_register_all(); + + // find the video encoder + AVCodec* avCodec = avcodec_find_encoder(AV_CODEC_ID_H264); + + if (!avCodec) + { + printf("codec not found!\n"); + return false; + } + + in->pAVCodecContext = avcodec_alloc_context3(avCodec); + + in->pAVCodecContext->bit_rate = 3*1024*1024*8; // 3MB + in->pAVCodecContext->width = 1920; + in->pAVCodecContext->height = 1080;//#todo from config + in->pAVCodecContext->time_base.num=1; + in->pAVCodecContext->time_base.den=25; + in->pAVCodecContext->gop_size = 20; + in->pAVCodecContext->max_b_frames = 0; + in->pAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P; + + if(avcodec_open2(in->pAVCodecContext, avCodec, NULL) >= 0) + { + in->pAVFrame = av_frame_alloc(); // Allocate video frame + + in->pAVFrame->format = in->pAVCodecContext->pix_fmt; + 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, + in->pAVCodecContext->pix_fmt, 16); + if (ret < 0) + { + printf("av_image_alloc error\n"); + return false; + } + } + else + { + printf("avcodec_open2 error\n"); + return false; + } + + return true; +} + +void copyAVFrame(AVFrame* dest, AVFrame* src) +{ + 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 +} + +bool encodeH264(H264Encoder_Internal* in, AVFrame* pAVFrame, size_t buffSize) +{ + in->buffSize = 0; + in->frameCount++; + + copyAVFrame(in->pAVFrame, pAVFrame); + in->pAVFrame->pts = in->frameCount; + + AVPacket pAVPacket = {0}; + av_init_packet(&pAVPacket); + + // encode the image + int gotPacket = 0; + int ret = avcodec_encode_video2(in->pAVCodecContext, &pAVPacket, in->pAVFrame, &gotPacket); + if (ret < 0) + { + printf("avcodec_encode_video2 (1) error=%d\n", ret); + return false; + } + + if (gotPacket > 0) + { + printf("Succeed to encode (1) frame=%d, size=%d\n", in->pAVFrame->pts, pAVPacket.size); + memcpy(in->buffer + in->buffSize, pAVPacket.data, pAVPacket.size); + in->buffSize += pAVPacket.size; + av_free_packet(&pAVPacket); + } + + //#todo finit + //Flush Encoder + //while (gotPacket > 0) + //{ + // ret = avcodec_encode_video2(in->pAVCodecContext, &pAVPacket, NULL, &gotPacket); + // if (ret < 0) + // { + // printf("avcodec_encode_video2 (2) error=%d\n", ret); + // return false; + // } + // if (gotPacket > 0) + // { + // printf("Succeed to encode (2) frame=%d, size=%d\n", in->pAVFrame->pts, pAVPacket.size); + // memcpy(in->buffer + in->buffSize, pAVPacket.data, pAVPacket.size); + // in->buffSize += pAVPacket.size; + // av_free_packet(&pAVPacket); + // } + //} + + //#test + if (in->buffSize > 0) + { + static FILE * pFile = fopen("out.h264","wba+"); + fwrite (in->buffer , sizeof(char), in->buffSize, pFile); + fflush(pFile); + } + + in->payError = (in->buffSize == 0); + return !(in->payError); } bool PL_H264Encoder::pay(const PipeMaterial& pm) { - PL_H264Encoder_Internal* in = (PL_H264Encoder_Internal*)internal; + H264Encoder_Internal* in = (H264Encoder_Internal*)internal; - //in->buffer readly - - //static size_t f=0; - //char fname[50]; - //sprintf(fname, "%u.bgra", ++f); - //FILE * pFile = fopen (fname,"wb"); - //fwrite (in->buffer , sizeof(char), in->buffSize, pFile); - //fclose(pFile); - - return true; + in->payError = true; + + if (!in->ffmpegInited) + { + bool ret = initH264EncoderEnv(in); + if (!ret) + { + printf("initH264EncoderEnv error"); + return false; + } + else + in->ffmpegInited = true; + } + + bool ret = encodeH264(in, (AVFrame*)pm.buffer, pm.buffSize); + in->payError = !ret; + return ret; } bool PL_H264Encoder::gain(PipeMaterial& pm) { - PL_H264Encoder_Internal* in = (PL_H264Encoder_Internal*)internal; + H264Encoder_Internal* in = (H264Encoder_Internal*)internal; - pm.buffer = in->buffer; - pm.buffSize = in->buffSize; + if (!in->payError) + { + pm.buffer = in->buffer; + pm.buffSize = in->buffSize; + } pm.former = this; - return true; + return !in->payError; } -- Gitblit v1.8.0