1 /*
2 * Copyright (c) 2024 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 <arpa/inet.h>
16 #include <sys/time.h>
17 #include <utility>
18 #include "hevcserverdec_sample.h"
19 #include <iostream>
20 #include "hevc_decoder_api.h"
21 using namespace OHOS;
22 using namespace OHOS::Media;
23 using namespace OHOS::MediaAVCodec;
24 using namespace OHOS::MediaAVCodec::Codec;
25 using namespace std;
26 namespace {
27 constexpr int32_t WIDTH = 1920;
28 constexpr int32_t HIGHT = 1080;
29 constexpr int32_t FORMAT = 2;
30 constexpr int32_t ANGLE = 0;
31 constexpr int32_t FORMAT_RATE = 30;
32 constexpr int32_t TIME = 12345;
33 constexpr int32_t MAX_SEND_FRAMES = 10;
34 } // namespace
35
OnError(AVCodecErrorType errorType,int32_t errorCode)36 void VDecServerSample::CallBack::OnError(AVCodecErrorType errorType, int32_t errorCode)
37 {
38 tester->Flush();
39 tester->Reset();
40 }
41
OnOutputFormatChanged(const Format & format)42 void VDecServerSample::CallBack::OnOutputFormatChanged(const Format &format)
43 {
44 tester->GetOutputFormat();
45 }
46
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)47 void VDecServerSample::CallBack::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
48 {
49 unique_lock<mutex> lock(tester->signal_->inMutex_);
50 tester->signal_->inIdxQueue_.push(index);
51 tester->signal_->inBufferQueue_.push(buffer);
52 tester->signal_->inCond_.notify_all();
53 }
54
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)55 void VDecServerSample::CallBack::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
56 {
57 tester->codec_->ReleaseOutputBuffer(index);
58 }
59
~VDecServerSample()60 VDecServerSample::~VDecServerSample()
61 {
62 if (codec_ != nullptr) {
63 codec_->Stop();
64 codec_->Release();
65 HevcDecoder *codec = reinterpret_cast<HevcDecoder*>(codec_.get());
66 codec->DecStrongRef(codec);
67 }
68 if (signal_ != nullptr) {
69 delete signal_;
70 signal_ = nullptr;
71 }
72 }
73
ConfigServerDecoder()74 int32_t VDecServerSample::ConfigServerDecoder()
75 {
76 Format fmt;
77 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, WIDTH);
78 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, HIGHT);
79 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, FORMAT);
80 fmt.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, FORMAT_RATE);
81 fmt.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, ANGLE);
82 return codec_->Configure(fmt);
83 }
84
SetCallback()85 int32_t VDecServerSample::SetCallback()
86 {
87 shared_ptr<CallBack> cb = make_shared<CallBack>(this);
88 return codec_->SetCallback(cb);
89 }
90
RunVideoServerDecoder()91 void VDecServerSample::RunVideoServerDecoder()
92 {
93 CreateHevcDecoderByName("OH.Media.Codec.Decoder.Video.HEVC", codec_);
94 if (codec_ == nullptr) {
95 cout << "Create failed" << endl;
96 return;
97 }
98 int32_t err = ConfigServerDecoder();
99 if (err != AVCS_ERR_OK) {
100 cout << "ConfigServerDecoder failed" << endl;
101 return;
102 }
103 signal_ = new VDecSignal();
104 if (signal_ == nullptr) {
105 cout << "Failed to new VDecSignal" << endl;
106 return;
107 }
108 err = SetCallback();
109 if (err != AVCS_ERR_OK) {
110 cout << "SetCallback failed" << endl;
111 return;
112 }
113 err = codec_->Start();
114 if (err != AVCS_ERR_OK) {
115 cout << "Start failed" << endl;
116 return;
117 }
118 isRunning_.store(true);
119 inputLoop_ = make_unique<thread>(&VDecServerSample::InputFunc, this);
120 if (inputLoop_ == nullptr) {
121 cout << "Failed to create input loop" << endl;
122 isRunning_.store(false);
123 }
124 }
125
InputFunc()126 void VDecServerSample::InputFunc()
127 {
128 while (sendFrameIndex < MAX_SEND_FRAMES) {
129 if (!isRunning_.load()) {
130 break;
131 }
132 unique_lock<mutex> lock(signal_->inMutex_);
133 signal_->inCond_.wait(lock, [this]() {
134 if (!isRunning_.load()) {
135 cout << "quit signal" << endl;
136 return true;
137 }
138 return signal_->inIdxQueue_.size() > 0;
139 });
140 if (!isRunning_.load()) {
141 break;
142 }
143 uint32_t index = signal_->inIdxQueue_.front();
144 auto buffer = signal_->inBufferQueue_.front();
145 signal_->inIdxQueue_.pop();
146 signal_->inBufferQueue_.pop();
147 lock.unlock();
148 if (buffer->memory_ == nullptr) {
149 isRunning_.store(false);
150 break;
151 }
152 uint8_t *bufferAddr = buffer->memory_->GetAddr();
153 if (memcpy_s(bufferAddr, buffer->memory_->GetCapacity(), fuzzData, fuzzSize) != EOK) {
154 break;
155 }
156 buffer->pts_ = TIME;
157 buffer->flag_ = 0;
158 buffer->memory_->SetOffset(0);
159 buffer->memory_->SetSize(fuzzSize);
160 int32_t err = codec_->QueueInputBuffer(index);
161 if (err != AVCS_ERR_OK) {
162 cout << "QueueInputBuffer fail" << endl;
163 break;
164 }
165 sendFrameIndex++;
166 }
167 }
168
WaitForEos()169 void VDecServerSample::WaitForEos()
170 {
171 if (inputLoop_ && inputLoop_->joinable()) {
172 inputLoop_->join();
173 }
174 }
175
GetOutputFormat()176 void VDecServerSample::GetOutputFormat()
177 {
178 Format fmt;
179 int32_t err = codec_->GetOutputFormat(fmt);
180 if (err != AVCS_ERR_OK) {
181 cout << "GetOutputFormat fail" << endl;
182 isRunning_.store(false);
183 signal_->inCond_.notify_all();
184 }
185 }
186
Flush()187 void VDecServerSample::Flush()
188 {
189 int32_t err = codec_->Flush();
190 if (err != AVCS_ERR_OK) {
191 cout << "Flush fail" << endl;
192 isRunning_.store(false);
193 signal_->inCond_.notify_all();
194 }
195 }
196
Reset()197 void VDecServerSample::Reset()
198 {
199 int32_t err = codec_->Reset();
200 if (err != AVCS_ERR_OK) {
201 cout << "Reset fail" << endl;
202 isRunning_.store(false);
203 signal_->inCond_.notify_all();
204 }
205 }