1 /*
2 * Copyright (c) 2020 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 "camera_kit.h"
17 #include "recorder.h"
18
19 #include <algorithm>
20 #include <cstring>
21 #include <fcntl.h>
22 #include <fstream>
23 #include <iostream>
24 #include <sstream>
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 using namespace std;
31 using namespace OHOS;
32 using namespace OHOS::Media;
33
SampleGetRecordFd()34 static int32_t SampleGetRecordFd()
35 {
36 struct timeval tv = {};
37 gettimeofday(&tv, nullptr);
38 struct tm *ltm = localtime(&tv.tv_sec);
39 int32_t fd = -1;
40 if (ltm != nullptr) {
41 ostringstream ss("Capture_");
42 ss << "Record" << ltm->tm_hour << "-" << ltm->tm_min << "-" << ltm->tm_sec << ".mp4";
43 fd = open(("/userdata/" + ss.str()).c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
44 cout << "Open "
45 << "/userdata/" << ss.str() << endl;
46
47 if (fd == -1) {
48 cout << "Open recorder file failed. strerr=" << strerror(errno) << endl;
49 }
50 }
51 return fd;
52 }
53
SampleSaveCapture(const char *p, uint32_t size)54 static void SampleSaveCapture(const char *p, uint32_t size)
55 {
56 cout << "Start saving picture" << endl;
57 struct timeval tv = {};
58 gettimeofday(&tv, nullptr);
59 struct tm *ltm = localtime(&tv.tv_sec);
60 if (ltm != nullptr) {
61 ostringstream ss("Capture_");
62 ss << "Capture" << ltm->tm_hour << "-" << ltm->tm_min << "-" << ltm->tm_sec << ".jpg";
63
64 ofstream pic("/userdata/" + ss.str(), ofstream::out | ofstream::trunc);
65 cout << "write " << size << " bytes" << endl;
66 pic.write(p, size);
67 pic.close();
68 cout << "Saving picture end" << endl;
69 }
70 }
71
SampleCreateRecorder()72 Recorder *SampleCreateRecorder()
73 {
74 int ret = 0;
75 int32_t sampleRate = 48000;
76 int32_t channelCount = 1;
77 AudioCodecFormat audioFormat = AAC_LC;
78 AudioSourceType inputSource = AUDIO_MIC;
79 int32_t audioEncodingBitRate = sampleRate;
80 VideoSourceType source = VIDEO_SOURCE_SURFACE_ES;
81 int32_t frameRate = 30;
82 double fps = 30;
83 int32_t rate = 4096;
84 int32_t sourceId = 0;
85 int32_t audioSourceId = 0;
86 int32_t width = 1920;
87 int32_t height = 1080;
88 VideoCodecFormat encoder = HEVC;
89 Recorder *recorder = new Recorder();
90 if ((ret = recorder->SetVideoSource(source, sourceId)) != SUCCESS) {
91 cout << "SetVideoSource failed." << ret << endl;
92 goto ERROR;
93 }
94 if ((ret = recorder->SetVideoEncoder(sourceId, encoder)) != SUCCESS) {
95 cout << "SetVideoEncoder failed." << ret << endl;
96 goto ERROR;
97 }
98 if ((ret = recorder->SetVideoSize(sourceId, width, height)) != SUCCESS) {
99 cout << "SetVideoSize failed." << ret << endl;
100 goto ERROR;
101 }
102 if ((ret = recorder->SetVideoFrameRate(sourceId, frameRate)) != SUCCESS) {
103 cout << "SetVideoFrameRate failed." << ret << endl;
104 goto ERROR;
105 }
106 if ((ret = recorder->SetVideoEncodingBitRate(sourceId, rate)) != SUCCESS) {
107 cout << "SetVideoEncodingBitRate failed." << ret << endl;
108 goto ERROR;
109 }
110 if ((ret = recorder->SetCaptureRate(sourceId, fps)) != SUCCESS) {
111 cout << "SetCaptureRate failed." << ret << endl;
112 goto ERROR;
113 }
114 if ((ret = recorder->SetAudioSource(inputSource, audioSourceId)) != SUCCESS) {
115 cout << "SetAudioSource failed." << ret << endl;
116 goto ERROR;
117 }
118 if ((ret = recorder->SetAudioEncoder(audioSourceId, audioFormat)) != SUCCESS) {
119 cout << "SetAudioEncoder failed." << ret << endl;
120 goto ERROR;
121 }
122 if ((ret = recorder->SetAudioSampleRate(audioSourceId, sampleRate)) != SUCCESS) {
123 cout << "SetAudioSampleRate failed." << ret << endl;
124 goto ERROR;
125 }
126 if ((ret = recorder->SetAudioChannels(audioSourceId, channelCount)) != SUCCESS) {
127 cout << "SetAudioChannels failed." << ret << endl;
128 goto ERROR;
129 }
130 if ((ret = recorder->SetAudioEncodingBitRate(audioSourceId, audioEncodingBitRate)) != SUCCESS) {
131 cout << "SetAudioEncodingBitRate failed." << ret << endl;
132 goto ERROR;
133 }
134 if ((ret = recorder->SetMaxDuration(36000)) != SUCCESS) { // 36000s=10h
135 cout << "SetAudioEncodingBitRate failed." << ret << endl;
136 goto ERROR;
137 }
138 return recorder;
139
140 ERROR:
141 delete recorder;
142 return nullptr;
143 }
144
145 class SampleFrameStateCallback : public FrameStateCallback {
146 void OnFrameFinished(Camera &camera, FrameConfig &fc, FrameResult &result) override
147 {
148 cout << "Receive frame complete inform." << endl;
149 if (fc.GetFrameConfigType() == FRAME_CONFIG_CAPTURE) {
150 cout << "Capture frame received." << endl;
151 list<Surface *> surfaceList = fc.GetSurfaces();
152 for (Surface *surface : surfaceList) {
153 SurfaceBuffer *buffer = surface->AcquireBuffer();
154 if (buffer != nullptr) {
155 char *virtAddr = static_cast<char *>(buffer->GetVirAddr());
156 if (virtAddr != nullptr) {
157 SampleSaveCapture(virtAddr, buffer->GetSize());
158 }
159 surface->ReleaseBuffer(buffer);
160 }
161 delete surface;
162 }
163 }
164 delete &fc;
165 }
166 };
167
168 class SampleCameraStateMng : public CameraStateCallback {
169 public:
170 SampleCameraStateMng() = delete;
SampleCameraStateMng(EventHandler &eventHdlr)171 SampleCameraStateMng(EventHandler &eventHdlr) : eventHdlr_(eventHdlr) {}
~SampleCameraStateMng()172 ~SampleCameraStateMng()
173 {
174 CloseRecorder();
175 }
176 void OnCreated(Camera &c) override
177 {
178 cout << "Sample recv OnCreate camera." << endl;
179 auto config = CameraConfig::CreateCameraConfig();
180 config->SetFrameStateCallback(&fsCb_, &eventHdlr_);
181 c.Configure(*config);
182 cam_ = &c;
183 }
184 void OnCreateFailed(const std::string cameraId, int32_t errorCode) override {}
185 void OnReleased(Camera &c) override {}
186
CloseRecorder()187 void CloseRecorder()
188 {
189 if (recorder_ != nullptr) {
190 recorder_->Stop(true);
191 recorder_->Release();
192 delete recorder_;
193 recorder_ = nullptr;
194 }
195 if (recordFd_ != -1) {
196 FILE *fp = fdopen(recordFd_, "w+");
197 if (fp) {
198 fflush(fp);
199 fsync(recordFd_);
200 fclose(fp);
201 close(recordFd_);
202 }
203 recordFd_ = -1;
204 }
205 }
206
PrepareRecorder()207 int PrepareRecorder()
208 {
209 if (cam_ == nullptr) {
210 cout << "Camera is not ready." << endl;
211 return -1;
212 }
213 if (recorder_ == nullptr) {
214 recorder_ = SampleCreateRecorder();
215 }
216 if (recorder_ == nullptr) {
217 cout << "Recorder not available." << endl;
218 return -1;
219 }
220 if (recordFd_ == -1) {
221 recordFd_ = SampleGetRecordFd();
222 }
223 if (recordFd_ == -1) {
224 cout << "Create fd failed." << endl;
225 return -1;
226 }
227 return SUCCESS;
228 }
229
StartRecord()230 void StartRecord()
231 {
232 if (recordState_ == STATE_RUNNING) {
233 cout << "Camera is already recording." << endl;
234 return;
235 }
236 int ret = PrepareRecorder();
237 if (ret != SUCCESS) {
238 cout << "PrepareRecorder failed." << endl;
239 CloseRecorder();
240 return;
241 }
242 ret = recorder_->SetOutputFile(recordFd_);
243 if (ret != SUCCESS) {
244 cout << "SetOutputPath failed. ret=" << ret << endl;
245 CloseRecorder();
246 return;
247 }
248 ret = recorder_->Prepare();
249 if (ret != SUCCESS) {
250 cout << "Prepare failed. ret=" << ret << endl;
251 CloseRecorder();
252 return;
253 }
254 ret = recorder_->Start();
255 if (ret != SUCCESS) {
256 cout << "recorder start failed. ret=" << ret << endl;
257 CloseRecorder();
258 return;
259 }
260 FrameConfig *fc = new FrameConfig(FRAME_CONFIG_RECORD);
261 auto surface = recorder_->GetSurface(0);
262 int width = 1920;
263 int height = 1080;
264 surface->SetWidthAndHeight(width, height);
265 int queueSize = 3;
266 surface->SetQueueSize(queueSize);
267 int size = 1024;
268 surface->SetSize(size * size);
269 fc->AddSurface(*surface);
270 ret = cam_->TriggerLoopingCapture(*fc);
271 if (ret != 0) {
272 delete fc;
273 CloseRecorder();
274 cout << "camera start recording failed. ret=" << ret << endl;
275 return;
276 }
277 recordState_ = STATE_RUNNING;
278 cout << "camera start recording succeed." << endl;
279 }
280
StartPreview()281 void StartPreview()
282 {
283 if (cam_ == nullptr) {
284 cout << "Camera is not ready." << endl;
285 return;
286 }
287 if (previewState_ == STATE_RUNNING) {
288 cout << "Camera is already previewing." << endl;
289 return;
290 }
291 FrameConfig *fc = new FrameConfig(FRAME_CONFIG_PREVIEW);
292 Surface *surface = Surface::CreateSurface();
293 if (surface == nullptr) {
294 delete fc;
295 cout << "CreateSurface failed" << endl;
296 return;
297 }
298 surface->SetWidthAndHeight(1920, 1080); /* 1920:width,1080:height */
299 surface->SetUserData("region_position_x", "0");
300 surface->SetUserData("region_position_y", "0");
301 surface->SetUserData("region_width", "480");
302 surface->SetUserData("region_height", "480");
303 fc->AddSurface(*surface);
304 int32_t ret = cam_->TriggerLoopingCapture(*fc);
305 if (ret != 0) {
306 delete fc;
307 cout << "camera start preview failed. ret=" << ret << endl;
308 return;
309 }
310 previewState_ = STATE_RUNNING;
311 cout << "camera start preview succeed." << endl;
312 }
Capture()313 void Capture()
314 {
315 if (cam_ == nullptr) {
316 cout << "Camera is not ready." << endl;
317 return;
318 }
319 FrameConfig *fc = new FrameConfig(FRAME_CONFIG_CAPTURE);
320 Surface *surface = Surface::CreateSurface();
321 if (surface == nullptr) {
322 delete fc;
323 cout << "CreateSurface failed" << endl;
324 return;
325 }
326 surface->SetWidthAndHeight(1920, 1080); /* 1920:width,1080:height */
327 fc->AddSurface(*surface);
328 cam_->TriggerSingleCapture(*fc);
329 }
Stop()330 void Stop()
331 {
332 if (cam_ == nullptr) {
333 cout << "Camera is not ready." << endl;
334 return;
335 }
336 cam_->StopLoopingCapture(-1);
337 if (recordState_ == STATE_RUNNING) {
338 CloseRecorder();
339 }
340 recordState_ = STATE_IDLE;
341 previewState_ = STATE_IDLE;
342 }
343
344 private:
345 enum State : int32_t { STATE_IDLE, STATE_RUNNING, STATE_BUTT };
346 State previewState_ = STATE_IDLE;
347 State recordState_ = STATE_IDLE;
348 EventHandler &eventHdlr_;
349 Camera *cam_ = nullptr;
350 int32_t recordFd_ = -1;
351 Recorder *recorder_ = nullptr;
352 SampleFrameStateCallback fsCb_;
353 };
354
355 class SampleCameraDeviceCallback : public CameraDeviceCallback {
356 };
357
SampleHelp()358 void SampleHelp()
359 {
360 cout << "*******************************************" << endl;
361 cout << "Select the behavior of avrecorder." << endl;
362 cout << "1: Capture" << endl;
363 cout << "2: Record(Press s to stop)" << endl;
364 cout << "3: Preview(Press s to stop)" << endl;
365 cout << "q: quit the sample." << endl;
366 cout << "*******************************************" << endl;
367 }
368
main()369 int main()
370 {
371 cout << "Camera sample begin." << endl;
372 SampleHelp();
373 CameraKit *camKit = CameraKit::GetInstance();
374 if (camKit == nullptr) {
375 cout << "Can not get CameraKit instance" << endl;
376 return 0;
377 }
378 list<string> camList = camKit->GetCameraIds();
379 string camId;
380 for (auto &cam : camList) {
381 camId = cam;
382 break;
383 }
384
385 if (camId.empty()) {
386 cout << "No available camera.(1080p wanted)" << endl;
387 return 0;
388 }
389
390 EventHandler eventHdlr; // Create a thread to handle callback events
391 SampleCameraStateMng CamStateMng(eventHdlr);
392
393 camKit->CreateCamera(camId, CamStateMng, eventHdlr);
394
395 char input;
396 while (cin >> input) {
397 switch (input) {
398 case '1':
399 CamStateMng.Capture();
400 break;
401 case '2':
402 CamStateMng.StartRecord();
403 break;
404 case '3':
405 CamStateMng.StartPreview();
406 break;
407 case 's':
408 CamStateMng.Stop();
409 break;
410 case 'q':
411 CamStateMng.Stop();
412 goto EXIT;
413 default:
414 SampleHelp();
415 break;
416 }
417 }
418 EXIT:
419 cout << "Camera sample end." << endl;
420 return 0;
421 }
422