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 #include "fcodec_sample.h"
16 #include <arpa/inet.h>
17 #include <sys/time.h>
18 #include <utility>
19 #include <iostream>
20 #include <chrono>
21 #include "native_avbuffer_info.h"
22 using namespace OHOS;
23 using namespace OHOS::Media;
24 using namespace OHOS::MediaAVCodec;
25 using namespace OHOS::MediaAVCodec::Codec;
26 using namespace std;
27
OnError(AVCodecErrorType errorType,int32_t errorCode)28 void FCodecServerSample::CallBack::OnError(AVCodecErrorType errorType, int32_t errorCode)
29 {
30 cout << "---- OnError ----" << endl;
31 tester->isRunning_.store(false);
32 tester->signal_->inCond_.notify_all();
33 }
34
OnOutputFormatChanged(const Format & format)35 void FCodecServerSample::CallBack::OnOutputFormatChanged(const Format &format)
36 {
37 cout << "---- OnOutputFormatChanged ----" << endl;
38 tester->GetOutputFormat();
39 }
40
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)41 void FCodecServerSample::CallBack::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
42 {
43 unique_lock<mutex> lock(tester->signal_->inMutex_);
44 tester->GetOutputFormat();
45 tester->signal_->inIdxQueue_.push(index);
46 tester->signal_->inBufferQueue_.push(buffer);
47 tester->signal_->inCond_.notify_all();
48 }
49
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)50 void FCodecServerSample::CallBack::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
51 {
52 tester->fcodec_->RenderOutputBuffer(index);
53 }
54
~FCodecServerSample()55 FCodecServerSample::~FCodecServerSample()
56 {
57 if (fcodec_ != nullptr) {
58 fcodec_->Stop();
59 fcodec_->Release();
60 }
61 cs = nullptr;
62 ps = nullptr;
63 if (signal_ != nullptr) {
64 delete signal_;
65 signal_ = nullptr;
66 }
67 cout << "FCodec released" << endl;
68 }
69
Configure()70 int32_t FCodecServerSample::Configure()
71 {
72 Format fmt;
73 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width);
74 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
75 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, 0);
76 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, 1);
77 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, 1);
78 fmt.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, frameRate);
79 return fcodec_->Configure(fmt);
80 }
81
SetSurface()82 int32_t FCodecServerSample::SetSurface()
83 {
84 cs = Surface::CreateSurfaceAsConsumer();
85 sptr<IBufferConsumerListener> listener = new TestConsumerListener(cs);
86 cs->RegisterConsumerListener(listener);
87 auto p = cs->GetProducer();
88 ps = Surface::CreateSurfaceAsProducer(p);
89 return fcodec_->SetOutputSurface(ps);
90 }
91
SetCallback()92 int32_t FCodecServerSample::SetCallback()
93 {
94 shared_ptr<CallBack> cb = make_shared<CallBack>(this);
95 return fcodec_->SetCallback(cb);
96 }
97
RunFCodecDecoder()98 void FCodecServerSample::RunFCodecDecoder()
99 {
100 fcodec_ = sptr<FCodec>(new FCodec("OH.Media.Codec.Decoder.Video.AVC"));
101 if (fcodec_ == nullptr) {
102 cout << "Create failed" << endl;
103 return;
104 }
105 int32_t err;
106 Media::Meta codecInfo;
107 int32_t instanceid = 0;
108 codecInfo.SetData("av_codec_event_info_instance_id", instanceid);
109 err = fcodec_->Init(codecInfo);
110 if (err != AVCS_ERR_OK) {
111 cout << "decoder Init failed!" << endl;
112 return;
113 }
114 err = Configure();
115 if (err != AVCS_ERR_OK) {
116 cout << "Configure failed" << endl;
117 return;
118 }
119 err = SetSurface();
120 if (err != AVCS_ERR_OK) {
121 cout << "SetSurface failed" << endl;
122 return;
123 }
124 signal_ = new VDecSignal();
125 if (signal_ == nullptr) {
126 cout << "Failed to new VDecSignal" << endl;
127 return;
128 }
129 err = SetCallback();
130 if (err != AVCS_ERR_OK) {
131 cout << "SetCallback failed" << endl;
132 return;
133 }
134 err = fcodec_->Start();
135 if (err != AVCS_ERR_OK) {
136 cout << "Start failed" << endl;
137 return;
138 }
139 isRunning_.store(true);
140 inputLoop_ = make_unique<thread>(&FCodecServerSample::InputFunc, this);
141 if (inputLoop_ == nullptr) {
142 cout << "Failed to create input loop" << endl;
143 isRunning_.store(false);
144 }
145 }
146
InputFunc()147 void FCodecServerSample::InputFunc()
148 {
149 int32_t time = 1000;
150 while (sendFrameIndex < frameIndex) {
151 if (!isRunning_.load()) {
152 break;
153 }
154 unique_lock<mutex> lock(signal_->inMutex_);
155 signal_->inCond_.wait_for(lock, std::chrono::milliseconds(time), [this]() {
156 if (!isRunning_.load()) {
157 cout << "quit signal" << endl;
158 return true;
159 }
160 return signal_->inIdxQueue_.size() > 0;
161 });
162 if (!isRunning_.load() || signal_->inIdxQueue_.size() == 0) {
163 break;
164 }
165 uint32_t index = signal_->inIdxQueue_.front();
166 auto buffer = signal_->inBufferQueue_.front();
167 signal_->inIdxQueue_.pop();
168 signal_->inBufferQueue_.pop();
169 lock.unlock();
170 if (buffer->memory_ == nullptr) {
171 isRunning_.store(false);
172 break;
173 }
174 uint8_t *bufferAddr = buffer->memory_->GetAddr();
175 uint32_t bufferSize = buffer->memory_->GetCapacity();
176 if (fuzzSize <= bufferSize) {
177 buffer->memory_->SetSize(fuzzSize);
178 } else {
179 buffer->memory_->SetSize(bufferSize);
180 }
181 if (memcpy_s(bufferAddr, bufferSize, fuzzData, fuzzSize) != EOK) {
182 break;
183 }
184 if (fuzzSize % 2u == 0u) {
185 buffer->flag_ = AVCODEC_BUFFER_FLAGS_CODEC_DATA;
186 }
187 buffer->flag_ = AVCODEC_BUFFER_FLAG_NONE;
188 int32_t err = fcodec_->QueueInputBuffer(index);
189 if (err != AVCS_ERR_OK) {
190 cout << "QueueInputBuffer failed" << endl;
191 break;
192 }
193 sendFrameIndex++;
194 }
195 }
196
WaitForEos()197 void FCodecServerSample::WaitForEos()
198 {
199 if (inputLoop_ && inputLoop_->joinable()) {
200 inputLoop_->join();
201 }
202 }
203
GetOutputFormat()204 void FCodecServerSample::GetOutputFormat()
205 {
206 Format fmt;
207 int32_t err = fcodec_->GetOutputFormat(fmt);
208 if (err != AVCS_ERR_OK) {
209 cout << "GetOutputFormat failed" << endl;
210 isRunning_.store(false);
211 signal_->inCond_.notify_all();
212 }
213 }
214
Flush()215 void FCodecServerSample::Flush()
216 {
217 int32_t err = fcodec_->Flush();
218 if (err != AVCS_ERR_OK) {
219 cout << "Flush failed" << endl;
220 isRunning_.store(false);
221 signal_->inCond_.notify_all();
222 }
223 }
224
Reset()225 void FCodecServerSample::Reset()
226 {
227 int32_t err = fcodec_->Reset();
228 if (err != AVCS_ERR_OK) {
229 cout << "Reset failed" << endl;
230 isRunning_.store(false);
231 signal_->inCond_.notify_all();
232 }
233 }