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