• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.test.silkfx.hdr
18 
19 import android.graphics.Gainmap
20 import android.view.Gravity
21 import android.view.LayoutInflater
22 import android.view.View
23 import android.view.ViewGroup
24 import android.widget.Button
25 import android.widget.PopupWindow
26 import android.widget.SeekBar
27 import android.widget.TextView
28 import com.android.test.silkfx.R
29 
30 data class GainmapMetadata(
31     var ratioMin: Float,
32     var ratioMax: Float,
33     var capacityMin: Float,
34     var capacityMax: Float,
35     var gamma: Float,
36     var offsetSdr: Float,
37     var offsetHdr: Float
38 )
39 
40 class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
41     private var gainmap: Gainmap? = null
42     private var showingEdits = false
43 
44     private var metadataPopup: PopupWindow? = null
45 
46     private var originalMetadata: GainmapMetadata = GainmapMetadata(
47         1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f)
48     private var currentMetadata: GainmapMetadata = originalMetadata.copy()
49 
50     private val maxProgress = 100.0f
51 
52     private val minRatioMin = .001f
53     private val maxRatioMin = 1.0f
54     private val minRatioMax = 1.0f
55     private val maxRatioMax = 16.0f
56     private val minCapacityMin = 1.0f
57     private val maxCapacityMin = maxRatioMax
58     private val minCapacityMax = 1.001f
59     private val maxCapacityMax = maxRatioMax
60     private val minGamma = 0.1f
61     private val maxGamma = 3.0f
62     // Min and max offsets are 0.0 and 1.0 respectively
63 
setGainmapnull64     fun setGainmap(newGainmap: Gainmap?) {
65         gainmap = newGainmap
66         originalMetadata = GainmapMetadata(gainmap!!.getRatioMin()[0],
67             gainmap!!.getRatioMax()[0], gainmap!!.getMinDisplayRatioForHdrTransition(),
68             gainmap!!.getDisplayRatioForFullHdr(), gainmap!!.getGamma()[0],
69             gainmap!!.getEpsilonSdr()[0], gainmap!!.getEpsilonHdr()[0])
70         currentMetadata = originalMetadata.copy()
71     }
72 
useOriginalMetadatanull73     fun useOriginalMetadata() {
74         showingEdits = false
75         applyMetadata(originalMetadata)
76     }
77 
useEditMetadatanull78     fun useEditMetadata() {
79         showingEdits = true
80         applyMetadata(currentMetadata)
81     }
82 
closeEditornull83     fun closeEditor() {
84         metadataPopup?.let {
85             it.dismiss()
86             metadataPopup = null
87         }
88     }
89 
openEditornull90     fun openEditor() {
91         if (metadataPopup != null) return
92 
93         val view = LayoutInflater.from(parent.getContext()).inflate(R.layout.gainmap_metadata, null)
94 
95         metadataPopup = PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT,
96             ViewGroup.LayoutParams.WRAP_CONTENT)
97         metadataPopup!!.showAtLocation(view, Gravity.CENTER, 0, 0)
98 
99         (view.getParent() as ViewGroup).removeView(view)
100         parent.addView(view)
101 
102         view.findViewById<Button>(R.id.gainmap_metadata_done)!!.setOnClickListener {
103             closeEditor()
104         }
105 
106         view.findViewById<Button>(R.id.gainmap_metadata_reset)!!.setOnClickListener {
107             resetGainmapMetadata()
108         }
109 
110         updateMetadataUi()
111 
112         val gainmapMinSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmin)
113         val gainmapMaxSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmax)
114         val capacityMinSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymin)
115         val capacityMaxSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymax)
116         val gammaSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gamma)
117         val offsetSdrSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_offsetsdr)
118         val offsetHdrSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_offsethdr)
119         arrayOf(gainmapMinSeek, gainmapMaxSeek, capacityMinSeek, capacityMaxSeek, gammaSeek,
120             offsetSdrSeek, offsetHdrSeek).forEach {
121             it.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
122                 override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
123                     if (!fromUser) return
124                     val normalized = progress.toFloat() / maxProgress
125                     when (seekBar) {
126                         gainmapMinSeek -> updateGainmapMin(normalized)
127                         gainmapMaxSeek -> updateGainmapMax(normalized)
128                         capacityMinSeek -> updateCapacityMin(normalized)
129                         capacityMaxSeek -> updateCapacityMax(normalized)
130                         gammaSeek -> updateGamma(normalized)
131                         offsetSdrSeek -> updateOffsetSdr(normalized)
132                         offsetHdrSeek -> updateOffsetHdr(normalized)
133                     }
134                 }
135 
136                 override fun onStartTrackingTouch(seekBar: SeekBar) {}
137                 override fun onStopTrackingTouch(seekBar: SeekBar) {}
138             })
139         }
140     }
141 
updateMetadataUinull142     private fun updateMetadataUi() {
143         val gainmapMinSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmin)
144         val gainmapMaxSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmax)
145         val capacityMinSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymin)
146         val capacityMaxSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymax)
147         val gammaSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gamma)
148         val offsetSdrSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_offsetsdr)
149         val offsetHdrSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_offsethdr)
150 
151         gainmapMinSeek.setProgress(
152             ((currentMetadata.ratioMin - minRatioMin) / maxRatioMin * maxProgress).toInt())
153         gainmapMaxSeek.setProgress(
154             ((currentMetadata.ratioMax - minRatioMax) / maxRatioMax * maxProgress).toInt())
155         capacityMinSeek.setProgress(
156             ((currentMetadata.capacityMin - minCapacityMin) / maxCapacityMin * maxProgress).toInt())
157         capacityMaxSeek.setProgress(
158             ((currentMetadata.capacityMax - minCapacityMax) / maxCapacityMax * maxProgress).toInt())
159         gammaSeek.setProgress(
160             ((currentMetadata.gamma - minGamma) / maxGamma * maxProgress).toInt())
161         // Log base 3 via: log_b(x) = log_y(x) / log_y(b)
162         offsetSdrSeek.setProgress(
163             ((1.0 - Math.log(currentMetadata.offsetSdr.toDouble() / Math.log(3.0)) / -11.0)
164              .toFloat() * maxProgress).toInt())
165         offsetHdrSeek.setProgress(
166             ((1.0 - Math.log(currentMetadata.offsetHdr.toDouble() / Math.log(3.0)) / -11.0)
167              .toFloat() * maxProgress).toInt())
168 
169         parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmin_val)!!.setText(
170             "%.3f".format(currentMetadata.ratioMin))
171         parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmax_val)!!.setText(
172             "%.3f".format(currentMetadata.ratioMax))
173         parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymin_val)!!.setText(
174             "%.3f".format(currentMetadata.capacityMin))
175         parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymax_val)!!.setText(
176             "%.3f".format(currentMetadata.capacityMax))
177         parent.findViewById<TextView>(R.id.gainmap_metadata_gamma_val)!!.setText(
178             "%.3f".format(currentMetadata.gamma))
179         parent.findViewById<TextView>(R.id.gainmap_metadata_offsetsdr_val)!!.setText(
180             "%.5f".format(currentMetadata.offsetSdr))
181         parent.findViewById<TextView>(R.id.gainmap_metadata_offsethdr_val)!!.setText(
182             "%.5f".format(currentMetadata.offsetHdr))
183     }
184 
resetGainmapMetadatanull185     private fun resetGainmapMetadata() {
186         currentMetadata = originalMetadata.copy()
187         applyMetadata(currentMetadata)
188         updateMetadataUi()
189     }
190 
applyMetadatanull191     private fun applyMetadata(newMetadata: GainmapMetadata) {
192         gainmap!!.setRatioMin(newMetadata.ratioMin, newMetadata.ratioMin, newMetadata.ratioMin)
193         gainmap!!.setRatioMax(newMetadata.ratioMax, newMetadata.ratioMax, newMetadata.ratioMax)
194         gainmap!!.setMinDisplayRatioForHdrTransition(newMetadata.capacityMin)
195         gainmap!!.setDisplayRatioForFullHdr(newMetadata.capacityMax)
196         gainmap!!.setGamma(newMetadata.gamma, newMetadata.gamma, newMetadata.gamma)
197         gainmap!!.setEpsilonSdr(newMetadata.offsetSdr, newMetadata.offsetSdr, newMetadata.offsetSdr)
198         gainmap!!.setEpsilonHdr(newMetadata.offsetHdr, newMetadata.offsetHdr, newMetadata.offsetHdr)
199         renderView.invalidate()
200     }
201 
updateGainmapMinnull202     private fun updateGainmapMin(normalized: Float) {
203         val newValue = minRatioMin + normalized * (maxRatioMin - minRatioMin)
204         parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmin_val)!!.setText(
205             "%.3f".format(newValue))
206         currentMetadata.ratioMin = newValue
207         if (showingEdits) {
208             gainmap!!.setRatioMin(newValue, newValue, newValue)
209             renderView.invalidate()
210         }
211     }
212 
updateGainmapMaxnull213     private fun updateGainmapMax(normalized: Float) {
214         val newValue = minRatioMax + normalized * (maxRatioMax - minRatioMax)
215         parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmax_val)!!.setText(
216             "%.3f".format(newValue))
217         currentMetadata.ratioMax = newValue
218         if (showingEdits) {
219             gainmap!!.setRatioMax(newValue, newValue, newValue)
220             renderView.invalidate()
221         }
222     }
223 
updateCapacityMinnull224     private fun updateCapacityMin(normalized: Float) {
225         val newValue = minCapacityMin + normalized * (maxCapacityMin - minCapacityMin)
226         parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymin_val)!!.setText(
227             "%.3f".format(newValue))
228         currentMetadata.capacityMin = newValue
229         if (showingEdits) {
230             gainmap!!.setMinDisplayRatioForHdrTransition(newValue)
231             renderView.invalidate()
232         }
233     }
234 
updateCapacityMaxnull235     private fun updateCapacityMax(normalized: Float) {
236         val newValue = minCapacityMax + normalized * (maxCapacityMax - minCapacityMax)
237         parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymax_val)!!.setText(
238             "%.3f".format(newValue))
239         currentMetadata.capacityMax = newValue
240         if (showingEdits) {
241             gainmap!!.setDisplayRatioForFullHdr(newValue)
242             renderView.invalidate()
243         }
244     }
245 
updateGammanull246     private fun updateGamma(normalized: Float) {
247         val newValue = minGamma + normalized * (maxGamma - minGamma)
248         parent.findViewById<TextView>(R.id.gainmap_metadata_gamma_val)!!.setText(
249             "%.3f".format(newValue))
250         currentMetadata.gamma = newValue
251         if (showingEdits) {
252             gainmap!!.setGamma(newValue, newValue, newValue)
253             renderView.invalidate()
254         }
255     }
256 
updateOffsetSdrnull257     private fun updateOffsetSdr(normalized: Float) {
258         var newValue = 0.0f
259         if (normalized > 0.0f ) {
260             newValue = Math.pow(3.0, (1.0 - normalized.toDouble()) * -11.0).toFloat()
261         }
262         parent.findViewById<TextView>(R.id.gainmap_metadata_offsetsdr_val)!!.setText(
263             "%.5f".format(newValue))
264         currentMetadata.offsetSdr = newValue
265         if (showingEdits) {
266             gainmap!!.setEpsilonSdr(newValue, newValue, newValue)
267             renderView.invalidate()
268         }
269     }
270 
updateOffsetHdrnull271     private fun updateOffsetHdr(normalized: Float) {
272         var newValue = 0.0f
273         if (normalized > 0.0f ) {
274             newValue = Math.pow(3.0, (1.0 - normalized.toDouble()) * -11.0).toFloat()
275         }
276         parent.findViewById<TextView>(R.id.gainmap_metadata_offsethdr_val)!!.setText(
277             "%.5f".format(newValue))
278         currentMetadata.offsetHdr = newValue
279         if (showingEdits) {
280             gainmap!!.setEpsilonHdr(newValue, newValue, newValue)
281             renderView.invalidate()
282         }
283     }
284 }
285