1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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 <fstream>
17 #include <iostream>
18 #include <thread>
19 #include "common/sharing_log.h"
20 #include "video_sink_decoder.h"
21
22 using namespace OHOS::Sharing;
23
24 namespace OHOS {
25 namespace Sharing {
26 constexpr int32_t START_CODE_OFFSET_ONE = -1;
27 constexpr int32_t START_CODE_OFFSET_SEC = -2;
28 constexpr int32_t START_CODE_OFFSET_THIRD = -3;
29 constexpr int32_t START_CODE_SIZE_FRAME = 4;
30 constexpr int32_t START_CODE_SIZE_SLICE = 3;
31 constexpr char START_CODE = 0x1;
32
33 class VideoSinkDecoderDemo : public VideoSinkDecoder,
34 public std::enable_shared_from_this<VideoSinkDecoderDemo> {
35 public:
VideoSinkDecoderDemo()36 VideoSinkDecoderDemo() : VideoSinkDecoder(1) {}
ReadOnePacket()37 DataBuffer::Ptr ReadOnePacket()
38 {
39 if (file_ == nullptr) {
40 file_ = std::make_unique<std::ifstream>();
41 file_->open("/data/public_file/640x480.h264", std::ios::in | std::ios::binary);
42 }
43
44 constexpr uint32_t bufferSize = 1000000;
45 auto fileBuffer = new char[bufferSize + 1];
46 memset(fileBuffer, 0, bufferSize + 1);
47 file_->read(fileBuffer, START_CODE_SIZE_FRAME);
48
49 if (file_->eof() || file_->fail()) {
50 SHARING_LOGD("read eof fail");
51 return nullptr;
52 }
53
54 char *temp = fileBuffer;
55 temp += START_CODE_SIZE_FRAME;
56 bool ret = true;
57 while (!file_->eof()) {
58 file_->read(temp, 1);
59 if (*temp == START_CODE) {
60 if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0) &&
61 (temp[START_CODE_OFFSET_THIRD] == 0)) {
62 file_->seekg(-START_CODE_SIZE_FRAME, std::ios_base::cur);
63 temp -= (START_CODE_SIZE_FRAME - 1);
64 ret = false;
65 break;
66 } else if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0)) {
67 file_->seekg(-START_CODE_SIZE_SLICE, std::ios_base::cur);
68 temp -= (START_CODE_SIZE_SLICE - 1);
69 ret = false;
70 break;
71 }
72 }
73 temp++;
74 }
75 auto size = (temp - fileBuffer);
76 if (size > 0) {
77 auto data = std::make_shared<DataBuffer>();
78 data->PushData(fileBuffer, size);
79 delete[] fileBuffer;
80 fileBuffer = nullptr;
81 return data;
82 }
83
84 delete[] fileBuffer;
85 fileBuffer = nullptr;
86 return nullptr;
87 }
88
PlayThread()89 void PlayThread()
90 {
91 while (!stop_) {
92 auto packetData = ReadOnePacket();
93 if (packetData) {
94 ProcessVideoData(packetData);
95 } else {
96 SHARING_LOGD("read null");
97 break;
98 }
99 }
100 }
101
ProcessVideoData(DataBuffer::Ptr data)102 void ProcessVideoData(DataBuffer::Ptr data)
103 {
104 int32_t bufferIndex = -1;
105 {
106 SHARING_LOGD("process video data");
107 std::unique_lock<std::mutex> lock(inMutex_);
108 SHARING_LOGD("process video data in");
109 if (inQueue_.empty()) {
110 while (!stop_) {
111 inCond_.wait_for(lock, std::chrono::milliseconds(DECODE_WAIT_MILLISECONDS),
112 [this]() { return (!inQueue_.empty()); });
113 if (inQueue_.empty()) {
114 SHARING_LOGD("index queue empty");
115 continue;
116 }
117 break;
118 }
119 }
120 SHARING_LOGD("process video data get buffer index");
121 bufferIndex = inQueue_.front();
122 inQueue_.pop();
123 }
124 SHARING_LOGD("process video data bufferIndex: %{public}d.", bufferIndex);
125 if (stop_) {
126 SHARING_LOGD("stop return");
127 return;
128 }
129
130 if (bufferIndex == -1) {
131 SHARING_LOGD("stop no process video data");
132 } else {
133 DecodeVideoData(data->Peek(), data->Size(), bufferIndex);
134 }
135 }
136
StartPlayThread()137 void StartPlayThread()
138 {
139 stop_ = false;
140 std::lock_guard<std::mutex> lock(playMutex_);
141 if (playThread_ != nullptr) {
142 SHARING_LOGD("play start thread already exist");
143 return;
144 }
145
146 playThread_ = std::make_shared<std::thread>(&VideoSinkDecoderDemo::PlayThread, this);
147 if (playThread_ == nullptr) {
148 SHARING_LOGE("play start create thread error");
149 }
150 }
151
StopPlayThread()152 void StopPlayThread()
153 {
154 SHARING_LOGD("trace");
155 stop_ = true;
156 std::lock_guard<std::mutex> lock(playMutex_);
157 SHARING_LOGD("wait play");
158 if (playThread_) {
159 if (playThread_->joinable()) {
160 playThread_->join();
161 }
162 playThread_ = nullptr;
163 }
164 SHARING_LOGD("stop play exit");
165 }
166
StartVideoDecoder()167 void StartVideoDecoder()
168 {
169 SHARING_LOGD("trace");
170 }
171
StopVideoDecoder()172 void StopVideoDecoder()
173 {
174 SHARING_LOGD("trace");
175 }
176
177 private:
178 std::atomic<bool> stop_ = true;
179 std::shared_ptr<std::thread> playThread_ = nullptr;
180 std::mutex playMutex_;
181 std::unique_ptr<std::ifstream> file_ = nullptr;
182 };
183 } // namespace Sharing
184 } // namespace OHOS
185
main()186 int main()
187 {
188 auto demo = std::make_shared<VideoSinkDecoderDemo>();
189 demo->StartVideoDecoder();
190 demo->StartPlayThread();
191 std::string inputCmd;
192 SHARING_LOGD("press [Enter] for stop");
193 getline(std::cin, inputCmd);
194 demo->StopVideoDecoder();
195 demo->StopPlayThread();
196
197 return 0;
198 }