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