• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "video_encoder.h"
17 
18 #undef LOG_TAG
19 #define LOG_TAG "VideoEncoder"
20 
21 namespace {
22 
ToGraphicPixelFormat(int32_t avPixelFormat,bool isHDRVivid)23 int32_t ToGraphicPixelFormat(int32_t avPixelFormat, bool isHDRVivid)
24 {
25     if (isHDRVivid) {
26         return NATIVEBUFFER_PIXEL_FMT_YCBCR_P010;
27     }
28     switch (avPixelFormat) {
29         case AV_PIXEL_FORMAT_RGBA:
30             return NATIVEBUFFER_PIXEL_FMT_RGBA_8888;
31         case AV_PIXEL_FORMAT_YUVI420:
32             return NATIVEBUFFER_PIXEL_FMT_YCBCR_420_P;
33         case AV_PIXEL_FORMAT_NV21:
34             return NATIVEBUFFER_PIXEL_FMT_YCRCB_420_SP;
35         default: // NV12 and others
36             return NATIVEBUFFER_PIXEL_FMT_YCRCB_420_SP;
37     }
38 }
39 } // namespace
40 
~VideoEncoder()41 VideoEncoder::~VideoEncoder()
42 {
43     Release();
44 }
45 
Create(const std::string & videoCodecMime)46 int32_t VideoEncoder::Create(const std::string &videoCodecMime)
47 {
48     encoder_ = OH_VideoEncoder_CreateByMime(videoCodecMime.c_str());
49     CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Create failed");
50     return AVCODEC_SAMPLE_ERR_OK;
51 }
52 
Config(SampleInfo & sampleInfo,CodecUserData * codecUserData)53 int32_t VideoEncoder::Config(SampleInfo &sampleInfo, CodecUserData *codecUserData)
54 {
55     CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
56     CHECK_AND_RETURN_RET_LOG(codecUserData != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Invalid param: codecUserData");
57 
58     // Configure video encoder
59     int32_t ret = Configure(sampleInfo);
60     CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Configure failed");
61 
62     // GetSurface from video encoder
63     ret = GetSurface(sampleInfo);
64     CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Get surface failed");
65 
66     // SetCallback for video encoder
67     ret = SetCallback(codecUserData);
68     CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
69                              "Set callback failed, ret: %{public}d", ret);
70 
71     // Prepare video encoder
72     ret = OH_VideoEncoder_Prepare(encoder_);
73     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Prepare failed, ret: %{public}d", ret);
74 
75     return AVCODEC_SAMPLE_ERR_OK;
76 }
77 
Start()78 int32_t VideoEncoder::Start()
79 {
80     CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
81 
82     int ret = OH_VideoEncoder_Start(encoder_);
83     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret);
84     return AVCODEC_SAMPLE_ERR_OK;
85 }
86 
PushInputBuffer(CodecBufferInfo & info)87 int32_t VideoEncoder::PushInputBuffer(CodecBufferInfo &info)
88 {
89     CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Decoder is null");
90 
91     int32_t ret = OH_AVBuffer_SetBufferAttr(reinterpret_cast<OH_AVBuffer *>(info.buffer), &info.attr);
92     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set avbuffer attr failed");
93     ret = OH_VideoEncoder_PushInputBuffer(encoder_, info.bufferIndex);
94     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Push input data failed");
95     return AVCODEC_SAMPLE_ERR_OK;
96 }
97 
FreeOutputBuffer(uint32_t bufferIndex)98 int32_t VideoEncoder::FreeOutputBuffer(uint32_t bufferIndex)
99 {
100     CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
101 
102     int32_t ret = OH_VideoEncoder_FreeOutputBuffer(encoder_, bufferIndex);
103     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
104         "Free output data failed, ret: %{public}d", ret);
105     return AVCODEC_SAMPLE_ERR_OK;
106 }
107 
NotifyEndOfStream()108 int32_t VideoEncoder::NotifyEndOfStream()
109 {
110     CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
111 
112     int32_t ret = OH_VideoEncoder_NotifyEndOfStream(encoder_);
113     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
114         "Notify end of stream failed, ret: %{public}d", ret);
115     return AVCODEC_SAMPLE_ERR_OK;
116 }
117 
Stop()118 int32_t VideoEncoder::Stop()
119 {
120     CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null");
121 
122     int ret = OH_VideoEncoder_Flush(encoder_);
123     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Flush failed, ret: %{public}d", ret);
124 
125     ret = OH_VideoEncoder_Stop(encoder_);
126     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Stop failed, ret: %{public}d", ret);
127     return AVCODEC_SAMPLE_ERR_OK;
128 }
129 
Release()130 int32_t VideoEncoder::Release()
131 {
132     if (encoder_ != nullptr) {
133         OH_VideoEncoder_Destroy(encoder_);
134         encoder_ = nullptr;
135     }
136     return AVCODEC_SAMPLE_ERR_OK;
137 }
138 
SetCallback(CodecUserData * codecUserData)139 int32_t VideoEncoder::SetCallback(CodecUserData *codecUserData)
140 {
141     int32_t ret = OH_VideoEncoder_RegisterCallback(encoder_,
142     {SampleCallback::OnCodecError, SampleCallback::OnCodecFormatChange,
143         SampleCallback::OnNeedInputBuffer, SampleCallback::OnNewOutputBuffer},
144         codecUserData);
145     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Set callback failed, ret: %{public}d", ret);
146 
147     return AVCODEC_SAMPLE_ERR_OK;
148 }
149 
Configure(const SampleInfo & sampleInfo)150 int32_t VideoEncoder::Configure(const SampleInfo &sampleInfo)
151 {
152     OH_AVFormat *format = OH_AVFormat_Create();
153     CHECK_AND_RETURN_RET_LOG(format != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed");
154 
155     OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoWidth);
156     OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight);
157     OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate);
158     OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.pixelFormat);
159     OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, sampleInfo.bitrateMode);
160     OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, sampleInfo.bitrate);
161     OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, sampleInfo.hevcProfile);
162     if (sampleInfo.isHDRVivid) {
163         OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, sampleInfo.iFrameInterval);
164         OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, sampleInfo.rangFlag);
165         OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES, sampleInfo.primary);
166         OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, sampleInfo.transfer);
167         OH_AVFormat_SetIntValue(format, OH_MD_KEY_MATRIX_COEFFICIENTS, sampleInfo.matrix);
168     }
169     AVCODEC_SAMPLE_LOGI("====== VideoEncoder config ======");
170     AVCODEC_SAMPLE_LOGI("%{public}d*%{public}d, %{public}.1ffps",
171         sampleInfo.videoWidth, sampleInfo.videoHeight, sampleInfo.frameRate);
172     // 1024: ratio of kbps to bps
173     AVCODEC_SAMPLE_LOGI("BitRate Mode: %{public}d, BitRate: %{public}" PRId64 "kbps",
174         sampleInfo.bitrateMode, sampleInfo.bitrate / 1024);
175     AVCODEC_SAMPLE_LOGI("====== VideoEncoder config ======");
176 
177     int ret = OH_VideoEncoder_Configure(encoder_, format);
178     OH_AVFormat_Destroy(format);
179     format = nullptr;
180     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Config failed, ret: %{public}d", ret);
181     return AVCODEC_SAMPLE_ERR_OK;
182 }
183 
GetSurface(SampleInfo & sampleInfo)184 int32_t VideoEncoder::GetSurface(SampleInfo &sampleInfo)
185 {
186     int32_t ret = OH_VideoEncoder_GetSurface(encoder_, &sampleInfo.window);
187     CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK && sampleInfo.window, AVCODEC_SAMPLE_ERR_ERROR,
188         "Get surface failed, ret: %{public}d", ret);
189     return AVCODEC_SAMPLE_ERR_OK;
190 }
191 
192