1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
| int32_t FFmpegH264EncoderImpl::InitEncode(const webrtc::VideoCodec *inst, int32_t number_of_cores, size_t max_payload_size) { ReportInit(); if (!inst || inst->codecType != webrtc::kVideoCodecH264) { ReportError(); return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; } if (inst->maxFramerate == 0) { ReportError(); return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; } if (inst->width < 1 || inst->height < 1) { ReportError(); return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; }
int32_t release_ret = Release(); if (release_ret != WEBRTC_VIDEO_CODEC_OK) { ReportError(); return release_ret; }
int number_of_streams = webrtc::SimulcastUtility::NumberOfSimulcastStreams(*inst); bool doing_simulcast = (number_of_streams > 1);
if (doing_simulcast && (!webrtc::SimulcastUtility::ValidSimulcastResolutions( *inst, number_of_streams) || !webrtc::SimulcastUtility::ValidSimulcastTemporalLayers( *inst, number_of_streams))) { return WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED; } encoded_images_.resize(static_cast<unsigned long>(number_of_streams)); encoded_image_buffers_.resize(static_cast<unsigned long>(number_of_streams)); encoders_.resize(static_cast<unsigned long>(number_of_streams)); configurations_.resize(static_cast<unsigned long>(number_of_streams)); for (int i = 0; i < number_of_streams; i++) { encoders_[i] = new CodecCtx(); } number_of_cores_ = number_of_cores; max_payload_size_ = max_payload_size; codec_ = *inst;
if (codec_.numberOfSimulcastStreams == 0) { codec_.simulcastStream[0].width = codec_.width; codec_.simulcastStream[0].height = codec_.height; }
for (int i = 0, idx = number_of_streams - 1; i < number_of_streams; ++i, --idx) { if (inst->simulcastStream[i].numberOfTemporalLayers > 1) { Release(); return WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED; }
configurations_[i].simulcast_idx = idx; configurations_[i].sending = false; configurations_[i].width = codec_.simulcastStream[idx].width; configurations_[i].height = codec_.simulcastStream[idx].height; configurations_[i].max_frame_rate = static_cast<float>(codec_.maxFramerate); configurations_[i].frame_dropping_on = codec_.H264()->frameDroppingOn; configurations_[i].key_frame_interval = codec_.H264()->keyFrameInterval;
configurations_[i].max_bps = codec_.maxBitrate * 1000; configurations_[i].target_bps = codec_.startBitrate * 1000; if (!OpenEncoder(encoders_[i], configurations_[i])) { Release(); ReportError(); return WEBRTC_VIDEO_CODEC_ERROR; } encoded_images_[i]._size = CalcBufferSize(webrtc::VideoType::kI420, codec_.simulcastStream[idx].width, codec_.simulcastStream[idx].height); encoded_images_[i]._buffer = new uint8_t[encoded_images_[i]._size]; encoded_image_buffers_[i].reset(encoded_images_[i]._buffer); encoded_images_[i]._completeFrame = true; encoded_images_[i]._encodedWidth = codec_.simulcastStream[idx].width; encoded_images_[i]._encodedHeight = codec_.simulcastStream[idx].height; encoded_images_[i]._length = 0; }
webrtc::SimulcastRateAllocator init_allocator(codec_); webrtc::BitrateAllocation allocation = init_allocator.GetAllocation( codec_.startBitrate * 1000, codec_.maxFramerate); return SetRateAllocation(allocation, codec_.maxFramerate); }
bool FFmpegH264EncoderImpl::OpenEncoder(FFmpegH264EncoderImpl::CodecCtx *ctx, H264Encoder::LayerConfig &config) { int ret; #ifdef WEBRTC_LINUX if (hardware_accelerate) { ctx->codec = avcodec_find_encoder_by_name("h264_nvenc"); } #endif if (!ctx->codec) { ctx->codec = avcodec_find_encoder_by_name("libx264"); } if (!ctx->codec) { WEBRTC_LOG("Codec not found", ERROR); return false; } WEBRTC_LOG("Open encoder: " + std::string(ctx->codec->name) + ", and generate frame, packet", INFO);
ctx->context = avcodec_alloc_context3(ctx->codec); if (!ctx->context) { WEBRTC_LOG("Could not allocate video codec context", ERROR); return false; } config.target_bps = config.max_bps; SetContext(ctx, config, true); ret = avcodec_open2(ctx->context, ctx->codec, nullptr); if (ret < 0) { WEBRTC_LOG("Could not open codec, error code:" + std::to_string(ret), ERROR); avcodec_free_context(&(ctx->context)); return false; }
ctx->frame = av_frame_alloc(); if (!ctx->frame) { WEBRTC_LOG("Could not allocate video frame", ERROR); return false; } ctx->frame->format = ctx->context->pix_fmt; ctx->frame->width = ctx->context->width; ctx->frame->height = ctx->context->height; ctx->frame->color_range = ctx->context->color_range;
ret = av_image_alloc(ctx->frame->data, ctx->frame->linesize, ctx->context->width, ctx->context->height, ctx->context->pix_fmt, 32); if (ret < 0) { WEBRTC_LOG("Could not allocate raw picture buffer", ERROR); return false; } ctx->frame->pts = 1; ctx->pkt = av_packet_alloc(); return true; }
void FFmpegH264EncoderImpl::SetContext(CodecCtx *ctx, H264Encoder::LayerConfig &config, bool init) { if (init) { AVRational rational = {1, 25}; ctx->context->time_base = rational; ctx->context->max_b_frames = 0; ctx->context->pix_fmt = AV_PIX_FMT_YUV420P; ctx->context->codec_type = AVMEDIA_TYPE_VIDEO; ctx->context->codec_id = AV_CODEC_ID_H264; ctx->context->gop_size = config.key_frame_interval; ctx->context->color_range = AVCOL_RANGE_JPEG; if (std::string(ctx->codec->name) == "libx264") { av_opt_set(ctx->context->priv_data, "preset", "ultrafast", 0); av_opt_set(ctx->context->priv_data, "tune", "zerolatency", 0); } av_log_set_level(AV_LOG_ERROR); WEBRTC_LOG("Init bitrate: " + std::to_string(config.target_bps), INFO); } else { WEBRTC_LOG("Change bitrate: " + std::to_string(config.target_bps), INFO); } config.key_frame_request = true; ctx->context->width = config.width; ctx->context->height = config.height;
ctx->context->bit_rate = config.target_bps * 0.7; ctx->context->rc_max_rate = config.target_bps * 0.85; ctx->context->rc_min_rate = config.target_bps * 0.1; ctx->context->rc_buffer_size = config.target_bps * 2; #ifdef WEBRTC_LINUX if (std::string(ctx->codec->name) == "h264_nvenc") { NvencContext* nvenc_ctx = (NvencContext*)ctx->context->priv_data; nvenc_ctx->encode_config.rcParams.averageBitRate = ctx->context->bit_rate; nvenc_ctx->encode_config.rcParams.maxBitRate = ctx->context->rc_max_rate; return; } #endif }
|