• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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