Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "mojo/services/media/common/cpp/video_converter.h" | |
| 6 | |
| 7 namespace mojo { | |
| 8 namespace media { | |
| 9 | |
| 10 VideoConverter::VideoConverter() { | |
| 11 BuildColorspaceTable(); | |
| 12 } | |
| 13 | |
| 14 VideoConverter::~VideoConverter() {} | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 uint8_t ToByte(float f) { | |
| 19 if (f < 0.0f) { | |
|
kulakowski
2016/06/17 21:15:40
I'm paranoid having once seen someone spend days d
dalesat
2016/06/18 00:07:08
This isn't terribly critical, being temporary code
| |
| 20 return 0u; | |
| 21 } | |
| 22 | |
| 23 if (f > 255.0f) { | |
| 24 return 255u; | |
| 25 } | |
| 26 | |
| 27 return static_cast<uint8_t>(f); | |
| 28 } | |
| 29 | |
| 30 size_t ColorspaceTableOffset(uint8_t y, uint8_t u, uint8_t v) { | |
|
kulakowski
2016/06/17 21:15:40
Why do this math yourself and not write [y][u][v]?
dalesat
2016/06/18 00:07:08
I'm just not familiar with using arrays of arrays
| |
| 31 return (y << 8u | u) << 8u | v; | |
| 32 } | |
| 33 | |
| 34 } // namespace | |
| 35 | |
| 36 void VideoConverter::BuildColorspaceTable() { | |
| 37 colorspace_table_.reset(new uint32_t[256 * 256 * 256]); | |
| 38 | |
| 39 uint32_t* p = colorspace_table_.get(); | |
| 40 | |
| 41 for (float y = 0.0f; y < 256.0f; y += 1.0f) { | |
|
kulakowski
2016/06/17 21:15:40
I hope you typed these constants correctly :)
I b
dalesat
2016/06/18 00:07:08
Doing the iteration with ints rather than floats m
| |
| 42 for (float u = 0.0f; u < 256.0f; u += 1.0f) { | |
| 43 for (float v = 0.0f; v < 256.0f; v += 1.0f) { | |
| 44 // R = 1.164(Y - 16) + 1.596(V - 128) | |
| 45 uint8_t r = ToByte(1.164f * (y - 16.0f) + 1.596f * (v - 128.0f)); | |
| 46 | |
| 47 // G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) | |
| 48 uint8_t g = ToByte(1.164f * (y - 16.0f) - 0.813f * (v - 128.0f) - | |
| 49 0.391f * (u - 128.0f)); | |
| 50 | |
| 51 // B = 1.164(Y - 16) + 2.018(U - 128) | |
| 52 uint8_t b = ToByte(1.164f * (y - 16.0f) + 2.018f * (u - 128.0f)); | |
| 53 | |
| 54 *p = r | g << 8u | b << 16u | 255u << 24u; | |
|
kulakowski
2016/06/17 21:15:40
I and someone looking over my shoulder both are un
dalesat
2016/06/18 00:07:08
Done.
| |
| 55 ++p; | |
| 56 } | |
| 57 } | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 void VideoConverter::SetMediaType(const MediaTypePtr& media_type) { | |
| 62 MOJO_DCHECK(media_type); | |
| 63 MOJO_DCHECK(media_type->medium == MediaTypeMedium::VIDEO); | |
| 64 MOJO_DCHECK(media_type->encoding == MediaType::kVideoEncodingUncompressed); | |
| 65 MOJO_DCHECK(media_type->details); | |
| 66 | |
| 67 const VideoMediaTypeDetailsPtr& details = media_type->details->get_video(); | |
| 68 MOJO_DCHECK(details); | |
| 69 MOJO_DCHECK(details->pixel_format == PixelFormat::YV12) | |
| 70 << "only YV12 video conversion is currently implemented"; | |
| 71 | |
| 72 layout_ = | |
| 73 VideoPacketLayout(details->pixel_format, details->width, details->height, | |
| 74 details->coded_width, details->coded_height); | |
| 75 | |
| 76 media_type_set_ = true; | |
| 77 } | |
| 78 | |
| 79 void VideoConverter::ConvertFrame(uint8_t* rgba_buffer, | |
| 80 uint32_t view_width, | |
| 81 uint32_t view_height, | |
| 82 void* payload, | |
| 83 uint64_t payload_size) { | |
| 84 MOJO_DCHECK(rgba_buffer != nullptr); | |
| 85 MOJO_DCHECK(view_width != 0); | |
| 86 MOJO_DCHECK(view_height != 0); | |
| 87 MOJO_DCHECK(payload != nullptr); | |
| 88 MOJO_DCHECK(payload_size != 0); | |
| 89 MOJO_DCHECK(media_type_set_) | |
| 90 << "need to call SetMediaType before ConvertFrame"; | |
| 91 | |
| 92 uint32_t height = std::min(layout_.height(), view_height); | |
| 93 uint32_t width = std::min(layout_.width(), view_width); | |
| 94 | |
| 95 // YV12 frames have three separate planes. The Y plane has 8-bit Y values for | |
| 96 // each pixel. The U and V planes have 8-bit U and V values for 2x2 grids of | |
| 97 // pixels, so those planes are each 1/4 the size of the Y plane. Both the | |
| 98 // inner and outer loops below are unrolled to deal with the 2x2 logic. | |
| 99 | |
| 100 size_t dest_line_stride = view_width; | |
| 101 size_t y_line_stride = | |
| 102 layout_.line_stride_for_plane(VideoPacketLayout::kYPlaneIndex); | |
| 103 size_t u_line_stride = | |
| 104 layout_.line_stride_for_plane(VideoPacketLayout::kUPlaneIndex); | |
| 105 size_t v_line_stride = | |
| 106 layout_.line_stride_for_plane(VideoPacketLayout::kVPlaneIndex); | |
| 107 | |
| 108 uint32_t* dest_line = reinterpret_cast<uint32_t*>( | |
| 109 rgba_buffer + dest_line_stride * (view_height - 1) * sizeof(uint32_t)); | |
| 110 uint8_t* y_line = | |
| 111 reinterpret_cast<uint8_t*>(payload) + | |
| 112 layout_.plane_offset_for_plane(VideoPacketLayout::kYPlaneIndex); | |
| 113 uint8_t* u_line = | |
| 114 reinterpret_cast<uint8_t*>(payload) + | |
| 115 layout_.plane_offset_for_plane(VideoPacketLayout::kUPlaneIndex); | |
| 116 uint8_t* v_line = | |
| 117 reinterpret_cast<uint8_t*>(payload) + | |
| 118 layout_.plane_offset_for_plane(VideoPacketLayout::kVPlaneIndex); | |
| 119 | |
| 120 for (uint32_t line = 0; line < height; ++line) { | |
| 121 ConvertLine(dest_line, y_line, u_line, v_line, width); | |
| 122 | |
| 123 dest_line -= dest_line_stride; | |
| 124 y_line += y_line_stride; | |
| 125 // Notice we aren't updating u_line and v_line here. | |
| 126 | |
| 127 // If we hadn't unrolled the loop, it would have ended here. | |
| 128 if (++line == height) { | |
| 129 break; | |
| 130 } | |
| 131 | |
| 132 ConvertLine(dest_line, y_line, u_line, v_line, width); | |
| 133 | |
| 134 dest_line -= dest_line_stride; | |
| 135 y_line += y_line_stride; | |
| 136 // Here, we ARE updating u_line and v_line, because we've moved vertically | |
| 137 // out of the 2x2 grid. | |
| 138 u_line += u_line_stride; | |
| 139 v_line += v_line_stride; | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 void VideoConverter::ConvertLine(uint32_t* dest_pixel, | |
| 144 uint8_t* y_pixel, | |
| 145 uint8_t* u_pixel, | |
| 146 uint8_t* v_pixel, | |
| 147 uint32_t width) { | |
| 148 for (uint32_t pixel = 0; pixel < width; ++pixel) { | |
| 149 *dest_pixel = | |
| 150 colorspace_table_ | |
| 151 .get()[ColorspaceTableOffset(*y_pixel, *u_pixel, *v_pixel)]; | |
| 152 ++dest_pixel; | |
| 153 ++y_pixel; | |
| 154 // Notice we aren't incrementing u_pixel and v_pixel here. | |
| 155 | |
| 156 // If we hadn't unrolled the loop, it would have ended here. | |
| 157 if (++pixel == width) { | |
| 158 break; | |
| 159 } | |
| 160 | |
| 161 *dest_pixel = | |
| 162 colorspace_table_ | |
| 163 .get()[ColorspaceTableOffset(*y_pixel, *u_pixel, *v_pixel)]; | |
| 164 ++dest_pixel; | |
| 165 ++y_pixel; | |
| 166 // Here, we ARE incrementing u_pixel and v_pixel, because we've moved | |
| 167 // horizontally out of the 2x2 grid. | |
| 168 ++u_pixel; | |
| 169 ++v_pixel; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 } // namespace media | |
| 174 } // namespace mojo | |
| OLD | NEW |