From 2740f31642251b4537af84b8b44023d4b132c68b Mon Sep 17 00:00:00 2001 From: dijunkun Date: Fri, 27 Sep 2024 17:29:47 +0800 Subject: [PATCH] [feat] add aom av1 decoder implementation --- .../video/decode/aom/aom_av1_decoder.cpp | 153 ++++++++++++++++++ src/media/video/decode/aom/aom_av1_decoder.h | 49 ++++++ .../video/decode/video_decoder_factory.cpp | 8 +- .../video/encode/aom/aom_av1_encoder.cpp | 4 +- xmake.lua | 10 +- 5 files changed, 216 insertions(+), 8 deletions(-) create mode 100644 src/media/video/decode/aom/aom_av1_decoder.cpp create mode 100644 src/media/video/decode/aom/aom_av1_decoder.h diff --git a/src/media/video/decode/aom/aom_av1_decoder.cpp b/src/media/video/decode/aom/aom_av1_decoder.cpp new file mode 100644 index 0000000..a59ecce --- /dev/null +++ b/src/media/video/decode/aom/aom_av1_decoder.cpp @@ -0,0 +1,153 @@ +#include "aom_av1_decoder.h" + +#include "log.h" + +#define SAVE_RECEIVED_AV1_STREAM 0 +#define SAVE_DECODED_NV12_STREAM 0 + +AomAv1Decoder::AomAv1Decoder() {} + +AomAv1Decoder::~AomAv1Decoder() { + if (SAVE_RECEIVED_AV1_STREAM && file_av1_) { + fflush(file_av1_); + fclose(file_av1_); + file_av1_ = nullptr; + } + + if (SAVE_DECODED_NV12_STREAM && file_nv12_) { + fflush(file_nv12_); + fclose(file_nv12_); + file_nv12_ = nullptr; + } + + if (nv12_frame_) { + delete nv12_frame_; + nv12_frame_ = nullptr; + } +} + +int AomAv1Decoder::Init() { + aom_av1_decoder_config_.threads = 8; + aom_av1_decoder_config_.w = 2560; + aom_av1_decoder_config_.h = 1440; + aom_av1_decoder_config_.allow_lowbitdepth = 1; + + extern aom_codec_iface_t my_codec; + if (AOM_CODEC_OK != aom_codec_dec_init(&aom_av1_decoder_ctx_, + aom_codec_av1_dx(), + &aom_av1_decoder_config_, 0)) { + LOG_ERROR("Failed to initialize decoder"); + return -1; + } + + aom_codec_control(&aom_av1_decoder_ctx_, AV1D_GET_IMG_FORMAT, + AOM_IMG_FMT_NV12); + + if (SAVE_RECEIVED_AV1_STREAM) { + file_av1_ = fopen("received_av1_stream.ivf", "w+b"); + if (!file_av1_) { + LOG_WARN("Fail to open received_av1_stream.ivf"); + } + } + + if (SAVE_DECODED_NV12_STREAM) { + file_nv12_ = fopen("decoded_nv12_stream.yuv", "w+b"); + if (!file_nv12_) { + LOG_WARN("Fail to open decoded_nv12_stream.yuv"); + } + } + + return 0; +} + +int AomAv1Decoder::Decode( + const uint8_t *data, int size, + std::function on_receive_decoded_frame) { + if (SAVE_RECEIVED_AV1_STREAM) { + fwrite((unsigned char *)data, 1, size, file_av1_); + } + + LOG_ERROR("Decode size {}", size); + + aom_codec_iter_t iter = nullptr; + aom_codec_err_t ret = + aom_codec_decode(&aom_av1_decoder_ctx_, data, size, nullptr); + if (AOM_CODEC_OK != ret) { + const char *error = aom_codec_error(&aom_av1_decoder_ctx_); + const char *detail = aom_codec_error_detail(&aom_av1_decoder_ctx_); + if (detail && error) { + LOG_ERROR("Failed to decode frame [{}], additional information [{}]", + error, detail); + } else { + LOG_ERROR("Failed to decode frame, ret [{}]", + aom_codec_err_to_string(ret)); + } + return -1; + } + + if (img_ = aom_codec_get_frame(&aom_av1_decoder_ctx_, &iter)) { + { + aom_codec_frame_flags_t flags; + ret = aom_codec_control(&aom_av1_decoder_ctx_, AOMD_GET_FRAME_FLAGS, + &flags); + if (ret == AOM_CODEC_OK) { + if (flags & AOM_FRAME_IS_KEY) { + LOG_ERROR("Key frame"); + } else { + LOG_ERROR("Inter frame"); + } + if (flags & (AOM_FRAME_IS_KEY | AOM_FRAME_IS_INTRAONLY)) { + LOG_ERROR("Key frame"); + } else if (flags & AOM_FRAME_IS_SWITCH) { + LOG_ERROR("Switch frame"); + } else { + LOG_ERROR("P frame"); + } + } + } + int corrupted = 0; + int ret = aom_codec_control(&aom_av1_decoder_ctx_, AOMD_GET_FRAME_CORRUPTED, + &corrupted); + if (ret != AOM_CODEC_OK) { + LOG_ERROR("Failed to get frame corrupted"); + return -1; + } + + frame_width_ = img_->d_w; + frame_height_ = img_->d_h; + + nv12_frame_size_ = frame_width_ * frame_height_ * 3 / 2; + + if (!nv12_frame_) { + nv12_frame_capacity_ = nv12_frame_size_; + nv12_frame_ = + new VideoFrame(nv12_frame_capacity_, frame_width_, frame_height_); + } + + if (nv12_frame_capacity_ < nv12_frame_size_) { + nv12_frame_capacity_ = nv12_frame_size_; + delete nv12_frame_; + nv12_frame_ = + new VideoFrame(nv12_frame_capacity_, frame_width_, frame_height_); + } + + if (nv12_frame_->Size() != nv12_frame_size_ || + nv12_frame_->Width() != frame_width_ || + nv12_frame_->Height() != frame_height_) { + nv12_frame_->SetSize(nv12_frame_size_); + nv12_frame_->SetWidth(frame_width_); + nv12_frame_->SetHeight(frame_height_); + } + + on_receive_decoded_frame(*nv12_frame_); + + if (SAVE_DECODED_NV12_STREAM) { + fwrite((unsigned char *)nv12_frame_->Buffer(), 1, nv12_frame_->Size(), + file_nv12_); + } + + return 0; + } + + return -1; +} \ No newline at end of file diff --git a/src/media/video/decode/aom/aom_av1_decoder.h b/src/media/video/decode/aom/aom_av1_decoder.h new file mode 100644 index 0000000..bcca059 --- /dev/null +++ b/src/media/video/decode/aom/aom_av1_decoder.h @@ -0,0 +1,49 @@ +/* + * @Author: DI JUNKUN + * @Date: 2024-09-25 + * Copyright (c) 2024 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _AOM_AV1_DECODER_H_ +#define _AOM_AV1_DECODER_H_ + +#include + +#include "aom/aom_codec.h" +#include "aom/aom_decoder.h" +#include "aom/aomdx.h" +#include "video_decoder.h" + +class AomAv1Decoder : public VideoDecoder { + public: + AomAv1Decoder(); + virtual ~AomAv1Decoder(); + + public: + int Init(); + + int Decode(const uint8_t *data, int size, + std::function on_receive_decoded_frame); + + std::string GetDecoderName() { return "AomAv1"; } + + private: + VideoFrame *nv12_frame_ = 0; + int nv12_frame_capacity_ = 0; + int nv12_frame_size_ = 0; + + int frame_width_ = 0; + int frame_height_ = 0; + + FILE *file_av1_ = nullptr; + FILE *file_nv12_ = nullptr; + + bool first_ = false; + + // aom av1 decoder + aom_codec_ctx_t aom_av1_decoder_ctx_; + aom_codec_dec_cfg_t aom_av1_decoder_config_; + aom_image_t *img_ = nullptr; +}; + +#endif \ No newline at end of file diff --git a/src/media/video/decode/video_decoder_factory.cpp b/src/media/video/decode/video_decoder_factory.cpp index 0439b9d..57f90e6 100644 --- a/src/media/video/decode/video_decoder_factory.cpp +++ b/src/media/video/decode/video_decoder_factory.cpp @@ -1,13 +1,13 @@ #include "video_decoder_factory.h" -#if __APPLE__ +#include "aom/aom_av1_decoder.h" #include "dav1d/dav1d_av1_decoder.h" #include "openh264/openh264_decoder.h" + +#if __APPLE__ #else -#include "dav1d/dav1d_av1_decoder.h" #include "nvcodec/nvidia_video_decoder.h" #include "nvcodec_api.h" -#include "openh264/openh264_decoder.h" #endif #include "log.h" @@ -21,6 +21,8 @@ std::unique_ptr VideoDecoderFactory::CreateVideoDecoder( if (av1_encoding) { LOG_INFO("Use dav1d decoder"); return std::make_unique(Dav1dAv1Decoder()); + // LOG_INFO("Use aom decoder"); + // return std::make_unique(AomAv1Decoder()); } else { #if __APPLE__ return std::make_unique(OpenH264Decoder()); diff --git a/src/media/video/encode/aom/aom_av1_encoder.cpp b/src/media/video/encode/aom/aom_av1_encoder.cpp index 9f783cf..2a66f65 100644 --- a/src/media/video/encode/aom/aom_av1_encoder.cpp +++ b/src/media/video/encode/aom/aom_av1_encoder.cpp @@ -129,9 +129,7 @@ int AomAv1Encoder::Init() { aom_codec_err_t ret = aom_codec_enc_config_default( aom_codec_av1_cx(), &aom_av1_encoder_config_, kUsageProfile); if (ret != AOM_CODEC_OK) { - LOG_ERROR( - "AomAv1Encoder::EncodeInit returned {} on aom_codec_enc_config_default", - (int)ret); + LOG_ERROR("Failed to get config: {}", aom_codec_err_to_string(ret)); return -1; } diff --git a/xmake.lua b/xmake.lua index 021bf3e..39184e2 100644 --- a/xmake.lua +++ b/xmake.lua @@ -112,6 +112,7 @@ target("media") "src/media/video/decode/openh264/*.cpp", "src/media/video/encode/aom/*.cpp", "src/media/video/decode/dav1d/*.cpp", + "src/media/video/decode/aom/*.cpp", "src/media/nvcodec/*.cpp") add_includedirs("src/media/video/encode", "src/media/video/decode", @@ -121,6 +122,7 @@ target("media") "src/media/video/decode/openh264", "src/media/video/encode/aom", "src/media/video/decode/dav1d", + "src/media/video/decode/aom", "src/media/nvcodec", "thirdparty/nvcodec/interface", {public = true}) add_includedirs(path.join(os.getenv("CUDA_PATH"), "include"), {public = true}) @@ -133,6 +135,7 @@ target("media") "src/media/video/decode/openh264/*.cpp", "src/media/video/encode/aom/*.cpp", "src/media/video/decode/dav1d/*.cpp", + "src/media/video/decode/aom/*.cpp", "src/media/nvcodec/*.cpp") add_includedirs("src/media/video/encode", "src/media/video/decode", @@ -142,6 +145,7 @@ target("media") "src/media/video/decode/openh264", "src/media/video/encode/aom", "src/media/video/decode/dav1d", + "src/media/video/decode/aom", "src/media/nvcodec", "thirdparty/nvcodec/interface", {public = true}) add_includedirs(path.join(os.getenv("CUDA_PATH"), "include"), {public = true}) @@ -151,13 +155,15 @@ target("media") "src/media/video/encode/openh264/*.cpp", "src/media/video/decode/openh264/*.cpp", "src/media/video/encode/aom/*.cpp", - "src/media/video/decode/dav1d/*.cpp") + "src/media/video/decode/dav1d/*.cpp", + "src/media/video/decode/aom/*.cpp") add_includedirs("src/media/video/encode", "src/media/video/decode", "src/media/video/encode/openh264", "src/media/video/decode/openh264", "src/media/video/encode/aom", - "src/media/video/decode/dav1d", {public = true}) + "src/media/video/decode/dav1d", + "src/media/video/decode/aom", {public = true}) end add_files("src/media/audio/encode/*.cpp", "src/media/audio/decode/*.cpp")