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