/* * Copyright (c) 2020 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "camera_kit.h" #include "recorder.h" #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace OHOS; using namespace OHOS::Media; static int32_t SampleGetRecordFd() { struct timeval tv = {}; gettimeofday(&tv, nullptr); struct tm *ltm = localtime(&tv.tv_sec); int32_t fd = -1; if (ltm != nullptr) { ostringstream ss("Capture_"); ss << "Record" << ltm->tm_hour << "-" << ltm->tm_min << "-" << ltm->tm_sec << ".mp4"; fd = open(("/userdata/" + ss.str()).c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); cout << "Open " << "/userdata/" << ss.str() << endl; if (fd == -1) { cout << "Open recorder file failed. strerr=" << strerror(errno) << endl; } } return fd; } static void SampleSaveCapture(const char *p, uint32_t size) { cout << "Start saving picture" << endl; struct timeval tv = {}; gettimeofday(&tv, nullptr); struct tm *ltm = localtime(&tv.tv_sec); if (ltm != nullptr) { ostringstream ss("Capture_"); ss << "Capture" << ltm->tm_hour << "-" << ltm->tm_min << "-" << ltm->tm_sec << ".jpg"; ofstream pic("/userdata/" + ss.str(), ofstream::out | ofstream::trunc); cout << "write " << size << " bytes" << endl; pic.write(p, size); pic.close(); cout << "Saving picture end" << endl; } } Recorder *SampleCreateRecorder() { int ret = 0; int32_t sampleRate = 48000; int32_t channelCount = 1; AudioCodecFormat audioFormat = AAC_LC; AudioSourceType inputSource = AUDIO_MIC; int32_t audioEncodingBitRate = sampleRate; VideoSourceType source = VIDEO_SOURCE_SURFACE_ES; int32_t frameRate = 30; double fps = 30; int32_t rate = 4096; int32_t sourceId = 0; int32_t audioSourceId = 0; int32_t width = 1920; int32_t height = 1080; VideoCodecFormat encoder = HEVC; Recorder *recorder = new Recorder(); if ((ret = recorder->SetVideoSource(source, sourceId)) != SUCCESS) { cout << "SetVideoSource failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetVideoEncoder(sourceId, encoder)) != SUCCESS) { cout << "SetVideoEncoder failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetVideoSize(sourceId, width, height)) != SUCCESS) { cout << "SetVideoSize failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetVideoFrameRate(sourceId, frameRate)) != SUCCESS) { cout << "SetVideoFrameRate failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetVideoEncodingBitRate(sourceId, rate)) != SUCCESS) { cout << "SetVideoEncodingBitRate failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetCaptureRate(sourceId, fps)) != SUCCESS) { cout << "SetCaptureRate failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetAudioSource(inputSource, audioSourceId)) != SUCCESS) { cout << "SetAudioSource failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetAudioEncoder(audioSourceId, audioFormat)) != SUCCESS) { cout << "SetAudioEncoder failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetAudioSampleRate(audioSourceId, sampleRate)) != SUCCESS) { cout << "SetAudioSampleRate failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetAudioChannels(audioSourceId, channelCount)) != SUCCESS) { cout << "SetAudioChannels failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetAudioEncodingBitRate(audioSourceId, audioEncodingBitRate)) != SUCCESS) { cout << "SetAudioEncodingBitRate failed." << ret << endl; goto ERROR; } if ((ret = recorder->SetMaxDuration(36000)) != SUCCESS) { // 36000s=10h cout << "SetAudioEncodingBitRate failed." << ret << endl; goto ERROR; } return recorder; ERROR: delete recorder; return nullptr; } class SampleFrameStateCallback : public FrameStateCallback { void OnFrameFinished(Camera &camera, FrameConfig &fc, FrameResult &result) override { cout << "Receive frame complete inform." << endl; if (fc.GetFrameConfigType() == FRAME_CONFIG_CAPTURE) { cout << "Capture frame received." << endl; list surfaceList = fc.GetSurfaces(); for (Surface *surface : surfaceList) { SurfaceBuffer *buffer = surface->AcquireBuffer(); if (buffer != nullptr) { char *virtAddr = static_cast(buffer->GetVirAddr()); if (virtAddr != nullptr) { SampleSaveCapture(virtAddr, buffer->GetSize()); } surface->ReleaseBuffer(buffer); } delete surface; } } delete &fc; } }; class SampleCameraStateMng : public CameraStateCallback { public: SampleCameraStateMng() = delete; SampleCameraStateMng(EventHandler &eventHdlr) : eventHdlr_(eventHdlr) {} ~SampleCameraStateMng() { CloseRecorder(); } void OnCreated(Camera &c) override { cout << "Sample recv OnCreate camera." << endl; auto config = CameraConfig::CreateCameraConfig(); config->SetFrameStateCallback(&fsCb_, &eventHdlr_); c.Configure(*config); cam_ = &c; } void OnCreateFailed(const std::string cameraId, int32_t errorCode) override {} void OnReleased(Camera &c) override {} void CloseRecorder() { if (recorder_ != nullptr) { recorder_->Stop(true); recorder_->Release(); delete recorder_; recorder_ = nullptr; } if (recordFd_ != -1) { FILE *fp = fdopen(recordFd_, "w+"); if (fp) { fflush(fp); fsync(recordFd_); fclose(fp); close(recordFd_); } recordFd_ = -1; } } int PrepareRecorder() { if (cam_ == nullptr) { cout << "Camera is not ready." << endl; return -1; } if (recorder_ == nullptr) { recorder_ = SampleCreateRecorder(); } if (recorder_ == nullptr) { cout << "Recorder not available." << endl; return -1; } if (recordFd_ == -1) { recordFd_ = SampleGetRecordFd(); } if (recordFd_ == -1) { cout << "Create fd failed." << endl; return -1; } return SUCCESS; } void StartRecord() { if (recordState_ == STATE_RUNNING) { cout << "Camera is already recording." << endl; return; } int ret = PrepareRecorder(); if (ret != SUCCESS) { cout << "PrepareRecorder failed." << endl; CloseRecorder(); return; } ret = recorder_->SetOutputFile(recordFd_); if (ret != SUCCESS) { cout << "SetOutputPath failed. ret=" << ret << endl; CloseRecorder(); return; } ret = recorder_->Prepare(); if (ret != SUCCESS) { cout << "Prepare failed. ret=" << ret << endl; CloseRecorder(); return; } ret = recorder_->Start(); if (ret != SUCCESS) { cout << "recorder start failed. ret=" << ret << endl; CloseRecorder(); return; } FrameConfig *fc = new FrameConfig(FRAME_CONFIG_RECORD); auto surface = recorder_->GetSurface(0); int width = 1920; int height = 1080; surface->SetWidthAndHeight(width, height); int queueSize = 3; surface->SetQueueSize(queueSize); int size = 1024; surface->SetSize(size * size); fc->AddSurface(*surface); ret = cam_->TriggerLoopingCapture(*fc); if (ret != 0) { delete fc; CloseRecorder(); cout << "camera start recording failed. ret=" << ret << endl; return; } recordState_ = STATE_RUNNING; cout << "camera start recording succeed." << endl; } void StartPreview() { if (cam_ == nullptr) { cout << "Camera is not ready." << endl; return; } if (previewState_ == STATE_RUNNING) { cout << "Camera is already previewing." << endl; return; } FrameConfig *fc = new FrameConfig(FRAME_CONFIG_PREVIEW); Surface *surface = Surface::CreateSurface(); if (surface == nullptr) { delete fc; cout << "CreateSurface failed" << endl; return; } surface->SetWidthAndHeight(1920, 1080); /* 1920:width,1080:height */ surface->SetUserData("region_position_x", "0"); surface->SetUserData("region_position_y", "0"); surface->SetUserData("region_width", "480"); surface->SetUserData("region_height", "480"); fc->AddSurface(*surface); int32_t ret = cam_->TriggerLoopingCapture(*fc); if (ret != 0) { delete fc; cout << "camera start preview failed. ret=" << ret << endl; return; } previewState_ = STATE_RUNNING; cout << "camera start preview succeed." << endl; } void Capture() { if (cam_ == nullptr) { cout << "Camera is not ready." << endl; return; } FrameConfig *fc = new FrameConfig(FRAME_CONFIG_CAPTURE); Surface *surface = Surface::CreateSurface(); if (surface == nullptr) { delete fc; cout << "CreateSurface failed" << endl; return; } surface->SetWidthAndHeight(1920, 1080); /* 1920:width,1080:height */ fc->AddSurface(*surface); cam_->TriggerSingleCapture(*fc); } void Stop() { if (cam_ == nullptr) { cout << "Camera is not ready." << endl; return; } cam_->StopLoopingCapture(-1); if (recordState_ == STATE_RUNNING) { CloseRecorder(); } recordState_ = STATE_IDLE; previewState_ = STATE_IDLE; } private: enum State : int32_t { STATE_IDLE, STATE_RUNNING, STATE_BUTT }; State previewState_ = STATE_IDLE; State recordState_ = STATE_IDLE; EventHandler &eventHdlr_; Camera *cam_ = nullptr; int32_t recordFd_ = -1; Recorder *recorder_ = nullptr; SampleFrameStateCallback fsCb_; }; class SampleCameraDeviceCallback : public CameraDeviceCallback { }; void SampleHelp() { cout << "*******************************************" << endl; cout << "Select the behavior of avrecorder." << endl; cout << "1: Capture" << endl; cout << "2: Record(Press s to stop)" << endl; cout << "3: Preview(Press s to stop)" << endl; cout << "q: quit the sample." << endl; cout << "*******************************************" << endl; } int main() { cout << "Camera sample begin." << endl; SampleHelp(); CameraKit *camKit = CameraKit::GetInstance(); if (camKit == nullptr) { cout << "Can not get CameraKit instance" << endl; return 0; } list camList = camKit->GetCameraIds(); string camId; for (auto &cam : camList) { camId = cam; break; } if (camId.empty()) { cout << "No available camera.(1080p wanted)" << endl; return 0; } EventHandler eventHdlr; // Create a thread to handle callback events SampleCameraStateMng CamStateMng(eventHdlr); camKit->CreateCamera(camId, CamStateMng, eventHdlr); char input; while (cin >> input) { switch (input) { case '1': CamStateMng.Capture(); break; case '2': CamStateMng.StartRecord(); break; case '3': CamStateMng.StartPreview(); break; case 's': CamStateMng.Stop(); break; case 'q': CamStateMng.Stop(); goto EXIT; default: SampleHelp(); break; } } EXIT: cout << "Camera sample end." << endl; return 0; }