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, 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 <fstream>
17 #include <map>
18 #include <securec.h>
19 #include "ext_stream.h"
20 #include "file_source_stream.h"
21 #include "v1_0/display_buffer_type.h"
22 #include "mock_jpeg_hw_decode_flow.h"
23 
24 namespace OHOS::ImagePlugin {
25 using namespace OHOS::HDI::Codec::Image::V2_0;
26 using namespace OHOS::HDI::Display::Buffer::V1_0;
27 
JpegHwDecoderFlow()28 JpegHwDecoderFlow::JpegHwDecoderFlow() : sampleSize_(1), outputColorFmt_(PIXEL_FMT_YCRCB_420_SP)
29 {
30     bufferMgr_ = IDisplayBuffer::Get();
31     outputBuffer_.id = 0;
32     outputBuffer_.size = 0;
33     outputBuffer_.buffer = nullptr;
34     outputBuffer_.fenceFd = -1;
35     outputBuffer_.bufferRole = CODEC_IMAGE_JPEG;
36 }
37 
~JpegHwDecoderFlow()38 JpegHwDecoderFlow::~JpegHwDecoderFlow()
39 {
40     bufferMgr_ = nullptr;
41 }
42 
AllocOutputBuffer()43 bool JpegHwDecoderFlow::AllocOutputBuffer()
44 {
45     AllocInfo alloc = {
46         .width = scaledImgSize_.width,
47         .height = scaledImgSize_.height,
48         .usage =  HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA,
49         .format = outputColorFmt_
50     };
51     BufferHandle *handle = nullptr;
52     int32_t ret = bufferMgr_->AllocMem(alloc, handle);
53     if (ret != HDF_SUCCESS) {
54         JPEG_HW_LOGE("failed to alloc output buffer, err=%{public}d", ret);
55         return false;
56     }
57     if (outputColorFmt_ == PIXEL_FMT_RGBA_8888) {
58         static constexpr uint32_t bitDepthForRgba = 4;
59         outputBufferSize_.width = static_cast<int32_t>((handle->stride) / bitDepthForRgba);
60     } else { // PIXEL_FMT_YCRCB_420_SP
61         outputBufferSize_.width = static_cast<int32_t>(handle->stride);
62     }
63     outputBufferSize_.height = static_cast<int32_t>(handle->height);
64     outputBuffer_.buffer = new NativeBuffer(handle);
65     return true;
66 }
67 
DoDecode()68 bool JpegHwDecoderFlow::DoDecode()
69 {
70     std::unique_ptr<Media::SourceStream> stream = Media::FileSourceStream::CreateSourceStream(inputFile_);
71     ImagePlugin::InputDataStream* inputStream = stream.get();
72     std::unique_ptr<SkCodec> demoCodec = SkCodec::MakeFromStream(std::make_unique<ExtStream>(inputStream));
73     JpegHardwareDecoder hwDecoder;
74     auto ret = hwDecoder.Decode(demoCodec.get(), inputStream, orgImgSize_, sampleSize_, outputBuffer_);
75     if (ret != 0) {
76         JPEG_HW_LOGE("failed to do jpeg hardware decode, err=%{public}u", ret);
77         return false;
78     }
79     return true;
80 }
81 
DumpDecodeResult()82 bool JpegHwDecoderFlow::DumpDecodeResult()
83 {
84     JPEG_HW_LOGI("dump decode result");
85     auto getColorDesc = [this]()->std::string {
86         if (outputColorFmt_ == PIXEL_FMT_YCRCB_420_SP) {
87             return "YUV";
88         } else if (outputColorFmt_ == PIXEL_FMT_RGBA_8888) {
89             return "RGB";
90         }
91         return "UnknownColorFormat";
92     };
93 
94     constexpr int maxPathLen = 256;
95     char outputFilePath[maxPathLen] = {0};
96     std::string colorDesc = getColorDesc();
97     int ret = sprintf_s(outputFilePath, sizeof(outputFilePath), "%s/out_%d(%d)x%d_org_%dx%d_%s.bin",
98                         outputPath_.c_str(), scaledImgSize_.width, outputBufferSize_.width, scaledImgSize_.height,
99                         orgImgSize_.width, orgImgSize_.height, colorDesc.c_str());
100     if (ret == -1) {
101         JPEG_HW_LOGE("failed to create dump file");
102         return false;
103     }
104 
105     std::ofstream dumpOutFile;
106     dumpOutFile.open(std::string(outputFilePath), std::ios_base::binary | std::ios_base::trunc);
107     if (!dumpOutFile.is_open()) {
108         JPEG_HW_LOGE("failed to dump decode result");
109         return false;
110     }
111 
112     BufferHandle *outputHandle = outputBuffer_.buffer->GetBufferHandle();
113     bufferMgr_->Mmap(*outputHandle);
114     (void)bufferMgr_->InvalidateCache(*outputHandle);
115     dumpOutFile.write(reinterpret_cast<char*>(outputHandle->virAddr), outputHandle->size);
116     dumpOutFile.flush();
117     (void)bufferMgr_->FlushCache(*outputHandle);
118     (void)bufferMgr_->Unmap(*outputHandle);
119     dumpOutFile.close();
120     return true;
121 }
122 
UserColorFmtToPixelFmt(UserColorFormat usrColorFmt)123 std::optional<PixelFormat> JpegHwDecoderFlow::UserColorFmtToPixelFmt(UserColorFormat usrColorFmt)
124 {
125     static const std::map<UserColorFormat, PixelFormat> colorMap = {
126         { UserColorFormat::YUV, PIXEL_FMT_YCRCB_420_SP },
127         { UserColorFormat::RGB, PIXEL_FMT_RGBA_8888 }
128     };
129     auto iter = colorMap.find(usrColorFmt);
130     if (iter == colorMap.end()) {
131         JPEG_HW_LOGE("unsupported color format(%{public}d)", static_cast<int>(usrColorFmt));
132         return std::nullopt;
133     }
134     return iter->second;
135 }
136 
Run(const CommandOpt & opt,bool needDumpOutput)137 bool JpegHwDecoderFlow::Run(const CommandOpt& opt, bool needDumpOutput)
138 {
139     JPEG_HW_LOGI("jpeg hardware decode demo start");
140     std::optional<PixelFormat> colorFmt = UserColorFmtToPixelFmt(opt.colorFmt);
141     if (!colorFmt.has_value()) {
142         JPEG_HW_LOGE("jpeg hardware decode demo failed");
143         return false;
144     }
145     inputFile_ = opt.inputFile;
146     outputPath_ = opt.outputPath;
147     outputColorFmt_ = colorFmt.value();
148     orgImgSize_.width = opt.width;
149     orgImgSize_.height = opt.height;
150     sampleSize_ = opt.sampleSize;
151     scaledImgSize_.width = static_cast<int32_t>(AlignUp(opt.width / opt.sampleSize, ALIGN_8));
152     scaledImgSize_.height = static_cast<int32_t>(AlignUp(opt.height / opt.sampleSize, ALIGN_8));
153     JPEG_HW_LOGD("orgImgSize=[%{public}ux%{public}u], scaledImgSize=[%{public}ux%{public}u], sampleSize=%{public}u",
154                  orgImgSize_.width, orgImgSize_.height, scaledImgSize_.width, scaledImgSize_.height, sampleSize_);
155 
156     bool ret = AllocOutputBuffer();
157     ret = ret && DoDecode();
158     if (needDumpOutput) {
159         ret = ret && DumpDecodeResult();
160     }
161     if (ret) {
162         JPEG_HW_LOGI("jpeg hardware decode demo succeed");
163     } else {
164         JPEG_HW_LOGE("jpeg hardware decode demo failed");
165     }
166     return ret;
167 }
168 } // namespace OHOS::ImagePlugin