1 /*
2 * Copyright (C) 2021 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 "avcodec_venc_demo.h"
17 #include <iostream>
18 #include <sync_fence.h>
19 #include "securec.h"
20 #include "demo_log.h"
21 #include "display_type.h"
22 #include "media_errors.h"
23
24 using namespace OHOS;
25 using namespace OHOS::Media;
26 using namespace std;
27 namespace {
28 constexpr uint32_t DEFAULT_WIDTH = 480;
29 constexpr uint32_t DEFAULT_HEIGHT = 360;
30 constexpr uint32_t DEFAULT_FRAME_RATE = 30;
31 constexpr uint32_t YUV_BUFFER_SIZE = 259200; // 480 * 360 * 3 / 2
32 constexpr uint32_t STRIDE_ALIGN = 8;
33
34 constexpr int32_t FAST_PRODUCER = 50; // 50 fps producer, used to test max_encoder_fps property
35 constexpr int32_t SLOW_PRODUCER = 20; // 20 fps producer, used to test repeat_frame_after property
36 constexpr uint32_t REPEAT_FRAME_AFTER_MS = 50;
37 constexpr uint32_t DEFAULT_FRAME_COUNT = 50;
38 }
39
40 static BufferFlushConfig g_flushConfig = {
41 .damage = {
42 .x = 0,
43 .y = 0,
44 .w = DEFAULT_WIDTH,
45 .h = DEFAULT_HEIGHT
46 },
47 .timestamp = 0
48 };
49
50 static BufferRequestConfig g_request = {
51 .width = DEFAULT_WIDTH,
52 .height = DEFAULT_HEIGHT,
53 .strideAlignment = STRIDE_ALIGN,
54 .format = PIXEL_FMT_YCRCB_420_SP,
55 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
56 .timeout = 0
57 };
58
RunCase(bool enableProp)59 void VEncDemo::RunCase(bool enableProp)
60 {
61 DEMO_CHECK_AND_RETURN_LOG(CreateVenc() == MSERR_OK, "Fatal: CreateVenc fail");
62
63 Format format;
64 format.PutIntValue("width", DEFAULT_WIDTH);
65 format.PutIntValue("height", DEFAULT_HEIGHT);
66 format.PutIntValue("pixel_format", NV21);
67 format.PutIntValue("frame_rate", DEFAULT_FRAME_RATE);
68 DEMO_CHECK_AND_RETURN_LOG(Configure(format) == MSERR_OK, "Fatal: Configure fail");
69
70 surface_ = GetVideoSurface();
71 DEMO_CHECK_AND_RETURN_LOG(surface_ != nullptr, "Fatal: GetVideoSurface fail");
72
73 DEMO_CHECK_AND_RETURN_LOG(Prepare() == MSERR_OK, "Fatal: Prepare fail");
74 DEMO_CHECK_AND_RETURN_LOG(Start() == MSERR_OK, "Fatal: Start fail");
75
76 if (enableProp) {
77 DEMO_CHECK_AND_RETURN_LOG(SetParameter(0, DEFAULT_FRAME_RATE, REPEAT_FRAME_AFTER_MS) == MSERR_OK,
78 "Fatal: SetParameter fail");
79 GenerateData(DEFAULT_FRAME_COUNT, FAST_PRODUCER);
80 GenerateData(DEFAULT_FRAME_COUNT, SLOW_PRODUCER);
81 DEMO_CHECK_AND_RETURN_LOG(SetParameter(1, 0, 0) == MSERR_OK, "Fatal: Set suspend fail");
82 GenerateData(DEFAULT_FRAME_COUNT, DEFAULT_FRAME_RATE);
83 } else {
84 GenerateData(DEFAULT_FRAME_COUNT, DEFAULT_FRAME_RATE);
85 }
86
87 DEMO_CHECK_AND_RETURN_LOG(Stop() == MSERR_OK, "Fatal: Stop fail");
88 DEMO_CHECK_AND_RETURN_LOG(Release() == MSERR_OK, "Fatal: Release fail");
89 }
90
GenerateData(uint32_t count,uint32_t fps)91 void VEncDemo::GenerateData(uint32_t count, uint32_t fps)
92 {
93 if (fps == 0) {
94 return;
95 }
96 constexpr uint32_t secToUs = 1000000;
97 uint32_t intervalUs = secToUs / fps;
98 uint32_t frameCount = 0;
99 while (frameCount <= count) {
100 usleep(intervalUs);
101
102 sptr<OHOS::SurfaceBuffer> buffer = nullptr;
103 int32_t fence = -1;
104 if (surface_->RequestBuffer(buffer, fence, g_request) != SURFACE_ERROR_OK) {
105 continue;
106 }
107 DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: SurfaceBuffer is nullptr");
108
109 sptr<SyncFence> tempFence = new SyncFence(fence);
110 tempFence->Wait(100); // 100ms
111
112 auto addr = static_cast<uint8_t *>(buffer->GetVirAddr());
113 if (addr == nullptr) {
114 cout << "Fatal: SurfaceBuffer address is nullptr" << endl;
115 (void)surface_->CancelBuffer(buffer);
116 break;
117 }
118 DEMO_CHECK_AND_BREAK_LOG(memset_s(addr, buffer->GetSize(), 0xFF, YUV_BUFFER_SIZE) == EOK, "Fatal");
119
120 const sptr<OHOS::BufferExtraData>& extraData = buffer->GetExtraData();
121 DEMO_CHECK_AND_BREAK_LOG(extraData != nullptr, "Fatal: SurfaceBuffer is nullptr");
122 (void)extraData->ExtraSet("timeStamp", timestampNs_);
123 timestampNs_ += static_cast<int64_t>(intervalUs * 1000); // us to ns
124
125 (void)surface_->FlushBuffer(buffer, -1, g_flushConfig);
126 cout << "Generate input buffer success, timestamp: " << timestampNs_ << endl;
127 frameCount++;
128 }
129 }
130
CreateVenc()131 int32_t VEncDemo::CreateVenc()
132 {
133 venc_ = VideoEncoderFactory::CreateByMime("video/mp4v-es");
134 DEMO_CHECK_AND_RETURN_RET_LOG(venc_ != nullptr, MSERR_UNKNOWN, "Fatal: CreateByMime fail");
135
136 signal_ = make_shared<VEncSignal>();
137 DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, MSERR_UNKNOWN, "Fatal: No memory");
138
139 cb_ = make_shared<VEncDemoCallback>(signal_);
140 DEMO_CHECK_AND_RETURN_RET_LOG(cb_ != nullptr, MSERR_UNKNOWN, "Fatal: No memory");
141 DEMO_CHECK_AND_RETURN_RET_LOG(venc_->SetCallback(cb_) == MSERR_OK, MSERR_UNKNOWN, "Fatal: SetCallback fail");
142
143 return MSERR_OK;
144 }
145
Configure(const Format & format)146 int32_t VEncDemo::Configure(const Format &format)
147 {
148 return venc_->Configure(format);
149 }
150
Prepare()151 int32_t VEncDemo::Prepare()
152 {
153 return venc_->Prepare();
154 }
155
Start()156 int32_t VEncDemo::Start()
157 {
158 isRunning_.store(true);
159 readLoop_ = make_unique<thread>(&VEncDemo::LoopFunc, this);
160 DEMO_CHECK_AND_RETURN_RET_LOG(readLoop_ != nullptr, MSERR_UNKNOWN, "Fatal: No memory");
161 return venc_->Start();
162 }
163
SetParameter(int32_t suspend,int32_t maxFps,int32_t repeatMs)164 int32_t VEncDemo::SetParameter(int32_t suspend, int32_t maxFps, int32_t repeatMs)
165 {
166 Format format;
167 format.PutIntValue("suspend_input_surface", suspend);
168 format.PutIntValue("max_encoder_fps", maxFps);
169 format.PutIntValue("repeat_frame_after", repeatMs);
170 return venc_->SetParameter(format);
171 }
172
Stop()173 int32_t VEncDemo::Stop()
174 {
175 isRunning_.store(false);
176
177 if (readLoop_ != nullptr && readLoop_->joinable()) {
178 unique_lock<mutex> queueLock(signal_->mutex_);
179 signal_->bufferQueue_.push(0);
180 signal_->cond_.notify_all();
181 queueLock.unlock();
182 readLoop_->join();
183 readLoop_.reset();
184 }
185
186 return venc_->Stop();
187 }
188
Flush()189 int32_t VEncDemo::Flush()
190 {
191 return venc_->Flush();
192 }
193
Reset()194 int32_t VEncDemo::Reset()
195 {
196 return venc_->Reset();
197 }
198
Release()199 int32_t VEncDemo::Release()
200 {
201 return venc_->Release();
202 }
203
GetVideoSurface()204 sptr<Surface> VEncDemo::GetVideoSurface()
205 {
206 return venc_->CreateInputSurface();
207 }
208
LoopFunc()209 void VEncDemo::LoopFunc()
210 {
211 while (true) {
212 if (!isRunning_.load()) {
213 break;
214 }
215
216 unique_lock<mutex> lock(signal_->mutex_);
217 signal_->cond_.wait(lock, [this](){ return signal_->bufferQueue_.size() > 0; });
218
219 if (!isRunning_.load()) {
220 break;
221 }
222
223 uint32_t index = signal_->bufferQueue_.front();
224 auto buffer = venc_->GetOutputBuffer(index);
225 if (!buffer) {
226 cout << "Fatal: GetOutputBuffer fail, exit" << endl;
227 break;
228 }
229
230 if (venc_->ReleaseOutputBuffer(index) != MSERR_OK) {
231 cout << "Fatal: ReleaseOutputBuffer fail, exit" << endl;
232 break;
233 }
234 signal_->bufferQueue_.pop();
235 }
236 }
237
VEncDemoCallback(shared_ptr<VEncSignal> signal)238 VEncDemoCallback::VEncDemoCallback(shared_ptr<VEncSignal> signal)
239 : signal_(signal)
240 {
241 }
242
OnError(AVCodecErrorType errorType,int32_t errorCode)243 void VEncDemoCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
244 {
245 cout << "Error received, errorType:" << errorType << " errorCode:" << errorCode << endl;
246 }
247
OnOutputFormatChanged(const Format & format)248 void VEncDemoCallback::OnOutputFormatChanged(const Format &format)
249 {
250 cout << "OnOutputFormatChanged received" << endl;
251 }
252
OnInputBufferAvailable(uint32_t index)253 void VEncDemoCallback::OnInputBufferAvailable(uint32_t index)
254 {
255 (void)index;
256 }
257
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag)258 void VEncDemoCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag)
259 {
260 cout << "OnOutputBufferAvailable received, index:" << index << " timestamp:" << info.presentationTimeUs << endl;
261 unique_lock<mutex> lock(signal_->mutex_);
262 signal_->bufferQueue_.push(index);
263 signal_->cond_.notify_all();
264 }
265