extern "C" { #include #include #include } #include"VideoEncoder.h" #include"libyuv/convert_from_argb.h" #include #include namespace { struct EncodecName_by_ID { AVCodecID id; char name[32]; }; constexpr EncodecName_by_ID encodec_name_by_id[]= { //{AV_CODEC_ID_H264 ,"h264_nvenc"}, //{AV_CODEC_ID_H264 ,"nvenc"}, //{AV_CODEC_ID_H264 ,"nvenc_h264"}, // //{AV_CODEC_ID_HEVC ,"hevc_nvenc"}, //{AV_CODEC_ID_HEVC ,"nvenc_hevc"}, //{AV_CODEC_ID_H264 ,"h264_amf"}, //{AV_CODEC_ID_HEVC ,"hevc_amf"}, //{AV_CODEC_ID_MJPEG ,"mjpeg_qsv"}, //{AV_CODEC_ID_MPEG2VIDEO ,"mpeg2_qsv"}, //{AV_CODEC_ID_H264 ,"h264_qsv"}, //{AV_CODEC_ID_HEVC ,"hevc_qsv"}, //{AV_CODEC_ID_VP9 ,"vp9_qsv"}, {AV_CODEC_ID_HEVC ,"libx265"}, {AV_CODEC_ID_H264 ,"libx264"}, {AV_CODEC_ID_NONE ,""} }; const AVCodec *GetAVEncodec(AVCodecID id,bool hardware) { //if(hardware) //{ const AVCodec *codec=nullptr; for(auto &c:encodec_name_by_id) { if(c.id==id) { codec=avcodec_find_encoder_by_name(c.name); if(codec) { std::cout<<"use encoder: "<bit_rate =bit_rate; codec_ctx->width =s.width; codec_ctx->height =s.height; codec_ctx->framerate =fr; codec_ctx->time_base.den=fr.num; codec_ctx->time_base.num=fr.den; codec_ctx->gop_size =25; codec_ctx->max_b_frames =3; codec_ctx->pix_fmt =AV_PIX_FMT_NV12; codec_ctx->codec_type =AVMEDIA_TYPE_VIDEO; video_stream=avformat_new_stream(fmt_ctx,codec); video_stream->codecpar->codec_id =fmt_ctx->video_codec_id; video_stream->codecpar->codec_type =AVMEDIA_TYPE_VIDEO; video_stream->codecpar->width =s.width; video_stream->codecpar->height =s.height; video_stream->codecpar->format =codec_ctx->pix_fmt; video_stream->codecpar->bit_rate =bit_rate; video_stream->time_base =codec_ctx->time_base; m_video_stream_index = 0; } bool Init() override { avcodec_parameters_to_context(codec_ctx,video_stream->codecpar); av_opt_set(codec_ctx->priv_data,"preset","veryslow",0); av_opt_set(codec_ctx->priv_data,"crf","10",0); if(fmt_ctx->oformat->flags&AVFMT_GLOBALHEADER) codec_ctx->flags|=AV_CODEC_FLAG_GLOBAL_HEADER; if(avcodec_open2(codec_ctx,codec,nullptr)<0) { std::cerr<<"avcodec open failed!"<codecpar,codec_ctx); if(avio_open2(&fmt_ctx->pb,filename,AVIO_FLAG_WRITE,nullptr,nullptr)<0) { std::cerr<<"avio open failed!"<format =codec_ctx->pix_fmt; frame->width =codec_ctx->width; frame->height =codec_ctx->height; int ret = av_frame_get_buffer(frame, 0); if(ret<0) { std::cerr<<"av frame get buffer failed!"<=0) { ret=avcodec_receive_packet(codec_ctx,packet); if(ret==AVERROR(EAGAIN)||ret==AVERROR_EOF) { return(true); } else if(ret<0) { return(false); } if(ret==0) { count++; if (count % codec_ctx->gop_size == 0) packet->flags |= AV_PKT_FLAG_KEY; if(packet->pts!=AV_NOPTS_VALUE) packet->pts=av_rescale_q(packet->pts,codec_ctx->time_base,video_stream->time_base); if(packet->dts!=AV_NOPTS_VALUE) packet->dts=av_rescale_q(packet->dts,codec_ctx->time_base,video_stream->time_base); packet->stream_index = m_video_stream_index; packet->duration = av_rescale_q(1, codec_ctx->time_base, video_stream->time_base); packet->pos = -1; std::cout<<'.'; if(av_interleaved_write_frame(fmt_ctx,packet)<0) return(false); av_packet_unref(packet); } } return(true); } bool WriteFrame(const uint8 *rgba_data) override { int ret=av_frame_make_writable(frame); if(ret<0) return(false); libyuv::ABGRToNV12( rgba_data,codec_ctx->width*4, frame->data[0],frame->linesize[0], frame->data[1],frame->linesize[1], codec_ctx->width,codec_ctx->height); frame->pts=pts; ++pts; return encode(frame); } bool Finish() override { if(!encode(NULL)) return(false); av_write_trailer(fmt_ctx); avio_close(fmt_ctx->pb); return(true); } };//class FFMPEGVideoEncoder:public VideoEncoder VideoEncoder *CreateVideoEncoder(const char *filename,const uint bit_rate,const bool use_hardware) { constexpr AVCodecID codec_list[] { AV_CODEC_ID_H264, AV_CODEC_ID_HEVC, AV_CODEC_ID_VP9, AV_CODEC_ID_AV1 }; const AVCodec *codec=nullptr; for(AVCodecID id:codec_list) { codec=GetAVEncodec(id,use_hardware); if(codec)break; } if(!codec) { std::cerr<<"We didn't find a encoder[H264,HEVC,VP9,AV1]"<