1 /*
2  * Copyright (c) 2023 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, Hardware
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 <algorithm>
17 #include <cstdio>
18 #include <ctime>
19 #include <iostream>
20 #include <string>
21 #include <securec.h>
22 #include <sys/time.h>
23 
24 #include "png.h"
25 #include "pipeline/rs_surface_capture_task.h"
26 #include "transaction/rs_interfaces.h"
27 
28 using namespace OHOS::Rosen;
29 using namespace OHOS::Media;
30 using namespace std;
31 
32 class SurfaceCaptureFuture : public SurfaceCaptureCallback {
33     public:
34          SurfaceCaptureFuture() = default;
~SurfaceCaptureFuture()35         ~SurfaceCaptureFuture() {};
OnSurfaceCapture(shared_ptr<PixelMap> pixelmap)36         void OnSurfaceCapture(shared_ptr<PixelMap> pixelmap) override
37         {
38             pixelMap_ = pixelmap;
39         }
GetPixelMap()40         shared_ptr<PixelMap> GetPixelMap()
41         {
42             return pixelMap_;
43         }
44     private:
45         shared_ptr<PixelMap> pixelMap_ = nullptr;
46 };
47 
48 const char *SNAPSHOT_PATH = "/data/surface_";
49 const char *SNAPSHOT_SUFFIX = ".png";
50 constexpr int MAX_TIME_STR_LEN = 40;
51 constexpr int YEAR_SINCE = 1900;
52 constexpr int BITMAP_DEPTH = 8;
53 
GenerateFileName()54 string GenerateFileName()
55 {
56     timeval tv;
57     string fileName = SNAPSHOT_PATH;
58 
59     if (gettimeofday(&tv, nullptr) == 0) {
60         struct tm *tmVal = localtime(&tv.tv_sec);
61         if (tmVal != nullptr) {
62             char timeStr[MAX_TIME_STR_LEN] = { 0 };
63             snprintf_s(timeStr, sizeof(timeStr), sizeof(timeStr) - 1,
64                 "%04d-%02d-%02d_%02d-%02d-%02d",
65                 tmVal->tm_year + YEAR_SINCE, tmVal->tm_mon + 1, tmVal->tm_mday,
66                 tmVal->tm_hour, tmVal->tm_min, tmVal->tm_sec);
67             fileName += timeStr;
68         }
69     }
70     fileName += SNAPSHOT_SUFFIX;
71     return fileName;
72 }
73 
WriteToPng(const std::string & filename,const WriteToPngParam & param)74 bool WriteToPng(const std::string &filename, const WriteToPngParam &param)
75 {
76     if (filename.empty()) {
77         RS_LOGI("WriteToPng filename is empty");
78         return false;
79     }
80     RS_LOGI("WriteToPng filename = %{public}s", filename.c_str());
81     png_structp pngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
82     if (pngStruct == nullptr) {
83         return false;
84     }
85     png_infop pngInfo = png_create_info_struct(pngStruct);
86     if (pngInfo == nullptr) {
87         png_destroy_write_struct(&pngStruct, nullptr);
88         return false;
89     }
90 
91     FILE *fp = fopen(filename.c_str(), "wb");
92     if (fp == nullptr) {
93         png_destroy_write_struct(&pngStruct, &pngInfo);
94         return false;
95     }
96     png_init_io(pngStruct, fp);
97 
98     // set png header
99     png_set_IHDR(pngStruct, pngInfo,
100         param.width, param.height,
101         param.bitDepth,
102         PNG_COLOR_TYPE_RGBA,
103         PNG_INTERLACE_NONE,
104         PNG_COMPRESSION_TYPE_BASE,
105         PNG_FILTER_TYPE_BASE);
106     png_set_packing(pngStruct); // set packing info
107     png_write_info(pngStruct, pngInfo); // write to header
108 
109     for (uint32_t i = 0; i < param.height; i++) {
110         png_write_row(pngStruct, param.data + (i * param.stride));
111     }
112     png_write_end(pngStruct, pngInfo);
113 
114     // free
115     png_destroy_write_struct(&pngStruct, &pngInfo);
116     int ret = fclose(fp);
117     return ret == 0;
118 }
119 
WritePixelMapToPng(PixelMap & pixelMap,std::string filename)120 bool WritePixelMapToPng(PixelMap& pixelMap, std::string filename)
121 {
122     struct timeval now;
123     gettimeofday(&now, nullptr);
124     constexpr int secToUsec = 1000 * 1000;
125     int64_t nowVal =  static_cast<int64_t>(now.tv_sec) * secToUsec + static_cast<int64_t>(now.tv_usec);
126     if (filename.size() == 0) {
127         filename = "/data/PixelMap_" + std::to_string(nowVal) + ".png";
128     }
129 
130     WriteToPngParam param;
131     param.width = static_cast<uint32_t>(pixelMap.GetWidth());
132     param.height = static_cast<uint32_t>(pixelMap.GetHeight());
133     param.data = pixelMap.GetPixels();
134     param.stride = static_cast<uint32_t>(pixelMap.GetRowBytes());
135     param.bitDepth = BITMAP_DEPTH;
136 
137     return WriteToPng(filename, param);
138 }
139 
main()140 int main()
141 {
142     cout << "Please input surfacenode id: ";
143     uint64_t input;
144     cin >> input;
145     shared_ptr<SurfaceCaptureFuture> callback = make_shared<SurfaceCaptureFuture>();
146     RSSurfaceCaptureConfig captureConfig;
147     RSInterfaces::GetInstance().TakeSurfaceCapture(input, callback, captureConfig);
148     sleep(2);
149     shared_ptr<PixelMap> pixelmap = callback->GetPixelMap();
150     if (pixelmap == nullptr) {
151         cout << "pixelmap is nullptr" << endl;
152         return 0;
153     }
154     string filename = GenerateFileName();
155     bool ret = WritePixelMapToPng(*pixelmap, filename);
156     if (ret) {
157         cout << "success: snapshot surface " << input << " , write to " << filename.c_str() << endl;
158     } else {
159         cout << "error: snapshot surface " << input << endl;
160     }
161     return 0;
162 }