| 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 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 return !coded_size.IsEmpty() && !visible_rect.IsEmpty() && | 188 return !coded_size.IsEmpty() && !visible_rect.IsEmpty() && |
| 189 !natural_size.IsEmpty(); | 189 !natural_size.IsEmpty(); |
| 190 } | 190 } |
| 191 | 191 |
| 192 // static | 192 // static |
| 193 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(VideoPixelFormat format, | 193 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(VideoPixelFormat format, |
| 194 const gfx::Size& coded_size, | 194 const gfx::Size& coded_size, |
| 195 const gfx::Rect& visible_rect, | 195 const gfx::Rect& visible_rect, |
| 196 const gfx::Size& natural_size, | 196 const gfx::Size& natural_size, |
| 197 base::TimeDelta timestamp) { | 197 base::TimeDelta timestamp) { |
| 198 if (!IsYuvPlanar(format)) { | 198 return CreateFrameInternal(format, coded_size, visible_rect, natural_size, |
| 199 NOTIMPLEMENTED(); | 199 timestamp, false); |
| 200 return nullptr; | |
| 201 } | |
| 202 | |
| 203 // Since we're creating a new YUV frame (and allocating memory for it | |
| 204 // ourselves), we can pad the requested |coded_size| if necessary if the | |
| 205 // request does not line up on sample boundaries. See discussion at | |
| 206 // http://crrev.com/1240833003 | |
| 207 const gfx::Size alignment = CommonAlignment(format); | |
| 208 const gfx::Size new_coded_size = | |
| 209 gfx::Size(RoundUp(coded_size.width(), alignment.width()), | |
| 210 RoundUp(coded_size.height(), alignment.height())); | |
| 211 DCHECK((new_coded_size.width() % alignment.width() == 0) && | |
| 212 (new_coded_size.height() % alignment.height() == 0)); | |
| 213 | |
| 214 const StorageType storage = STORAGE_OWNED_MEMORY; | |
| 215 if (!IsValidConfig(format, storage, new_coded_size, visible_rect, | |
| 216 natural_size)) { | |
| 217 DLOG(ERROR) << __FUNCTION__ << " Invalid config." | |
| 218 << ConfigToString(format, storage, coded_size, visible_rect, | |
| 219 natural_size); | |
| 220 return nullptr; | |
| 221 } | |
| 222 | |
| 223 scoped_refptr<VideoFrame> frame(new VideoFrame( | |
| 224 format, storage, new_coded_size, visible_rect, natural_size, timestamp)); | |
| 225 frame->AllocateYUV(); | |
| 226 return frame; | |
| 227 } | 200 } |
| 228 | 201 |
| 229 // static | 202 // static |
| 203 scoped_refptr<VideoFrame> VideoFrame::CreateZeroInitializedFrame( |
| 204 VideoPixelFormat format, |
| 205 const gfx::Size& coded_size, |
| 206 const gfx::Rect& visible_rect, |
| 207 const gfx::Size& natural_size, |
| 208 base::TimeDelta timestamp) { |
| 209 return CreateFrameInternal(format, coded_size, visible_rect, natural_size, |
| 210 timestamp, true); |
| 211 } |
| 212 |
| 213 // static |
| 230 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( | 214 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( |
| 231 VideoPixelFormat format, | 215 VideoPixelFormat format, |
| 232 const gpu::MailboxHolder& mailbox_holder, | 216 const gpu::MailboxHolder& mailbox_holder, |
| 233 const ReleaseMailboxCB& mailbox_holder_release_cb, | 217 const ReleaseMailboxCB& mailbox_holder_release_cb, |
| 234 const gfx::Size& coded_size, | 218 const gfx::Size& coded_size, |
| 235 const gfx::Rect& visible_rect, | 219 const gfx::Rect& visible_rect, |
| 236 const gfx::Size& natural_size, | 220 const gfx::Size& natural_size, |
| 237 base::TimeDelta timestamp) { | 221 base::TimeDelta timestamp) { |
| 238 if (format != PIXEL_FORMAT_ARGB && format != PIXEL_FORMAT_UYVY) { | 222 if (format != PIXEL_FORMAT_ARGB && format != PIXEL_FORMAT_UYVY) { |
| 239 DLOG(ERROR) << "Unsupported pixel format supported, got " | 223 DLOG(ERROR) << "Unsupported pixel format supported, got " |
| (...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 base::AutoLock locker(release_sync_point_lock_); | 874 base::AutoLock locker(release_sync_point_lock_); |
| 891 release_sync_point = release_sync_point_; | 875 release_sync_point = release_sync_point_; |
| 892 } | 876 } |
| 893 base::ResetAndReturn(&mailbox_holders_release_cb_).Run(release_sync_point); | 877 base::ResetAndReturn(&mailbox_holders_release_cb_).Run(release_sync_point); |
| 894 } | 878 } |
| 895 | 879 |
| 896 for (auto& callback : done_callbacks_) | 880 for (auto& callback : done_callbacks_) |
| 897 base::ResetAndReturn(&callback).Run(); | 881 base::ResetAndReturn(&callback).Run(); |
| 898 } | 882 } |
| 899 | 883 |
| 900 void VideoFrame::AllocateYUV() { | 884 // static |
| 885 scoped_refptr<VideoFrame> VideoFrame::CreateFrameInternal( |
| 886 VideoPixelFormat format, |
| 887 const gfx::Size& coded_size, |
| 888 const gfx::Rect& visible_rect, |
| 889 const gfx::Size& natural_size, |
| 890 base::TimeDelta timestamp, |
| 891 bool zero_initialize_memory) { |
| 892 if (!IsYuvPlanar(format)) { |
| 893 NOTIMPLEMENTED(); |
| 894 return nullptr; |
| 895 } |
| 896 |
| 897 // Since we're creating a new YUV frame (and allocating memory for it |
| 898 // ourselves), we can pad the requested |coded_size| if necessary if the |
| 899 // request does not line up on sample boundaries. See discussion at |
| 900 // http://crrev.com/1240833003 |
| 901 const gfx::Size alignment = CommonAlignment(format); |
| 902 const gfx::Size new_coded_size = |
| 903 gfx::Size(RoundUp(coded_size.width(), alignment.width()), |
| 904 RoundUp(coded_size.height(), alignment.height())); |
| 905 DCHECK((new_coded_size.width() % alignment.width() == 0) && |
| 906 (new_coded_size.height() % alignment.height() == 0)); |
| 907 |
| 908 const StorageType storage = STORAGE_OWNED_MEMORY; |
| 909 if (!IsValidConfig(format, storage, new_coded_size, visible_rect, |
| 910 natural_size)) { |
| 911 DLOG(ERROR) << __FUNCTION__ << " Invalid config." |
| 912 << ConfigToString(format, storage, coded_size, visible_rect, |
| 913 natural_size); |
| 914 return nullptr; |
| 915 } |
| 916 |
| 917 scoped_refptr<VideoFrame> frame(new VideoFrame( |
| 918 format, storage, new_coded_size, visible_rect, natural_size, timestamp)); |
| 919 frame->AllocateYUV(zero_initialize_memory); |
| 920 return frame; |
| 921 } |
| 922 |
| 923 void VideoFrame::AllocateYUV(bool zero_initialize_memory) { |
| 901 DCHECK_EQ(storage_type_, STORAGE_OWNED_MEMORY); | 924 DCHECK_EQ(storage_type_, STORAGE_OWNED_MEMORY); |
| 902 static_assert(0 == kYPlane, "y plane data must be index 0"); | 925 static_assert(0 == kYPlane, "y plane data must be index 0"); |
| 903 | 926 |
| 904 size_t data_size = 0; | 927 size_t data_size = 0; |
| 905 size_t offset[kMaxPlanes]; | 928 size_t offset[kMaxPlanes]; |
| 906 for (size_t plane = 0; plane < NumPlanes(format_); ++plane) { | 929 for (size_t plane = 0; plane < NumPlanes(format_); ++plane) { |
| 907 // The *2 in alignment for height is because some formats (e.g. h264) allow | 930 // The *2 in alignment for height is because some formats (e.g. h264) allow |
| 908 // interlaced coding, and then the size needs to be a multiple of two | 931 // interlaced coding, and then the size needs to be a multiple of two |
| 909 // macroblocks (vertically). See | 932 // macroblocks (vertically). See |
| 910 // libavcodec/utils.c:avcodec_align_dimensions2(). | 933 // libavcodec/utils.c:avcodec_align_dimensions2(). |
| 911 const size_t height = RoundUp(rows(plane), kFrameSizeAlignment * 2); | 934 const size_t height = RoundUp(rows(plane), kFrameSizeAlignment * 2); |
| 912 strides_[plane] = RoundUp(row_bytes(plane), kFrameSizeAlignment); | 935 strides_[plane] = RoundUp(row_bytes(plane), kFrameSizeAlignment); |
| 913 offset[plane] = data_size; | 936 offset[plane] = data_size; |
| 914 data_size += height * strides_[plane]; | 937 data_size += height * strides_[plane]; |
| 915 } | 938 } |
| 916 | 939 |
| 917 // The extra line of UV being allocated is because h264 chroma MC | 940 // The extra line of UV being allocated is because h264 chroma MC |
| 918 // overreads by one line in some cases, see libavcodec/utils.c: | 941 // overreads by one line in some cases, see libavcodec/utils.c: |
| 919 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: | 942 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm: |
| 920 // put_h264_chroma_mc4_ssse3(). | 943 // put_h264_chroma_mc4_ssse3(). |
| 921 DCHECK(IsValidPlane(kUPlane, format_)); | 944 DCHECK(IsValidPlane(kUPlane, format_)); |
| 922 data_size += strides_[kUPlane] + kFrameSizePadding; | 945 data_size += strides_[kUPlane] + kFrameSizePadding; |
| 923 | 946 |
| 924 uint8* data = reinterpret_cast<uint8*>( | 947 uint8* data = reinterpret_cast<uint8*>( |
| 925 base::AlignedAlloc(data_size, kFrameAddressAlignment)); | 948 base::AlignedAlloc(data_size, kFrameAddressAlignment)); |
| 949 if (zero_initialize_memory) |
| 950 memset(data, 0, data_size); |
| 926 | 951 |
| 927 for (size_t plane = 0; plane < NumPlanes(format_); ++plane) | 952 for (size_t plane = 0; plane < NumPlanes(format_); ++plane) |
| 928 data_[plane] = data + offset[plane]; | 953 data_[plane] = data + offset[plane]; |
| 929 | 954 |
| 930 AddDestructionObserver(base::Bind(&base::AlignedFree, data)); | 955 AddDestructionObserver(base::Bind(&base::AlignedFree, data)); |
| 931 } | 956 } |
| 932 | 957 |
| 933 } // namespace media | 958 } // namespace media |
| OLD | NEW |