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
30using namespace std;
31using namespace OHOS;
32using namespace OHOS::Media;
33
34static 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
54static 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
72Recorder *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
140ERROR:
141    delete recorder;
142    return nullptr;
143}
144
145class 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
168class SampleCameraStateMng : public CameraStateCallback {
169public:
170    SampleCameraStateMng() = delete;
171    SampleCameraStateMng(EventHandler &eventHdlr) : eventHdlr_(eventHdlr) {}
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
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
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
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
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    }
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    }
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
344private:
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
355class SampleCameraDeviceCallback : public CameraDeviceCallback {
356};
357
358void 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
369int 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    }
418EXIT:
419    cout << "Camera sample end." << endl;
420    return 0;
421}
422