Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sample] [Media] - Implementation of "UltraHDR to HDR Video" #83

Merged
merged 7 commits into from
Aug 21, 2023
Next Next commit
Testing Implementation for UltraHDR to HDR Video
  • Loading branch information
madebymozart committed Aug 7, 2023
commit d4daae5bdbc486b277c963d736042441da13c1b5
14 changes: 11 additions & 3 deletions .idea/runConfigurations/app.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ androidxTestExtTruth = "1.5.0"
androidxTestRules = "1.5.0"
androidxTestRunner = "1.5.2"
androidxUiAutomator = "2.2.0"
media3 = "1.0.2"
media3 = "1.1.0"

[libraries]

Expand Down
2 changes: 2 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ The sample demonstrates the importance of having proper labels for
buildSpannedString is useful for quickly building a rich text.
- [UltraHDR Image Capture](camera/camera2/src/main/java/com/example/platform/camera/imagecapture/Camera2UltraHDRCapture.kt):
This sample demonstrates how to capture a 10-bit compressed still image and
- [UltraHDR to HDR Video](media/ultrahdr/src/main/java/com/example/platform/media/ultrahdr/video/UltraHDRToHDRVideo.kt):
This sample demonstrates converting a series of UltraHDR images into a
- [Visualizing an UltraHDR Gainmap](graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/display/VisualizingAnUltraHDRGainmap.kt):
This sample demonstrates visualizing the underlying gainmap of an UltraHDR
- [WindowInsetsAnimation](user-interface/window-insets/src/main/java/com/example/platform/ui/insets/WindowInsetsAnimation.kt):
Expand Down
4 changes: 2 additions & 2 deletions samples/graphics/ultrahdr/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# UltraHDR Samples
# UltraHDR Graphics Samples

This is a catalog of graphics related UltraHDR samples that demonstrate the usage and capabilities of UltraHDR images on the Android Platform

> 🚧 **Work-in-Progress:** We are activtly working on bringing more UltraHDR samples
> 🚧 **Work-in-Progress:** We are actively working on bringing more UltraHDR samples

Check out the UltraHDR HDR specifications at https://developer.android.com/guide/topics/media/hdr-image-format

Expand Down
3 changes: 3 additions & 0 deletions samples/graphics/ultrahdr/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
<string name="visualizing_ultrahdr_gainmap_mode_title_ultrahdr">UltraHDR</string>
<string name="visualizing_ultrahdr_gainmap_mode_title_no_ultrahdr">Not UltraHDR</string>

<!-- UltraHDR to HDR Video String -->
<string name="ultrahdr_to_hdr_video_button_covert">Convert To Video</string>

<!-- ColorModeControls Strings -->
<string name="color_mode_sdr">SDR</string>
<string name="color_mode_hdr">HDR</string>
Expand Down
24 changes: 24 additions & 0 deletions samples/media/ultrahdr/README.md
marcelpinto marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# UltraHDR Media Samples

This is a catalog of media related UltraHDR samples that demonstrate the usage and capabilities of UltraHDR images on the Android Platform

> 🚧 **Work-in-Progress:** We are actively working on bringing more UltraHDR samples

Check out the UltraHDR HDR specifications at https://developer.android.com/guide/topics/media/hdr-image-format

## License
```
Copyright 2023 The Android Open Source Project

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

https://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.
```
36 changes: 36 additions & 0 deletions samples/media/ultrahdr/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2023 The Android Open Source Project
*
* 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
*
* https://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.
*/


plugins {
id("com.example.platform.sample")
}

android {
namespace = "com.example.platform.media.ultrahdr"
viewBinding.isEnabled = true
}

dependencies {
// Media3 Ui
implementation(libs.androidx.media3.ui)

// Media3 ExoPlayer
implementation(libs.androidx.media3.exoplayer)

// Link to UltraHDR Graphics Samples
implementation(project(mapOf("path" to ":samples:graphics:ultrahdr")))
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* Copyright 2023 The Android Open Source Project
*
* 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
*
* https://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.
*/

package com.example.platform.media.ultrahdr.video

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ColorSpace
import android.graphics.HardwareBufferRenderer
import android.graphics.RenderNode
import android.hardware.DataSpace
import android.hardware.HardwareBuffer
import android.media.Image
import android.media.ImageWriter
import android.media.MediaCodec
import android.media.MediaCodecList
import android.media.MediaFormat
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Surface
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.compose.ui.graphics.asImageBitmap
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.example.platform.media.ultrahdr.databinding.UltrahdrToHdrVideoBinding
import com.google.android.catalog.framework.annotations.Sample
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.CountDownLatch


@Sample(
name = "UltraHDR to HDR Video",
description = "This sample demonstrates converting a series of UltraHDR images into a " +
"10-bit HDR video",
documentation = "https://developer.android.com/guide/topics/media/hdr-image-format",
tags = ["UltraHDR"],
)
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
class UltraHDRToHDRVideo : Fragment() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider moving the concurrency and processing bits into a separate state holder class. As it stands, the UI and its state are really strongly coupled.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered using Compose? It is required that all new samples are written in Compose.

/**
* Android ViewBinding.
*/
private var _binding: UltrahdrToHdrVideoBinding? = null
private val binding get() = _binding!!

/**
* [MediaCodec] encoder that will be used to encode the video.
*/
private val encoder: MediaCodec by lazy {
val format = MediaFormat.createVideoFormat(
MediaFormat.MIMETYPE_VIDEO_HEVC,
1920,
1080,
)

val codecName = MediaCodecList(MediaCodecList.ALL_CODECS).findEncoderForFormat(format)
MediaCodec.createEncoderByType(codecName)
}

/**
* List for UltraHDR Images
*/
private val ultraHDRImages = listOf(
ULTRA_HDR_IMAGE_1,
ULTRA_HDR_IMAGE_2,
ULTRA_HDR_IMAGE_3,
)

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = UltrahdrToHdrVideoBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.colorModeControls.setWindow(requireActivity().window)
binding.covertButton.setOnClickListener {
convertImagesToVideo()
}

val stream = context?.assets?.open(ULTRA_HDR_IMAGE_2)
val bitmap = BitmapFactory.decodeStream(stream)

binding.imageContainer.setImageBitmap(bitmap)
}

private fun convertImagesToVideo() = lifecycleScope.launch(Dispatchers.Main) {
val stream = context?.assets?.open(ULTRA_HDR_IMAGE_1)
val bitmap = BitmapFactory.decodeStream(stream)

val surface = encoder.createInputSurface()
val writer = ImageWriter.Builder(surface)
.setHardwareBufferFormat(HardwareBuffer.RGBA_1010102)
.setDataSpace(DataSpace.DATASPACE_BT2020_HLG)
.build()

val image = writer.dequeueInputImage()

val render =
renderImageFrameWithHardware(bitmap, image, ColorSpace.get(ColorSpace.Named.BT2020_HLG))

binding.imageContainer.setImageBitmap(render)
}

private suspend fun renderImageFrameWithHardware(
bitmap: Bitmap,
image: Image,
dest: ColorSpace,
): Bitmap = withContext(Dispatchers.IO) {
val renderer = HardwareBufferRenderer(image.hardwareBuffer!!)
val content = RenderNode("frame")
content.setPosition(0, 0, bitmap.width, bitmap.height)

val canvas = content.beginRecording()
canvas.drawBitmap(bitmap, .0f, .0f, null)
content.endRecording()

renderer.setContentRoot(content)
renderer.obtainRenderRequest()
.setColorSpace(dest)
.draw(
{ runnable -> runnable.run() },
) { result -> result.fence.awaitForever() }

return@withContext Bitmap.wrapHardwareBuffer(image.hardwareBuffer!!, dest)!!
}

override fun onDetach() {
super.onDetach()
binding.colorModeControls.detach()
}

companion object {
/**
* Tag
*/
private val TAG = UltraHDRToHDRVideo::class.java.simpleName

/**
* Sample UltraHDR images paths
*/
private const val ULTRA_HDR_IMAGE_1 = "gainmaps/desert_palms.jpg"
private const val ULTRA_HDR_IMAGE_2 = "gainmaps/desert_sunset.jpg"
private const val ULTRA_HDR_IMAGE_3 = "gainmaps/desert_wanda.jpg"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2023 The Android Open Source Project
~
~ 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
~
~ https://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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<com.example.platform.graphics.ultrahdr.common.ColorModeControls
android:id="@+id/color_mode_controls"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<Button
android:id="@+id/covert_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="16dp"
android:contentDescription="@null"
android:scaleType="fitCenter"
android:text="@string/ultrahdr_to_hdr_video_button_covert" />


<ImageView
android:id="@+id/image_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:contentDescription="@null" />


</LinearLayout>
20 changes: 20 additions & 0 deletions samples/media/ultrahdr/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2023 The Android Open Source Project
~
~ 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
~
~ https://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.
-->

<resources>
<!-- UltraHDR to HDR Video String -->
<string name="ultrahdr_to_hdr_video_button_covert">Convert To Video</string>
</resources>