20 #include <aws/core/utils/logging/LogMacros.h> 27 #include <libavcodec/avcodec.h> 28 #include <libavutil/imgutils.h> 29 #include <libavutil/opt.h> 30 #include <libswscale/swscale.h> 63 src_encoding_(AV_PIX_FMT_NONE),
67 convert_ctx_(nullptr),
80 if (
nullptr != param_) {
81 AWS_LOG_ERROR(__func__,
"Unable to setup codec context. param_ must be null");
84 param_ = avcodec_alloc_context3(codec);
85 if (
nullptr == param_) {
86 AWS_LOG_ERROR(__func__,
"Could not allocate video codec context");
90 param_->bit_rate = bitrate_;
92 param_->width = dst_width_;
93 param_->height = dst_height_;
95 param_->time_base = (AVRational){fps_den_, fps_num_};
96 frame_duration_ = (1e6 * fps_den_) / fps_num_;
97 param_->gop_size =
static_cast<int>(ceil(kFragmentDuration * fps_num_ / fps_den_));
98 param_->keyint_min = param_->gop_size - 1;
100 param_->pix_fmt = AV_PIX_FMT_YUV420P;
102 param_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
103 param_->flags2 &= ~AV_CODEC_FLAG2_LOCAL_HEADER;
110 if (
nullptr == codec) {
111 AWS_LOG_ERROR(__func__,
"Invalid codec");
115 AWS_LOGSTREAM_INFO(__func__,
"Attempting to open codec: " << codec->name);
117 if (
AWS_ERR_OK != set_param(codec) || avcodec_open2(param_, codec, &opts) < 0 ) {
118 AWS_LOG_ERROR(__func__,
"Could not open codec");
119 if (
nullptr != param_) {
120 avcodec_close(param_);
131 const std::string & codec_name,
const int dst_width,
const int dst_height,
132 const int fps_num,
const int fps_den,
const int64_t bitrate)
134 if (src_width <= 0) {
135 AWS_LOGSTREAM_ERROR(__func__,
"Invalid video source width " << src_width <<
"!");
138 if (src_height <= 0) {
139 AWS_LOGSTREAM_ERROR(__func__,
"Invalid video source height " << src_height <<
"!");
142 if (dst_width <= 0) {
143 AWS_LOGSTREAM_ERROR(__func__,
"Invalid output video width " << dst_width <<
"!");
146 if (dst_height <= 0) {
147 AWS_LOGSTREAM_ERROR(__func__,
"Invalid video source height " << dst_height <<
"!");
151 AWS_LOGSTREAM_ERROR(__func__,
"Invalid FPS numerator " << fps_num <<
"!");
155 AWS_LOGSTREAM_ERROR(__func__,
"Invalid FPS denominator " << fps_den <<
"!");
159 AWS_LOGSTREAM_ERROR(__func__,
"Invalid bit rate " << bitrate <<
"!");
163 src_width_ = src_width;
164 src_height_ = src_height;
165 src_encoding_ = src_encoding;
166 if (src_encoding_ == AV_PIX_FMT_RGB24) {
167 src_stride_ = 3 * src_width_;
168 }
else if (src_encoding_ == AV_PIX_FMT_BGR24) {
169 src_stride_ = 3 * src_width_;
170 }
else if (src_encoding_ == AV_PIX_FMT_RGBA) {
171 src_stride_ = 4 * src_width_;
172 }
else if (src_encoding_ == AV_PIX_FMT_BGRA) {
173 src_stride_ = 4 * src_width_;
175 AWS_LOG_ERROR(__func__,
"Trying to work with unsupported encoding!");
179 dst_width_ = dst_width;
180 dst_height_ = dst_height;
185 avcodec_register_all();
188 AVCodec * codec =
nullptr;
189 AVDictionary * opts =
nullptr;
190 if (codec_name.empty()) {
191 codec = avcodec_find_encoder_by_name(kDefaultHardwareCodec);
193 codec = avcodec_find_encoder_by_name(kDefaultSoftwareCodec);
194 av_dict_set(&opts,
"preset",
"veryfast", 0);
195 av_dict_set(&opts,
"tune",
"zerolatency", 0);
198 AWS_LOGSTREAM_ERROR(__func__, kDefaultHardwareCodec <<
" and " << kDefaultSoftwareCodec
199 <<
" codecs were not available!");
204 codec = avcodec_find_encoder_by_name(codec_name.c_str());
206 AWS_LOGSTREAM_ERROR(__func__, codec_name <<
" codec not found!");
210 AWS_LOGSTREAM_INFO(__func__,
"Encoding using " << codec->name <<
" codec");
214 dst_width_ = param_->width;
215 dst_height_ = param_->height;
217 pic_in_ = av_frame_alloc();
218 if (
nullptr == pic_in_) {
219 AWS_LOG_ERROR(__func__,
"Could not allocate video frame");
222 pic_in_->format = param_->pix_fmt;
223 pic_in_->width = param_->width;
224 pic_in_->height = param_->height;
229 int ret = av_image_alloc(pic_in_->data, pic_in_->linesize, param_->width, param_->height,
230 param_->pix_fmt, 32);
232 AWS_LOGSTREAM_ERROR(__func__,
233 "Could not allocate raw picture buffer" 234 " (av_image_alloc() returned: " 239 convert_ctx_ = sws_getContext(src_width_, src_height_, src_encoding_, dst_width_, dst_height_,
240 AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR,
nullptr,
nullptr,
nullptr);
247 if (
nullptr != convert_ctx_) {
248 sws_freeContext(convert_ctx_);
251 if (
nullptr != param_) {
252 avcodec_close(param_);
256 if (
nullptr != pic_in_) {
257 av_freep(&pic_in_->data[0]);
258 av_frame_free(&pic_in_);
264 if (
nullptr == img_data) {
271 const uint8_t * buf_in[4] = {img_data,
nullptr,
nullptr,
nullptr};
272 sws_scale(convert_ctx_, (
const uint8_t *
const *)buf_in, &src_stride_, 0, src_height_,
273 pic_in_->data, pic_in_->linesize);
276 av_init_packet(&pkt);
282 int ret = avcodec_encode_video2(param_, &pkt, pic_in_, &got_output);
285 AWS_LOGSTREAM_ERROR(__func__,
286 "Error encoding frame (avcodec_encode_video2() returned: " << ret <<
")");
292 res.
frame_pts = frame_duration_ * (0 <= pkt.pts ? pkt.pts : 0);
293 res.
frame_dts = frame_duration_ * (0 <= pkt.dts ? pkt.dts : 0);
295 res.
key_frame = pkt.flags & AV_PKT_FLAG_KEY;
296 av_free_packet(&pkt);
306 if (param_ !=
nullptr && param_->extradata !=
nullptr && param_->extradata_size > 0) {
307 return std::vector<uint8_t>(param_->extradata, param_->extradata + param_->extradata_size);
309 return std::vector<uint8_t>();
330 H264Encoder::H264Encoder() {}
332 H264Encoder::~H264Encoder() {}
334 AwsError H264Encoder::Initialize(
const int src_width,
const int src_height,
335 const AVPixelFormat src_encoding,
338 int dst_width, dst_height;
342 dst_width = src_width;
343 dst_height = src_height;
346 int fps_num, fps_den;
350 AWS_LOG_WARN(__func__,
"fps not set");
363 return impl_->Initialize(src_width, src_height, src_encoding, codec, dst_width, dst_height,
364 fps_num, fps_den, bitrate);
369 return impl_->Encode(img_data, res);
372 std::vector<uint8_t> H264Encoder::GetExtraData()
const {
return impl_->GetExtraData(); }
constexpr char kOutputWidthKey[]
constexpr int kDefaultFpsNumerator
std::vector< uint8_t > GetExtraData() const
constexpr char kDefaultHardwareCodec[]
constexpr int kDefaultMaxBFrames
struct SwsContext * convert_ctx_
AwsError set_param(AVCodec *codec)
constexpr char kDefaultSoftwareCodec[]
constexpr float kFragmentDuration
AwsError open_codec(AVCodec *codec, AVDictionary *opts)
AwsError Encode(const uint8_t *img_data, H264EncoderResult &res)
constexpr char kFpsDenominatorKey[]
AVPixelFormat src_encoding_
constexpr int kDefaultFpsDenominator
AwsError Initialize(const int src_width, const int src_height, const AVPixelFormat src_encoding, const std::string &codec_name, const int dst_width, const int dst_height, const int fps_num, const int fps_den, const int64_t bitrate)
virtual AwsError ReadParam(const ParameterPath ¶m_path, std::vector< std::string > &out) const =0
constexpr int kDefaultBitrate
std::vector< uint8_t > frame_data
constexpr char kBitrateKey[]
constexpr char kCodecKey[]
constexpr char kOutputHeightKey[]
constexpr char kFpsNumeratorKey[]