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 }