| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/video_frame.h" | 5 #include "media/base/video_frame.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 case VideoFrame::I420: | 60 case VideoFrame::I420: |
| 61 case VideoFrame::YV12A: | 61 case VideoFrame::YV12A: |
| 62 case VideoFrame::NV12: | 62 case VideoFrame::NV12: |
| 63 return gfx::Size(2, 2); | 63 return gfx::Size(2, 2); |
| 64 | 64 |
| 65 case VideoFrame::UNKNOWN: | 65 case VideoFrame::UNKNOWN: |
| 66 #if defined(VIDEO_HOLE) | 66 #if defined(VIDEO_HOLE) |
| 67 case VideoFrame::HOLE: | 67 case VideoFrame::HOLE: |
| 68 #endif // defined(VIDEO_HOLE) | 68 #endif // defined(VIDEO_HOLE) |
| 69 case VideoFrame::NATIVE_TEXTURE: | 69 case VideoFrame::NATIVE_TEXTURE: |
| 70 case VideoFrame::ARGB: | |
| 71 break; | 70 break; |
| 72 } | 71 } |
| 73 } | 72 } |
| 74 NOTREACHED(); | 73 NOTREACHED(); |
| 75 return gfx::Size(); | 74 return gfx::Size(); |
| 76 } | 75 } |
| 77 | 76 |
| 78 // Return the alignment for the whole frame, calculated as the max of the | 77 // Return the alignment for the whole frame, calculated as the max of the |
| 79 // alignment for each individual plane. | 78 // alignment for each individual plane. |
| 80 static gfx::Size CommonAlignment(VideoFrame::Format format) { | 79 static gfx::Size CommonAlignment(VideoFrame::Format format) { |
| 81 int max_sample_width = 0; | 80 int max_sample_width = 0; |
| 82 int max_sample_height = 0; | 81 int max_sample_height = 0; |
| 83 for (size_t plane = 0; plane < VideoFrame::NumPlanes(format); ++plane) { | 82 for (size_t plane = 0; plane < VideoFrame::NumPlanes(format); ++plane) { |
| 84 const gfx::Size sample_size = SampleSize(format, plane); | 83 const gfx::Size sample_size = SampleSize(format, plane); |
| 85 max_sample_width = std::max(max_sample_width, sample_size.width()); | 84 max_sample_width = std::max(max_sample_width, sample_size.width()); |
| 86 max_sample_height = std::max(max_sample_height, sample_size.height()); | 85 max_sample_height = std::max(max_sample_height, sample_size.height()); |
| 87 } | 86 } |
| 88 return gfx::Size(max_sample_width, max_sample_height); | 87 return gfx::Size(max_sample_width, max_sample_height); |
| 89 } | 88 } |
| 90 | 89 |
| 91 // Returns the number of bytes per element for given |plane| and |format|. E.g. | 90 // Returns the number of bytes per element for given |plane| and |format|. E.g. |
| 92 // 2 for the UV plane in NV12. | 91 // 2 for the UV plane in NV12. |
| 93 static int BytesPerElement(VideoFrame::Format format, size_t plane) { | 92 static int BytesPerElement(VideoFrame::Format format, size_t plane) { |
| 94 DCHECK(VideoFrame::IsValidPlane(plane, format)); | 93 DCHECK(VideoFrame::IsValidPlane(plane, format)); |
| 95 if (format == VideoFrame::ARGB) | 94 return (format == VideoFrame::NV12 && plane == VideoFrame::kUVPlane) ? 2 : 1; |
| 96 return 4; | |
| 97 | |
| 98 if (format == VideoFrame::NV12 && plane == VideoFrame::kUVPlane) | |
| 99 return 2; | |
| 100 | |
| 101 return 1; | |
| 102 } | 95 } |
| 103 | 96 |
| 104 // Rounds up |coded_size| if necessary for |format|. | 97 // Rounds up |coded_size| if necessary for |format|. |
| 105 static gfx::Size AdjustCodedSize(VideoFrame::Format format, | 98 static gfx::Size AdjustCodedSize(VideoFrame::Format format, |
| 106 const gfx::Size& coded_size) { | 99 const gfx::Size& coded_size) { |
| 107 const gfx::Size alignment = CommonAlignment(format); | 100 const gfx::Size alignment = CommonAlignment(format); |
| 108 return gfx::Size(RoundUp(coded_size.width(), alignment.width()), | 101 return gfx::Size(RoundUp(coded_size.width(), alignment.width()), |
| 109 RoundUp(coded_size.height(), alignment.height())); | 102 RoundUp(coded_size.height(), alignment.height())); |
| 110 } | 103 } |
| 111 | 104 |
| 112 // static | 105 // static |
| 113 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( | 106 scoped_refptr<VideoFrame> VideoFrame::CreateFrame( |
| 114 VideoFrame::Format format, | 107 VideoFrame::Format format, |
| 115 const gfx::Size& coded_size, | 108 const gfx::Size& coded_size, |
| 116 const gfx::Rect& visible_rect, | 109 const gfx::Rect& visible_rect, |
| 117 const gfx::Size& natural_size, | 110 const gfx::Size& natural_size, |
| 118 base::TimeDelta timestamp) { | 111 base::TimeDelta timestamp) { |
| 119 switch (format) { | 112 DCHECK(format != VideoFrame::UNKNOWN && |
| 120 case VideoFrame::YV12: | 113 format != VideoFrame::NV12 && |
| 121 case VideoFrame::YV16: | 114 format != VideoFrame::NATIVE_TEXTURE); |
| 122 case VideoFrame::I420: | |
| 123 case VideoFrame::YV12A: | |
| 124 case VideoFrame::YV12J: | |
| 125 case VideoFrame::YV24: | |
| 126 break; | |
| 127 | |
| 128 case VideoFrame::UNKNOWN: | |
| 129 case VideoFrame::NV12: | |
| 130 case VideoFrame::NATIVE_TEXTURE: | |
| 131 #if defined(VIDEO_HOLE) | 115 #if defined(VIDEO_HOLE) |
| 132 case VideoFrame::HOLE: | 116 DCHECK(format != VideoFrame::HOLE); |
| 133 #endif // defined(VIDEO_HOLE) | 117 #endif // defined(VIDEO_HOLE) |
| 134 case VideoFrame::ARGB: | |
| 135 NOTIMPLEMENTED(); | |
| 136 return nullptr; | |
| 137 } | |
| 138 | 118 |
| 139 // Since we're creating a new YUV frame (and allocating memory for it | 119 // Since we're creating a new YUV frame (and allocating memory for it |
| 140 // ourselves), we can pad the requested |coded_size| if necessary if the | 120 // ourselves), we can pad the requested |coded_size| if necessary if the |
| 141 // request does not line up on sample boundaries. | 121 // request does not line up on sample boundaries. |
| 142 const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); | 122 const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size); |
| 143 DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size)); | 123 DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size)); |
| 144 | 124 |
| 145 scoped_refptr<VideoFrame> frame( | 125 scoped_refptr<VideoFrame> frame( |
| 146 new VideoFrame(format, | 126 new VideoFrame(format, |
| 147 new_coded_size, | 127 new_coded_size, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 172 return "HOLE"; | 152 return "HOLE"; |
| 173 #endif // defined(VIDEO_HOLE) | 153 #endif // defined(VIDEO_HOLE) |
| 174 case VideoFrame::YV12A: | 154 case VideoFrame::YV12A: |
| 175 return "YV12A"; | 155 return "YV12A"; |
| 176 case VideoFrame::YV12J: | 156 case VideoFrame::YV12J: |
| 177 return "YV12J"; | 157 return "YV12J"; |
| 178 case VideoFrame::NV12: | 158 case VideoFrame::NV12: |
| 179 return "NV12"; | 159 return "NV12"; |
| 180 case VideoFrame::YV24: | 160 case VideoFrame::YV24: |
| 181 return "YV24"; | 161 return "YV24"; |
| 182 case VideoFrame::ARGB: | |
| 183 return "ARGB"; | |
| 184 } | 162 } |
| 185 NOTREACHED() << "Invalid videoframe format provided: " << format; | 163 NOTREACHED() << "Invalid videoframe format provided: " << format; |
| 186 return ""; | 164 return ""; |
| 187 } | 165 } |
| 188 | 166 |
| 189 // static | 167 // static |
| 190 bool VideoFrame::IsValidConfig(VideoFrame::Format format, | 168 bool VideoFrame::IsValidConfig(VideoFrame::Format format, |
| 191 const gfx::Size& coded_size, | 169 const gfx::Size& coded_size, |
| 192 const gfx::Rect& visible_rect, | 170 const gfx::Rect& visible_rect, |
| 193 const gfx::Size& natural_size) { | 171 const gfx::Size& natural_size) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 217 #endif // defined(VIDEO_HOLE) | 195 #endif // defined(VIDEO_HOLE) |
| 218 return true; | 196 return true; |
| 219 | 197 |
| 220 case VideoFrame::YV24: | 198 case VideoFrame::YV24: |
| 221 case VideoFrame::YV12: | 199 case VideoFrame::YV12: |
| 222 case VideoFrame::YV12J: | 200 case VideoFrame::YV12J: |
| 223 case VideoFrame::I420: | 201 case VideoFrame::I420: |
| 224 case VideoFrame::YV12A: | 202 case VideoFrame::YV12A: |
| 225 case VideoFrame::NV12: | 203 case VideoFrame::NV12: |
| 226 case VideoFrame::YV16: | 204 case VideoFrame::YV16: |
| 227 case VideoFrame::ARGB: | |
| 228 // Check that software-allocated buffer formats are aligned correctly and | 205 // Check that software-allocated buffer formats are aligned correctly and |
| 229 // not empty. | 206 // not empty. |
| 230 const gfx::Size alignment = CommonAlignment(format); | 207 const gfx::Size alignment = CommonAlignment(format); |
| 231 return RoundUp(visible_rect.right(), alignment.width()) <= | 208 return RoundUp(visible_rect.right(), alignment.width()) <= |
| 232 static_cast<size_t>(coded_size.width()) && | 209 static_cast<size_t>(coded_size.width()) && |
| 233 RoundUp(visible_rect.bottom(), alignment.height()) <= | 210 RoundUp(visible_rect.bottom(), alignment.height()) <= |
| 234 static_cast<size_t>(coded_size.height()) && | 211 static_cast<size_t>(coded_size.height()) && |
| 235 !coded_size.IsEmpty() && !visible_rect.IsEmpty() && | 212 !coded_size.IsEmpty() && !visible_rect.IsEmpty() && |
| 236 !natural_size.IsEmpty(); | 213 !natural_size.IsEmpty(); |
| 237 } | 214 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 Format format, | 297 Format format, |
| 321 const gfx::Size& coded_size, | 298 const gfx::Size& coded_size, |
| 322 const gfx::Rect& visible_rect, | 299 const gfx::Rect& visible_rect, |
| 323 const gfx::Size& natural_size, | 300 const gfx::Size& natural_size, |
| 324 const std::vector<int> dmabuf_fds, | 301 const std::vector<int> dmabuf_fds, |
| 325 base::TimeDelta timestamp, | 302 base::TimeDelta timestamp, |
| 326 const base::Closure& no_longer_needed_cb) { | 303 const base::Closure& no_longer_needed_cb) { |
| 327 if (!IsValidConfig(format, coded_size, visible_rect, natural_size)) | 304 if (!IsValidConfig(format, coded_size, visible_rect, natural_size)) |
| 328 return NULL; | 305 return NULL; |
| 329 | 306 |
| 330 // TODO(posciak): This is not exactly correct, it's possible for one | |
| 331 // buffer to contain more than one plane. | |
| 332 if (dmabuf_fds.size() != NumPlanes(format)) { | 307 if (dmabuf_fds.size() != NumPlanes(format)) { |
| 333 LOG(FATAL) << "Not enough dmabuf fds provided!"; | 308 LOG(FATAL) << "Not enough dmabuf fds provided!"; |
| 334 return NULL; | 309 return NULL; |
| 335 } | 310 } |
| 336 | 311 |
| 337 scoped_refptr<VideoFrame> frame( | 312 scoped_refptr<VideoFrame> frame( |
| 338 new VideoFrame(format, | 313 new VideoFrame(format, |
| 339 coded_size, | 314 coded_size, |
| 340 visible_rect, | 315 visible_rect, |
| 341 natural_size, | 316 natural_size, |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 #endif // defined(VIDEO_HOLE) | 515 #endif // defined(VIDEO_HOLE) |
| 541 | 516 |
| 542 // static | 517 // static |
| 543 size_t VideoFrame::NumPlanes(Format format) { | 518 size_t VideoFrame::NumPlanes(Format format) { |
| 544 switch (format) { | 519 switch (format) { |
| 545 case VideoFrame::NATIVE_TEXTURE: | 520 case VideoFrame::NATIVE_TEXTURE: |
| 546 #if defined(VIDEO_HOLE) | 521 #if defined(VIDEO_HOLE) |
| 547 case VideoFrame::HOLE: | 522 case VideoFrame::HOLE: |
| 548 #endif // defined(VIDEO_HOLE) | 523 #endif // defined(VIDEO_HOLE) |
| 549 return 0; | 524 return 0; |
| 550 case VideoFrame::ARGB: | |
| 551 return 1; | |
| 552 case VideoFrame::NV12: | 525 case VideoFrame::NV12: |
| 553 return 2; | 526 return 2; |
| 554 case VideoFrame::YV12: | 527 case VideoFrame::YV12: |
| 555 case VideoFrame::YV16: | 528 case VideoFrame::YV16: |
| 556 case VideoFrame::I420: | 529 case VideoFrame::I420: |
| 557 case VideoFrame::YV12J: | 530 case VideoFrame::YV12J: |
| 558 case VideoFrame::YV24: | 531 case VideoFrame::YV24: |
| 559 return 3; | 532 return 3; |
| 560 case VideoFrame::YV12A: | 533 case VideoFrame::YV12A: |
| 561 return 4; | 534 return 4; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 574 total += PlaneAllocationSize(format, i, coded_size); | 547 total += PlaneAllocationSize(format, i, coded_size); |
| 575 return total; | 548 return total; |
| 576 } | 549 } |
| 577 | 550 |
| 578 // static | 551 // static |
| 579 gfx::Size VideoFrame::PlaneSize(Format format, | 552 gfx::Size VideoFrame::PlaneSize(Format format, |
| 580 size_t plane, | 553 size_t plane, |
| 581 const gfx::Size& coded_size) { | 554 const gfx::Size& coded_size) { |
| 582 DCHECK(IsValidPlane(plane, format)); | 555 DCHECK(IsValidPlane(plane, format)); |
| 583 | 556 |
| 584 int width = coded_size.width(); | 557 // Align to multiple-of-two size overall. This ensures that non-subsampled |
| 585 int height = coded_size.height(); | 558 // planes can be addressed by pixel with the same scaling as the subsampled |
| 586 if (format != VideoFrame::ARGB) { | 559 // planes. |
| 587 // Align to multiple-of-two size overall. This ensures that non-subsampled | 560 const int width = RoundUp(coded_size.width(), 2); |
| 588 // planes can be addressed by pixel with the same scaling as the subsampled | 561 const int height = RoundUp(coded_size.height(), 2); |
| 589 // planes. | |
| 590 width = RoundUp(width, 2); | |
| 591 height = RoundUp(height, 2); | |
| 592 } | |
| 593 | 562 |
| 594 const gfx::Size subsample = SampleSize(format, plane); | 563 const gfx::Size subsample = SampleSize(format, plane); |
| 595 DCHECK(width % subsample.width() == 0); | 564 DCHECK(width % subsample.width() == 0); |
| 596 DCHECK(height % subsample.height() == 0); | 565 DCHECK(height % subsample.height() == 0); |
| 597 return gfx::Size(BytesPerElement(format, plane) * width / subsample.width(), | 566 return gfx::Size(BytesPerElement(format, plane) * width / subsample.width(), |
| 598 height / subsample.height()); | 567 height / subsample.height()); |
| 599 } | 568 } |
| 600 | 569 |
| 601 size_t VideoFrame::PlaneAllocationSize(Format format, | 570 size_t VideoFrame::PlaneAllocationSize(Format format, |
| 602 size_t plane, | 571 size_t plane, |
| 603 const gfx::Size& coded_size) { | 572 const gfx::Size& coded_size) { |
| 573 // VideoFrame formats are (so far) all YUV and 1 byte per sample. |
| 604 return PlaneSize(format, plane, coded_size).GetArea(); | 574 return PlaneSize(format, plane, coded_size).GetArea(); |
| 605 } | 575 } |
| 606 | 576 |
| 607 // static | 577 // static |
| 608 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) { | 578 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) { |
| 609 DCHECK(IsValidPlane(plane, format)); | 579 DCHECK(IsValidPlane(plane, format)); |
| 610 const int bits_per_element = 8 * BytesPerElement(format, plane); | 580 const int bits_per_element = 8 * BytesPerElement(format, plane); |
| 611 const int horiz_pixels_per_element = SampleSize(format, plane).width(); | 581 const int pixels_per_element = SampleSize(format, plane).width(); |
| 612 DCHECK_EQ(bits_per_element % horiz_pixels_per_element, 0); | 582 DCHECK(bits_per_element % pixels_per_element == 0); |
| 613 return bits_per_element / horiz_pixels_per_element; | 583 return bits_per_element / pixels_per_element; |
| 614 } | 584 } |
| 615 | 585 |
| 616 // static | 586 // static |
| 617 int VideoFrame::PlaneBitsPerPixel(Format format, size_t plane) { | 587 int VideoFrame::PlaneBitsPerPixel(Format format, size_t plane) { |
| 618 DCHECK(IsValidPlane(plane, format)); | 588 DCHECK(IsValidPlane(plane, format)); |
| 619 return PlaneHorizontalBitsPerPixel(format, plane) / | 589 return PlaneHorizontalBitsPerPixel(format, plane) / |
| 620 SampleSize(format, plane).height(); | 590 SampleSize(format, plane).height(); |
| 621 } | 591 } |
| 622 | 592 |
| 623 // Release data allocated by AllocateYUV(). | 593 // Release data allocated by AllocateYUV(). |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 808 for (size_t plane = 0; plane < NumPlanes(format_); ++plane) { | 778 for (size_t plane = 0; plane < NumPlanes(format_); ++plane) { |
| 809 for (int row = 0; row < rows(plane); ++row) { | 779 for (int row = 0; row < rows(plane); ++row) { |
| 810 base::MD5Update(context, base::StringPiece( | 780 base::MD5Update(context, base::StringPiece( |
| 811 reinterpret_cast<char*>(data(plane) + stride(plane) * row), | 781 reinterpret_cast<char*>(data(plane) + stride(plane) * row), |
| 812 row_bytes(plane))); | 782 row_bytes(plane))); |
| 813 } | 783 } |
| 814 } | 784 } |
| 815 } | 785 } |
| 816 | 786 |
| 817 } // namespace media | 787 } // namespace media |
| OLD | NEW |