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