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